Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2021 Intel Corporation. All rights reserved.
3 : : */
4 : :
5 : : #include "nvme_internal.h"
6 : :
7 : : #include "spdk/endian.h"
8 : :
9 : : struct nvme_discovery_ctx {
10 : : struct spdk_nvme_ctrlr *ctrlr;
11 : : struct spdk_nvmf_discovery_log_page *log_page;
12 : : uint64_t start_genctr;
13 : : uint64_t end_genctr;
14 : : spdk_nvme_discovery_cb cb_fn;
15 : : void *cb_arg;
16 : : };
17 : :
18 : : static void
19 : 45 : get_log_page_completion_final(void *cb_arg, const struct spdk_nvme_cpl *cpl)
20 : : {
21 : 45 : struct nvme_discovery_ctx *ctx = cb_arg;
22 : : int rc;
23 : :
24 [ + - - + ]: 45 : if (spdk_nvme_cpl_is_error(cpl)) {
25 : 0 : free(ctx->log_page);
26 : 0 : ctx->cb_fn(ctx->cb_arg, 0, cpl, NULL);
27 : 0 : free(ctx);
28 : 0 : return;
29 : : }
30 : :
31 : : /* Compare original genctr with latest genctr. If it changed, we need to restart. */
32 [ + + ]: 45 : if (ctx->start_genctr == ctx->end_genctr) {
33 : 40 : ctx->cb_fn(ctx->cb_arg, 0, cpl, ctx->log_page);
34 : : } else {
35 : 5 : free(ctx->log_page);
36 : 5 : rc = spdk_nvme_ctrlr_get_discovery_log_page(ctx->ctrlr, ctx->cb_fn, ctx->cb_arg);
37 [ - + ]: 5 : if (rc != 0) {
38 : 0 : ctx->cb_fn(ctx->cb_arg, rc, NULL, NULL);
39 : : }
40 : : }
41 : 45 : free(ctx);
42 : : }
43 : :
44 : : static void
45 : 45 : get_log_page_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
46 : : {
47 : 45 : struct nvme_discovery_ctx *ctx = cb_arg;
48 : : int rc;
49 : :
50 [ + - - + ]: 45 : if (spdk_nvme_cpl_is_error(cpl)) {
51 : 0 : free(ctx->log_page);
52 : 0 : ctx->cb_fn(ctx->cb_arg, 0, cpl, NULL);
53 : 0 : free(ctx);
54 : 0 : return;
55 : : }
56 : :
57 : 45 : rc = spdk_nvme_ctrlr_cmd_get_log_page(ctx->ctrlr, SPDK_NVME_LOG_DISCOVERY, 0,
58 : 45 : &ctx->end_genctr, sizeof(ctx->end_genctr), 0,
59 : : get_log_page_completion_final, ctx);
60 [ - + ]: 45 : if (rc != 0) {
61 : 0 : free(ctx->log_page);
62 : 0 : ctx->cb_fn(ctx->cb_arg, rc, NULL, NULL);
63 : 0 : free(ctx);
64 : : }
65 : : }
66 : :
67 : : static void
68 : 45 : discovery_log_header_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
69 : : {
70 : : struct spdk_nvmf_discovery_log_page *new_page;
71 : 45 : struct nvme_discovery_ctx *ctx = cb_arg;
72 : : size_t page_size;
73 : : uint16_t recfmt;
74 : : uint64_t numrec;
75 : : int rc;
76 : :
77 [ + - - + ]: 45 : if (spdk_nvme_cpl_is_error(cpl)) {
78 : : /* Return without printing anything - this may not be a discovery controller */
79 : 0 : ctx->cb_fn(ctx->cb_arg, 0, cpl, NULL);
80 : 0 : free(ctx->log_page);
81 : 0 : free(ctx);
82 : 0 : return;
83 : : }
84 : :
85 : : /* Got the first 4K of the discovery log page */
86 : 45 : recfmt = from_le16(&ctx->log_page->recfmt);
87 [ - + ]: 45 : if (recfmt != 0) {
88 : 0 : SPDK_ERRLOG("Unrecognized discovery log record format %" PRIu16 "\n", recfmt);
89 : 0 : ctx->cb_fn(ctx->cb_arg, -EINVAL, NULL, NULL);
90 : 0 : free(ctx->log_page);
91 : 0 : free(ctx);
92 : 0 : return;
93 : : }
94 : :
95 : 45 : numrec = from_le64(&ctx->log_page->numrec);
96 : :
97 [ - + ]: 45 : if (numrec == 0) {
98 : : /* No entries in the discovery log. So we can just return the header to the
99 : : * caller.
100 : : */
101 : 0 : get_log_page_completion(ctx, cpl);
102 : 0 : return;
103 : : }
104 : :
105 : 45 : ctx->start_genctr = ctx->log_page->genctr;
106 : :
107 : : /*
108 : : * Now that we know how many entries should be in the log page, we can allocate
109 : : * the full log page buffer.
110 : : */
111 : 45 : page_size = sizeof(struct spdk_nvmf_discovery_log_page);
112 : 45 : page_size += numrec * sizeof(struct spdk_nvmf_discovery_log_page_entry);
113 : 45 : new_page = realloc(ctx->log_page, page_size);
114 [ - + ]: 45 : if (new_page == NULL) {
115 : 0 : SPDK_ERRLOG("Could not allocate buffer for log page (%" PRIu64 " entries)\n",
116 : : numrec);
117 : 0 : ctx->cb_fn(ctx->cb_arg, -ENOMEM, NULL, NULL);
118 : 0 : free(ctx->log_page);
119 : 0 : free(ctx);
120 : 0 : return;
121 : : }
122 : :
123 : 45 : ctx->log_page = new_page;
124 : :
125 : : /* Retrieve the entire discovery log page */
126 : 45 : rc = spdk_nvme_ctrlr_cmd_get_log_page(ctx->ctrlr, SPDK_NVME_LOG_DISCOVERY,
127 : 45 : 0, (char *)ctx->log_page, page_size, 0,
128 : : get_log_page_completion, ctx);
129 [ - + ]: 45 : if (rc != 0) {
130 : 0 : free(ctx->log_page);
131 : 0 : ctx->cb_fn(ctx->cb_arg, rc, NULL, NULL);
132 : 0 : free(ctx);
133 : : }
134 : : }
135 : :
136 : : int
137 : 45 : spdk_nvme_ctrlr_get_discovery_log_page(struct spdk_nvme_ctrlr *ctrlr,
138 : : spdk_nvme_discovery_cb cb_fn, void *cb_arg)
139 : : {
140 : : struct nvme_discovery_ctx *ctx;
141 : : int rc;
142 : :
143 : 45 : ctx = calloc(1, sizeof(*ctx));
144 [ - + ]: 45 : if (ctx == NULL) {
145 : 0 : return -ENOMEM;
146 : : }
147 : :
148 : 45 : ctx->log_page = calloc(1, sizeof(*ctx->log_page));
149 [ - + ]: 45 : if (ctx->log_page == NULL) {
150 : 0 : free(ctx);
151 : 0 : return -ENOMEM;
152 : : }
153 : :
154 : 45 : ctx->ctrlr = ctrlr;
155 : 45 : ctx->cb_fn = cb_fn;
156 : 45 : ctx->cb_arg = cb_arg;
157 : :
158 : 45 : rc = spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_LOG_DISCOVERY, 0,
159 : 45 : ctx->log_page, sizeof(*ctx->log_page), 0,
160 : : discovery_log_header_completion, ctx);
161 [ - + ]: 45 : if (rc != 0) {
162 : 0 : free(ctx->log_page);
163 : 0 : free(ctx);
164 : : }
165 : :
166 : 45 : return rc;
167 : : }
|