Branch data 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 : 116 : get_property(struct ftl_properties *properties, const char *name)
54 : : {
55 : : struct ftl_property *entry;
56 : :
57 [ + + # # : 356 : LIST_FOREACH(entry, &properties->list, entry) {
# # # # #
# # # #
# ]
58 : : /* TODO think about strncmp */
59 [ - + - + : 246 : if (0 == strcmp(entry->name, name)) {
+ + # # #
# ]
60 : 6 : return entry;
61 : : }
62 : 0 : }
63 : :
64 : 110 : return NULL;
65 : 0 : }
66 : :
67 : : void
68 : 110 : 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 [ # # # # ]: 110 : struct ftl_properties *properties = dev->properties;
77 : :
78 [ - + ]: 110 : 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 : 0 : } else {
82 : 110 : struct ftl_property *prop = calloc(1, sizeof(*prop));
83 [ - + ]: 110 : if (NULL == prop) {
84 [ # # # # : 0 : FTL_ERRLOG(dev, "FTL property registration ERROR, out of memory, name %s\n", name);
# # # # ]
85 [ # # ]: 0 : ftl_abort();
86 : 0 : }
87 : :
88 [ # # # # ]: 110 : prop->name = name;
89 [ # # # # ]: 110 : prop->value = value;
90 [ # # # # ]: 110 : prop->size = size;
91 [ # # # # ]: 110 : prop->unit = unit;
92 [ # # # # ]: 110 : prop->desc = desc;
93 [ # # # # ]: 110 : prop->dump = dump;
94 [ # # # # ]: 110 : prop->decode = decode;
95 [ # # # # ]: 110 : prop->set = set;
96 [ # # # # : 110 : prop->verbose_mode = verbose_mode;
# # ]
97 [ + + # # : 110 : LIST_INSERT_HEAD(&properties->list, prop, entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
98 : : }
99 : 110 : }
100 : :
101 : : int
102 : 22 : ftl_properties_init(struct spdk_ftl_dev *dev)
103 : : {
104 [ # # # # ]: 22 : dev->properties = calloc(1, sizeof(*dev->properties));
105 [ - + # # : 22 : if (!dev->properties) {
# # ]
106 : 0 : return -ENOMEM;
107 : : }
108 : :
109 [ # # # # : 22 : LIST_INIT(&dev->properties->list);
# # # # #
# ]
110 : 22 : return 0;
111 : 0 : }
112 : :
113 : : void
114 : 22 : ftl_properties_deinit(struct spdk_ftl_dev *dev)
115 : : {
116 [ # # # # ]: 22 : struct ftl_properties *properties = dev->properties;
117 : : struct ftl_property *prop;
118 : :
119 [ - + ]: 22 : if (!properties) {
120 : 0 : return;
121 : : }
122 : :
123 [ + + # # : 132 : while (!LIST_EMPTY(&properties->list)) {
# # # # ]
124 [ # # # # : 110 : prop = LIST_FIRST(&properties->list);
# # ]
125 [ + + # # : 110 : LIST_REMOVE(prop, entry);
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
126 : 110 : free(prop);
127 : : }
128 : :
129 [ # # # # ]: 22 : free(dev->properties);
130 : 0 : }
131 : :
132 : : static bool
133 : 21 : is_property_visible(struct spdk_ftl_dev *dev, struct ftl_property *prop)
134 : : {
135 [ - + + + : 21 : if (prop->verbose_mode && !dev->conf.verbose_mode) {
- + - + #
# # # # #
# # # # ]
136 : 0 : return false;
137 : : }
138 : :
139 : 21 : return true;
140 : 0 : }
141 : :
142 : : static void
143 : 15 : ftl_property_dump_common_begin(const struct ftl_property *property,
144 : : struct spdk_json_write_ctx *w)
145 : : {
146 [ # # # # ]: 15 : spdk_json_write_named_string(w, "name", property->name);
147 : 15 : }
148 : :
149 : : static void
150 : 15 : ftl_property_dump_common_end(const struct ftl_property *property,
151 : : struct spdk_json_write_ctx *w)
152 : : {
153 [ + + # # : 15 : if (property->unit) {
# # ]
154 [ # # # # ]: 6 : spdk_json_write_named_string(w, "unit", property->unit);
155 : 0 : }
156 [ + + # # : 15 : if (property->desc) {
# # ]
157 [ # # # # ]: 6 : spdk_json_write_named_string(w, "desc", property->desc);
158 : 0 : }
159 : :
160 [ + + - + : 15 : if (!property->decode || !property->set) {
# # # # #
# # # ]
161 : 9 : spdk_json_write_named_bool(w, "read-only", true);
162 : 0 : }
163 : 15 : }
164 : :
165 : : void
166 : 3 : ftl_property_dump(struct spdk_ftl_dev *dev, struct spdk_jsonrpc_request *request)
167 : : {
168 [ # # # # ]: 3 : struct ftl_properties *properties = dev->properties;
169 : : struct ftl_property *prop;
170 : : struct spdk_json_write_ctx *w;
171 : :
172 : 3 : w = spdk_jsonrpc_begin_result(request);
173 : :
174 : 3 : spdk_json_write_object_begin(w);
175 [ # # # # : 3 : spdk_json_write_named_string(w, "name", dev->conf.name);
# # ]
176 : :
177 : 3 : spdk_json_write_named_array_begin(w, "properties");
178 [ + + # # : 18 : LIST_FOREACH(prop, &properties->list, entry) {
# # # # #
# # # #
# ]
179 [ - + ]: 15 : if (!is_property_visible(dev, prop)) {
180 : 0 : continue;
181 : : }
182 : :
183 : 15 : spdk_json_write_object_begin(w);
184 : 15 : ftl_property_dump_common_begin(prop, w);
185 [ # # # # : 15 : prop->dump(dev, prop, w);
# # # # ]
186 : 15 : ftl_property_dump_common_end(prop, w);
187 : 15 : spdk_json_write_object_end(w);
188 : 0 : }
189 : 3 : spdk_json_write_array_end(w);
190 : :
191 : 3 : spdk_json_write_object_end(w);
192 : 3 : spdk_jsonrpc_end_result(request, w);
193 : 3 : }
194 : :
195 : : void
196 : 6 : ftl_property_dump_bool(struct spdk_ftl_dev *dev, const struct ftl_property *property,
197 : : struct spdk_json_write_ctx *w)
198 : : {
199 [ # # # # ]: 6 : bool *value = property->value;
200 : :
201 [ - + # # : 6 : assert(property->size == sizeof(*value));
# # # # ]
202 [ - + # # ]: 6 : spdk_json_write_named_bool(w, "value", *value);
203 : 6 : }
204 : :
205 : : void
206 : 3 : ftl_property_dump_uint64(struct spdk_ftl_dev *dev, const struct ftl_property *property,
207 : : struct spdk_json_write_ctx *w)
208 : : {
209 [ # # # # ]: 3 : uint64_t *value = property->value;
210 : :
211 [ - + # # : 3 : assert(property->size == sizeof(*value));
# # # # ]
212 [ # # ]: 3 : spdk_json_write_named_uint64(w, "value", *value);
213 : 3 : }
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 : 3 : 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 [ # # # # ]: 3 : struct ftl_properties *properties = dev->properties;
230 : 3 : struct ftl_property *prop = get_property(properties, name);
231 : : int rc;
232 : :
233 [ - + ]: 3 : if (!prop) {
234 [ # # # # : 0 : FTL_ERRLOG(dev, "Property doesn't exist, name %s\n", name);
# # # # ]
235 : 0 : return -ENOENT;
236 : : }
237 : :
238 [ - + # # : 3 : if (!prop->decode) {
# # ]
239 [ # # # # : 0 : FTL_ERRLOG(dev, "Property is read only, name %s\n", name);
# # # # ]
240 : 0 : return -EACCES;
241 : : }
242 : :
243 [ - + ]: 3 : 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 [ - + # # : 3 : assert(prop->size);
# # # # ]
249 [ - + # # : 3 : assert(NULL == *output);
# # ]
250 : :
251 : : /* Allocate buffer for the new value of the property */
252 [ # # # # : 3 : *output = calloc(1, prop->size);
# # ]
253 [ - + # # ]: 3 : if (NULL == *output) {
254 [ # # # # : 0 : FTL_ERRLOG(dev, "Property allocation memory error, name %s\n", name);
# # # # ]
255 : 0 : return -EACCES;
256 : : }
257 [ # # # # : 3 : *output_size = prop->size;
# # ]
258 : :
259 [ # # # # : 3 : rc = prop->decode(dev, prop, value, value_size, *output, *output_size);
# # # # #
# # # ]
260 [ - + ]: 3 : 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 : 3 : return 0;
268 : 0 : }
269 : :
270 : : int
271 : 3 : 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 [ # # # # ]: 3 : struct ftl_properties *properties = dev->properties;
275 : 3 : struct ftl_property *prop = get_property(properties, name);
276 : :
277 [ - + ]: 3 : if (!prop) {
278 [ # # # # : 0 : FTL_ERRLOG(dev, "Property doesn't exist, name %s\n", name);
# # # # ]
279 : 0 : return -ENOENT;
280 : : }
281 : :
282 [ - + # # : 3 : if (!prop->set) {
# # ]
283 [ # # # # : 0 : FTL_ERRLOG(dev, "Property is read only, name %s\n", name);
# # # # ]
284 : 0 : return -EACCES;
285 : : }
286 : :
287 [ - + ]: 3 : 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 [ # # # # : 3 : prop->set(dev, mngt, prop, value, value_size);
# # # # ]
293 : 3 : return 0;
294 : 0 : }
295 : :
296 : : void
297 : 3 : 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 [ - + # # : 3 : ftl_bug(property->size != new_value_size);
# # # # ]
301 [ - + - + : 3 : memcpy(property->value, new_value, property->size);
# # # # #
# # # ]
302 : 3 : ftl_mngt_next_step(mngt);
303 : 3 : }
304 : :
305 : : int
306 : 3 : 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 : 3 : bool *out = output;
310 : :
311 [ - + ]: 3 : if (sizeof(bool) != output_size) {
312 : 0 : return -ENOBUFS;
313 : : }
314 : :
315 [ - + - + ]: 3 : if (strnlen(value, value_size) == value_size) {
316 : 0 : return -EINVAL;
317 : : }
318 : :
319 [ - + + - : 3 : if (0 == strncmp(value, "true", strlen("true"))) {
# # ]
320 [ # # ]: 3 : *out = true;
321 : 3 : 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 : 0 : }
|