Merge tag 'for-5.18/64bit-pi-2022-03-25' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / drivers / nvme / host / core.c
index aeda4d0..677fa4b 100644 (file)
@@ -785,6 +785,30 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,
        return BLK_STS_OK;
 }
 
+static void nvme_set_ref_tag(struct nvme_ns *ns, struct nvme_command *cmnd,
+                             struct request *req)
+{
+       u32 upper, lower;
+       u64 ref48;
+
+       /* both rw and write zeroes share the same reftag format */
+       switch (ns->guard_type) {
+       case NVME_NVM_NS_16B_GUARD:
+               cmnd->rw.reftag = cpu_to_le32(t10_pi_ref_tag(req));
+               break;
+       case NVME_NVM_NS_64B_GUARD:
+               ref48 = ext_pi_ref_tag(req);
+               lower = lower_32_bits(ref48);
+               upper = upper_32_bits(ref48);
+
+               cmnd->rw.reftag = cpu_to_le32(lower);
+               cmnd->rw.cdw3 = cpu_to_le32(upper);
+               break;
+       default:
+               break;
+       }
+}
+
 static inline blk_status_t nvme_setup_write_zeroes(struct nvme_ns *ns,
                struct request *req, struct nvme_command *cmnd)
 {
@@ -806,8 +830,7 @@ static inline blk_status_t nvme_setup_write_zeroes(struct nvme_ns *ns,
                switch (ns->pi_type) {
                case NVME_NS_DPS_PI_TYPE1:
                case NVME_NS_DPS_PI_TYPE2:
-                       cmnd->write_zeroes.reftag =
-                               cpu_to_le32(t10_pi_ref_tag(req));
+                       nvme_set_ref_tag(ns, cmnd, req);
                        break;
                }
        }
@@ -833,7 +856,8 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
        cmnd->rw.opcode = op;
        cmnd->rw.flags = 0;
        cmnd->rw.nsid = cpu_to_le32(ns->head->ns_id);
-       cmnd->rw.rsvd2 = 0;
+       cmnd->rw.cdw2 = 0;
+       cmnd->rw.cdw3 = 0;
        cmnd->rw.metadata = 0;
        cmnd->rw.slba = cpu_to_le64(nvme_sect_to_lba(ns, blk_rq_pos(req)));
        cmnd->rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1);
@@ -864,7 +888,7 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
                                        NVME_RW_PRINFO_PRCHK_REF;
                        if (op == nvme_cmd_zone_append)
                                control |= NVME_RW_APPEND_PIREMAP;
-                       cmnd->rw.reftag = cpu_to_le32(t10_pi_ref_tag(req));
+                       nvme_set_ref_tag(ns, cmnd, req);
                        break;
                }
        }
@@ -1520,33 +1544,58 @@ int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 }
 
 #ifdef CONFIG_BLK_DEV_INTEGRITY
-static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type,
+static void nvme_init_integrity(struct gendisk *disk, struct nvme_ns *ns,
                                u32 max_integrity_segments)
 {
        struct blk_integrity integrity = { };
 
-       switch (pi_type) {
+       switch (ns->pi_type) {
        case NVME_NS_DPS_PI_TYPE3:
-               integrity.profile = &t10_pi_type3_crc;
-               integrity.tag_size = sizeof(u16) + sizeof(u32);
-               integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
+               switch (ns->guard_type) {
+               case NVME_NVM_NS_16B_GUARD:
+                       integrity.profile = &t10_pi_type3_crc;
+                       integrity.tag_size = sizeof(u16) + sizeof(u32);
+                       integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
+                       break;
+               case NVME_NVM_NS_64B_GUARD:
+                       integrity.profile = &ext_pi_type3_crc64;
+                       integrity.tag_size = sizeof(u16) + 6;
+                       integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
+                       break;
+               default:
+                       integrity.profile = NULL;
+                       break;
+               }
                break;
        case NVME_NS_DPS_PI_TYPE1:
        case NVME_NS_DPS_PI_TYPE2:
-               integrity.profile = &t10_pi_type1_crc;
-               integrity.tag_size = sizeof(u16);
-               integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
+               switch (ns->guard_type) {
+               case NVME_NVM_NS_16B_GUARD:
+                       integrity.profile = &t10_pi_type1_crc;
+                       integrity.tag_size = sizeof(u16);
+                       integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
+                       break;
+               case NVME_NVM_NS_64B_GUARD:
+                       integrity.profile = &ext_pi_type1_crc64;
+                       integrity.tag_size = sizeof(u16);
+                       integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
+                       break;
+               default:
+                       integrity.profile = NULL;
+                       break;
+               }
                break;
        default:
                integrity.profile = NULL;
                break;
        }
-       integrity.tuple_size = ms;
+
+       integrity.tuple_size = ns->ms;
        blk_integrity_register(disk, &integrity);
        blk_queue_max_integrity_segments(disk->queue, max_integrity_segments);
 }
 #else
-static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type,
+static void nvme_init_integrity(struct gendisk *disk, struct nvme_ns *ns,
                                u32 max_integrity_segments)
 {
 }
@@ -1588,20 +1637,73 @@ static bool nvme_ns_ids_equal(struct nvme_ns_ids *a, struct nvme_ns_ids *b)
                a->csi == b->csi;
 }
 
-static void nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id)
+static int nvme_init_ms(struct nvme_ns *ns, struct nvme_id_ns *id)
 {
+       bool first = id->dps & NVME_NS_DPS_PI_FIRST;
+       unsigned lbaf = nvme_lbaf_index(id->flbas);
        struct nvme_ctrl *ctrl = ns->ctrl;
+       struct nvme_command c = { };
+       struct nvme_id_ns_nvm *nvm;
+       int ret = 0;
+       u32 elbaf;
+
+       ns->pi_size = 0;
+       ns->ms = le16_to_cpu(id->lbaf[lbaf].ms);
+       if (!(ctrl->ctratt & NVME_CTRL_ATTR_ELBAS)) {
+               ns->pi_size = sizeof(struct t10_pi_tuple);
+               ns->guard_type = NVME_NVM_NS_16B_GUARD;
+               goto set_pi;
+       }
 
-       /*
-        * The PI implementation requires the metadata size to be equal to the
-        * t10 pi tuple size.
-        */
-       ns->ms = le16_to_cpu(id->lbaf[id->flbas & NVME_NS_FLBAS_LBA_MASK].ms);
-       if (ns->ms == sizeof(struct t10_pi_tuple))
+       nvm = kzalloc(sizeof(*nvm), GFP_KERNEL);
+       if (!nvm)
+               return -ENOMEM;
+
+       c.identify.opcode = nvme_admin_identify;
+       c.identify.nsid = cpu_to_le32(ns->head->ns_id);
+       c.identify.cns = NVME_ID_CNS_CS_NS;
+       c.identify.csi = NVME_CSI_NVM;
+
+       ret = nvme_submit_sync_cmd(ns->ctrl->admin_q, &c, nvm, sizeof(*nvm));
+       if (ret)
+               goto free_data;
+
+       elbaf = le32_to_cpu(nvm->elbaf[lbaf]);
+
+       /* no support for storage tag formats right now */
+       if (nvme_elbaf_sts(elbaf))
+               goto free_data;
+
+       ns->guard_type = nvme_elbaf_guard_type(elbaf);
+       switch (ns->guard_type) {
+       case NVME_NVM_NS_64B_GUARD:
+               ns->pi_size = sizeof(struct crc64_pi_tuple);
+               break;
+       case NVME_NVM_NS_16B_GUARD:
+               ns->pi_size = sizeof(struct t10_pi_tuple);
+               break;
+       default:
+               break;
+       }
+
+free_data:
+       kfree(nvm);
+set_pi:
+       if (ns->pi_size && (first || ns->ms == ns->pi_size))
                ns->pi_type = id->dps & NVME_NS_DPS_PI_MASK;
        else
                ns->pi_type = 0;
 
+       return ret;
+}
+
+static void nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id)
+{
+       struct nvme_ctrl *ctrl = ns->ctrl;
+
+       if (nvme_init_ms(ns, id))
+               return;
+
        ns->features &= ~(NVME_NS_METADATA_SUPPORTED | NVME_NS_EXT_LBAS);
        if (!ns->ms || !(ctrl->ops->flags & NVME_F_METADATA_SUPPORTED))
                return;
@@ -1717,7 +1819,7 @@ static void nvme_update_disk_info(struct gendisk *disk,
        if (ns->ms) {
                if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) &&
                    (ns->features & NVME_NS_METADATA_SUPPORTED))
-                       nvme_init_integrity(disk, ns->ms, ns->pi_type,
+                       nvme_init_integrity(disk, ns,
                                            ns->ctrl->max_integrity_segments);
                else if (!nvme_ns_has_pi(ns))
                        capacity = 0;
@@ -1772,7 +1874,7 @@ static void nvme_set_chunk_sectors(struct nvme_ns *ns, struct nvme_id_ns *id)
 
 static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
 {
-       unsigned lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
+       unsigned lbaf = nvme_lbaf_index(id->flbas);
        int ret;
 
        blk_mq_freeze_queue(ns->disk->queue);
@@ -2117,20 +2219,27 @@ static int nvme_configure_timestamp(struct nvme_ctrl *ctrl)
        return ret;
 }
 
-static int nvme_configure_acre(struct nvme_ctrl *ctrl)
+static int nvme_configure_host_options(struct nvme_ctrl *ctrl)
 {
        struct nvme_feat_host_behavior *host;
+       u8 acre = 0, lbafee = 0;
        int ret;
 
        /* Don't bother enabling the feature if retry delay is not reported */
-       if (!ctrl->crdt[0])
+       if (ctrl->crdt[0])
+               acre = NVME_ENABLE_ACRE;
+       if (ctrl->ctratt & NVME_CTRL_ATTR_ELBAS)
+               lbafee = NVME_ENABLE_LBAFEE;
+
+       if (!acre && !lbafee)
                return 0;
 
        host = kzalloc(sizeof(*host), GFP_KERNEL);
        if (!host)
                return 0;
 
-       host->acre = NVME_ENABLE_ACRE;
+       host->acre = acre;
+       host->lbafee = lbafee;
        ret = nvme_set_features(ctrl, NVME_FEAT_HOST_BEHAVIOR, 0,
                                host, sizeof(*host), NULL);
        kfree(host);
@@ -2968,7 +3077,7 @@ int nvme_init_ctrl_finish(struct nvme_ctrl *ctrl)
        if (ret < 0)
                return ret;
 
-       ret = nvme_configure_acre(ctrl);
+       ret = nvme_configure_host_options(ctrl);
        if (ret < 0)
                return ret;
 
@@ -4704,12 +4813,14 @@ static inline void _nvme_check_size(void)
        BUILD_BUG_ON(sizeof(struct nvme_id_ctrl) != NVME_IDENTIFY_DATA_SIZE);
        BUILD_BUG_ON(sizeof(struct nvme_id_ns) != NVME_IDENTIFY_DATA_SIZE);
        BUILD_BUG_ON(sizeof(struct nvme_id_ns_zns) != NVME_IDENTIFY_DATA_SIZE);
+       BUILD_BUG_ON(sizeof(struct nvme_id_ns_nvm) != NVME_IDENTIFY_DATA_SIZE);
        BUILD_BUG_ON(sizeof(struct nvme_id_ctrl_zns) != NVME_IDENTIFY_DATA_SIZE);
        BUILD_BUG_ON(sizeof(struct nvme_id_ctrl_nvm) != NVME_IDENTIFY_DATA_SIZE);
        BUILD_BUG_ON(sizeof(struct nvme_lba_range_type) != 64);
        BUILD_BUG_ON(sizeof(struct nvme_smart_log) != 512);
        BUILD_BUG_ON(sizeof(struct nvme_dbbuf) != 64);
        BUILD_BUG_ON(sizeof(struct nvme_directive_cmd) != 64);
+       BUILD_BUG_ON(sizeof(struct nvme_feat_host_behavior) != 512);
 }