1fa378811SMateusz Kozlowski /* SPDX-License-Identifier: BSD-3-Clause
2fa378811SMateusz Kozlowski * Copyright 2023 Solidigm All Rights Reserved
3fa378811SMateusz Kozlowski */
4fa378811SMateusz Kozlowski
5fa378811SMateusz Kozlowski #include "spdk/queue.h"
6309682caSMateusz Kozlowski #include "spdk/json.h"
7309682caSMateusz Kozlowski #include "spdk/jsonrpc.h"
8fa378811SMateusz Kozlowski
9fa378811SMateusz Kozlowski #include "ftl_core.h"
10fa378811SMateusz Kozlowski #include "ftl_property.h"
11c959f72eSMateusz Kozlowski #include "mngt/ftl_mngt.h"
12fa378811SMateusz Kozlowski
13fa378811SMateusz Kozlowski struct ftl_properties {
14fa378811SMateusz Kozlowski LIST_HEAD(, ftl_property) list;
15fa378811SMateusz Kozlowski };
16fa378811SMateusz Kozlowski
17fa378811SMateusz Kozlowski /**
18fa378811SMateusz Kozlowski * @brief FTL property descriptor
19fa378811SMateusz Kozlowski */
20fa378811SMateusz Kozlowski struct ftl_property {
21fa378811SMateusz Kozlowski /** Name of the property */
22fa378811SMateusz Kozlowski const char *name;
23fa378811SMateusz Kozlowski
24cb883c5aSMateusz Kozlowski /* Pointer to the value of property */
25cb883c5aSMateusz Kozlowski void *value;
26cb883c5aSMateusz Kozlowski
27cb883c5aSMateusz Kozlowski /* The value size of the property */
28cb883c5aSMateusz Kozlowski size_t size;
29cb883c5aSMateusz Kozlowski
30804f67cfSMateusz Kozlowski /** The unit of the property value */
31804f67cfSMateusz Kozlowski const char *unit;
32804f67cfSMateusz Kozlowski
33804f67cfSMateusz Kozlowski /** The property description for user help */
34804f67cfSMateusz Kozlowski const char *desc;
35804f67cfSMateusz Kozlowski
36cb883c5aSMateusz Kozlowski /* The function to dump the value of property into the specified JSON RPC request */
37cb883c5aSMateusz Kozlowski ftl_property_dump_fn dump;
38cb883c5aSMateusz Kozlowski
39c959f72eSMateusz Kozlowski /* Decode property value and store it in output */
40c959f72eSMateusz Kozlowski ftl_property_decode_fn decode;
41c959f72eSMateusz Kozlowski
42c959f72eSMateusz Kozlowski /* Set the FTL property */
43c959f72eSMateusz Kozlowski ftl_property_set_fn set;
44c959f72eSMateusz Kozlowski
45ebcb0d71SMateusz Kozlowski /* It indicates the property is available in verbose mode only */
46ebcb0d71SMateusz Kozlowski bool verbose_mode;
47ebcb0d71SMateusz Kozlowski
48fa378811SMateusz Kozlowski /** Link to put the property to the list */
49fa378811SMateusz Kozlowski LIST_ENTRY(ftl_property) entry;
50fa378811SMateusz Kozlowski };
51fa378811SMateusz Kozlowski
52fa378811SMateusz Kozlowski static struct ftl_property *
get_property(struct ftl_properties * properties,const char * name)53c959f72eSMateusz Kozlowski get_property(struct ftl_properties *properties, const char *name)
54fa378811SMateusz Kozlowski {
55fa378811SMateusz Kozlowski struct ftl_property *entry;
56fa378811SMateusz Kozlowski
57fa378811SMateusz Kozlowski LIST_FOREACH(entry, &properties->list, entry) {
58fa378811SMateusz Kozlowski /* TODO think about strncmp */
59fa378811SMateusz Kozlowski if (0 == strcmp(entry->name, name)) {
60fa378811SMateusz Kozlowski return entry;
61fa378811SMateusz Kozlowski }
62fa378811SMateusz Kozlowski }
63fa378811SMateusz Kozlowski
64fa378811SMateusz Kozlowski return NULL;
65fa378811SMateusz Kozlowski }
66fa378811SMateusz Kozlowski
67fa378811SMateusz Kozlowski void
ftl_property_register(struct spdk_ftl_dev * dev,const char * name,void * value,size_t size,const char * unit,const char * desc,ftl_property_dump_fn dump,ftl_property_decode_fn decode,ftl_property_set_fn set,bool verbose_mode)68c959f72eSMateusz Kozlowski ftl_property_register(struct spdk_ftl_dev *dev,
69c959f72eSMateusz Kozlowski const char *name, void *value, size_t size,
70804f67cfSMateusz Kozlowski const char *unit, const char *desc,
71c959f72eSMateusz Kozlowski ftl_property_dump_fn dump,
72c959f72eSMateusz Kozlowski ftl_property_decode_fn decode,
73ebcb0d71SMateusz Kozlowski ftl_property_set_fn set,
74ebcb0d71SMateusz Kozlowski bool verbose_mode)
75fa378811SMateusz Kozlowski {
76fa378811SMateusz Kozlowski struct ftl_properties *properties = dev->properties;
77fa378811SMateusz Kozlowski
78c959f72eSMateusz Kozlowski if (get_property(properties, name)) {
79fa378811SMateusz Kozlowski FTL_ERRLOG(dev, "FTL property registration ERROR, already exist, name %s\n", name);
80fa378811SMateusz Kozlowski ftl_abort();
81fa378811SMateusz Kozlowski } else {
82fa378811SMateusz Kozlowski struct ftl_property *prop = calloc(1, sizeof(*prop));
83fa378811SMateusz Kozlowski if (NULL == prop) {
84fa378811SMateusz Kozlowski FTL_ERRLOG(dev, "FTL property registration ERROR, out of memory, name %s\n", name);
85fa378811SMateusz Kozlowski ftl_abort();
86fa378811SMateusz Kozlowski }
87fa378811SMateusz Kozlowski
88fa378811SMateusz Kozlowski prop->name = name;
89cb883c5aSMateusz Kozlowski prop->value = value;
90cb883c5aSMateusz Kozlowski prop->size = size;
91*d6641ee5SMarcin Spiewak prop->unit = unit;
92804f67cfSMateusz Kozlowski prop->desc = desc;
93cb883c5aSMateusz Kozlowski prop->dump = dump;
94c959f72eSMateusz Kozlowski prop->decode = decode;
95c959f72eSMateusz Kozlowski prop->set = set;
96ebcb0d71SMateusz Kozlowski prop->verbose_mode = verbose_mode;
97fa378811SMateusz Kozlowski LIST_INSERT_HEAD(&properties->list, prop, entry);
98fa378811SMateusz Kozlowski }
99fa378811SMateusz Kozlowski }
100fa378811SMateusz Kozlowski
101fa378811SMateusz Kozlowski int
ftl_properties_init(struct spdk_ftl_dev * dev)102fa378811SMateusz Kozlowski ftl_properties_init(struct spdk_ftl_dev *dev)
103fa378811SMateusz Kozlowski {
104fa378811SMateusz Kozlowski dev->properties = calloc(1, sizeof(*dev->properties));
105fa378811SMateusz Kozlowski if (!dev->properties) {
106fa378811SMateusz Kozlowski return -ENOMEM;
107fa378811SMateusz Kozlowski }
108fa378811SMateusz Kozlowski
109fa378811SMateusz Kozlowski LIST_INIT(&dev->properties->list);
110fa378811SMateusz Kozlowski return 0;
111fa378811SMateusz Kozlowski }
112fa378811SMateusz Kozlowski
113fa378811SMateusz Kozlowski void
ftl_properties_deinit(struct spdk_ftl_dev * dev)114fa378811SMateusz Kozlowski ftl_properties_deinit(struct spdk_ftl_dev *dev)
115fa378811SMateusz Kozlowski {
116fa378811SMateusz Kozlowski struct ftl_properties *properties = dev->properties;
117fa378811SMateusz Kozlowski struct ftl_property *prop;
118fa378811SMateusz Kozlowski
119fa378811SMateusz Kozlowski if (!properties) {
120fa378811SMateusz Kozlowski return;
121fa378811SMateusz Kozlowski }
122fa378811SMateusz Kozlowski
123fa378811SMateusz Kozlowski while (!LIST_EMPTY(&properties->list)) {
124fa378811SMateusz Kozlowski prop = LIST_FIRST(&properties->list);
125fa378811SMateusz Kozlowski LIST_REMOVE(prop, entry);
126fa378811SMateusz Kozlowski free(prop);
127fa378811SMateusz Kozlowski }
128fa378811SMateusz Kozlowski
129fa378811SMateusz Kozlowski free(dev->properties);
130fa378811SMateusz Kozlowski }
131309682caSMateusz Kozlowski
132ebcb0d71SMateusz Kozlowski static bool
is_property_visible(struct spdk_ftl_dev * dev,struct ftl_property * prop)133ebcb0d71SMateusz Kozlowski is_property_visible(struct spdk_ftl_dev *dev, struct ftl_property *prop)
134ebcb0d71SMateusz Kozlowski {
135ebcb0d71SMateusz Kozlowski if (prop->verbose_mode && !dev->conf.verbose_mode) {
136ebcb0d71SMateusz Kozlowski return false;
137ebcb0d71SMateusz Kozlowski }
138ebcb0d71SMateusz Kozlowski
139ebcb0d71SMateusz Kozlowski return true;
140ebcb0d71SMateusz Kozlowski }
141ebcb0d71SMateusz Kozlowski
142804f67cfSMateusz Kozlowski static void
ftl_property_dump_common_begin(const struct ftl_property * property,struct spdk_json_write_ctx * w)143804f67cfSMateusz Kozlowski ftl_property_dump_common_begin(const struct ftl_property *property,
144804f67cfSMateusz Kozlowski struct spdk_json_write_ctx *w)
145804f67cfSMateusz Kozlowski {
146804f67cfSMateusz Kozlowski spdk_json_write_named_string(w, "name", property->name);
147804f67cfSMateusz Kozlowski }
148804f67cfSMateusz Kozlowski
149804f67cfSMateusz Kozlowski static void
ftl_property_dump_common_end(const struct ftl_property * property,struct spdk_json_write_ctx * w)150804f67cfSMateusz Kozlowski ftl_property_dump_common_end(const struct ftl_property *property,
151804f67cfSMateusz Kozlowski struct spdk_json_write_ctx *w)
152804f67cfSMateusz Kozlowski {
153804f67cfSMateusz Kozlowski if (property->unit) {
154804f67cfSMateusz Kozlowski spdk_json_write_named_string(w, "unit", property->unit);
155804f67cfSMateusz Kozlowski }
156804f67cfSMateusz Kozlowski if (property->desc) {
157804f67cfSMateusz Kozlowski spdk_json_write_named_string(w, "desc", property->desc);
158804f67cfSMateusz Kozlowski }
159804f67cfSMateusz Kozlowski
160804f67cfSMateusz Kozlowski if (!property->decode || !property->set) {
161804f67cfSMateusz Kozlowski spdk_json_write_named_bool(w, "read-only", true);
162804f67cfSMateusz Kozlowski }
163804f67cfSMateusz Kozlowski }
164804f67cfSMateusz Kozlowski
165309682caSMateusz Kozlowski void
ftl_property_dump(struct spdk_ftl_dev * dev,struct spdk_jsonrpc_request * request)166309682caSMateusz Kozlowski ftl_property_dump(struct spdk_ftl_dev *dev, struct spdk_jsonrpc_request *request)
167309682caSMateusz Kozlowski {
168309682caSMateusz Kozlowski struct ftl_properties *properties = dev->properties;
169309682caSMateusz Kozlowski struct ftl_property *prop;
170309682caSMateusz Kozlowski struct spdk_json_write_ctx *w;
171309682caSMateusz Kozlowski
172309682caSMateusz Kozlowski w = spdk_jsonrpc_begin_result(request);
173804f67cfSMateusz Kozlowski
174309682caSMateusz Kozlowski spdk_json_write_object_begin(w);
175309682caSMateusz Kozlowski spdk_json_write_named_string(w, "name", dev->conf.name);
176309682caSMateusz Kozlowski
177804f67cfSMateusz Kozlowski spdk_json_write_named_array_begin(w, "properties");
178309682caSMateusz Kozlowski LIST_FOREACH(prop, &properties->list, entry) {
179ebcb0d71SMateusz Kozlowski if (!is_property_visible(dev, prop)) {
180ebcb0d71SMateusz Kozlowski continue;
181ebcb0d71SMateusz Kozlowski }
182ebcb0d71SMateusz Kozlowski
183804f67cfSMateusz Kozlowski spdk_json_write_object_begin(w);
184804f67cfSMateusz Kozlowski ftl_property_dump_common_begin(prop, w);
185119935ccSMateusz Kozlowski prop->dump(dev, prop, w);
186804f67cfSMateusz Kozlowski ftl_property_dump_common_end(prop, w);
187309682caSMateusz Kozlowski spdk_json_write_object_end(w);
188804f67cfSMateusz Kozlowski }
189804f67cfSMateusz Kozlowski spdk_json_write_array_end(w);
190309682caSMateusz Kozlowski
191309682caSMateusz Kozlowski spdk_json_write_object_end(w);
192309682caSMateusz Kozlowski spdk_jsonrpc_end_result(request, w);
193309682caSMateusz Kozlowski }
194cb883c5aSMateusz Kozlowski
195cb883c5aSMateusz Kozlowski void
ftl_property_dump_bool(struct spdk_ftl_dev * dev,const struct ftl_property * property,struct spdk_json_write_ctx * w)196119935ccSMateusz Kozlowski ftl_property_dump_bool(struct spdk_ftl_dev *dev, const struct ftl_property *property,
197cb883c5aSMateusz Kozlowski struct spdk_json_write_ctx *w)
198cb883c5aSMateusz Kozlowski {
199cb883c5aSMateusz Kozlowski bool *value = property->value;
200cb883c5aSMateusz Kozlowski
201cb883c5aSMateusz Kozlowski assert(property->size == sizeof(*value));
202804f67cfSMateusz Kozlowski spdk_json_write_named_bool(w, "value", *value);
203cb883c5aSMateusz Kozlowski }
204cb883c5aSMateusz Kozlowski
205cb883c5aSMateusz Kozlowski void
ftl_property_dump_uint64(struct spdk_ftl_dev * dev,const struct ftl_property * property,struct spdk_json_write_ctx * w)206119935ccSMateusz Kozlowski ftl_property_dump_uint64(struct spdk_ftl_dev *dev, const struct ftl_property *property,
207cb883c5aSMateusz Kozlowski struct spdk_json_write_ctx *w)
208cb883c5aSMateusz Kozlowski {
209cb883c5aSMateusz Kozlowski uint64_t *value = property->value;
210cb883c5aSMateusz Kozlowski
211cb883c5aSMateusz Kozlowski assert(property->size == sizeof(*value));
212804f67cfSMateusz Kozlowski spdk_json_write_named_uint64(w, "value", *value);
213cb883c5aSMateusz Kozlowski }
214cb883c5aSMateusz Kozlowski
215cb883c5aSMateusz Kozlowski void
ftl_property_dump_uint32(struct spdk_ftl_dev * dev,const struct ftl_property * property,struct spdk_json_write_ctx * w)216119935ccSMateusz Kozlowski ftl_property_dump_uint32(struct spdk_ftl_dev *dev, const struct ftl_property *property,
217cb883c5aSMateusz Kozlowski struct spdk_json_write_ctx *w)
218cb883c5aSMateusz Kozlowski {
219cb883c5aSMateusz Kozlowski uint32_t *value = property->value;
220cb883c5aSMateusz Kozlowski
221cb883c5aSMateusz Kozlowski assert(property->size == sizeof(*value));
222804f67cfSMateusz Kozlowski spdk_json_write_named_uint32(w, "value", *value);
223cb883c5aSMateusz Kozlowski }
224c959f72eSMateusz Kozlowski
225c959f72eSMateusz Kozlowski int
ftl_property_decode(struct spdk_ftl_dev * dev,const char * name,const char * value,size_t value_size,void ** output,size_t * output_size)226c959f72eSMateusz Kozlowski ftl_property_decode(struct spdk_ftl_dev *dev, const char *name, const char *value,
227c959f72eSMateusz Kozlowski size_t value_size, void **output, size_t *output_size)
228c959f72eSMateusz Kozlowski {
229c959f72eSMateusz Kozlowski struct ftl_properties *properties = dev->properties;
230c959f72eSMateusz Kozlowski struct ftl_property *prop = get_property(properties, name);
231c959f72eSMateusz Kozlowski int rc;
232c959f72eSMateusz Kozlowski
233c959f72eSMateusz Kozlowski if (!prop) {
234c959f72eSMateusz Kozlowski FTL_ERRLOG(dev, "Property doesn't exist, name %s\n", name);
235c959f72eSMateusz Kozlowski return -ENOENT;
236c959f72eSMateusz Kozlowski }
237c959f72eSMateusz Kozlowski
238c959f72eSMateusz Kozlowski if (!prop->decode) {
239c959f72eSMateusz Kozlowski FTL_ERRLOG(dev, "Property is read only, name %s\n", name);
240c959f72eSMateusz Kozlowski return -EACCES;
241c959f72eSMateusz Kozlowski }
242c959f72eSMateusz Kozlowski
243ebcb0d71SMateusz Kozlowski if (!is_property_visible(dev, prop)) {
244ebcb0d71SMateusz Kozlowski FTL_ERRLOG(dev, "Property is inactive, enable verbose mode to access it, name %s.\n", name);
245ebcb0d71SMateusz Kozlowski return -EACCES;
246ebcb0d71SMateusz Kozlowski }
247ebcb0d71SMateusz Kozlowski
248c959f72eSMateusz Kozlowski assert(prop->size);
249c959f72eSMateusz Kozlowski assert(NULL == *output);
250c959f72eSMateusz Kozlowski
251c959f72eSMateusz Kozlowski /* Allocate buffer for the new value of the property */
252c959f72eSMateusz Kozlowski *output = calloc(1, prop->size);
253c959f72eSMateusz Kozlowski if (NULL == *output) {
254c959f72eSMateusz Kozlowski FTL_ERRLOG(dev, "Property allocation memory error, name %s\n", name);
255c959f72eSMateusz Kozlowski return -EACCES;
256c959f72eSMateusz Kozlowski }
257c959f72eSMateusz Kozlowski *output_size = prop->size;
258c959f72eSMateusz Kozlowski
259c959f72eSMateusz Kozlowski rc = prop->decode(dev, prop, value, value_size, *output, *output_size);
260c959f72eSMateusz Kozlowski if (rc) {
261c959f72eSMateusz Kozlowski FTL_ERRLOG(dev, "Property decode error, name %s\n", name);
262c959f72eSMateusz Kozlowski free(*output);
263c959f72eSMateusz Kozlowski *output = NULL;
264c959f72eSMateusz Kozlowski return rc;
265c959f72eSMateusz Kozlowski }
266c959f72eSMateusz Kozlowski
267c959f72eSMateusz Kozlowski return 0;
268c959f72eSMateusz Kozlowski }
269c959f72eSMateusz Kozlowski
270c959f72eSMateusz Kozlowski int
ftl_property_set(struct spdk_ftl_dev * dev,struct ftl_mngt_process * mngt,const char * name,void * value,size_t value_size)271c959f72eSMateusz Kozlowski ftl_property_set(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
272c959f72eSMateusz Kozlowski const char *name, void *value, size_t value_size)
273c959f72eSMateusz Kozlowski {
274c959f72eSMateusz Kozlowski struct ftl_properties *properties = dev->properties;
275c959f72eSMateusz Kozlowski struct ftl_property *prop = get_property(properties, name);
276c959f72eSMateusz Kozlowski
277c959f72eSMateusz Kozlowski if (!prop) {
278c959f72eSMateusz Kozlowski FTL_ERRLOG(dev, "Property doesn't exist, name %s\n", name);
279c959f72eSMateusz Kozlowski return -ENOENT;
280c959f72eSMateusz Kozlowski }
281c959f72eSMateusz Kozlowski
282c959f72eSMateusz Kozlowski if (!prop->set) {
283c959f72eSMateusz Kozlowski FTL_ERRLOG(dev, "Property is read only, name %s\n", name);
284c959f72eSMateusz Kozlowski return -EACCES;
285c959f72eSMateusz Kozlowski }
286c959f72eSMateusz Kozlowski
287ebcb0d71SMateusz Kozlowski if (!is_property_visible(dev, prop)) {
288ebcb0d71SMateusz Kozlowski FTL_ERRLOG(dev, "Property is inactive, enable verbose mode to access it, name %s\n", name);
289ebcb0d71SMateusz Kozlowski return -EACCES;
290ebcb0d71SMateusz Kozlowski }
291ebcb0d71SMateusz Kozlowski
292c959f72eSMateusz Kozlowski prop->set(dev, mngt, prop, value, value_size);
293c959f72eSMateusz Kozlowski return 0;
294c959f72eSMateusz Kozlowski }
295c959f72eSMateusz Kozlowski
296c959f72eSMateusz Kozlowski void
ftl_property_set_generic(struct spdk_ftl_dev * dev,struct ftl_mngt_process * mngt,const struct ftl_property * property,void * new_value,size_t new_value_size)297c959f72eSMateusz Kozlowski ftl_property_set_generic(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
298c959f72eSMateusz Kozlowski const struct ftl_property *property, void *new_value, size_t new_value_size)
299c959f72eSMateusz Kozlowski {
300c959f72eSMateusz Kozlowski ftl_bug(property->size != new_value_size);
301c959f72eSMateusz Kozlowski memcpy(property->value, new_value, property->size);
302c959f72eSMateusz Kozlowski ftl_mngt_next_step(mngt);
303c959f72eSMateusz Kozlowski }
304c959f72eSMateusz Kozlowski
305c959f72eSMateusz Kozlowski int
ftl_property_decode_bool(struct spdk_ftl_dev * dev,struct ftl_property * property,const char * value,size_t value_size,void * output,size_t output_size)306c959f72eSMateusz Kozlowski ftl_property_decode_bool(struct spdk_ftl_dev *dev, struct ftl_property *property,
307c959f72eSMateusz Kozlowski const char *value, size_t value_size, void *output, size_t output_size)
308c959f72eSMateusz Kozlowski {
309c959f72eSMateusz Kozlowski bool *out = output;
310c959f72eSMateusz Kozlowski
311c959f72eSMateusz Kozlowski if (sizeof(bool) != output_size) {
312c959f72eSMateusz Kozlowski return -ENOBUFS;
313c959f72eSMateusz Kozlowski }
314c959f72eSMateusz Kozlowski
315c959f72eSMateusz Kozlowski if (strnlen(value, value_size) == value_size) {
316c959f72eSMateusz Kozlowski return -EINVAL;
317c959f72eSMateusz Kozlowski }
318c959f72eSMateusz Kozlowski
319c959f72eSMateusz Kozlowski if (0 == strncmp(value, "true", strlen("true"))) {
320c959f72eSMateusz Kozlowski *out = true;
321c959f72eSMateusz Kozlowski return 0;
322c959f72eSMateusz Kozlowski }
323c959f72eSMateusz Kozlowski
324c959f72eSMateusz Kozlowski if (0 == strncmp(value, "false", strlen("false"))) {
325c959f72eSMateusz Kozlowski *out = false;
326c959f72eSMateusz Kozlowski return 0;
327c959f72eSMateusz Kozlowski }
328c959f72eSMateusz Kozlowski
329c959f72eSMateusz Kozlowski return -EINVAL;
330c959f72eSMateusz Kozlowski }
331