Line data Source code
1 : /* SPDX-License-Identifier: BSD-3-Clause
2 : * Copyright 2023 Solidigm All Rights Reserved
3 : */
4 :
5 : #include "spdk/queue.h"
6 : #include "spdk/json.h"
7 : #include "spdk/jsonrpc.h"
8 :
9 : #include "ftl_core.h"
10 : #include "ftl_property.h"
11 : #include "mngt/ftl_mngt.h"
12 :
13 : struct ftl_properties {
14 : LIST_HEAD(, ftl_property) list;
15 : };
16 :
17 : /**
18 : * @brief FTL property descriptor
19 : */
20 : struct ftl_property {
21 : /** Name of the property */
22 : const char *name;
23 :
24 : /* Pointer to the value of property */
25 : void *value;
26 :
27 : /* The value size of the property */
28 : size_t size;
29 :
30 : /** The unit of the property value */
31 : const char *unit;
32 :
33 : /** The property description for user help */
34 : const char *desc;
35 :
36 : /* The function to dump the value of property into the specified JSON RPC request */
37 : ftl_property_dump_fn dump;
38 :
39 : /* Decode property value and store it in output */
40 : ftl_property_decode_fn decode;
41 :
42 : /* Set the FTL property */
43 : ftl_property_set_fn set;
44 :
45 : /* It indicates the property is available in verbose mode only */
46 : bool verbose_mode;
47 :
48 : /** Link to put the property to the list */
49 : LIST_ENTRY(ftl_property) entry;
50 : };
51 :
52 : static struct ftl_property *
53 0 : get_property(struct ftl_properties *properties, const char *name)
54 : {
55 : struct ftl_property *entry;
56 :
57 0 : LIST_FOREACH(entry, &properties->list, entry) {
58 : /* TODO think about strncmp */
59 0 : if (0 == strcmp(entry->name, name)) {
60 0 : return entry;
61 : }
62 : }
63 :
64 0 : return NULL;
65 : }
66 :
67 : void
68 0 : ftl_property_register(struct spdk_ftl_dev *dev,
69 : const char *name, void *value, size_t size,
70 : const char *unit, const char *desc,
71 : ftl_property_dump_fn dump,
72 : ftl_property_decode_fn decode,
73 : ftl_property_set_fn set,
74 : bool verbose_mode)
75 : {
76 0 : struct ftl_properties *properties = dev->properties;
77 :
78 0 : if (get_property(properties, name)) {
79 0 : FTL_ERRLOG(dev, "FTL property registration ERROR, already exist, name %s\n", name);
80 0 : ftl_abort();
81 : } else {
82 0 : struct ftl_property *prop = calloc(1, sizeof(*prop));
83 0 : if (NULL == prop) {
84 0 : FTL_ERRLOG(dev, "FTL property registration ERROR, out of memory, name %s\n", name);
85 0 : ftl_abort();
86 : }
87 :
88 0 : prop->name = name;
89 0 : prop->value = value;
90 0 : prop->size = size;
91 0 : prop->unit = unit;
92 0 : prop->desc = desc;
93 0 : prop->dump = dump;
94 0 : prop->decode = decode;
95 0 : prop->set = set;
96 0 : prop->verbose_mode = verbose_mode;
97 0 : LIST_INSERT_HEAD(&properties->list, prop, entry);
98 : }
99 0 : }
100 :
101 : int
102 0 : ftl_properties_init(struct spdk_ftl_dev *dev)
103 : {
104 0 : dev->properties = calloc(1, sizeof(*dev->properties));
105 0 : if (!dev->properties) {
106 0 : return -ENOMEM;
107 : }
108 :
109 0 : LIST_INIT(&dev->properties->list);
110 0 : return 0;
111 : }
112 :
113 : void
114 0 : ftl_properties_deinit(struct spdk_ftl_dev *dev)
115 : {
116 0 : struct ftl_properties *properties = dev->properties;
117 : struct ftl_property *prop;
118 :
119 0 : if (!properties) {
120 0 : return;
121 : }
122 :
123 0 : while (!LIST_EMPTY(&properties->list)) {
124 0 : prop = LIST_FIRST(&properties->list);
125 0 : LIST_REMOVE(prop, entry);
126 0 : free(prop);
127 : }
128 :
129 0 : free(dev->properties);
130 : }
131 :
132 : static bool
133 0 : is_property_visible(struct spdk_ftl_dev *dev, struct ftl_property *prop)
134 : {
135 0 : if (prop->verbose_mode && !dev->conf.verbose_mode) {
136 0 : return false;
137 : }
138 :
139 0 : return true;
140 : }
141 :
142 : static void
143 0 : ftl_property_dump_common_begin(const struct ftl_property *property,
144 : struct spdk_json_write_ctx *w)
145 : {
146 0 : spdk_json_write_named_string(w, "name", property->name);
147 0 : }
148 :
149 : static void
150 0 : ftl_property_dump_common_end(const struct ftl_property *property,
151 : struct spdk_json_write_ctx *w)
152 : {
153 0 : if (property->unit) {
154 0 : spdk_json_write_named_string(w, "unit", property->unit);
155 : }
156 0 : if (property->desc) {
157 0 : spdk_json_write_named_string(w, "desc", property->desc);
158 : }
159 :
160 0 : if (!property->decode || !property->set) {
161 0 : spdk_json_write_named_bool(w, "read-only", true);
162 : }
163 0 : }
164 :
165 : void
166 0 : ftl_property_dump(struct spdk_ftl_dev *dev, struct spdk_jsonrpc_request *request)
167 : {
168 0 : struct ftl_properties *properties = dev->properties;
169 : struct ftl_property *prop;
170 : struct spdk_json_write_ctx *w;
171 :
172 0 : w = spdk_jsonrpc_begin_result(request);
173 :
174 0 : spdk_json_write_object_begin(w);
175 0 : spdk_json_write_named_string(w, "name", dev->conf.name);
176 :
177 0 : spdk_json_write_named_array_begin(w, "properties");
178 0 : LIST_FOREACH(prop, &properties->list, entry) {
179 0 : if (!is_property_visible(dev, prop)) {
180 0 : continue;
181 : }
182 :
183 0 : spdk_json_write_object_begin(w);
184 0 : ftl_property_dump_common_begin(prop, w);
185 0 : prop->dump(dev, prop, w);
186 0 : ftl_property_dump_common_end(prop, w);
187 0 : spdk_json_write_object_end(w);
188 : }
189 0 : spdk_json_write_array_end(w);
190 :
191 0 : spdk_json_write_object_end(w);
192 0 : spdk_jsonrpc_end_result(request, w);
193 0 : }
194 :
195 : void
196 0 : ftl_property_dump_bool(struct spdk_ftl_dev *dev, const struct ftl_property *property,
197 : struct spdk_json_write_ctx *w)
198 : {
199 0 : bool *value = property->value;
200 :
201 0 : assert(property->size == sizeof(*value));
202 0 : spdk_json_write_named_bool(w, "value", *value);
203 0 : }
204 :
205 : void
206 0 : ftl_property_dump_uint64(struct spdk_ftl_dev *dev, const struct ftl_property *property,
207 : struct spdk_json_write_ctx *w)
208 : {
209 0 : uint64_t *value = property->value;
210 :
211 0 : assert(property->size == sizeof(*value));
212 0 : spdk_json_write_named_uint64(w, "value", *value);
213 0 : }
214 :
215 : void
216 0 : ftl_property_dump_uint32(struct spdk_ftl_dev *dev, const struct ftl_property *property,
217 : struct spdk_json_write_ctx *w)
218 : {
219 0 : uint32_t *value = property->value;
220 :
221 0 : assert(property->size == sizeof(*value));
222 0 : spdk_json_write_named_uint32(w, "value", *value);
223 0 : }
224 :
225 : int
226 0 : ftl_property_decode(struct spdk_ftl_dev *dev, const char *name, const char *value,
227 : size_t value_size, void **output, size_t *output_size)
228 : {
229 0 : struct ftl_properties *properties = dev->properties;
230 0 : struct ftl_property *prop = get_property(properties, name);
231 : int rc;
232 :
233 0 : if (!prop) {
234 0 : FTL_ERRLOG(dev, "Property doesn't exist, name %s\n", name);
235 0 : return -ENOENT;
236 : }
237 :
238 0 : if (!prop->decode) {
239 0 : FTL_ERRLOG(dev, "Property is read only, name %s\n", name);
240 0 : return -EACCES;
241 : }
242 :
243 0 : if (!is_property_visible(dev, prop)) {
244 0 : FTL_ERRLOG(dev, "Property is inactive, enable verbose mode to access it, name %s.\n", name);
245 0 : return -EACCES;
246 : }
247 :
248 0 : assert(prop->size);
249 0 : assert(NULL == *output);
250 :
251 : /* Allocate buffer for the new value of the property */
252 0 : *output = calloc(1, prop->size);
253 0 : if (NULL == *output) {
254 0 : FTL_ERRLOG(dev, "Property allocation memory error, name %s\n", name);
255 0 : return -EACCES;
256 : }
257 0 : *output_size = prop->size;
258 :
259 0 : rc = prop->decode(dev, prop, value, value_size, *output, *output_size);
260 0 : if (rc) {
261 0 : FTL_ERRLOG(dev, "Property decode error, name %s\n", name);
262 0 : free(*output);
263 0 : *output = NULL;
264 0 : return rc;
265 : }
266 :
267 0 : return 0;
268 : }
269 :
270 : int
271 0 : ftl_property_set(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
272 : const char *name, void *value, size_t value_size)
273 : {
274 0 : struct ftl_properties *properties = dev->properties;
275 0 : struct ftl_property *prop = get_property(properties, name);
276 :
277 0 : if (!prop) {
278 0 : FTL_ERRLOG(dev, "Property doesn't exist, name %s\n", name);
279 0 : return -ENOENT;
280 : }
281 :
282 0 : if (!prop->set) {
283 0 : FTL_ERRLOG(dev, "Property is read only, name %s\n", name);
284 0 : return -EACCES;
285 : }
286 :
287 0 : if (!is_property_visible(dev, prop)) {
288 0 : FTL_ERRLOG(dev, "Property is inactive, enable verbose mode to access it, name %s\n", name);
289 0 : return -EACCES;
290 : }
291 :
292 0 : prop->set(dev, mngt, prop, value, value_size);
293 0 : return 0;
294 : }
295 :
296 : void
297 0 : ftl_property_set_generic(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
298 : const struct ftl_property *property, void *new_value, size_t new_value_size)
299 : {
300 0 : ftl_bug(property->size != new_value_size);
301 0 : memcpy(property->value, new_value, property->size);
302 0 : ftl_mngt_next_step(mngt);
303 0 : }
304 :
305 : int
306 0 : ftl_property_decode_bool(struct spdk_ftl_dev *dev, struct ftl_property *property,
307 : const char *value, size_t value_size, void *output, size_t output_size)
308 : {
309 0 : bool *out = output;
310 :
311 0 : if (sizeof(bool) != output_size) {
312 0 : return -ENOBUFS;
313 : }
314 :
315 0 : if (strnlen(value, value_size) == value_size) {
316 0 : return -EINVAL;
317 : }
318 :
319 0 : if (0 == strncmp(value, "true", strlen("true"))) {
320 0 : *out = true;
321 0 : return 0;
322 : }
323 :
324 0 : if (0 == strncmp(value, "false", strlen("false"))) {
325 0 : *out = false;
326 0 : return 0;
327 : }
328 :
329 0 : return -EINVAL;
330 : }
|