Skip to content

Commit 9350e73

Browse files
brandon-paupore-sndkdwsuse
authored andcommitted
libnvme: 64-bit Reference Tags and TP-4068 changes
Adds support for expanded reference and storage tags, automatically placing them into the appropriate bits based on Protection Information Format and Storage Tag Size. This includes updates to nvme_io_args expanding the size of the tags and adding these STS and PIF values. Also adds a new copy range format as defined by the NVMe 2.0 spec, as it determines the reference/storage tags associated to the range being copied. Signed-off-by: Brandon Paupore <[email protected]> Signed-off-by: Jeff Lien <[email protected]>
1 parent 0b14eb6 commit 9350e73

6 files changed

Lines changed: 248 additions & 44 deletions

File tree

src/libnvme.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
LIBNVME_1_1 {
22
global:
33
nvme_get_version;
4+
nvme_init_copy_range_f1;
45
};
56

67
LIBNVME_1_0 {

src/nvme/ioctl.c

Lines changed: 142 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,13 @@ enum nvme_cmd_dword_fields {
267267
NVME_FORMAT_CDW10_PI_SHIFT = 5,
268268
NVME_FORMAT_CDW10_PIL_SHIFT = 8,
269269
NVME_FORMAT_CDW10_SES_SHIFT = 9,
270+
NVME_FORMAT_CDW10_LBAFU_SHIFT = 12,
270271
NVME_FORMAT_CDW10_LBAF_MASK = 0xf,
271272
NVME_FORMAT_CDW10_MSET_MASK = 0x1,
272273
NVME_FORMAT_CDW10_PI_MASK = 0x7,
273274
NVME_FORMAT_CDW10_PIL_MASK = 0x1,
274275
NVME_FORMAT_CDW10_SES_MASK = 0x7,
276+
NVME_FORMAT_CDW10_LBAFU_MASK = 0x3,
275277
NVME_SANITIZE_CDW10_SANACT_SHIFT = 0,
276278
NVME_SANITIZE_CDW10_AUSE_SHIFT = 3,
277279
NVME_SANITIZE_CDW10_OWPASS_SHIFT = 4,
@@ -1159,11 +1161,25 @@ int nvme_get_features_iocs_profile(int fd, enum nvme_get_features_sel sel,
11591161

11601162
int nvme_format_nvm(struct nvme_format_nvm_args *args)
11611163
{
1162-
__u32 cdw10 = NVME_SET(args->lbaf, FORMAT_CDW10_LBAF) |
1163-
NVME_SET(args->mset, FORMAT_CDW10_MSET) |
1164-
NVME_SET(args->pi, FORMAT_CDW10_PI) |
1165-
NVME_SET(args->pil, FORMAT_CDW10_PIL) |
1166-
NVME_SET(args->ses, FORMAT_CDW10_SES);
1164+
const size_t size_v1 = sizeof_args(struct nvme_format_nvm_args, lbaf, __u64);
1165+
const size_t size_v2 = sizeof_args(struct nvme_format_nvm_args, lbafu, __u64);
1166+
__u32 cdw10;
1167+
1168+
if (args->args_size < size_v1 || args->args_size > size_v2) {
1169+
errno = EINVAL;
1170+
return -1;
1171+
}
1172+
1173+
cdw10 = NVME_SET(args->lbaf, FORMAT_CDW10_LBAF) |
1174+
NVME_SET(args->mset, FORMAT_CDW10_MSET) |
1175+
NVME_SET(args->pi, FORMAT_CDW10_PI) |
1176+
NVME_SET(args->pil, FORMAT_CDW10_PIL) |
1177+
NVME_SET(args->ses, FORMAT_CDW10_SES);
1178+
1179+
if (args->args_size == size_v2) {
1180+
/* set lbafu extension */
1181+
cdw10 |= NVME_SET(args->lbafu, FORMAT_CDW10_LBAFU);
1182+
}
11671183

11681184
struct nvme_passthru_cmd cmd = {
11691185
.opcode = nvme_admin_format_nvm,
@@ -1172,10 +1188,6 @@ int nvme_format_nvm(struct nvme_format_nvm_args *args)
11721188
.timeout_ms = args->timeout,
11731189
};
11741190

1175-
if (args->args_size < sizeof(*args)) {
1176-
errno = EINVAL;
1177-
return -1;
1178-
}
11791191
return nvme_submit_admin_passthru(args->fd, &cmd, args->result);
11801192
}
11811193

@@ -1588,16 +1600,81 @@ int nvme_io_passthru(int fd, __u8 opcode, __u8 flags, __u16 rsvd,
15881600
timeout_ms, result);
15891601
}
15901602

1603+
static int nvme_set_var_size_tags(__u32 *cmd_dw2, __u32 *cmd_dw3, __u32 *cmd_dw14,
1604+
__u8 pif, __u8 sts, __u64 reftag, __u64 storage_tag)
1605+
{
1606+
__u32 cdw2 = 0, cdw3 = 0, cdw14;
1607+
1608+
switch (pif) {
1609+
/* 16b Protection Information */
1610+
case 0:
1611+
cdw14 = reftag & 0xffffffff;
1612+
cdw14 |= ((storage_tag << (32 - sts)) & 0xffffffff);
1613+
break;
1614+
/* 32b Protection Information */
1615+
case 1:
1616+
cdw14 = reftag & 0xffffffff;
1617+
cdw3 = reftag >> 32;
1618+
cdw14 |= ((storage_tag << (80 - sts)) & 0xffff0000);
1619+
if (sts >= 48)
1620+
cdw3 |= ((storage_tag >> (sts - 48)) & 0xffffffff);
1621+
else
1622+
cdw3 |= ((storage_tag << (48 - sts)) & 0xffffffff);
1623+
cdw2 = (storage_tag >> (sts - 16)) & 0xffff;
1624+
break;
1625+
/* 64b Protection Information */
1626+
case 2:
1627+
cdw14 = reftag & 0xffffffff;
1628+
cdw3 = (reftag >> 32) & 0xffff;
1629+
cdw14 |= ((storage_tag << (48 - sts)) & 0xffffffff);
1630+
if (sts >= 16)
1631+
cdw3 |= ((storage_tag >> (sts - 16)) & 0xffff);
1632+
else
1633+
cdw3 |= ((storage_tag << (16 - sts)) & 0xffff);
1634+
break;
1635+
default:
1636+
perror("Unsupported Protection Information Format");
1637+
errno = EINVAL;
1638+
return -1;
1639+
}
1640+
1641+
*cmd_dw2 = cdw2;
1642+
*cmd_dw3 = cdw3;
1643+
*cmd_dw14 = cdw14;
1644+
return 0;
1645+
}
1646+
15911647
int nvme_io(struct nvme_io_args *args, __u8 opcode)
15921648
{
1593-
__u32 cdw2 = args->storage_tag & 0xffffffff;
1594-
__u32 cdw3 = (args->storage_tag >> 32) & 0xffff;
1595-
__u32 cdw10 = args->slba & 0xffffffff;
1596-
__u32 cdw11 = args->slba >> 32;
1597-
__u32 cdw12 = args->nlb | (args->control << 16);
1598-
__u32 cdw13 = args->dsm | (args->dspec << 16);
1599-
__u32 cdw14 = args->reftag;
1600-
__u32 cdw15 = args->apptag | (args->appmask << 16);
1649+
const size_t size_v1 = sizeof_args(struct nvme_io_args, dsm, __u64);
1650+
const size_t size_v2 = sizeof_args(struct nvme_io_args, pif, __u64);
1651+
__u32 cdw2, cdw3, cdw10, cdw11, cdw12, cdw13, cdw14, cdw15;
1652+
1653+
if (args->args_size < size_v1 || args->args_size > size_v2) {
1654+
errno = EINVAL;
1655+
return -1;
1656+
}
1657+
1658+
cdw10 = args->slba & 0xffffffff;
1659+
cdw11 = args->slba >> 32;
1660+
cdw12 = args->nlb | (args->control << 16);
1661+
cdw13 = args->dsm | (args->dspec << 16);
1662+
cdw15 = args->apptag | (args->appmask << 16);
1663+
1664+
if (args->args_size == size_v1) {
1665+
cdw2 = (args->storage_tag >> 32) & 0xffff;
1666+
cdw3 = args->storage_tag & 0xffffffff;
1667+
cdw14 = args->reftag;
1668+
} else {
1669+
if (nvme_set_var_size_tags(&cdw2, &cdw3, &cdw14,
1670+
args->pif,
1671+
args->sts,
1672+
args->reftag_u64,
1673+
args->storage_tag)) {
1674+
errno = EINVAL;
1675+
return -1;
1676+
}
1677+
}
16011678

16021679
struct nvme_passthru_cmd cmd = {
16031680
.opcode = opcode,
@@ -1617,10 +1694,6 @@ int nvme_io(struct nvme_io_args *args, __u8 opcode)
16171694
.timeout_ms = args->timeout,
16181695
};
16191696

1620-
if (args->args_size < sizeof(*args)) {
1621-
errno = EINVAL;
1622-
return -1;
1623-
}
16241697
return nvme_submit_io_passthru(args->fd, &cmd, args->result);
16251698
}
16261699

@@ -1645,29 +1718,48 @@ int nvme_dsm(struct nvme_dsm_args *args)
16451718

16461719
int nvme_copy(struct nvme_copy_args *args)
16471720
{
1648-
__u32 cdw12 = ((args->nr - 1) & 0xff) | ((args->format & 0xf) << 8) |
1721+
const size_t size_v1 = sizeof_args(struct nvme_copy_args, format, __u64);
1722+
const size_t size_v2 = sizeof_args(struct nvme_copy_args, ilbrt_u64, __u64);
1723+
__u32 cdw3, cdw12, cdw14, data_len;
1724+
1725+
if (args->args_size < size_v1 || args->args_size > size_v2) {
1726+
errno = EINVAL;
1727+
return -1;
1728+
}
1729+
1730+
cdw12 = ((args->nr - 1) & 0xff) | ((args->format & 0xf) << 8) |
16491731
((args->prinfor & 0xf) << 12) | ((args->dtype & 0xf) << 20) |
16501732
((args->prinfow & 0xf) << 26) | ((args->fua & 0x1) << 30) |
16511733
((args->lr & 0x1) << 31);
16521734

1735+
if (args->args_size == size_v1) {
1736+
cdw3 = 0;
1737+
cdw14 = args->ilbrt;
1738+
} else {
1739+
cdw3 = (args->ilbrt_u64 >> 32) & 0xffffffff;
1740+
cdw14 = args->ilbrt_u64 & 0xffffffff;
1741+
}
1742+
1743+
if (args->format == 1)
1744+
data_len = args->nr * sizeof(struct nvme_copy_range_f1);
1745+
else
1746+
data_len = args->nr * sizeof(struct nvme_copy_range);
1747+
16531748
struct nvme_passthru_cmd cmd = {
16541749
.opcode = nvme_cmd_copy,
16551750
.nsid = args->nsid,
16561751
.addr = (__u64)(uintptr_t)args->copy,
1657-
.data_len = args->nr * sizeof(*args->copy),
1752+
.data_len = data_len,
1753+
.cdw3 = cdw3,
16581754
.cdw10 = args->sdlba & 0xffffffff,
16591755
.cdw11 = args->sdlba >> 32,
16601756
.cdw12 = cdw12,
16611757
.cdw13 = (args->dspec & 0xffff) << 16,
1662-
.cdw14 = args->ilbrt,
1758+
.cdw14 = cdw14,
16631759
.cdw15 = (args->lbatm << 16) | args->lbat,
16641760
.timeout_ms = args->timeout,
16651761
};
16661762

1667-
if (args->args_size < sizeof(*args)) {
1668-
errno = EINVAL;
1669-
return -1;
1670-
}
16711763
return nvme_submit_io_passthru(args->fd, &cmd, args->result);
16721764
}
16731765

@@ -1821,15 +1913,32 @@ int nvme_zns_mgmt_recv(struct nvme_zns_mgmt_recv_args *args)
18211913

18221914
int nvme_zns_append(struct nvme_zns_append_args *args)
18231915
{
1824-
__u32 cdw10 = args->zslba & 0xffffffff;
1825-
__u32 cdw11 = args->zslba >> 32;
1826-
__u32 cdw12 = args->nlb | (args->control << 16);
1827-
__u32 cdw14 = args->ilbrt;
1828-
__u32 cdw15 = args->lbat | (args->lbatm << 16);
1916+
const size_t size_v1 = sizeof_args(struct nvme_zns_append_args, lbatm, __u64);
1917+
const size_t size_v2 = sizeof_args(struct nvme_zns_append_args, ilbrt_u64, __u64);
1918+
__u32 cdw3, cdw10, cdw11, cdw12, cdw14, cdw15;
1919+
1920+
if (args->args_size < size_v1 || args->args_size > size_v2) {
1921+
errno = EINVAL;
1922+
return -1;
1923+
}
1924+
1925+
cdw10 = args->zslba & 0xffffffff;
1926+
cdw11 = args->zslba >> 32;
1927+
cdw12 = args->nlb | (args->control << 16);
1928+
cdw15 = args->lbat | (args->lbatm << 16);
1929+
1930+
if (args->args_size == size_v1) {
1931+
cdw3 = 0;
1932+
cdw14 = args->ilbrt;
1933+
} else {
1934+
cdw3 = (args->ilbrt_u64 >> 32) & 0xffffffff;
1935+
cdw14 = args->ilbrt_u64 & 0xffffffff;
1936+
}
18291937

18301938
struct nvme_passthru_cmd64 cmd = {
18311939
.opcode = nvme_zns_cmd_append,
18321940
.nsid = args->nsid,
1941+
.cdw3 = cdw3,
18331942
.cdw10 = cdw10,
18341943
.cdw11 = cdw11,
18351944
.cdw12 = cdw12,
@@ -1842,10 +1951,6 @@ int nvme_zns_append(struct nvme_zns_append_args *args)
18421951
.timeout_ms = args->timeout,
18431952
};
18441953

1845-
if (args->args_size < sizeof(*args)) {
1846-
errno = EINVAL;
1847-
return -1;
1848-
}
18491954
return nvme_submit_io_passthru64(args->fd, &cmd, args->result);
18501955
}
18511956

src/nvme/ioctl.h

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,17 @@ struct nvme_passthru_cmd64 {
132132

133133
#endif /* _LINUX_NVME_IOCTL_H */
134134

135+
/**
136+
* Helper function used to determine structure sizes
137+
*/
138+
#define sizeof_args(type, member, align) \
139+
({ \
140+
type s; \
141+
size_t t = offsetof(type, member) + sizeof(s.member); \
142+
size_t p = (sizeof(align) - (t % sizeof(align))) % sizeof(align); \
143+
t + p; \
144+
})
145+
135146
/**
136147
* nvme_submit_admin_passthru64() - Submit a 64-bit nvme passthrough admin
137148
* command
@@ -2905,7 +2916,8 @@ int nvme_get_features_iocs_profile(int fd, enum nvme_get_features_sel sel,
29052916
* @pi: Protection information type
29062917
* @pil: Protection information location (beginning or end), true if end
29072918
* @ses: Secure erase settings
2908-
* @lbaf: Logical block address format
2919+
* @lbaf: Logical block address format least significant 4 bits
2920+
* @lbafu: Logical block address format most significant 2 bits
29092921
*/
29102922
struct nvme_format_nvm_args {
29112923
__u32 *result;
@@ -2918,6 +2930,8 @@ struct nvme_format_nvm_args {
29182930
enum nvme_cmd_format_pil pil;
29192931
enum nvme_cmd_format_ses ses;
29202932
__u8 lbaf;
2933+
__u8 rsvd1[7];
2934+
__u8 lbafu;
29212935
};
29222936

29232937
/**
@@ -3836,8 +3850,7 @@ static inline int nvme_flush(int fd, __u32 nsid) {
38363850
* struct nvme_io_args - Arguments for NVMe I/O commands
38373851
* @slba: Starting logical block
38383852
* @storage_tag: This filed specifies Variable Sized Expected Logical Block
3839-
* Storage Tag (ELBST) and Expected Logical Block Reference
3840-
* Tag (ELBRT)
3853+
* Storage Tag (ELBST) or Logical Block Storage Tag (LBST)
38413854
* @result: The command completion result from CQE dword0
38423855
* @data: Pointer to user address of the data buffer
38433856
* @metadata: Pointer to user address of the metadata buffer
@@ -3855,11 +3868,21 @@ static inline int nvme_flush(int fd, __u32 nsid) {
38553868
* @appmask: This field specifies the Application Tag expected value. Used
38563869
* only if the namespace is formatted to use end-to-end protection
38573870
* information.
3858-
* @reftag: This field specifies the Initial Logical Block Reference Tag
3859-
* expected value. Used only if the namespace is formatted to use
3860-
* end-to-end protection information.
3871+
* @reftag: This field specifies the variable sized Expected Initial
3872+
* Logical Block Reference Tag (EILBRT) or Initial Logical Block
3873+
* Reference Tag (ILBRT). Used only if the namespace is formatted
3874+
* to use end-to-end protection information.
38613875
* @dspec: Directive specific value
38623876
* @dsm: Data set management attributes, see &enum nvme_io_dsm_flags
3877+
* @reftag_u64: This field specifies the variable sized Expected Initial
3878+
* Logical Block Reference Tag (EILBRT) or Initial Logical Block
3879+
* Reference Tag (ILBRT). It is the 8 byte version required for
3880+
* enhanced protection information. Used only if the namespace is
3881+
* formatted to use end-to-end protection information.
3882+
* @sts: Storage tag size in bits, set by namespace Extended LBA Format
3883+
* @pif: Protection information format, determines how variable sized
3884+
* storage_tag and reftag are put into dwords 2, 3, and 14. Set by
3885+
* namespace Extended LBA Format.
38633886
*/
38643887
struct nvme_io_args {
38653888
__u64 slba;
@@ -3880,6 +3903,10 @@ struct nvme_io_args {
38803903
__u16 appmask;
38813904
__u16 dspec;
38823905
__u8 dsm;
3906+
__u8 rsvd1[1];
3907+
__u64 reftag_u64;
3908+
__u8 sts;
3909+
__u8 pif;
38833910
};
38843911

38853912
/**
@@ -4035,6 +4062,8 @@ int nvme_dsm(struct nvme_dsm_args *args);
40354062
* @prinfow: Protection information field for write
40364063
* @dtype: Directive type
40374064
* @format: Descriptor format
4065+
* @ilbrt_u64: Initial logical block reference tag - 8 byte
4066+
* version required for enhanced protection info
40384067
*/
40394068
struct nvme_copy_args {
40404069
__u64 sdlba;
@@ -4055,6 +4084,7 @@ struct nvme_copy_args {
40554084
__u8 prinfow;
40564085
__u8 dtype;
40574086
__u8 format;
4087+
__u64 ilbrt_u64;
40584088
};
40594089

40604090
/**
@@ -4347,6 +4377,9 @@ static inline int nvme_zns_report_zones(int fd, __u32 nsid, __u64 slba,
43474377
* @control:
43484378
* @lbat: Logical block application tag
43494379
* @lbatm: Logical block application tag mask
4380+
* @ilbrt_u64: Initial logical block reference tag - 8 byte
4381+
* version required for enhanced protection info
4382+
*
43504383
*/
43514384
struct nvme_zns_append_args {
43524385
__u64 zslba;
@@ -4364,6 +4397,8 @@ struct nvme_zns_append_args {
43644397
__u16 control;
43654398
__u16 lbat;
43664399
__u16 lbatm;
4400+
__u8 rsvd1[4];
4401+
__u64 ilbrt_u64;
43674402
};
43684403

43694404
/**

0 commit comments

Comments
 (0)