Skip to content

Commit e2e5ef6

Browse files
committed
cmds: move nvme_get_log and related code to cmds.c
Group all generic commands into one file. Signed-off-by: Daniel Wagner <[email protected]>
1 parent 224c9b6 commit e2e5ef6

2 files changed

Lines changed: 214 additions & 214 deletions

File tree

libnvme/src/nvme/cmds.c

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,220 @@
1515
#include "cleanup.h"
1616
#include "private.h"
1717

18+
static bool force_4k;
19+
20+
__attribute__((constructor))
21+
static void nvme_init_env(void)
22+
{
23+
char *val;
24+
25+
val = getenv("LIBNVME_FORCE_4K");
26+
if (!val)
27+
return;
28+
if (!strcmp(val, "1") ||
29+
!strcasecmp(val, "true") ||
30+
!strncasecmp(val, "enable", 6))
31+
force_4k = true;
32+
}
33+
34+
35+
int nvme_get_log(struct nvme_transport_handle *hdl,
36+
struct nvme_passthru_cmd *cmd, bool rae,
37+
__u32 xfer_len)
38+
{
39+
__u64 offset = 0, xfer, data_len = cmd->data_len;
40+
__u64 start = (__u64)cmd->cdw13 << 32 | cmd->cdw12;
41+
__u64 lpo;
42+
void *ptr = (void *)(uintptr_t)cmd->addr;
43+
int ret;
44+
bool _rae;
45+
__u32 numd;
46+
__u16 numdu, numdl;
47+
__u32 cdw10 = cmd->cdw10 & (NVME_VAL(LOG_CDW10_LID) |
48+
NVME_VAL(LOG_CDW10_LSP));
49+
__u32 cdw11 = cmd->cdw11 & NVME_VAL(LOG_CDW11_LSI);
50+
51+
if (force_4k)
52+
xfer_len = NVME_LOG_PAGE_PDU_SIZE;
53+
54+
/*
55+
* 4k is the smallest possible transfer unit, so restricting to 4k
56+
* avoids having to check the MDTS value of the controller.
57+
*/
58+
do {
59+
if (!force_4k) {
60+
xfer = data_len - offset;
61+
if (xfer > xfer_len)
62+
xfer = xfer_len;
63+
} else {
64+
xfer = NVME_LOG_PAGE_PDU_SIZE;
65+
}
66+
67+
/*
68+
* Always retain regardless of the RAE parameter until the very
69+
* last portion of this log page so the data remains latched
70+
* during the fetch sequence.
71+
*/
72+
lpo = start + offset;
73+
numd = (xfer >> 2) - 1;
74+
numdu = numd >> 16;
75+
numdl = numd & 0xffff;
76+
_rae = offset + xfer < data_len || rae;
77+
78+
cmd->cdw10 = cdw10 |
79+
NVME_SET(!!_rae, LOG_CDW10_RAE) |
80+
NVME_SET(numdl, LOG_CDW10_NUMDL);
81+
cmd->cdw11 = cdw11 |
82+
NVME_SET(numdu, LOG_CDW11_NUMDU);
83+
cmd->cdw12 = lpo & 0xffffffff;
84+
cmd->cdw13 = lpo >> 32;
85+
cmd->data_len = xfer;
86+
cmd->addr = (__u64)(uintptr_t)ptr;
87+
88+
if (hdl->ctx->uring_enabled)
89+
ret = nvme_uring_cmd_admin_passthru_async(hdl, cmd);
90+
else
91+
ret = nvme_submit_admin_passthru(hdl, cmd);
92+
if (ret)
93+
return ret;
94+
95+
offset += xfer;
96+
ptr += xfer;
97+
} while (offset < data_len);
98+
99+
if (hdl->ctx->uring_enabled) {
100+
ret = nvme_uring_cmd_wait_complete(hdl);
101+
if (ret)
102+
return ret;
103+
}
104+
105+
return 0;
106+
}
107+
108+
static int read_ana_chunk(struct nvme_transport_handle *hdl, enum nvme_log_ana_lsp lsp, bool rae,
109+
__u8 *log, __u8 **read, __u8 *to_read, __u8 *log_end)
110+
{
111+
struct nvme_passthru_cmd cmd;
112+
113+
if (to_read > log_end)
114+
return -ENOSPC;
115+
116+
while (*read < to_read) {
117+
__u32 len = min_t(__u32, log_end - *read, NVME_LOG_PAGE_PDU_SIZE);
118+
int ret;
119+
120+
nvme_init_get_log_ana(&cmd, lsp, *read - log, *read, len);
121+
ret = nvme_get_log(hdl, &cmd, rae, NVME_LOG_PAGE_PDU_SIZE);
122+
if (ret)
123+
return ret;
124+
125+
*read += len;
126+
}
127+
return 0;
128+
}
129+
130+
static int try_read_ana(struct nvme_transport_handle *hdl, enum nvme_log_ana_lsp lsp, bool rae,
131+
struct nvme_ana_log *log, __u8 *log_end,
132+
__u8 *read, __u8 **to_read, bool *may_retry)
133+
{
134+
__u16 ngrps = le16_to_cpu(log->ngrps);
135+
136+
while (ngrps--) {
137+
__u8 *group = *to_read;
138+
int ret;
139+
__le32 nnsids;
140+
141+
*to_read += sizeof(*log->descs);
142+
ret = read_ana_chunk(hdl, lsp, rae,
143+
(__u8 *)log, &read, *to_read, log_end);
144+
if (ret) {
145+
/*
146+
* If the provided buffer isn't long enough,
147+
* the log page may have changed while reading it
148+
* and the computed length was inaccurate.
149+
* Have the caller check chgcnt and retry.
150+
*/
151+
*may_retry = ret == -ENOSPC;
152+
return ret;
153+
}
154+
155+
/*
156+
* struct nvme_ana_group_desc has 8-byte alignment
157+
* but the group pointer is only 4-byte aligned.
158+
* Don't dereference the misaligned pointer.
159+
*/
160+
memcpy(&nnsids,
161+
group + offsetof(struct nvme_ana_group_desc, nnsids),
162+
sizeof(nnsids));
163+
*to_read += le32_to_cpu(nnsids) * sizeof(__le32);
164+
ret = read_ana_chunk(hdl, lsp, rae,
165+
(__u8 *)log, &read, *to_read, log_end);
166+
if (ret) {
167+
*may_retry = ret == -ENOSPC;
168+
return ret;
169+
}
170+
}
171+
172+
*may_retry = true;
173+
return 0;
174+
}
175+
176+
int nvme_get_ana_log_atomic(struct nvme_transport_handle *hdl, bool rae, bool rgo,
177+
struct nvme_ana_log *log, __u32 *len,
178+
unsigned int retries)
179+
{
180+
const enum nvme_log_ana_lsp lsp =
181+
rgo ? NVME_LOG_ANA_LSP_RGO_GROUPS_ONLY : 0;
182+
/* Get Log Page can only fetch multiples of dwords */
183+
__u8 * const log_end = (__u8 *)log + (*len & -4);
184+
__u8 *read = (__u8 *)log;
185+
__u8 *to_read;
186+
int ret;
187+
188+
if (!retries)
189+
return -EINVAL;
190+
191+
to_read = (__u8 *)log->descs;
192+
ret = read_ana_chunk(hdl, lsp, rae,
193+
(__u8 *)log, &read, to_read, log_end);
194+
if (ret)
195+
return ret;
196+
197+
do {
198+
bool may_retry = false;
199+
int saved_ret;
200+
int saved_errno;
201+
__le64 chgcnt;
202+
203+
saved_ret = try_read_ana(hdl, lsp, rae, log, log_end,
204+
read, &to_read, &may_retry);
205+
/*
206+
* If the log page was read with multiple Get Log Page commands,
207+
* chgcnt must be checked afterwards to ensure atomicity
208+
*/
209+
*len = to_read - (__u8 *)log;
210+
if (*len <= NVME_LOG_PAGE_PDU_SIZE || !may_retry)
211+
return saved_ret;
212+
213+
saved_errno = errno;
214+
chgcnt = log->chgcnt;
215+
read = (__u8 *)log;
216+
to_read = (__u8 *)log->descs;
217+
ret = read_ana_chunk(hdl, lsp, rae,
218+
(__u8 *)log, &read, to_read, log_end);
219+
if (ret)
220+
return ret;
221+
222+
if (log->chgcnt == chgcnt) {
223+
/* Log hasn't changed; return try_read_ana() result */
224+
errno = saved_errno;
225+
return saved_ret;
226+
}
227+
} while (--retries);
228+
229+
return -EAGAIN;
230+
}
231+
18232
int nvme_set_etdas(struct nvme_transport_handle *hdl, bool *changed)
19233
{
20234
struct nvme_feat_host_behavior da4;

0 commit comments

Comments
 (0)