4 * Copyright (c) Intel Corporation.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 #include "spdk/nvme.h"
46 struct spdk_pci_addr pci_addr
;
47 struct spdk_nvme_ctrlr
*ctrlr
;
51 static struct dev devs
[MAX_DEVS
];
52 static int num_devs
= 0;
54 #define foreach_dev(iter) \
55 for (iter = devs; iter - devs < num_devs; iter++)
57 static int outstanding_commands
;
58 static int reserve_command_result
;
59 static int set_feature_result
;
66 static struct feature features
[256];
68 #define HOST_ID 0xABABABABCDCDCDCD
69 #define CR_KEY 0xDEADBEAF5A5A5A5B
72 get_feature_completion(void *cb_arg
, const struct spdk_nvme_cpl
*cpl
)
74 struct feature
*feature
= cb_arg
;
75 int fid
= feature
- features
;
77 if (spdk_nvme_cpl_is_error(cpl
)) {
78 fprintf(stdout
, "get_feature(0x%02X) failed\n", fid
);
80 feature
->result
= cpl
->cdw0
;
81 feature
->valid
= true;
83 outstanding_commands
--;
87 set_feature_completion(void *cb_arg
, const struct spdk_nvme_cpl
*cpl
)
89 struct feature
*feature
= cb_arg
;
90 int fid
= feature
- features
;
92 if (spdk_nvme_cpl_is_error(cpl
)) {
93 fprintf(stdout
, "set_feature(0x%02X) failed\n", fid
);
94 set_feature_result
= -1;
96 set_feature_result
= 0;
98 outstanding_commands
--;
102 get_host_identifier(struct spdk_nvme_ctrlr
*ctrlr
)
106 struct spdk_nvme_cmd cmd
= {};
108 cmd
.opc
= SPDK_NVME_OPC_GET_FEATURES
;
109 cmd
.cdw10
= SPDK_NVME_FEAT_HOST_IDENTIFIER
;
111 outstanding_commands
= 0;
112 ret
= spdk_nvme_ctrlr_cmd_admin_raw(ctrlr
, &cmd
, &host_id
, sizeof(host_id
),
113 get_feature_completion
, &features
[SPDK_NVME_FEAT_HOST_IDENTIFIER
]);
115 fprintf(stdout
, "Get Feature: Failed\n");
119 outstanding_commands
++;
121 while (outstanding_commands
) {
122 spdk_nvme_ctrlr_process_admin_completions(ctrlr
);
125 if (features
[SPDK_NVME_FEAT_HOST_IDENTIFIER
].valid
) {
126 fprintf(stdout
, "Get Feature: Host Identifier 0x%" PRIx64
"\n", host_id
);
133 set_host_identifier(struct spdk_nvme_ctrlr
*ctrlr
)
137 struct spdk_nvme_cmd cmd
= {};
139 cmd
.opc
= SPDK_NVME_OPC_SET_FEATURES
;
140 cmd
.cdw10
= SPDK_NVME_FEAT_HOST_IDENTIFIER
;
144 outstanding_commands
= 0;
145 set_feature_result
= -1;
147 fprintf(stdout
, "Set Feature: Host Identifier 0x%" PRIx64
"\n", host_id
);
148 ret
= spdk_nvme_ctrlr_cmd_admin_raw(ctrlr
, &cmd
, &host_id
, sizeof(host_id
),
149 set_feature_completion
, &features
[SPDK_NVME_FEAT_HOST_IDENTIFIER
]);
151 fprintf(stdout
, "Set Feature: Failed\n");
155 outstanding_commands
++;
157 while (outstanding_commands
) {
158 spdk_nvme_ctrlr_process_admin_completions(ctrlr
);
161 if (set_feature_result
)
162 fprintf(stdout
, "Set Feature: Host Identifier Failed\n");
168 reservation_ns_completion(void *cb_arg
, const struct spdk_nvme_cpl
*cpl
)
170 if (spdk_nvme_cpl_is_error(cpl
)) {
171 reserve_command_result
= -1;
173 reserve_command_result
= 0;
176 outstanding_commands
--;
180 reservation_ns_register(struct spdk_nvme_ctrlr
*ctrlr
, struct spdk_nvme_qpair
*qpair
,
184 struct spdk_nvme_reservation_register_data rr_data
;
185 struct spdk_nvme_ns
*ns
;
187 ns
= spdk_nvme_ctrlr_get_ns(ctrlr
, ns_id
);
189 rr_data
.crkey
= CR_KEY
;
190 rr_data
.nrkey
= CR_KEY
;
192 outstanding_commands
= 0;
193 reserve_command_result
= -1;
195 ret
= spdk_nvme_ns_cmd_reservation_register(ns
, qpair
, &rr_data
, true,
196 SPDK_NVME_RESERVE_REGISTER_KEY
,
197 SPDK_NVME_RESERVE_PTPL_NO_CHANGES
,
198 reservation_ns_completion
, NULL
);
200 fprintf(stderr
, "Reservation Register Failed\n");
204 outstanding_commands
++;
205 while (outstanding_commands
) {
206 spdk_nvme_qpair_process_completions(qpair
, 100);
209 if (reserve_command_result
)
210 fprintf(stderr
, "Reservation Register Failed\n");
216 reservation_ns_report(struct spdk_nvme_ctrlr
*ctrlr
, struct spdk_nvme_qpair
*qpair
, uint16_t ns_id
)
219 uint8_t payload
[0x1000];
220 struct spdk_nvme_reservation_status_data
*status
;
221 struct spdk_nvme_reservation_ctrlr_data
*cdata
;
222 struct spdk_nvme_ns
*ns
;
224 ns
= spdk_nvme_ctrlr_get_ns(ctrlr
, ns_id
);
226 outstanding_commands
= 0;
227 reserve_command_result
= -1;
229 ret
= spdk_nvme_ns_cmd_reservation_report(ns
, qpair
, payload
, 0x1000,
230 reservation_ns_completion
, NULL
);
232 fprintf(stderr
, "Reservation Report Failed\n");
236 outstanding_commands
++;
237 while (outstanding_commands
) {
238 spdk_nvme_qpair_process_completions(qpair
, 100);
241 if (reserve_command_result
) {
242 fprintf(stderr
, "Reservation Report Failed\n");
246 status
= (struct spdk_nvme_reservation_status_data
*)payload
;
247 fprintf(stdout
, "Reservation Generation Counter %u\n", status
->generation
);
248 fprintf(stdout
, "Reservation type %u\n", status
->type
);
249 fprintf(stdout
, "Reservation Number of Registered Controllers %u\n", status
->nr_regctl
);
250 fprintf(stdout
, "Reservation Persist Through Power Loss State %u\n", status
->ptpl_state
);
251 for (i
= 0; i
< status
->nr_regctl
; i
++) {
252 cdata
= (struct spdk_nvme_reservation_ctrlr_data
*)(payload
+ sizeof(struct
253 spdk_nvme_reservation_status_data
) * (i
+ 1));
254 fprintf(stdout
, "Controller ID %u\n", cdata
->ctrlr_id
);
255 fprintf(stdout
, "Controller Reservation Status %u\n", cdata
->rcsts
.status
);
256 fprintf(stdout
, "Controller Host ID 0x%"PRIx64
"\n", cdata
->host_id
);
257 fprintf(stdout
, "Controller Reservation Key 0x%"PRIx64
"\n", cdata
->key
);
264 reservation_ns_acquire(struct spdk_nvme_ctrlr
*ctrlr
, struct spdk_nvme_qpair
*qpair
, uint16_t ns_id
)
267 struct spdk_nvme_reservation_acquire_data cdata
;
268 struct spdk_nvme_ns
*ns
;
270 ns
= spdk_nvme_ctrlr_get_ns(ctrlr
, ns_id
);
271 cdata
.crkey
= CR_KEY
;
274 outstanding_commands
= 0;
275 reserve_command_result
= -1;
277 ret
= spdk_nvme_ns_cmd_reservation_acquire(ns
, qpair
, &cdata
,
279 SPDK_NVME_RESERVE_ACQUIRE
,
280 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE
,
281 reservation_ns_completion
, NULL
);
283 fprintf(stderr
, "Reservation Acquire Failed\n");
287 outstanding_commands
++;
288 while (outstanding_commands
) {
289 spdk_nvme_qpair_process_completions(qpair
, 100);
292 if (reserve_command_result
)
293 fprintf(stderr
, "Reservation Acquire Failed\n");
299 reservation_ns_release(struct spdk_nvme_ctrlr
*ctrlr
, struct spdk_nvme_qpair
*qpair
, uint16_t ns_id
)
302 struct spdk_nvme_reservation_key_data cdata
;
303 struct spdk_nvme_ns
*ns
;
305 ns
= spdk_nvme_ctrlr_get_ns(ctrlr
, ns_id
);
306 cdata
.crkey
= CR_KEY
;
308 outstanding_commands
= 0;
309 reserve_command_result
= -1;
311 ret
= spdk_nvme_ns_cmd_reservation_release(ns
, qpair
, &cdata
,
313 SPDK_NVME_RESERVE_RELEASE
,
314 SPDK_NVME_RESERVE_WRITE_EXCLUSIVE
,
315 reservation_ns_completion
, NULL
);
317 fprintf(stderr
, "Reservation Release Failed\n");
321 outstanding_commands
++;
322 while (outstanding_commands
) {
323 spdk_nvme_qpair_process_completions(qpair
, 100);
326 if (reserve_command_result
)
327 fprintf(stderr
, "Reservation Release Failed\n");
333 reserve_controller(struct spdk_nvme_ctrlr
*ctrlr
, struct spdk_nvme_qpair
*qpair
,
334 const struct spdk_pci_addr
*pci_addr
)
336 const struct spdk_nvme_ctrlr_data
*cdata
;
338 cdata
= spdk_nvme_ctrlr_get_data(ctrlr
);
340 printf("=====================================================\n");
341 printf("NVMe Controller at PCI bus %d, device %d, function %d\n",
342 pci_addr
->bus
, pci_addr
->dev
, pci_addr
->func
);
343 printf("=====================================================\n");
345 printf("Reservations: %s\n",
346 cdata
->oncs
.reservations
? "Supported" : "Not Supported");
348 if (!cdata
->oncs
.reservations
)
351 set_host_identifier(ctrlr
);
352 get_host_identifier(ctrlr
);
354 /* tested 1 namespace */
355 reservation_ns_register(ctrlr
, qpair
, 1);
356 reservation_ns_acquire(ctrlr
, qpair
, 1);
357 reservation_ns_report(ctrlr
, qpair
, 1);
358 reservation_ns_release(ctrlr
, qpair
, 1);
362 probe_cb(void *cb_ctx
, const struct spdk_nvme_transport_id
*trid
,
363 struct spdk_nvme_ctrlr_opts
*opts
)
369 attach_cb(void *cb_ctx
, const struct spdk_nvme_transport_id
*trid
,
370 struct spdk_nvme_ctrlr
*ctrlr
, const struct spdk_nvme_ctrlr_opts
*opts
)
374 /* add to dev list */
375 dev
= &devs
[num_devs
++];
376 spdk_pci_addr_parse(&dev
->pci_addr
, trid
->traddr
);
380 int main(int argc
, char **argv
)
384 struct spdk_env_opts opts
;
386 spdk_env_opts_init(&opts
);
387 opts
.name
= "reserve";
388 opts
.core_mask
= "0x1";
389 spdk_env_init(&opts
);
391 if (spdk_nvme_probe(NULL
, NULL
, probe_cb
, attach_cb
, NULL
) != 0) {
392 fprintf(stderr
, "spdk_nvme_probe() failed\n");
399 struct spdk_nvme_qpair
*qpair
;
401 qpair
= spdk_nvme_ctrlr_alloc_io_qpair(iter
->ctrlr
, 0);
403 fprintf(stderr
, "spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
406 reserve_controller(iter
->ctrlr
, qpair
, &iter
->pci_addr
);
410 printf("Cleaning up...\n");
412 for (i
= 0; i
< num_devs
; i
++) {
413 struct dev
*dev
= &devs
[i
];
414 spdk_nvme_detach(dev
->ctrlr
);