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 0 : get_log_page_completion_final(void *cb_arg, const struct spdk_nvme_cpl *cpl)
20 : {
21 0 : struct nvme_discovery_ctx *ctx = cb_arg;
22 : int rc;
23 :
24 0 : 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 0 : if (ctx->start_genctr == ctx->end_genctr) {
33 0 : ctx->cb_fn(ctx->cb_arg, 0, cpl, ctx->log_page);
34 : } else {
35 0 : free(ctx->log_page);
36 0 : rc = spdk_nvme_ctrlr_get_discovery_log_page(ctx->ctrlr, ctx->cb_fn, ctx->cb_arg);
37 0 : if (rc != 0) {
38 0 : ctx->cb_fn(ctx->cb_arg, rc, NULL, NULL);
39 : }
40 : }
41 0 : free(ctx);
42 : }
43 :
44 : static void
45 0 : get_log_page_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
46 : {
47 0 : struct nvme_discovery_ctx *ctx = cb_arg;
48 : int rc;
49 :
50 0 : 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 0 : rc = spdk_nvme_ctrlr_cmd_get_log_page(ctx->ctrlr, SPDK_NVME_LOG_DISCOVERY, 0,
58 0 : &ctx->end_genctr, sizeof(ctx->end_genctr), 0,
59 : get_log_page_completion_final, ctx);
60 0 : 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 0 : discovery_log_header_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
69 : {
70 : struct spdk_nvmf_discovery_log_page *new_page;
71 0 : 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 0 : 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 0 : recfmt = from_le16(&ctx->log_page->recfmt);
87 0 : 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 0 : numrec = from_le64(&ctx->log_page->numrec);
96 :
97 0 : 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 0 : 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 0 : page_size = sizeof(struct spdk_nvmf_discovery_log_page);
112 0 : page_size += numrec * sizeof(struct spdk_nvmf_discovery_log_page_entry);
113 0 : new_page = realloc(ctx->log_page, page_size);
114 0 : 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 0 : ctx->log_page = new_page;
124 :
125 : /* Retrieve the entire discovery log page */
126 0 : rc = spdk_nvme_ctrlr_cmd_get_log_page(ctx->ctrlr, SPDK_NVME_LOG_DISCOVERY,
127 0 : 0, (char *)ctx->log_page, page_size, 0,
128 : get_log_page_completion, ctx);
129 0 : 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 0 : 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 0 : ctx = calloc(1, sizeof(*ctx));
144 0 : if (ctx == NULL) {
145 0 : return -ENOMEM;
146 : }
147 :
148 0 : ctx->log_page = calloc(1, sizeof(*ctx->log_page));
149 0 : if (ctx->log_page == NULL) {
150 0 : free(ctx);
151 0 : return -ENOMEM;
152 : }
153 :
154 0 : ctx->ctrlr = ctrlr;
155 0 : ctx->cb_fn = cb_fn;
156 0 : ctx->cb_arg = cb_arg;
157 :
158 0 : rc = spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_LOG_DISCOVERY, 0,
159 0 : ctx->log_page, sizeof(*ctx->log_page), 0,
160 : discovery_log_header_completion, ctx);
161 0 : if (rc != 0) {
162 0 : free(ctx->log_page);
163 0 : free(ctx);
164 : }
165 :
166 0 : return rc;
167 : }
|