[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen master] x86: support SMBIOS v3



commit 54057a28f22b4f398933d8d136475285bdfd4f83
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Thu Jan 29 14:24:04 2015 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Thu Jan 29 14:24:04 2015 +0100

    x86: support SMBIOS v3
    
    While presumably of primary use to ARM64 (once the code gets
    generalized), we should still support this more modern variant,
    allowing for the actual DMI data to reside in memory above 4Gb.
    
    While based on draft version 3.0.0d, it is assumed that the final
    version of the specification will not render this implementation
    invalid (not the least because Linux 3.19 already makes the same
    assumption).
    
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Acked-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
---
 xen/arch/x86/dmi_scan.c  |  303 +++++++++++++++++++++++++++++++++++-----------
 xen/arch/x86/e820.c      |   18 ++-
 xen/common/efi/boot.c    |   11 ++-
 xen/common/efi/runtime.c |    1 +
 xen/include/xen/dmi.h    |    4 +-
 xen/include/xen/efi.h    |    1 +
 6 files changed, 260 insertions(+), 78 deletions(-)

diff --git a/xen/arch/x86/dmi_scan.c b/xen/arch/x86/dmi_scan.c
index 500133a..187c01e 100644
--- a/xen/arch/x86/dmi_scan.c
+++ b/xen/arch/x86/dmi_scan.c
@@ -38,6 +38,18 @@ struct __packed smbios_eps {
        struct dmi_eps dmi;
 };
 
+struct __packed smbios3_eps {
+       char anchor[5];                 /* "_SM3_" */
+       u8 checksum;
+       u8 length;
+       u8 major, minor;
+       u8 docrev;
+       u8 revision;
+       u8 _rsrvd_;
+       u32 max_size;
+       u64 address;
+};
+
 struct dmi_header
 {
        u8      type;
@@ -45,6 +57,53 @@ struct dmi_header
        u16     handle;
 };
 
+enum dmi_entry_type {
+       DMI_ENTRY_BIOS = 0,
+       DMI_ENTRY_SYSTEM,
+       DMI_ENTRY_BASEBOARD,
+       DMI_ENTRY_CHASSIS,
+       DMI_ENTRY_PROCESSOR,
+       DMI_ENTRY_MEM_CONTROLLER,
+       DMI_ENTRY_MEM_MODULE,
+       DMI_ENTRY_CACHE,
+       DMI_ENTRY_PORT_CONNECTOR,
+       DMI_ENTRY_SYSTEM_SLOT,
+       DMI_ENTRY_ONBOARD_DEVICE,
+       DMI_ENTRY_OEMSTRINGS,
+       DMI_ENTRY_SYSCONF,
+       DMI_ENTRY_BIOS_LANG,
+       DMI_ENTRY_GROUP_ASSOC,
+       DMI_ENTRY_SYSTEM_EVENT_LOG,
+       DMI_ENTRY_PHYS_MEM_ARRAY,
+       DMI_ENTRY_MEM_DEVICE,
+       DMI_ENTRY_32_MEM_ERROR,
+       DMI_ENTRY_MEM_ARRAY_MAPPED_ADDR,
+       DMI_ENTRY_MEM_DEV_MAPPED_ADDR,
+       DMI_ENTRY_BUILTIN_POINTING_DEV,
+       DMI_ENTRY_PORTABLE_BATTERY,
+       DMI_ENTRY_SYSTEM_RESET,
+       DMI_ENTRY_HW_SECURITY,
+       DMI_ENTRY_SYSTEM_POWER_CONTROLS,
+       DMI_ENTRY_VOLTAGE_PROBE,
+       DMI_ENTRY_COOLING_DEV,
+       DMI_ENTRY_TEMP_PROBE,
+       DMI_ENTRY_ELECTRICAL_CURRENT_PROBE,
+       DMI_ENTRY_OOB_REMOTE_ACCESS,
+       DMI_ENTRY_BIS_ENTRY,
+       DMI_ENTRY_SYSTEM_BOOT,
+       DMI_ENTRY_MGMT_DEV,
+       DMI_ENTRY_MGMT_DEV_COMPONENT,
+       DMI_ENTRY_MGMT_DEV_THRES,
+       DMI_ENTRY_MEM_CHANNEL,
+       DMI_ENTRY_IPMI_DEV,
+       DMI_ENTRY_SYS_POWER_SUPPLY,
+       DMI_ENTRY_ADDITIONAL,
+       DMI_ENTRY_ONBOARD_DEV_EXT,
+       DMI_ENTRY_MGMT_CONTROLLER_HOST,
+       DMI_ENTRY_INACTIVE = 126,
+       DMI_ENTRY_END_OF_TABLE = 127,
+};
+
 #undef DMI_DEBUG
 
 #ifdef DMI_DEBUG
@@ -74,7 +133,8 @@ static char * __init dmi_string(struct dmi_header *dm, u8 s)
  *     pointing to completely the wrong place for example
  */
  
-static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct 
dmi_header *))
+static int __init dmi_table(paddr_t base, u32 len, int num,
+                           void (*decode)(struct dmi_header *))
 {
        u8 *buf;
        struct dmi_header *dm;
@@ -92,7 +152,7 @@ static int __init dmi_table(u32 base, int len, int num, void 
(*decode)(struct dm
         *      OR we run off the end of the table (also happens)
         */
  
-       while(i<num && data-buf+sizeof(struct dmi_header)<=len)
+       while((num < 0 || i < num) && data-buf+sizeof(struct dmi_header)<=len)
        {
                dm=(struct dmi_header *)data;
                /*
@@ -105,6 +165,8 @@ static int __init dmi_table(u32 base, int len, int num, 
void (*decode)(struct dm
                        data++;
                if(data-buf<len-1)
                        decode(dm);
+               if (dm->type == DMI_ENTRY_END_OF_TABLE)
+                   break;
                data+=2;
                i++;
        }
@@ -127,16 +189,28 @@ static inline bool_t __init dmi_checksum(const void 
__iomem *buf,
 
 static u32 __initdata efi_dmi_address;
 static u32 __initdata efi_dmi_size;
+static u64 __initdata efi_smbios3_address;
+static u32 __initdata efi_smbios3_size;
 
 /*
  * Important: This function gets called while still in EFI
  * (pseudo-)physical mode.
  */
-void __init dmi_efi_get_table(void *smbios)
+void __init dmi_efi_get_table(const void *smbios, const void *smbios3)
 {
-       struct smbios_eps *eps = smbios;
+       const struct smbios_eps *eps = smbios;
+       const struct smbios3_eps *eps3 = smbios3;
+
+       if (eps3 && memcmp(eps3->anchor, "_SM3_", 5) &&
+           eps3->length >= sizeof(*eps3) &&
+           dmi_checksum(eps3, eps3->length)) {
+               efi_smbios3_address = eps3->address;
+               efi_smbios3_size = eps3->max_size;
+               return;
+       }
 
-       if (memcmp(eps->anchor, "_SM_", 4) &&
+       if (eps && memcmp(eps->anchor, "_SM_", 4) &&
+           eps->length >= sizeof(*eps) &&
            dmi_checksum(eps, eps->length) &&
            memcmp(eps->dmi.anchor, "_DMI_", 5) == 0 &&
            dmi_checksum(&eps->dmi, sizeof(eps->dmi))) {
@@ -145,99 +219,190 @@ void __init dmi_efi_get_table(void *smbios)
        }
 }
 
-int __init dmi_get_table(u32 *base, u32 *len)
+const char *__init dmi_get_table(paddr_t *base, u32 *len)
 {
-       struct dmi_eps eps;
-       char __iomem *p, *q;
+       static unsigned int __initdata instance;
 
        if (efi_enabled) {
-               if (!efi_dmi_size)
-                       return -1;
-               *base = efi_dmi_address;
-               *len = efi_dmi_size;
-               return 0;
-       }
-
-       p = maddr_to_virt(0xF0000);
-       for (q = p; q < p + 0x10000; q += 16) {
-               memcpy_fromio(&eps, q, 15);
-               if (memcmp(eps.anchor, "_DMI_", 5) == 0 &&
-                   dmi_checksum(&eps, sizeof(eps))) {
-                       *base = eps.address;
-                       *len = eps.size;
-                       return 0;
+               if (efi_smbios3_size && !(instance & 1)) {
+                       *base = efi_smbios3_address;
+                       *len = efi_smbios3_size;
+                       instance |= 1;
+                       return "SMBIOSv3";
+               }
+               if (efi_dmi_size && !(instance & 2)) {
+                       *base = efi_dmi_address;
+                       *len = efi_dmi_size;
+                       instance |= 2;
+                       return "DMI";
+               }
+       } else {
+               char __iomem *p = maddr_to_virt(0xF0000), *q;
+               union {
+                       struct dmi_eps dmi;
+                       struct smbios3_eps smbios3;
+               } eps;
+
+               for (q = p; q <= p + 0x10000 - sizeof(eps.dmi); q += 16) {
+                       memcpy_fromio(&eps, q, sizeof(eps.dmi));
+                       if (!(instance & 1) &&
+                           memcmp(eps.dmi.anchor, "_DMI_", 5) == 0 &&
+                           dmi_checksum(&eps.dmi, sizeof(eps.dmi))) {
+                               *base = eps.dmi.address;
+                               *len = eps.dmi.size;
+                               instance |= 1;
+                               return "DMI";
+                       }
+
+                       BUILD_BUG_ON(sizeof(eps.smbios3) <= sizeof(eps.dmi));
+                       if ((instance & 2) ||
+                           q > p + 0x10000 - sizeof(eps.smbios3))
+                               continue;
+                       memcpy_fromio(&eps.dmi + 1, q + sizeof(eps.dmi),
+                                     sizeof(eps.smbios3) - sizeof(eps.dmi));
+                       if (!memcmp(eps.smbios3.anchor, "_SM3_", 5) &&
+                           eps.smbios3.length >= sizeof(eps.smbios3) &&
+                           q <= p + 0x10000 - eps.smbios3.length &&
+                           dmi_checksum(q, eps.smbios3.length)) {
+                               *base = eps.smbios3.address;
+                               *len = eps.smbios3.max_size;
+                               instance |= 2;
+                               return "SMBIOSv3";
+                       }
                }
        }
-       return -1;
+       return NULL;
 }
 
+typedef union {
+       const struct smbios_eps __iomem *legacy;
+       const struct smbios3_eps __iomem *v3;
+} smbios_eps_u __attribute__((transparent_union));
+
 static int __init _dmi_iterate(const struct dmi_eps *dmi,
-                              const struct smbios_eps __iomem *smbios,
+                              const smbios_eps_u smbios,
                               void (*decode)(struct dmi_header *))
 {
-       u16 num = dmi->num_structures;
-       u16 len = dmi->size;
-       u32 base = dmi->address;
+       int num;
+       u32 len;
+       paddr_t base;
+
+       if (!dmi) {
+               num = -1;
+               len = smbios.v3->max_size;
+               base = smbios.v3->address;
+               printk(KERN_INFO "SMBIOS %d.%d present.\n",
+                      smbios.v3->major, smbios.v3->minor);
+               dmi_printk((KERN_INFO "SMBIOS v3 table at 0x%"PRIpaddr".\n", 
base));
+       } else {
+               num = dmi->num_structures;
+               len = dmi->size;
+               base = dmi->address;
 
-       /*
-        * DMI version 0.0 means that the real version is taken from
-        * the SMBIOS version, which we may not know at this point.
-        */
-       if (dmi->revision)
-               printk(KERN_INFO "DMI %d.%d present.\n",
-                      dmi->revision >> 4,  dmi->revision & 0x0f);
-       else if (!smbios)
-               printk(KERN_INFO "DMI present.\n");
-       dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
-                   num, len));
-       dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", base));
+               /*
+                * DMI version 0.0 means that the real version is taken from
+                * the SMBIOS version, which we may not know at this point.
+                */
+               if (dmi->revision)
+                       printk(KERN_INFO "DMI %d.%d present.\n",
+                              dmi->revision >> 4,  dmi->revision & 0x0f);
+               else if (!smbios.legacy)
+                       printk(KERN_INFO "DMI present.\n");
+               dmi_printk((KERN_INFO "%d structures occupying %u bytes.\n",
+                           num, len));
+               dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", (u32)base));
+       }
        return dmi_table(base, len, num, decode);
 }
 
 static int __init dmi_iterate(void (*decode)(struct dmi_header *))
 {
-       struct dmi_eps eps;
+       struct dmi_eps dmi;
+       struct smbios3_eps smbios3;
        char __iomem *p, *q;
 
+       dmi.size = 0;
+       smbios3.length = 0;
+
        p = maddr_to_virt(0xF0000);
        for (q = p; q < p + 0x10000; q += 16) {
-               memcpy_fromio(&eps, q, sizeof(eps));
-               if (memcmp(eps.anchor, "_DMI_", 5) == 0 &&
-                   dmi_checksum(&eps, sizeof(eps)))
-                       return _dmi_iterate(&eps, NULL, decode);
+               if (!dmi.size) {
+                       memcpy_fromio(&dmi, q, sizeof(dmi));
+                       if (memcmp(dmi.anchor, "_DMI_", 5) ||
+                           !dmi_checksum(&dmi, sizeof(dmi)))
+                               dmi.size = 0;
+               }
+               if (!smbios3.length &&
+                   q <= p + 0x10000 - sizeof(smbios3)) {
+                       memcpy_fromio(&smbios3, q, sizeof(smbios3));
+                       if (memcmp(smbios3.anchor, "_SM3_", 5) ||
+                           smbios3.length < sizeof(smbios3) ||
+                           q < p + 0x10000 - smbios3.length ||
+                           !dmi_checksum(q, smbios3.length))
+                               smbios3.length = 0;
+               }
        }
+
+       if (smbios3.length)
+               return _dmi_iterate(NULL, &smbios3, decode);
+       if (dmi.size)
+               return _dmi_iterate(&dmi, NULL, decode);
        return -1;
 }
 
 static int __init dmi_efi_iterate(void (*decode)(struct dmi_header *))
 {
-       struct smbios_eps eps;
-       const struct smbios_eps __iomem *p;
        int ret = -1;
 
-       if (efi.smbios == EFI_INVALID_TABLE_ADDR)
-               return -1;
+       while (efi.smbios3 != EFI_INVALID_TABLE_ADDR) {
+               struct smbios3_eps eps;
+               const struct smbios3_eps __iomem *p;
 
-       p = bt_ioremap(efi.smbios, sizeof(eps));
-       if (!p)
-               return -1;
-       memcpy_fromio(&eps, p, sizeof(eps));
-       bt_iounmap(p, sizeof(eps));
+               p = bt_ioremap(efi.smbios3, sizeof(eps));
+               if (!p)
+                       break;
+               memcpy_fromio(&eps, p, sizeof(eps));
+               bt_iounmap(p, sizeof(eps));
 
-       if (memcmp(eps.anchor, "_SM_", 4))
-               return -1;
+               if (memcmp(eps.anchor, "_SM3_", 5) ||
+                   eps.length < sizeof(eps))
+                       break;
 
-       p = bt_ioremap(efi.smbios, eps.length);
-       if (!p)
-               return -1;
-       if (dmi_checksum(p, eps.length) &&
-           memcmp(eps.dmi.anchor, "_DMI_", 5) == 0 &&
-           dmi_checksum(&eps.dmi, sizeof(eps.dmi))) {
-               printk(KERN_INFO "SMBIOS %d.%d present.\n",
-                      eps.major, eps.minor);
-               ret = _dmi_iterate(&eps.dmi, p, decode);
+               p = bt_ioremap(efi.smbios3, eps.length);
+               if (!p)
+                       break;
+               if (dmi_checksum(p, eps.length))
+                       ret = _dmi_iterate(NULL, p, decode);
+               bt_iounmap(p, eps.length);
+               break;
+       }
+
+       if (ret != 0 && efi.smbios != EFI_INVALID_TABLE_ADDR) {
+               struct smbios_eps eps;
+               const struct smbios_eps __iomem *p;
+
+               p = bt_ioremap(efi.smbios, sizeof(eps));
+               if (!p)
+                       return -1;
+               memcpy_fromio(&eps, p, sizeof(eps));
+               bt_iounmap(p, sizeof(eps));
+
+               if (memcmp(eps.anchor, "_SM_", 4) ||
+                   eps.length < sizeof(eps))
+                       return -1;
+
+               p = bt_ioremap(efi.smbios, eps.length);
+               if (!p)
+                       return -1;
+               if (dmi_checksum(p, eps.length) &&
+                   memcmp(eps.dmi.anchor, "_DMI_", 5) == 0 &&
+                   dmi_checksum(&eps.dmi, sizeof(eps.dmi))) {
+                       printk(KERN_INFO "SMBIOS %d.%d present.\n",
+                              eps.major, eps.minor);
+                       ret = _dmi_iterate(&eps.dmi, p, decode);
+               }
+               bt_iounmap(p, eps.length);
        }
-       bt_iounmap(p, eps.length);
 
        return ret;
 }
@@ -476,7 +641,7 @@ static void __init dmi_decode(struct dmi_header *dm)
        
        switch(dm->type)
        {
-               case  0:
+               case DMI_ENTRY_BIOS:
                        dmi_printk(("BIOS Vendor: %s\n",
                                dmi_string(dm, data[4])));
                        dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
@@ -487,7 +652,7 @@ static void __init dmi_decode(struct dmi_header *dm)
                                dmi_string(dm, data[8])));
                        dmi_save_ident(dm, DMI_BIOS_DATE, 8);
                        break;
-               case 1:
+               case DMI_ENTRY_SYSTEM:
                        dmi_printk(("System Vendor: %s\n",
                                dmi_string(dm, data[4])));
                        dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
@@ -500,7 +665,7 @@ static void __init dmi_decode(struct dmi_header *dm)
                        dmi_printk(("Serial Number: %s\n",
                                dmi_string(dm, data[7])));
                        break;
-               case 2:
+               case DMI_ENTRY_BASEBOARD:
                        dmi_printk(("Board Vendor: %s\n",
                                dmi_string(dm, data[4])));
                        dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
diff --git a/xen/arch/x86/e820.c b/xen/arch/x86/e820.c
index bf84bae..743a375 100644
--- a/xen/arch/x86/e820.c
+++ b/xen/arch/x86/e820.c
@@ -504,11 +504,19 @@ static uint64_t __init mtrr_top_of_ram(void)
 
 static void __init reserve_dmi_region(void)
 {
-    u32 base, len;
-    if ( (dmi_get_table(&base, &len) == 0) && ((base + len) > base) &&
-         reserve_e820_ram(&e820, base, base + len) )
-        printk("WARNING: DMI table located in E820 RAM %08x-%08x. Fixed.\n",
-               base, base+len);
+    for ( ; ; )
+    {
+        paddr_t base;
+        u32 len;
+        const char *what = dmi_get_table(&base, &len);
+
+        if ( !what )
+            break;
+        if ( ((base + len) > base) &&
+             reserve_e820_ram(&e820, base, base + len) )
+            printk("WARNING: %s table located in E820 RAM 
%"PRIpaddr"-%"PRIpaddr". Fixed.\n",
+                   what, base, base + len);
+    }
 }
 
 static void __init machine_specific_memory_setup(
diff --git a/xen/common/efi/boot.c b/xen/common/efi/boot.c
index ac6881e..f5e179b 100644
--- a/xen/common/efi/boot.c
+++ b/xen/common/efi/boot.c
@@ -32,6 +32,8 @@
 /* Using SetVirtualAddressMap() is incompatible with kexec: */
 #undef USE_SET_VIRTUAL_ADDRESS_MAP
 
+#define SMBIOS3_TABLE_GUID \
+  { 0xf2fd1544, 0x9794, 0x4a2c, {0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 
0x94} }
 #define SHIM_LOCK_PROTOCOL_GUID \
   { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 
0x23} }
 
@@ -993,6 +995,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE 
*SystemTable)
         static EFI_GUID __initdata acpi_guid = ACPI_TABLE_GUID;
         static EFI_GUID __initdata mps_guid = MPS_TABLE_GUID;
         static EFI_GUID __initdata smbios_guid = SMBIOS_TABLE_GUID;
+        static EFI_GUID __initdata smbios3_guid = SMBIOS3_TABLE_GUID;
 
         if ( match_guid(&acpi2_guid, &efi_ct[i].VendorGuid) )
               efi.acpi20 = (long)efi_ct[i].VendorTable;
@@ -1002,11 +1005,15 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE 
*SystemTable)
               efi.mps = (long)efi_ct[i].VendorTable;
         if ( match_guid(&smbios_guid, &efi_ct[i].VendorGuid) )
               efi.smbios = (long)efi_ct[i].VendorTable;
+        if ( match_guid(&smbios3_guid, &efi_ct[i].VendorGuid) )
+              efi.smbios3 = (long)efi_ct[i].VendorTable;
     }
 
 #ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */
-    if (efi.smbios != EFI_INVALID_TABLE_ADDR)
-        dmi_efi_get_table((void *)(long)efi.smbios);
+    dmi_efi_get_table(efi.smbios != EFI_INVALID_TABLE_ADDR
+                      ? (void *)(long)efi.smbios : NULL,
+                      efi.smbios3 != EFI_INVALID_TABLE_ADDR
+                      ? (void *)(long)efi.smbios3 : NULL);
 #endif
 
     /* Collect PCI ROM contents. */
diff --git a/xen/common/efi/runtime.c b/xen/common/efi/runtime.c
index c840e08..7ed5bfa 100644
--- a/xen/common/efi/runtime.c
+++ b/xen/common/efi/runtime.c
@@ -45,6 +45,7 @@ struct efi __read_mostly efi = {
        .acpi20 = EFI_INVALID_TABLE_ADDR,
        .mps    = EFI_INVALID_TABLE_ADDR,
        .smbios = EFI_INVALID_TABLE_ADDR,
+       .smbios3 = EFI_INVALID_TABLE_ADDR,
 };
 
 const struct efi_pci_rom *__read_mostly efi_pci_roms;
diff --git a/xen/include/xen/dmi.h b/xen/include/xen/dmi.h
index 8205893..df26d4b 100644
--- a/xen/include/xen/dmi.h
+++ b/xen/include/xen/dmi.h
@@ -34,8 +34,8 @@ struct dmi_system_id {
 
 extern int dmi_check_system(struct dmi_system_id *list);
 extern void dmi_scan_machine(void);
-extern int dmi_get_table(u32 *base, u32 *len);
-extern void dmi_efi_get_table(void *);
+extern const char *dmi_get_table(paddr_t *base, u32 *len);
+extern void dmi_efi_get_table(const void *smbios, const void *smbios3);
 bool_t dmi_get_date(int field, int *yearp, int *monthp, int *dayp);
 extern void dmi_end_boot(void);
 
diff --git a/xen/include/xen/efi.h b/xen/include/xen/efi.h
index 5e02724..48de8e0 100644
--- a/xen/include/xen/efi.h
+++ b/xen/include/xen/efi.h
@@ -15,6 +15,7 @@ struct efi {
     unsigned long acpi;         /* ACPI table (IA64 ext 0.71) */
     unsigned long acpi20;       /* ACPI table (ACPI 2.0) */
     unsigned long smbios;       /* SM BIOS table */
+    unsigned long smbios3;      /* SMBIOS v3 table */
 };
 
 extern struct efi efi;
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.