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 : 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 : : }
|