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.
35 * NVMe over Fabrics transport-independent functions
38 #include "nvme_internal.h"
40 #include "spdk/endian.h"
41 #include "spdk/string.h"
44 nvme_fabric_prop_set_cmd(struct spdk_nvme_ctrlr
*ctrlr
,
45 uint32_t offset
, uint8_t size
, uint64_t value
)
47 struct spdk_nvmf_fabric_prop_set_cmd cmd
= {};
48 struct nvme_completion_poll_status status
;
51 assert(size
== SPDK_NVMF_PROP_SIZE_4
|| size
== SPDK_NVMF_PROP_SIZE_8
);
53 cmd
.opcode
= SPDK_NVME_OPC_FABRIC
;
54 cmd
.fctype
= SPDK_NVMF_FABRIC_COMMAND_PROPERTY_SET
;
56 cmd
.attrib
.size
= size
;
57 cmd
.value
.u64
= value
;
59 rc
= spdk_nvme_ctrlr_cmd_admin_raw(ctrlr
, (struct spdk_nvme_cmd
*)&cmd
,
61 nvme_completion_poll_cb
, &status
);
66 if (spdk_nvme_wait_for_completion(ctrlr
->adminq
, &status
)) {
67 SPDK_ERRLOG("Property Set failed\n");
75 nvme_fabric_prop_get_cmd(struct spdk_nvme_ctrlr
*ctrlr
,
76 uint32_t offset
, uint8_t size
, uint64_t *value
)
78 struct spdk_nvmf_fabric_prop_set_cmd cmd
= {};
79 struct nvme_completion_poll_status status
;
80 struct spdk_nvmf_fabric_prop_get_rsp
*response
;
83 assert(size
== SPDK_NVMF_PROP_SIZE_4
|| size
== SPDK_NVMF_PROP_SIZE_8
);
85 cmd
.opcode
= SPDK_NVME_OPC_FABRIC
;
86 cmd
.fctype
= SPDK_NVMF_FABRIC_COMMAND_PROPERTY_GET
;
88 cmd
.attrib
.size
= size
;
90 rc
= spdk_nvme_ctrlr_cmd_admin_raw(ctrlr
, (struct spdk_nvme_cmd
*)&cmd
,
91 NULL
, 0, nvme_completion_poll_cb
,
97 if (spdk_nvme_wait_for_completion(ctrlr
->adminq
, &status
)) {
98 SPDK_ERRLOG("Property Get failed\n");
102 response
= (struct spdk_nvmf_fabric_prop_get_rsp
*)&status
.cpl
;
104 if (size
== SPDK_NVMF_PROP_SIZE_4
) {
105 *value
= response
->value
.u32
.low
;
107 *value
= response
->value
.u64
;
114 nvme_fabric_ctrlr_set_reg_4(struct spdk_nvme_ctrlr
*ctrlr
, uint32_t offset
, uint32_t value
)
116 return nvme_fabric_prop_set_cmd(ctrlr
, offset
, SPDK_NVMF_PROP_SIZE_4
, value
);
120 nvme_fabric_ctrlr_set_reg_8(struct spdk_nvme_ctrlr
*ctrlr
, uint32_t offset
, uint64_t value
)
122 return nvme_fabric_prop_set_cmd(ctrlr
, offset
, SPDK_NVMF_PROP_SIZE_8
, value
);
126 nvme_fabric_ctrlr_get_reg_4(struct spdk_nvme_ctrlr
*ctrlr
, uint32_t offset
, uint32_t *value
)
130 rc
= nvme_fabric_prop_get_cmd(ctrlr
, offset
, SPDK_NVMF_PROP_SIZE_4
, &tmp_value
);
133 *value
= (uint32_t)tmp_value
;
139 nvme_fabric_ctrlr_get_reg_8(struct spdk_nvme_ctrlr
*ctrlr
, uint32_t offset
, uint64_t *value
)
141 return nvme_fabric_prop_get_cmd(ctrlr
, offset
, SPDK_NVMF_PROP_SIZE_8
, value
);
145 nvme_fabric_discover_probe(struct spdk_nvmf_discovery_log_page_entry
*entry
,
146 void *cb_ctx
, spdk_nvme_probe_cb probe_cb
)
148 struct spdk_nvme_transport_id trid
;
152 memset(&trid
, 0, sizeof(trid
));
154 if (entry
->subtype
== SPDK_NVMF_SUBTYPE_DISCOVERY
) {
155 SPDK_WARNLOG("Skipping unsupported discovery service referral\n");
157 } else if (entry
->subtype
!= SPDK_NVMF_SUBTYPE_NVME
) {
158 SPDK_WARNLOG("Skipping unknown subtype %u\n", entry
->subtype
);
162 trid
.trtype
= entry
->trtype
;
163 if (!spdk_nvme_transport_available(trid
.trtype
)) {
164 SPDK_WARNLOG("NVMe transport type %u not available; skipping probe\n",
169 trid
.adrfam
= entry
->adrfam
;
171 /* Ensure that subnqn is null terminated. */
172 end
= memchr(entry
->subnqn
, '\0', SPDK_NVMF_NQN_MAX_LEN
+ 1);
174 SPDK_ERRLOG("Discovery entry SUBNQN is not null terminated\n");
177 len
= end
- entry
->subnqn
;
178 memcpy(trid
.subnqn
, entry
->subnqn
, len
);
179 trid
.subnqn
[len
] = '\0';
181 /* Convert traddr to a null terminated string. */
182 len
= spdk_strlen_pad(entry
->traddr
, sizeof(entry
->traddr
), ' ');
183 memcpy(trid
.traddr
, entry
->traddr
, len
);
184 if (spdk_str_chomp(trid
.traddr
) != 0) {
185 SPDK_DEBUGLOG(SPDK_LOG_NVME
, "Trailing newlines removed from discovery TRADDR\n");
188 /* Convert trsvcid to a null terminated string. */
189 len
= spdk_strlen_pad(entry
->trsvcid
, sizeof(entry
->trsvcid
), ' ');
190 memcpy(trid
.trsvcid
, entry
->trsvcid
, len
);
191 if (spdk_str_chomp(trid
.trsvcid
) != 0) {
192 SPDK_DEBUGLOG(SPDK_LOG_NVME
, "Trailing newlines removed from discovery TRSVCID\n");
195 SPDK_DEBUGLOG(SPDK_LOG_NVME
, "subnqn=%s, trtype=%u, traddr=%s, trsvcid=%s\n",
196 trid
.subnqn
, trid
.trtype
,
197 trid
.traddr
, trid
.trsvcid
);
199 nvme_ctrlr_probe(&trid
, NULL
, probe_cb
, cb_ctx
);
203 nvme_fabric_get_discovery_log_page(struct spdk_nvme_ctrlr
*ctrlr
,
204 void *log_page
, uint32_t size
, uint64_t offset
)
206 struct nvme_completion_poll_status status
;
209 rc
= spdk_nvme_ctrlr_cmd_get_log_page(ctrlr
, SPDK_NVME_LOG_DISCOVERY
, 0, log_page
, size
, offset
,
210 nvme_completion_poll_cb
, &status
);
215 if (spdk_nvme_wait_for_completion(ctrlr
->adminq
, &status
)) {
223 nvme_fabric_ctrlr_discover(struct spdk_nvme_ctrlr
*ctrlr
,
224 void *cb_ctx
, spdk_nvme_probe_cb probe_cb
)
226 struct spdk_nvmf_discovery_log_page
*log_page
;
227 struct spdk_nvmf_discovery_log_page_entry
*log_page_entry
;
230 uint64_t i
, numrec
, buffer_max_entries_first
, buffer_max_entries
, log_page_offset
= 0;
231 uint64_t remaining_num_rec
= 0;
234 memset(buffer
, 0x0, 4096);
235 buffer_max_entries_first
= (sizeof(buffer
) - offsetof(struct spdk_nvmf_discovery_log_page
,
237 sizeof(struct spdk_nvmf_discovery_log_page_entry
);
238 buffer_max_entries
= sizeof(buffer
) / sizeof(struct spdk_nvmf_discovery_log_page_entry
);
240 rc
= nvme_fabric_get_discovery_log_page(ctrlr
, buffer
, sizeof(buffer
), log_page_offset
);
242 SPDK_DEBUGLOG(SPDK_LOG_NVME
, "Get Log Page - Discovery error\n");
246 if (!remaining_num_rec
) {
247 log_page
= (struct spdk_nvmf_discovery_log_page
*)buffer
;
248 recfmt
= from_le16(&log_page
->recfmt
);
250 SPDK_ERRLOG("Unrecognized discovery log record format %" PRIu16
"\n", recfmt
);
253 remaining_num_rec
= log_page
->numrec
;
254 log_page_offset
= offsetof(struct spdk_nvmf_discovery_log_page
, entries
[0]);
255 log_page_entry
= &log_page
->entries
[0];
256 numrec
= spdk_min(remaining_num_rec
, buffer_max_entries_first
);
258 numrec
= spdk_min(remaining_num_rec
, buffer_max_entries
);
259 log_page_entry
= (struct spdk_nvmf_discovery_log_page_entry
*)buffer
;
262 for (i
= 0; i
< numrec
; i
++) {
263 nvme_fabric_discover_probe(log_page_entry
++, cb_ctx
, probe_cb
);
265 remaining_num_rec
-= numrec
;
266 log_page_offset
+= numrec
* sizeof(struct spdk_nvmf_discovery_log_page_entry
);
267 } while (remaining_num_rec
!= 0);
273 nvme_fabric_qpair_connect(struct spdk_nvme_qpair
*qpair
, uint32_t num_entries
)
275 struct nvme_completion_poll_status status
;
276 struct spdk_nvmf_fabric_connect_rsp
*rsp
;
277 struct spdk_nvmf_fabric_connect_cmd cmd
;
278 struct spdk_nvmf_fabric_connect_data
*nvmf_data
;
279 struct spdk_nvme_ctrlr
*ctrlr
;
282 if (num_entries
== 0 || num_entries
> SPDK_NVME_IO_QUEUE_MAX_ENTRIES
) {
286 ctrlr
= qpair
->ctrlr
;
291 nvmf_data
= spdk_dma_zmalloc(sizeof(*nvmf_data
), 0, NULL
);
293 SPDK_ERRLOG("nvmf_data allocation error\n");
297 memset(&cmd
, 0, sizeof(cmd
));
298 cmd
.opcode
= SPDK_NVME_OPC_FABRIC
;
299 cmd
.fctype
= SPDK_NVMF_FABRIC_COMMAND_CONNECT
;
301 cmd
.sqsize
= num_entries
- 1;
302 cmd
.kato
= ctrlr
->opts
.keep_alive_timeout_ms
;
304 if (nvme_qpair_is_admin_queue(qpair
)) {
305 nvmf_data
->cntlid
= 0xFFFF;
307 nvmf_data
->cntlid
= ctrlr
->cntlid
;
310 SPDK_STATIC_ASSERT(sizeof(nvmf_data
->hostid
) == sizeof(ctrlr
->opts
.extended_host_id
),
311 "host ID size mismatch");
312 memcpy(nvmf_data
->hostid
, ctrlr
->opts
.extended_host_id
, sizeof(nvmf_data
->hostid
));
313 snprintf(nvmf_data
->hostnqn
, sizeof(nvmf_data
->hostnqn
), "%s", ctrlr
->opts
.hostnqn
);
314 snprintf(nvmf_data
->subnqn
, sizeof(nvmf_data
->subnqn
), "%s", ctrlr
->trid
.subnqn
);
316 rc
= spdk_nvme_ctrlr_cmd_io_raw(ctrlr
, qpair
,
317 (struct spdk_nvme_cmd
*)&cmd
,
318 nvmf_data
, sizeof(*nvmf_data
),
319 nvme_completion_poll_cb
, &status
);
321 SPDK_ERRLOG("Connect command failed\n");
322 spdk_dma_free(nvmf_data
);
326 if (spdk_nvme_wait_for_completion(qpair
, &status
)) {
327 SPDK_ERRLOG("Connect command failed\n");
328 spdk_dma_free(nvmf_data
);
332 if (nvme_qpair_is_admin_queue(qpair
)) {
333 rsp
= (struct spdk_nvmf_fabric_connect_rsp
*)&status
.cpl
;
334 ctrlr
->cntlid
= rsp
->status_code_specific
.success
.cntlid
;
335 SPDK_DEBUGLOG(SPDK_LOG_NVME
, "CNTLID 0x%04" PRIx16
"\n", ctrlr
->cntlid
);
338 spdk_dma_free(nvmf_data
);