Skip to content

Commit 4020aad

Browse files
keithbuschaxboe
authored andcommitted
nvme: add support for enhanced metadata
NVM Express ratified TP 4068 defines new protection information formats. Implement support for the CRC64 guard tags. Since the block layer doesn't support variable length reference tags, driver support for the Storage Tag space is not supported at this time. Cc: Hannes Reinecke <[email protected]> Cc: "Martin K. Petersen" <[email protected]> Cc: Klaus Jensen <[email protected]> Signed-off-by: Keith Busch <[email protected]> Reviewed-by: Martin K. Petersen <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent a7d4383 commit 4020aad

File tree

3 files changed

+188
-31
lines changed

3 files changed

+188
-31
lines changed

drivers/nvme/host/core.c

Lines changed: 138 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,30 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,
813813
return BLK_STS_OK;
814814
}
815815

816+
static void nvme_set_ref_tag(struct nvme_ns *ns, struct nvme_command *cmnd,
817+
struct request *req)
818+
{
819+
u32 upper, lower;
820+
u64 ref48;
821+
822+
/* both rw and write zeroes share the same reftag format */
823+
switch (ns->guard_type) {
824+
case NVME_NVM_NS_16B_GUARD:
825+
cmnd->rw.reftag = cpu_to_le32(t10_pi_ref_tag(req));
826+
break;
827+
case NVME_NVM_NS_64B_GUARD:
828+
ref48 = ext_pi_ref_tag(req);
829+
lower = lower_32_bits(ref48);
830+
upper = upper_32_bits(ref48);
831+
832+
cmnd->rw.reftag = cpu_to_le32(lower);
833+
cmnd->rw.cdw3 = cpu_to_le32(upper);
834+
break;
835+
default:
836+
break;
837+
}
838+
}
839+
816840
static inline blk_status_t nvme_setup_write_zeroes(struct nvme_ns *ns,
817841
struct request *req, struct nvme_command *cmnd)
818842
{
@@ -834,8 +858,7 @@ static inline blk_status_t nvme_setup_write_zeroes(struct nvme_ns *ns,
834858
switch (ns->pi_type) {
835859
case NVME_NS_DPS_PI_TYPE1:
836860
case NVME_NS_DPS_PI_TYPE2:
837-
cmnd->write_zeroes.reftag =
838-
cpu_to_le32(t10_pi_ref_tag(req));
861+
nvme_set_ref_tag(ns, cmnd, req);
839862
break;
840863
}
841864
}
@@ -861,7 +884,8 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
861884
cmnd->rw.opcode = op;
862885
cmnd->rw.flags = 0;
863886
cmnd->rw.nsid = cpu_to_le32(ns->head->ns_id);
864-
cmnd->rw.rsvd2 = 0;
887+
cmnd->rw.cdw2 = 0;
888+
cmnd->rw.cdw3 = 0;
865889
cmnd->rw.metadata = 0;
866890
cmnd->rw.slba = cpu_to_le64(nvme_sect_to_lba(ns, blk_rq_pos(req)));
867891
cmnd->rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1);
@@ -892,7 +916,7 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
892916
NVME_RW_PRINFO_PRCHK_REF;
893917
if (op == nvme_cmd_zone_append)
894918
control |= NVME_RW_APPEND_PIREMAP;
895-
cmnd->rw.reftag = cpu_to_le32(t10_pi_ref_tag(req));
919+
nvme_set_ref_tag(ns, cmnd, req);
896920
break;
897921
}
898922
}
@@ -1544,33 +1568,58 @@ int nvme_getgeo(struct block_device *bdev, struct hd_geometry *geo)
15441568
}
15451569

15461570
#ifdef CONFIG_BLK_DEV_INTEGRITY
1547-
static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type,
1571+
static void nvme_init_integrity(struct gendisk *disk, struct nvme_ns *ns,
15481572
u32 max_integrity_segments)
15491573
{
15501574
struct blk_integrity integrity = { };
15511575

1552-
switch (pi_type) {
1576+
switch (ns->pi_type) {
15531577
case NVME_NS_DPS_PI_TYPE3:
1554-
integrity.profile = &t10_pi_type3_crc;
1555-
integrity.tag_size = sizeof(u16) + sizeof(u32);
1556-
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
1578+
switch (ns->guard_type) {
1579+
case NVME_NVM_NS_16B_GUARD:
1580+
integrity.profile = &t10_pi_type3_crc;
1581+
integrity.tag_size = sizeof(u16) + sizeof(u32);
1582+
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
1583+
break;
1584+
case NVME_NVM_NS_64B_GUARD:
1585+
integrity.profile = &ext_pi_type3_crc64;
1586+
integrity.tag_size = sizeof(u16) + 6;
1587+
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
1588+
break;
1589+
default:
1590+
integrity.profile = NULL;
1591+
break;
1592+
}
15571593
break;
15581594
case NVME_NS_DPS_PI_TYPE1:
15591595
case NVME_NS_DPS_PI_TYPE2:
1560-
integrity.profile = &t10_pi_type1_crc;
1561-
integrity.tag_size = sizeof(u16);
1562-
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
1596+
switch (ns->guard_type) {
1597+
case NVME_NVM_NS_16B_GUARD:
1598+
integrity.profile = &t10_pi_type1_crc;
1599+
integrity.tag_size = sizeof(u16);
1600+
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
1601+
break;
1602+
case NVME_NVM_NS_64B_GUARD:
1603+
integrity.profile = &ext_pi_type1_crc64;
1604+
integrity.tag_size = sizeof(u16);
1605+
integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
1606+
break;
1607+
default:
1608+
integrity.profile = NULL;
1609+
break;
1610+
}
15631611
break;
15641612
default:
15651613
integrity.profile = NULL;
15661614
break;
15671615
}
1568-
integrity.tuple_size = ms;
1616+
1617+
integrity.tuple_size = ns->ms;
15691618
blk_integrity_register(disk, &integrity);
15701619
blk_queue_max_integrity_segments(disk->queue, max_integrity_segments);
15711620
}
15721621
#else
1573-
static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type,
1622+
static void nvme_init_integrity(struct gendisk *disk, struct nvme_ns *ns,
15741623
u32 max_integrity_segments)
15751624
{
15761625
}
@@ -1612,17 +1661,73 @@ static bool nvme_ns_ids_equal(struct nvme_ns_ids *a, struct nvme_ns_ids *b)
16121661
a->csi == b->csi;
16131662
}
16141663

1615-
static void nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id)
1664+
static int nvme_init_ms(struct nvme_ns *ns, struct nvme_id_ns *id)
16161665
{
1666+
bool first = id->dps & NVME_NS_DPS_PI_FIRST;
1667+
unsigned lbaf = nvme_lbaf_index(id->flbas);
16171668
struct nvme_ctrl *ctrl = ns->ctrl;
1669+
struct nvme_command c = { };
1670+
struct nvme_id_ns_nvm *nvm;
1671+
int ret = 0;
1672+
u32 elbaf;
1673+
1674+
ns->pi_size = 0;
1675+
ns->ms = le16_to_cpu(id->lbaf[lbaf].ms);
1676+
if (!(ctrl->ctratt & NVME_CTRL_ATTR_ELBAS)) {
1677+
ns->pi_size = sizeof(struct t10_pi_tuple);
1678+
ns->guard_type = NVME_NVM_NS_16B_GUARD;
1679+
goto set_pi;
1680+
}
1681+
1682+
nvm = kzalloc(sizeof(*nvm), GFP_KERNEL);
1683+
if (!nvm)
1684+
return -ENOMEM;
16181685

1619-
ns->ms = le16_to_cpu(id->lbaf[id->flbas & NVME_NS_FLBAS_LBA_MASK].ms);
1620-
if (id->dps & NVME_NS_DPS_PI_FIRST ||
1621-
ns->ms == sizeof(struct t10_pi_tuple))
1686+
c.identify.opcode = nvme_admin_identify;
1687+
c.identify.nsid = cpu_to_le32(ns->head->ns_id);
1688+
c.identify.cns = NVME_ID_CNS_CS_NS;
1689+
c.identify.csi = NVME_CSI_NVM;
1690+
1691+
ret = nvme_submit_sync_cmd(ns->ctrl->admin_q, &c, nvm, sizeof(*nvm));
1692+
if (ret)
1693+
goto free_data;
1694+
1695+
elbaf = le32_to_cpu(nvm->elbaf[lbaf]);
1696+
1697+
/* no support for storage tag formats right now */
1698+
if (nvme_elbaf_sts(elbaf))
1699+
goto free_data;
1700+
1701+
ns->guard_type = nvme_elbaf_guard_type(elbaf);
1702+
switch (ns->guard_type) {
1703+
case NVME_NVM_NS_64B_GUARD:
1704+
ns->pi_size = sizeof(struct crc64_pi_tuple);
1705+
break;
1706+
case NVME_NVM_NS_16B_GUARD:
1707+
ns->pi_size = sizeof(struct t10_pi_tuple);
1708+
break;
1709+
default:
1710+
break;
1711+
}
1712+
1713+
free_data:
1714+
kfree(nvm);
1715+
set_pi:
1716+
if (ns->pi_size && (first || ns->ms == ns->pi_size))
16221717
ns->pi_type = id->dps & NVME_NS_DPS_PI_MASK;
16231718
else
16241719
ns->pi_type = 0;
16251720

1721+
return ret;
1722+
}
1723+
1724+
static void nvme_configure_metadata(struct nvme_ns *ns, struct nvme_id_ns *id)
1725+
{
1726+
struct nvme_ctrl *ctrl = ns->ctrl;
1727+
1728+
if (nvme_init_ms(ns, id))
1729+
return;
1730+
16261731
ns->features &= ~(NVME_NS_METADATA_SUPPORTED | NVME_NS_EXT_LBAS);
16271732
if (!ns->ms || !(ctrl->ops->flags & NVME_F_METADATA_SUPPORTED))
16281733
return;
@@ -1738,7 +1843,7 @@ static void nvme_update_disk_info(struct gendisk *disk,
17381843
if (ns->ms) {
17391844
if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) &&
17401845
(ns->features & NVME_NS_METADATA_SUPPORTED))
1741-
nvme_init_integrity(disk, ns->ms, ns->pi_type,
1846+
nvme_init_integrity(disk, ns,
17421847
ns->ctrl->max_integrity_segments);
17431848
else if (!nvme_ns_has_pi(ns))
17441849
capacity = 0;
@@ -1793,7 +1898,7 @@ static void nvme_set_chunk_sectors(struct nvme_ns *ns, struct nvme_id_ns *id)
17931898

17941899
static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_id_ns *id)
17951900
{
1796-
unsigned lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
1901+
unsigned lbaf = nvme_lbaf_index(id->flbas);
17971902
int ret;
17981903

17991904
blk_mq_freeze_queue(ns->disk->queue);
@@ -2138,20 +2243,27 @@ static int nvme_configure_timestamp(struct nvme_ctrl *ctrl)
21382243
return ret;
21392244
}
21402245

2141-
static int nvme_configure_acre(struct nvme_ctrl *ctrl)
2246+
static int nvme_configure_host_options(struct nvme_ctrl *ctrl)
21422247
{
21432248
struct nvme_feat_host_behavior *host;
2249+
u8 acre = 0, lbafee = 0;
21442250
int ret;
21452251

21462252
/* Don't bother enabling the feature if retry delay is not reported */
2147-
if (!ctrl->crdt[0])
2253+
if (ctrl->crdt[0])
2254+
acre = NVME_ENABLE_ACRE;
2255+
if (ctrl->ctratt & NVME_CTRL_ATTR_ELBAS)
2256+
lbafee = NVME_ENABLE_LBAFEE;
2257+
2258+
if (!acre && !lbafee)
21482259
return 0;
21492260

21502261
host = kzalloc(sizeof(*host), GFP_KERNEL);
21512262
if (!host)
21522263
return 0;
21532264

2154-
host->acre = NVME_ENABLE_ACRE;
2265+
host->acre = acre;
2266+
host->lbafee = lbafee;
21552267
ret = nvme_set_features(ctrl, NVME_FEAT_HOST_BEHAVIOR, 0,
21562268
host, sizeof(*host), NULL);
21572269
kfree(host);
@@ -2989,7 +3101,7 @@ int nvme_init_ctrl_finish(struct nvme_ctrl *ctrl)
29893101
if (ret < 0)
29903102
return ret;
29913103

2992-
ret = nvme_configure_acre(ctrl);
3104+
ret = nvme_configure_host_options(ctrl);
29933105
if (ret < 0)
29943106
return ret;
29953107

@@ -4703,12 +4815,14 @@ static inline void _nvme_check_size(void)
47034815
BUILD_BUG_ON(sizeof(struct nvme_id_ctrl) != NVME_IDENTIFY_DATA_SIZE);
47044816
BUILD_BUG_ON(sizeof(struct nvme_id_ns) != NVME_IDENTIFY_DATA_SIZE);
47054817
BUILD_BUG_ON(sizeof(struct nvme_id_ns_zns) != NVME_IDENTIFY_DATA_SIZE);
4818+
BUILD_BUG_ON(sizeof(struct nvme_id_ns_nvm) != NVME_IDENTIFY_DATA_SIZE);
47064819
BUILD_BUG_ON(sizeof(struct nvme_id_ctrl_zns) != NVME_IDENTIFY_DATA_SIZE);
47074820
BUILD_BUG_ON(sizeof(struct nvme_id_ctrl_nvm) != NVME_IDENTIFY_DATA_SIZE);
47084821
BUILD_BUG_ON(sizeof(struct nvme_lba_range_type) != 64);
47094822
BUILD_BUG_ON(sizeof(struct nvme_smart_log) != 512);
47104823
BUILD_BUG_ON(sizeof(struct nvme_dbbuf) != 64);
47114824
BUILD_BUG_ON(sizeof(struct nvme_directive_cmd) != 64);
4825+
BUILD_BUG_ON(sizeof(struct nvme_feat_host_behavior) != 512);
47124826
}
47134827

47144828

drivers/nvme/host/nvme.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,9 +453,11 @@ struct nvme_ns {
453453

454454
int lba_shift;
455455
u16 ms;
456+
u16 pi_size;
456457
u16 sgs;
457458
u32 sws;
458459
u8 pi_type;
460+
u8 guard_type;
459461
#ifdef CONFIG_BLK_DEV_ZONED
460462
u64 zsze;
461463
#endif
@@ -478,7 +480,7 @@ struct nvme_ns {
478480
/* NVMe ns supports metadata actions by the controller (generate/strip) */
479481
static inline bool nvme_ns_has_pi(struct nvme_ns *ns)
480482
{
481-
return ns->pi_type && ns->ms == sizeof(struct t10_pi_tuple);
483+
return ns->pi_type && ns->ms == ns->pi_size;
482484
}
483485

484486
struct nvme_ctrl_ops {

0 commit comments

Comments
 (0)