return error;
 }
 
+static bool nvme_multi_css(struct nvme_ctrl *ctrl)
+{
+       return (ctrl->ctrl_config & NVME_CC_CSS_MASK) == NVME_CC_CSS_CSI;
+}
+
 static int nvme_process_ns_desc(struct nvme_ctrl *ctrl, struct nvme_ns_ids *ids,
-               struct nvme_ns_id_desc *cur)
+               struct nvme_ns_id_desc *cur, bool *csi_seen)
 {
        const char *warn_str = "ctrl returned bogus length:";
        void *data = cur;
                }
                uuid_copy(&ids->uuid, data + sizeof(*cur));
                return NVME_NIDT_UUID_LEN;
+       case NVME_NIDT_CSI:
+               if (cur->nidl != NVME_NIDT_CSI_LEN) {
+                       dev_warn(ctrl->device, "%s %d for NVME_NIDT_CSI\n",
+                                warn_str, cur->nidl);
+                       return -1;
+               }
+               memcpy(&ids->csi, data + sizeof(*cur), NVME_NIDT_CSI_LEN);
+               *csi_seen = true;
+               return NVME_NIDT_CSI_LEN;
        default:
                /* Skip unknown types */
                return cur->nidl;
                struct nvme_ns_ids *ids)
 {
        struct nvme_command c = { };
-       int status;
+       bool csi_seen = false;
+       int status, pos, len;
        void *data;
-       int pos;
-       int len;
 
        c.identify.opcode = nvme_admin_identify;
        c.identify.nsid = cpu_to_le32(nsid);
                  * device just because of a temporal retry-able error (such
                  * as path of transport errors).
                  */
-               if (status > 0 && (status & NVME_SC_DNR))
+               if (status > 0 && (status & NVME_SC_DNR) && !nvme_multi_css(ctrl))
                        status = 0;
                goto free_data;
        }
                if (cur->nidl == 0)
                        break;
 
-               len = nvme_process_ns_desc(ctrl, ids, cur);
+               len = nvme_process_ns_desc(ctrl, ids, cur, &csi_seen);
                if (len < 0)
-                       goto free_data;
+                       break;
 
                len += sizeof(*cur);
        }
+
+       if (nvme_multi_css(ctrl) && !csi_seen) {
+               dev_warn(ctrl->device, "Command set not reported for nsid:%d\n",
+                        nsid);
+               status = -EINVAL;
+       }
+
 free_data:
        kfree(data);
        return status;
                memcpy(ids->eui64, id->eui64, sizeof(id->eui64));
        if (ctrl->vs >= NVME_VS(1, 2, 0))
                memcpy(ids->nguid, id->nguid, sizeof(id->nguid));
-       if (ctrl->vs >= NVME_VS(1, 3, 0))
+       if (ctrl->vs >= NVME_VS(1, 3, 0) || nvme_multi_css(ctrl))
                return nvme_identify_ns_descs(ctrl, nsid, ids);
        return 0;
 }
 {
        return uuid_equal(&a->uuid, &b->uuid) &&
                memcmp(&a->nguid, &b->nguid, sizeof(a->nguid)) == 0 &&
-               memcmp(&a->eui64, &b->eui64, sizeof(a->eui64)) == 0;
+               memcmp(&a->eui64, &b->eui64, sizeof(a->eui64)) == 0 &&
+               a->csi == b->csi;
 }
 
 static int nvme_setup_streams_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
        if (ns->lba_shift == 0)
                ns->lba_shift = 9;
 
+       switch (ns->head->ids.csi) {
+       case NVME_CSI_NVM:
+               break;
+       default:
+               dev_warn(ctrl->device, "unknown csi:%d ns:%d\n",
+                       ns->head->ids.csi, ns->head->ns_id);
+               return -ENODEV;
+       }
+
        if ((ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) &&
            is_power_of_2(ctrl->max_hw_sectors))
                iob = ctrl->max_hw_sectors;
 
        ctrl->page_size = 1 << page_shift;
 
-       ctrl->ctrl_config = NVME_CC_CSS_NVM;
+       if (NVME_CAP_CSS(ctrl->cap) & NVME_CAP_CSS_CSI)
+               ctrl->ctrl_config = NVME_CC_CSS_CSI;
+       else
+               ctrl->ctrl_config = NVME_CC_CSS_NVM;
        ctrl->ctrl_config |= (page_shift - 12) << NVME_CC_MPS_SHIFT;
        ctrl->ctrl_config |= NVME_CC_AMS_RR | NVME_CC_SHN_NONE;
        ctrl->ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES;
 
 #define NVME_CAP_TIMEOUT(cap)  (((cap) >> 24) & 0xff)
 #define NVME_CAP_STRIDE(cap)   (((cap) >> 32) & 0xf)
 #define NVME_CAP_NSSRC(cap)    (((cap) >> 36) & 0x1)
+#define NVME_CAP_CSS(cap)      (((cap) >> 37) & 0xff)
 #define NVME_CAP_MPSMIN(cap)   (((cap) >> 48) & 0xf)
 #define NVME_CAP_MPSMAX(cap)   (((cap) >> 52) & 0xf)
 
 
 enum {
        NVME_CC_ENABLE          = 1 << 0,
-       NVME_CC_CSS_NVM         = 0 << 4,
        NVME_CC_EN_SHIFT        = 0,
        NVME_CC_CSS_SHIFT       = 4,
        NVME_CC_MPS_SHIFT       = 7,
        NVME_CC_SHN_SHIFT       = 14,
        NVME_CC_IOSQES_SHIFT    = 16,
        NVME_CC_IOCQES_SHIFT    = 20,
+       NVME_CC_CSS_NVM         = 0 << NVME_CC_CSS_SHIFT,
+       NVME_CC_CSS_CSI         = 6 << NVME_CC_CSS_SHIFT,
+       NVME_CC_CSS_MASK        = 7 << NVME_CC_CSS_SHIFT,
        NVME_CC_AMS_RR          = 0 << NVME_CC_AMS_SHIFT,
        NVME_CC_AMS_WRRU        = 1 << NVME_CC_AMS_SHIFT,
        NVME_CC_AMS_VS          = 7 << NVME_CC_AMS_SHIFT,
        NVME_CC_SHN_MASK        = 3 << NVME_CC_SHN_SHIFT,
        NVME_CC_IOSQES          = NVME_NVM_IOSQES << NVME_CC_IOSQES_SHIFT,
        NVME_CC_IOCQES          = NVME_NVM_IOCQES << NVME_CC_IOCQES_SHIFT,
+       NVME_CAP_CSS_NVM        = 1 << 0,
+       NVME_CAP_CSS_CSI        = 1 << 6,
        NVME_CSTS_RDY           = 1 << 0,
        NVME_CSTS_CFS           = 1 << 1,
        NVME_CSTS_NSSRO         = 1 << 4,
        NVME_ID_CNS_CTRL                = 0x01,
        NVME_ID_CNS_NS_ACTIVE_LIST      = 0x02,
        NVME_ID_CNS_NS_DESC_LIST        = 0x03,
+       NVME_ID_CNS_CS_NS               = 0x05,
+       NVME_ID_CNS_CS_CTRL             = 0x06,
        NVME_ID_CNS_NS_PRESENT_LIST     = 0x10,
        NVME_ID_CNS_NS_PRESENT          = 0x11,
        NVME_ID_CNS_CTRL_NS_LIST        = 0x12,
        NVME_ID_CNS_UUID_LIST           = 0x17,
 };
 
+enum {
+       NVME_CSI_NVM                    = 0,
+};
+
 enum {
        NVME_DIR_IDENTIFY               = 0x00,
        NVME_DIR_STREAMS                = 0x01,
 #define NVME_NIDT_EUI64_LEN    8
 #define NVME_NIDT_NGUID_LEN    16
 #define NVME_NIDT_UUID_LEN     16
+#define NVME_NIDT_CSI_LEN      1
 
 enum {
        NVME_NIDT_EUI64         = 0x01,
        NVME_NIDT_NGUID         = 0x02,
        NVME_NIDT_UUID          = 0x03,
+       NVME_NIDT_CSI           = 0x04,
 };
 
 struct nvme_smart_log {
        __u8                    cns;
        __u8                    rsvd3;
        __le16                  ctrlid;
-       __u32                   rsvd11[5];
+       __u8                    rsvd11[3];
+       __u8                    csi;
+       __u32                   rsvd12[4];
 };
 
 #define NVME_IDENTIFY_DATA_SIZE 4096