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