Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2016 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/endian.h"
9 : : #include "spdk/nvme.h"
10 : : #include "spdk/env.h"
11 : : #include "spdk/log.h"
12 : :
13 : : #define MAX_DEVS 64
14 : :
15 : : struct dev {
16 : : struct spdk_pci_addr pci_addr;
17 : : struct spdk_nvme_ctrlr *ctrlr;
18 : : char name[100];
19 : : };
20 : :
21 : : static struct dev g_devs[MAX_DEVS];
22 : : static int g_num_devs = 0;
23 : :
24 : : #define foreach_dev(iter) \
25 : : for (iter = g_devs; iter - g_devs < g_num_devs; iter++)
26 : :
27 : : static int g_outstanding_commands;
28 : : static int g_reserve_command_result;
29 : : static bool g_feat_host_id_successful;
30 : :
31 : : #define HOST_ID 0xABABABABCDCDCDCD
32 : : #define EXT_HOST_ID ((uint8_t[]){0x0f, 0x97, 0xcd, 0x74, 0x8c, 0x80, 0x41, 0x42, \
33 : : 0x99, 0x0f, 0x65, 0xc4, 0xf0, 0x39, 0x24, 0x20})
34 : :
35 : : #define CR_KEY 0xDEADBEAF5A5A5A5B
36 : :
37 : : static void
38 : 0 : feat_host_id_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
39 : : {
40 [ # # # # ]: 0 : if (spdk_nvme_cpl_is_error(cpl)) {
41 : 0 : fprintf(stdout, "Get/Set Features - Host Identifier failed\n");
42 : 0 : g_feat_host_id_successful = false;
43 : : } else {
44 : 0 : g_feat_host_id_successful = true;
45 : : }
46 : 0 : g_outstanding_commands--;
47 : 0 : }
48 : :
49 : : static int
50 : 0 : get_host_identifier(struct spdk_nvme_ctrlr *ctrlr)
51 : : {
52 : : int ret;
53 : 0 : uint8_t host_id[16];
54 : : uint32_t host_id_size;
55 : : uint32_t cdw11;
56 : :
57 [ # # ]: 0 : if (spdk_nvme_ctrlr_get_data(ctrlr)->ctratt.bits.host_id_exhid_supported) {
58 : 0 : host_id_size = 16;
59 : 0 : cdw11 = 1;
60 : 0 : printf("Using 128-bit extended host identifier\n");
61 : : } else {
62 : 0 : host_id_size = 8;
63 : 0 : cdw11 = 0;
64 : 0 : printf("Using 64-bit host identifier\n");
65 : : }
66 : :
67 : 0 : g_outstanding_commands = 0;
68 : 0 : ret = spdk_nvme_ctrlr_cmd_get_feature(ctrlr, SPDK_NVME_FEAT_HOST_IDENTIFIER, cdw11, host_id,
69 : : host_id_size,
70 : : feat_host_id_completion, NULL);
71 [ # # ]: 0 : if (ret) {
72 : 0 : fprintf(stdout, "Get Feature: Failed\n");
73 : 0 : return -1;
74 : : }
75 : :
76 : 0 : g_outstanding_commands++;
77 : 0 : g_feat_host_id_successful = false;
78 : :
79 [ # # ]: 0 : while (g_outstanding_commands) {
80 : 0 : spdk_nvme_ctrlr_process_admin_completions(ctrlr);
81 : : }
82 : :
83 [ # # ]: 0 : if (g_feat_host_id_successful) {
84 : 0 : spdk_log_dump(stdout, "Get Feature: Host Identifier:", host_id, host_id_size);
85 : 0 : return 0;
86 : : }
87 : :
88 : 0 : return -1;
89 : : }
90 : :
91 : : static int
92 : 0 : set_host_identifier(struct spdk_nvme_ctrlr *ctrlr)
93 : : {
94 : : int ret;
95 : 0 : uint8_t host_id[16] = {};
96 : : uint32_t host_id_size;
97 : : uint32_t cdw11;
98 : :
99 [ # # ]: 0 : if (spdk_nvme_ctrlr_get_data(ctrlr)->ctratt.bits.host_id_exhid_supported) {
100 : 0 : host_id_size = 16;
101 : 0 : cdw11 = 1;
102 : 0 : printf("Using 128-bit extended host identifier\n");
103 : 0 : memcpy(host_id, EXT_HOST_ID, host_id_size);
104 : : } else {
105 : 0 : host_id_size = 8;
106 : 0 : cdw11 = 0;
107 : 0 : to_be64(host_id, HOST_ID);
108 : 0 : printf("Using 64-bit host identifier\n");
109 : : }
110 : :
111 : 0 : g_outstanding_commands = 0;
112 : 0 : ret = spdk_nvme_ctrlr_cmd_set_feature(ctrlr, SPDK_NVME_FEAT_HOST_IDENTIFIER, cdw11, 0, host_id,
113 : : host_id_size, feat_host_id_completion, NULL);
114 [ # # ]: 0 : if (ret) {
115 : 0 : fprintf(stdout, "Set Feature: Failed\n");
116 : 0 : return -1;
117 : : }
118 : :
119 : 0 : g_outstanding_commands++;
120 : 0 : g_feat_host_id_successful = false;
121 : :
122 [ # # ]: 0 : while (g_outstanding_commands) {
123 : 0 : spdk_nvme_ctrlr_process_admin_completions(ctrlr);
124 : : }
125 : :
126 [ # # ]: 0 : if (g_feat_host_id_successful) {
127 : 0 : spdk_log_dump(stdout, "Set Feature: Host Identifier:", host_id, host_id_size);
128 : 0 : return 0;
129 : : }
130 : :
131 : 0 : fprintf(stderr, "Set Feature: Host Identifier Failed\n");
132 : 0 : return -1;
133 : : }
134 : :
135 : : static void
136 : 0 : reservation_ns_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
137 : : {
138 [ # # # # ]: 0 : if (spdk_nvme_cpl_is_error(cpl)) {
139 : 0 : g_reserve_command_result = -1;
140 : : } else {
141 : 0 : g_reserve_command_result = 0;
142 : : }
143 : :
144 : 0 : g_outstanding_commands--;
145 : 0 : }
146 : :
147 : : static int
148 : 0 : reservation_ns_register(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair,
149 : : uint32_t ns_id, bool reg)
150 : : {
151 : : int ret;
152 : 0 : struct spdk_nvme_reservation_register_data rr_data;
153 : : enum spdk_nvme_reservation_register_action action;
154 : : struct spdk_nvme_ns *ns;
155 : :
156 : 0 : ns = spdk_nvme_ctrlr_get_ns(ctrlr, ns_id);
157 : :
158 [ # # ]: 0 : if (reg) {
159 : 0 : rr_data.crkey = 0;
160 : 0 : rr_data.nrkey = CR_KEY;
161 : 0 : action = SPDK_NVME_RESERVE_REGISTER_KEY;
162 : : } else {
163 : 0 : rr_data.crkey = CR_KEY;
164 : 0 : rr_data.nrkey = 0;
165 : 0 : action = SPDK_NVME_RESERVE_UNREGISTER_KEY;
166 : : }
167 : :
168 : 0 : g_outstanding_commands = 0;
169 : 0 : g_reserve_command_result = -1;
170 : :
171 : 0 : ret = spdk_nvme_ns_cmd_reservation_register(ns, qpair, &rr_data, true,
172 : : action,
173 : : SPDK_NVME_RESERVE_PTPL_CLEAR_POWER_ON,
174 : : reservation_ns_completion, NULL);
175 [ # # ]: 0 : if (ret) {
176 : 0 : fprintf(stderr, "Reservation Register Failed\n");
177 : 0 : return -1;
178 : : }
179 : :
180 : 0 : g_outstanding_commands++;
181 [ # # ]: 0 : while (g_outstanding_commands) {
182 : 0 : spdk_nvme_qpair_process_completions(qpair, 100);
183 : : }
184 : :
185 [ # # ]: 0 : if (g_reserve_command_result) {
186 : 0 : fprintf(stderr, "Reservation Register Failed\n");
187 : 0 : return -1;
188 : : }
189 : :
190 : 0 : return 0;
191 : : }
192 : :
193 : : static int
194 : 0 : reservation_ns_report(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair, uint32_t ns_id)
195 : : {
196 : : int ret, i;
197 : : uint8_t *payload;
198 : : struct spdk_nvme_reservation_status_data *status;
199 : : struct spdk_nvme_registered_ctrlr_data *cdata;
200 : : struct spdk_nvme_ns *ns;
201 : :
202 : 0 : ns = spdk_nvme_ctrlr_get_ns(ctrlr, ns_id);
203 : :
204 : 0 : g_outstanding_commands = 0;
205 : 0 : g_reserve_command_result = -1;
206 : :
207 : 0 : payload = spdk_dma_zmalloc(0x1000, 0x1000, NULL);
208 [ # # ]: 0 : if (!payload) {
209 : 0 : fprintf(stderr, "DMA Buffer Allocation Failed\n");
210 : 0 : return -1;
211 : : }
212 : :
213 : 0 : ret = spdk_nvme_ns_cmd_reservation_report(ns, qpair, payload, 0x1000,
214 : : reservation_ns_completion, NULL);
215 [ # # ]: 0 : if (ret) {
216 : 0 : fprintf(stderr, "Reservation Report Failed\n");
217 : 0 : spdk_dma_free(payload);
218 : 0 : return -1;
219 : : }
220 : :
221 : 0 : g_outstanding_commands++;
222 [ # # ]: 0 : while (g_outstanding_commands) {
223 : 0 : spdk_nvme_qpair_process_completions(qpair, 100);
224 : : }
225 : :
226 [ # # ]: 0 : if (g_reserve_command_result) {
227 : 0 : fprintf(stderr, "Reservation Report Failed\n");
228 : 0 : spdk_dma_free(payload);
229 : 0 : return -1;
230 : : }
231 : :
232 : 0 : status = (struct spdk_nvme_reservation_status_data *)payload;
233 : 0 : fprintf(stdout, "Reservation Generation Counter %u\n", status->gen);
234 : 0 : fprintf(stdout, "Reservation type %u\n", status->rtype);
235 : 0 : fprintf(stdout, "Reservation Number of Registered Controllers %u\n", status->regctl);
236 : 0 : fprintf(stdout, "Reservation Persist Through Power Loss State %u\n", status->ptpls);
237 [ # # ]: 0 : for (i = 0; i < status->regctl; i++) {
238 : 0 : cdata = (struct spdk_nvme_registered_ctrlr_data *)(payload +
239 : 0 : sizeof(struct spdk_nvme_reservation_status_data) +
240 : : sizeof(struct spdk_nvme_registered_ctrlr_data) * i);
241 : 0 : fprintf(stdout, "Controller ID %u\n", cdata->cntlid);
242 : 0 : fprintf(stdout, "Controller Reservation Status %u\n", cdata->rcsts.status);
243 : 0 : fprintf(stdout, "Controller Host ID 0x%"PRIx64"\n", cdata->hostid);
244 : 0 : fprintf(stdout, "Controller Reservation Key 0x%"PRIx64"\n", cdata->rkey);
245 : : }
246 : :
247 : 0 : spdk_dma_free(payload);
248 : 0 : return 0;
249 : : }
250 : :
251 : : static int
252 : 0 : reservation_ns_acquire(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair, uint32_t ns_id)
253 : : {
254 : : int ret;
255 : 0 : struct spdk_nvme_reservation_acquire_data cdata;
256 : : struct spdk_nvme_ns *ns;
257 : :
258 : 0 : ns = spdk_nvme_ctrlr_get_ns(ctrlr, ns_id);
259 : 0 : cdata.crkey = CR_KEY;
260 : 0 : cdata.prkey = 0;
261 : :
262 : 0 : g_outstanding_commands = 0;
263 : 0 : g_reserve_command_result = -1;
264 : :
265 : 0 : ret = spdk_nvme_ns_cmd_reservation_acquire(ns, qpair, &cdata,
266 : : false,
267 : : SPDK_NVME_RESERVE_ACQUIRE,
268 : : SPDK_NVME_RESERVE_WRITE_EXCLUSIVE,
269 : : reservation_ns_completion, NULL);
270 [ # # ]: 0 : if (ret) {
271 : 0 : fprintf(stderr, "Reservation Acquire Failed\n");
272 : 0 : return -1;
273 : : }
274 : :
275 : 0 : g_outstanding_commands++;
276 [ # # ]: 0 : while (g_outstanding_commands) {
277 : 0 : spdk_nvme_qpair_process_completions(qpair, 100);
278 : : }
279 : :
280 [ # # ]: 0 : if (g_reserve_command_result) {
281 : 0 : fprintf(stderr, "Reservation Acquire Failed\n");
282 : 0 : return -1;
283 : : }
284 : :
285 : 0 : return 0;
286 : : }
287 : :
288 : : static int
289 : 0 : reservation_ns_release(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_qpair *qpair, uint32_t ns_id)
290 : : {
291 : : int ret;
292 : 0 : struct spdk_nvme_reservation_key_data cdata;
293 : : struct spdk_nvme_ns *ns;
294 : :
295 : 0 : ns = spdk_nvme_ctrlr_get_ns(ctrlr, ns_id);
296 : 0 : cdata.crkey = CR_KEY;
297 : :
298 : 0 : g_outstanding_commands = 0;
299 : 0 : g_reserve_command_result = -1;
300 : :
301 : 0 : ret = spdk_nvme_ns_cmd_reservation_release(ns, qpair, &cdata,
302 : : false,
303 : : SPDK_NVME_RESERVE_RELEASE,
304 : : SPDK_NVME_RESERVE_WRITE_EXCLUSIVE,
305 : : reservation_ns_completion, NULL);
306 [ # # ]: 0 : if (ret) {
307 : 0 : fprintf(stderr, "Reservation Release Failed\n");
308 : 0 : return -1;
309 : : }
310 : :
311 : 0 : g_outstanding_commands++;
312 [ # # ]: 0 : while (g_outstanding_commands) {
313 : 0 : spdk_nvme_qpair_process_completions(qpair, 100);
314 : : }
315 : :
316 [ # # ]: 0 : if (g_reserve_command_result) {
317 : 0 : fprintf(stderr, "Reservation Release Failed\n");
318 : 0 : return -1;
319 : : }
320 : :
321 : 0 : return 0;
322 : : }
323 : :
324 : : static int
325 : 3 : reserve_controller(struct spdk_nvme_ctrlr *ctrlr, const struct spdk_pci_addr *pci_addr)
326 : : {
327 : : const struct spdk_nvme_ctrlr_data *cdata;
328 : : struct spdk_nvme_qpair *qpair;
329 : : int ret;
330 : :
331 : 3 : cdata = spdk_nvme_ctrlr_get_data(ctrlr);
332 : :
333 : 3 : printf("=====================================================\n");
334 : 3 : printf("NVMe Controller at PCI bus %d, device %d, function %d\n",
335 : 3 : pci_addr->bus, pci_addr->dev, pci_addr->func);
336 : 3 : printf("=====================================================\n");
337 : :
338 : 3 : printf("Reservations: %s\n",
339 [ - + ]: 3 : cdata->oncs.reservations ? "Supported" : "Not Supported");
340 : :
341 [ + - ]: 3 : if (!cdata->oncs.reservations) {
342 : 3 : return 0;
343 : : }
344 : :
345 : 0 : qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0);
346 [ # # ]: 0 : if (!qpair) {
347 : 0 : fprintf(stderr, "spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
348 : 0 : return -EIO;
349 : : }
350 : :
351 : 0 : ret = set_host_identifier(ctrlr);
352 [ # # ]: 0 : if (ret) {
353 : 0 : goto out;
354 : : }
355 : :
356 : 0 : ret = get_host_identifier(ctrlr);
357 [ # # ]: 0 : if (ret) {
358 : 0 : goto out;
359 : : }
360 : :
361 : : /* tested 1 namespace */
362 : 0 : ret += reservation_ns_register(ctrlr, qpair, 1, 1);
363 : 0 : ret += reservation_ns_acquire(ctrlr, qpair, 1);
364 : 0 : ret += reservation_ns_release(ctrlr, qpair, 1);
365 : 0 : ret += reservation_ns_register(ctrlr, qpair, 1, 0);
366 : 0 : ret += reservation_ns_report(ctrlr, qpair, 1);
367 : :
368 : 0 : out:
369 : 0 : spdk_nvme_ctrlr_free_io_qpair(qpair);
370 : 0 : return ret;
371 : : }
372 : :
373 : : static bool
374 : 0 : probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
375 : : struct spdk_nvme_ctrlr_opts *opts)
376 : : {
377 : 0 : return true;
378 : : }
379 : :
380 : : static void
381 : 3 : attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
382 : : struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
383 : : {
384 : : struct dev *dev;
385 : :
386 : : /* add to dev list */
387 : 3 : dev = &g_devs[g_num_devs++];
388 : 3 : spdk_pci_addr_parse(&dev->pci_addr, trid->traddr);
389 : 3 : dev->ctrlr = ctrlr;
390 : 3 : }
391 : :
392 : : int
393 : 2 : main(int argc, char **argv)
394 : : {
395 : : struct dev *iter;
396 : 0 : struct spdk_env_opts opts;
397 : 2 : int ret = 0;
398 : 2 : struct spdk_nvme_detach_ctx *detach_ctx = NULL;
399 : :
400 : 2 : spdk_env_opts_init(&opts);
401 : 2 : opts.name = "reserve";
402 : 2 : opts.core_mask = "0x1";
403 : 2 : opts.shm_id = 0;
404 [ - + ]: 2 : if (spdk_env_init(&opts) < 0) {
405 : 0 : fprintf(stderr, "Unable to initialize SPDK env\n");
406 : 0 : return 1;
407 : : }
408 : :
409 [ - + ]: 2 : if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
410 : 0 : fprintf(stderr, "spdk_nvme_probe() failed\n");
411 : 0 : return 1;
412 : : }
413 : :
414 [ + + ]: 5 : foreach_dev(iter) {
415 : 3 : ret = reserve_controller(iter->ctrlr, &iter->pci_addr);
416 [ - + ]: 3 : if (ret) {
417 : 0 : break;
418 : : }
419 : : }
420 : :
421 [ - + ]: 2 : printf("Reservation test %s\n", ret ? "failed" : "passed");
422 : :
423 [ + + ]: 5 : foreach_dev(iter) {
424 : 3 : spdk_nvme_detach_async(iter->ctrlr, &detach_ctx);
425 : : }
426 : :
427 [ - + ]: 2 : if (detach_ctx) {
428 : 0 : spdk_nvme_detach_poll(detach_ctx);
429 : : }
430 : :
431 : 2 : return ret;
432 : : }
|