s390: nvme dump support
authorJason J. Herne <jjherne@linux.ibm.com>
Tue, 17 Mar 2020 13:23:41 +0000 (09:23 -0400)
committerVasily Gorbik <gor@linux.ibm.com>
Fri, 2 Oct 2020 12:40:48 +0000 (14:40 +0200)
Add the nvme dump ipl type, associated data, and sysfs entries. This allows
booting into a stand alone dump environment that resides on an nvme device.

Signed-off-by: Jason J. Herne <jjherne@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/include/asm/ipl.h
arch/s390/kernel/ipl.c

index 7d5cfdda527713191c0450f9de5873c35babf126..a72d195bf92d10d5a45433beab71a0d1e2d5310d 100644 (file)
@@ -66,6 +66,7 @@ enum ipl_type {
        IPL_TYPE_FCP_DUMP       = 8,
        IPL_TYPE_NSS            = 16,
        IPL_TYPE_NVME           = 32,
+       IPL_TYPE_NVME_DUMP      = 64,
 };
 
 struct ipl_info
index 90a2a17239b0e252602d2d3c681deaf2a1a7911c..c5f9d6f88d27596f5a00a533c0d55b4028ad17b1 100644 (file)
 #define IPL_FCP_STR            "fcp"
 #define IPL_FCP_DUMP_STR       "fcp_dump"
 #define IPL_NVME_STR           "nvme"
+#define IPL_NVME_DUMP_STR      "nvme_dump"
 #define IPL_NSS_STR            "nss"
 
 #define DUMP_CCW_STR           "ccw"
 #define DUMP_FCP_STR           "fcp"
+#define DUMP_NVME_STR          "nvme"
 #define DUMP_NONE_STR          "none"
 
 /*
@@ -96,6 +98,8 @@ static char *ipl_type_str(enum ipl_type type)
                return IPL_NSS_STR;
        case IPL_TYPE_NVME:
                return IPL_NVME_STR;
+       case IPL_TYPE_NVME_DUMP:
+               return IPL_NVME_DUMP_STR;
        case IPL_TYPE_UNKNOWN:
        default:
                return IPL_UNKNOWN_STR;
@@ -106,6 +110,7 @@ enum dump_type {
        DUMP_TYPE_NONE  = 1,
        DUMP_TYPE_CCW   = 2,
        DUMP_TYPE_FCP   = 4,
+       DUMP_TYPE_NVME  = 8,
 };
 
 static char *dump_type_str(enum dump_type type)
@@ -117,6 +122,8 @@ static char *dump_type_str(enum dump_type type)
                return DUMP_CCW_STR;
        case DUMP_TYPE_FCP:
                return DUMP_FCP_STR;
+       case DUMP_TYPE_NVME:
+               return DUMP_NVME_STR;
        default:
                return NULL;
        }
@@ -144,6 +151,7 @@ static struct ipl_parameter_block *reipl_block_actual;
 static int dump_capabilities = DUMP_TYPE_NONE;
 static enum dump_type dump_type = DUMP_TYPE_NONE;
 static struct ipl_parameter_block *dump_block_fcp;
+static struct ipl_parameter_block *dump_block_nvme;
 static struct ipl_parameter_block *dump_block_ccw;
 
 static struct sclp_ipl_info sclp_ipl_info;
@@ -266,7 +274,10 @@ static __init enum ipl_type get_ipl_type(void)
                else
                        return IPL_TYPE_FCP;
        case IPL_PBT_NVME:
-               return IPL_TYPE_NVME;
+               if (ipl_block.nvme.opt == IPL_PB0_NVME_OPT_DUMP)
+                       return IPL_TYPE_NVME_DUMP;
+               else
+                       return IPL_TYPE_NVME;
        }
        return IPL_TYPE_UNKNOWN;
 }
@@ -324,6 +335,7 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj,
        case IPL_TYPE_FCP_DUMP:
                return sprintf(page, "0.0.%04x\n", ipl_block.fcp.devno);
        case IPL_TYPE_NVME:
+       case IPL_TYPE_NVME_DUMP:
                return sprintf(page, "%08ux\n", ipl_block.nvme.fid);
        default:
                return 0;
@@ -531,6 +543,7 @@ static int __init ipl_init(void)
                rc = sysfs_create_group(&ipl_kset->kobj, &ipl_fcp_attr_group);
                break;
        case IPL_TYPE_NVME:
+       case IPL_TYPE_NVME_DUMP:
                rc = sysfs_create_group(&ipl_kset->kobj, &ipl_nvme_attr_group);
                break;
        default:
@@ -1109,6 +1122,7 @@ static void __reipl_run(void *unused)
                diag308(DIAG308_LOAD_CLEAR, NULL);
                break;
        case IPL_TYPE_FCP_DUMP:
+       case IPL_TYPE_NVME_DUMP:
                break;
        }
        disabled_wait();
@@ -1382,6 +1396,29 @@ static struct attribute_group dump_fcp_attr_group = {
        .attrs = dump_fcp_attrs,
 };
 
+/* NVME dump device attributes */
+DEFINE_IPL_ATTR_RW(dump_nvme, fid, "0x%08llx\n", "%llx\n",
+                  dump_block_nvme->nvme.fid);
+DEFINE_IPL_ATTR_RW(dump_nvme, nsid, "0x%08llx\n", "%llx\n",
+                  dump_block_nvme->nvme.nsid);
+DEFINE_IPL_ATTR_RW(dump_nvme, bootprog, "%lld\n", "%llx\n",
+                  dump_block_nvme->nvme.bootprog);
+DEFINE_IPL_ATTR_RW(dump_nvme, br_lba, "%lld\n", "%llx\n",
+                  dump_block_nvme->nvme.br_lba);
+
+static struct attribute *dump_nvme_attrs[] = {
+       &sys_dump_nvme_fid_attr.attr,
+       &sys_dump_nvme_nsid_attr.attr,
+       &sys_dump_nvme_bootprog_attr.attr,
+       &sys_dump_nvme_br_lba_attr.attr,
+       NULL,
+};
+
+static struct attribute_group dump_nvme_attr_group = {
+       .name  = IPL_NVME_STR,
+       .attrs = dump_nvme_attrs,
+};
+
 /* CCW dump device attributes */
 DEFINE_IPL_CCW_ATTR_RW(dump_ccw, device, dump_block_ccw->ccw);
 
@@ -1423,6 +1460,8 @@ static ssize_t dump_type_store(struct kobject *kobj,
                rc = dump_set_type(DUMP_TYPE_CCW);
        else if (strncmp(buf, DUMP_FCP_STR, strlen(DUMP_FCP_STR)) == 0)
                rc = dump_set_type(DUMP_TYPE_FCP);
+       else if (strncmp(buf, DUMP_NVME_STR, strlen(DUMP_NVME_STR)) == 0)
+               rc = dump_set_type(DUMP_TYPE_NVME);
        return (rc != 0) ? rc : len;
 }
 
@@ -1450,6 +1489,9 @@ static void __dump_run(void *unused)
        case DUMP_TYPE_FCP:
                diag308_dump(dump_block_fcp);
                break;
+       case DUMP_TYPE_NVME:
+               diag308_dump(dump_block_nvme);
+               break;
        default:
                break;
        }
@@ -1506,6 +1548,29 @@ static int __init dump_fcp_init(void)
        return 0;
 }
 
+static int __init dump_nvme_init(void)
+{
+       int rc;
+
+       if (!sclp_ipl_info.has_dump)
+               return 0; /* LDIPL DUMP is not installed */
+       dump_block_nvme = (void *) get_zeroed_page(GFP_KERNEL);
+       if (!dump_block_nvme)
+               return -ENOMEM;
+       rc = sysfs_create_group(&dump_kset->kobj, &dump_nvme_attr_group);
+       if (rc) {
+               free_page((unsigned long)dump_block_nvme);
+               return rc;
+       }
+       dump_block_nvme->hdr.len = IPL_BP_NVME_LEN;
+       dump_block_nvme->hdr.version = IPL_PARM_BLOCK_VERSION;
+       dump_block_nvme->fcp.len = IPL_BP0_NVME_LEN;
+       dump_block_nvme->fcp.pbt = IPL_PBT_NVME;
+       dump_block_nvme->fcp.opt = IPL_PB0_NVME_OPT_DUMP;
+       dump_capabilities |= DUMP_TYPE_NVME;
+       return 0;
+}
+
 static int __init dump_init(void)
 {
        int rc;
@@ -1522,6 +1587,9 @@ static int __init dump_init(void)
        if (rc)
                return rc;
        rc = dump_fcp_init();
+       if (rc)
+               return rc;
+       rc = dump_nvme_init();
        if (rc)
                return rc;
        dump_set_type(DUMP_TYPE_NONE);
@@ -1956,6 +2024,7 @@ void __init setup_ipl(void)
                ipl_info.data.fcp.lun = ipl_block.fcp.lun;
                break;
        case IPL_TYPE_NVME:
+       case IPL_TYPE_NVME_DUMP:
                ipl_info.data.nvme.fid = ipl_block.nvme.fid;
                ipl_info.data.nvme.nsid = ipl_block.nvme.nsid;
                break;