1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2023-2024 Chelsio Communications, Inc.
5 * Written by: John Baldwin <jhb@FreeBSD.org>
6 */
7
8 #include <sys/types.h>
9 #include <sys/memdesc.h>
10 #include <sys/systm.h>
11 #include <dev/nvme/nvme.h>
12 #include <dev/nvmf/nvmf.h>
13 #include <dev/nvmf/nvmf_proto.h>
14 #include <dev/nvmf/host/nvmf_var.h>
15
16 bool
nvmf_cmd_get_property(struct nvmf_softc * sc,uint32_t offset,uint8_t size,nvmf_request_complete_t * cb,void * cb_arg,int how)17 nvmf_cmd_get_property(struct nvmf_softc *sc, uint32_t offset, uint8_t size,
18 nvmf_request_complete_t *cb, void *cb_arg, int how)
19 {
20 struct nvmf_fabric_prop_get_cmd cmd;
21 struct nvmf_request *req;
22
23 memset(&cmd, 0, sizeof(cmd));
24 cmd.opcode = NVME_OPC_FABRICS_COMMANDS;
25 cmd.fctype = NVMF_FABRIC_COMMAND_PROPERTY_GET;
26 switch (size) {
27 case 4:
28 cmd.attrib.size = NVMF_PROP_SIZE_4;
29 break;
30 case 8:
31 cmd.attrib.size = NVMF_PROP_SIZE_8;
32 break;
33 default:
34 panic("Invalid property size");
35 }
36 cmd.ofst = htole32(offset);
37
38 req = nvmf_allocate_request(sc->admin, &cmd, cb, cb_arg, how);
39 if (req != NULL)
40 nvmf_submit_request(req);
41 return (req != NULL);
42 }
43
44 bool
nvmf_cmd_set_property(struct nvmf_softc * sc,uint32_t offset,uint8_t size,uint64_t value,nvmf_request_complete_t * cb,void * cb_arg,int how)45 nvmf_cmd_set_property(struct nvmf_softc *sc, uint32_t offset, uint8_t size,
46 uint64_t value, nvmf_request_complete_t *cb, void *cb_arg, int how)
47 {
48 struct nvmf_fabric_prop_set_cmd cmd;
49 struct nvmf_request *req;
50
51 memset(&cmd, 0, sizeof(cmd));
52 cmd.opcode = NVME_OPC_FABRICS_COMMANDS;
53 cmd.fctype = NVMF_FABRIC_COMMAND_PROPERTY_SET;
54 switch (size) {
55 case 4:
56 cmd.attrib.size = NVMF_PROP_SIZE_4;
57 cmd.value.u32.low = htole32(value);
58 break;
59 case 8:
60 cmd.attrib.size = NVMF_PROP_SIZE_8;
61 cmd.value.u64 = htole64(value);
62 break;
63 default:
64 panic("Invalid property size");
65 }
66 cmd.ofst = htole32(offset);
67
68 req = nvmf_allocate_request(sc->admin, &cmd, cb, cb_arg, how);
69 if (req != NULL)
70 nvmf_submit_request(req);
71 return (req != NULL);
72 }
73
74 bool
nvmf_cmd_keep_alive(struct nvmf_softc * sc,nvmf_request_complete_t * cb,void * cb_arg,int how)75 nvmf_cmd_keep_alive(struct nvmf_softc *sc, nvmf_request_complete_t *cb,
76 void *cb_arg, int how)
77 {
78 struct nvme_command cmd;
79 struct nvmf_request *req;
80
81 memset(&cmd, 0, sizeof(cmd));
82 cmd.opc = NVME_OPC_KEEP_ALIVE;
83
84 req = nvmf_allocate_request(sc->admin, &cmd, cb, cb_arg, how);
85 if (req != NULL)
86 nvmf_submit_request(req);
87 return (req != NULL);
88 }
89
90 bool
nvmf_cmd_identify_active_namespaces(struct nvmf_softc * sc,uint32_t id,struct nvme_ns_list * nslist,nvmf_request_complete_t * req_cb,void * req_cb_arg,nvmf_io_complete_t * io_cb,void * io_cb_arg,int how)91 nvmf_cmd_identify_active_namespaces(struct nvmf_softc *sc, uint32_t id,
92 struct nvme_ns_list *nslist, nvmf_request_complete_t *req_cb,
93 void *req_cb_arg, nvmf_io_complete_t *io_cb, void *io_cb_arg, int how)
94 {
95 struct nvme_command cmd;
96 struct memdesc mem;
97 struct nvmf_request *req;
98
99 memset(&cmd, 0, sizeof(cmd));
100 cmd.opc = NVME_OPC_IDENTIFY;
101
102 /* 5.15.1 Use CNS of 0x02 for namespace data. */
103 cmd.cdw10 = htole32(2);
104 cmd.nsid = htole32(id);
105
106 req = nvmf_allocate_request(sc->admin, &cmd, req_cb, req_cb_arg, how);
107 if (req == NULL)
108 return (false);
109 mem = memdesc_vaddr(nslist, sizeof(*nslist));
110 nvmf_capsule_append_data(req->nc, &mem, sizeof(*nslist), false,
111 io_cb, io_cb_arg);
112 nvmf_submit_request(req);
113 return (true);
114 }
115
116 bool
nvmf_cmd_identify_namespace(struct nvmf_softc * sc,uint32_t id,struct nvme_namespace_data * nsdata,nvmf_request_complete_t * req_cb,void * req_cb_arg,nvmf_io_complete_t * io_cb,void * io_cb_arg,int how)117 nvmf_cmd_identify_namespace(struct nvmf_softc *sc, uint32_t id,
118 struct nvme_namespace_data *nsdata, nvmf_request_complete_t *req_cb,
119 void *req_cb_arg, nvmf_io_complete_t *io_cb, void *io_cb_arg, int how)
120 {
121 struct nvme_command cmd;
122 struct memdesc mem;
123 struct nvmf_request *req;
124
125 memset(&cmd, 0, sizeof(cmd));
126 cmd.opc = NVME_OPC_IDENTIFY;
127
128 /* 5.15.1 Use CNS of 0x00 for namespace data. */
129 cmd.cdw10 = htole32(0);
130 cmd.nsid = htole32(id);
131
132 req = nvmf_allocate_request(sc->admin, &cmd, req_cb, req_cb_arg, how);
133 if (req == NULL)
134 return (false);
135 mem = memdesc_vaddr(nsdata, sizeof(*nsdata));
136 nvmf_capsule_append_data(req->nc, &mem, sizeof(*nsdata), false,
137 io_cb, io_cb_arg);
138 nvmf_submit_request(req);
139 return (true);
140 }
141
142 bool
nvmf_cmd_get_log_page(struct nvmf_softc * sc,uint32_t nsid,uint8_t lid,uint64_t offset,void * buf,size_t len,nvmf_request_complete_t * req_cb,void * req_cb_arg,nvmf_io_complete_t * io_cb,void * io_cb_arg,int how)143 nvmf_cmd_get_log_page(struct nvmf_softc *sc, uint32_t nsid, uint8_t lid,
144 uint64_t offset, void *buf, size_t len, nvmf_request_complete_t *req_cb,
145 void *req_cb_arg, nvmf_io_complete_t *io_cb, void *io_cb_arg, int how)
146 {
147 struct nvme_command cmd;
148 struct memdesc mem;
149 struct nvmf_request *req;
150 size_t numd;
151
152 MPASS(len != 0 && len % 4 == 0);
153 MPASS(offset % 4 == 0);
154
155 numd = (len / 4) - 1;
156 memset(&cmd, 0, sizeof(cmd));
157 cmd.opc = NVME_OPC_GET_LOG_PAGE;
158 cmd.nsid = htole32(nsid);
159 cmd.cdw10 = htole32(numd << 16 | lid);
160 cmd.cdw11 = htole32(numd >> 16);
161 cmd.cdw12 = htole32(offset);
162 cmd.cdw13 = htole32(offset >> 32);
163
164 req = nvmf_allocate_request(sc->admin, &cmd, req_cb, req_cb_arg, how);
165 if (req == NULL)
166 return (false);
167 mem = memdesc_vaddr(buf, len);
168 nvmf_capsule_append_data(req->nc, &mem, len, false, io_cb, io_cb_arg);
169 nvmf_submit_request(req);
170 return (true);
171 }
172