1293cdc48SArtur Paszkiewicz /* SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse * Copyright (C) 2022 Intel Corporation.
3293cdc48SArtur Paszkiewicz * All rights reserved.
4293cdc48SArtur Paszkiewicz */
5293cdc48SArtur Paszkiewicz
6293cdc48SArtur Paszkiewicz #include "spdk/queue.h"
7293cdc48SArtur Paszkiewicz #include "spdk/assert.h"
8293cdc48SArtur Paszkiewicz #include "spdk/env.h"
9293cdc48SArtur Paszkiewicz
10293cdc48SArtur Paszkiewicz #include "ftl_mngt.h"
11293cdc48SArtur Paszkiewicz #include "ftl_core.h"
12293cdc48SArtur Paszkiewicz
13293cdc48SArtur Paszkiewicz struct ftl_mngt_step_status {
14293cdc48SArtur Paszkiewicz uint64_t start;
15293cdc48SArtur Paszkiewicz uint64_t stop;
16293cdc48SArtur Paszkiewicz int status;
17293cdc48SArtur Paszkiewicz int silent;
18293cdc48SArtur Paszkiewicz TAILQ_ENTRY(ftl_mngt_step) entry;
19293cdc48SArtur Paszkiewicz };
20293cdc48SArtur Paszkiewicz
21293cdc48SArtur Paszkiewicz struct ftl_mngt_step {
22293cdc48SArtur Paszkiewicz void *ctx;
23293cdc48SArtur Paszkiewicz const struct ftl_mngt_step_desc *desc;
24293cdc48SArtur Paszkiewicz struct ftl_mngt_step_status action;
25293cdc48SArtur Paszkiewicz struct ftl_mngt_step_status rollback;
26293cdc48SArtur Paszkiewicz };
27293cdc48SArtur Paszkiewicz
28293cdc48SArtur Paszkiewicz struct ftl_mngt_process {
29293cdc48SArtur Paszkiewicz struct spdk_ftl_dev *dev;
30293cdc48SArtur Paszkiewicz int status;
31b71eebd8SArtur Paszkiewicz bool silent;
32293cdc48SArtur Paszkiewicz bool rollback;
33293cdc48SArtur Paszkiewicz bool continuing;
34293cdc48SArtur Paszkiewicz struct {
35b71eebd8SArtur Paszkiewicz ftl_mngt_completion cb;
36293cdc48SArtur Paszkiewicz void *cb_ctx;
37293cdc48SArtur Paszkiewicz struct spdk_thread *thread;
38293cdc48SArtur Paszkiewicz } caller;
39293cdc48SArtur Paszkiewicz void *ctx;
40293cdc48SArtur Paszkiewicz uint64_t tsc_start;
41293cdc48SArtur Paszkiewicz uint64_t tsc_stop;
42293cdc48SArtur Paszkiewicz const struct ftl_mngt_process_desc *desc;
43293cdc48SArtur Paszkiewicz TAILQ_HEAD(, ftl_mngt_step) action_queue_todo;
44293cdc48SArtur Paszkiewicz TAILQ_HEAD(, ftl_mngt_step) action_queue_done;
45293cdc48SArtur Paszkiewicz TAILQ_HEAD(, ftl_mngt_step) rollback_queue_todo;
46293cdc48SArtur Paszkiewicz TAILQ_HEAD(, ftl_mngt_step) rollback_queue_done;
47293cdc48SArtur Paszkiewicz struct {
48293cdc48SArtur Paszkiewicz struct ftl_mngt_step step;
49293cdc48SArtur Paszkiewicz struct ftl_mngt_step_desc desc;
50293cdc48SArtur Paszkiewicz } cleanup;
51293cdc48SArtur Paszkiewicz struct ftl_mng_tracer *tracer;
52293cdc48SArtur Paszkiewicz };
53293cdc48SArtur Paszkiewicz
54293cdc48SArtur Paszkiewicz static void action_next(struct ftl_mngt_process *mngt);
55293cdc48SArtur Paszkiewicz static void action_msg(void *ctx);
56293cdc48SArtur Paszkiewicz static void action_execute(struct ftl_mngt_process *mngt);
57293cdc48SArtur Paszkiewicz static void action_done(struct ftl_mngt_process *mngt, int status);
58293cdc48SArtur Paszkiewicz static void rollback_next(struct ftl_mngt_process *mngt);
59293cdc48SArtur Paszkiewicz static void rollback_msg(void *ctx);
60293cdc48SArtur Paszkiewicz static void rollback_execute(struct ftl_mngt_process *mngt);
61293cdc48SArtur Paszkiewicz static void rollback_done(struct ftl_mngt_process *mngt, int status);
62293cdc48SArtur Paszkiewicz
63293cdc48SArtur Paszkiewicz static inline struct ftl_mngt_step *
get_current_step(struct ftl_mngt_process * mngt)64293cdc48SArtur Paszkiewicz get_current_step(struct ftl_mngt_process *mngt)
65293cdc48SArtur Paszkiewicz {
66293cdc48SArtur Paszkiewicz if (!mngt->rollback) {
67293cdc48SArtur Paszkiewicz return TAILQ_FIRST(&mngt->action_queue_todo);
68293cdc48SArtur Paszkiewicz } else {
69293cdc48SArtur Paszkiewicz return TAILQ_FIRST(&mngt->rollback_queue_todo);
70293cdc48SArtur Paszkiewicz }
71293cdc48SArtur Paszkiewicz }
72293cdc48SArtur Paszkiewicz
73293cdc48SArtur Paszkiewicz static int
init_step(struct ftl_mngt_process * mngt,const struct ftl_mngt_step_desc * desc)74293cdc48SArtur Paszkiewicz init_step(struct ftl_mngt_process *mngt,
75293cdc48SArtur Paszkiewicz const struct ftl_mngt_step_desc *desc)
76293cdc48SArtur Paszkiewicz {
77293cdc48SArtur Paszkiewicz struct ftl_mngt_step *step;
78293cdc48SArtur Paszkiewicz
79293cdc48SArtur Paszkiewicz step = calloc(1, sizeof(*step));
80293cdc48SArtur Paszkiewicz if (!step) {
81293cdc48SArtur Paszkiewicz return -ENOMEM;
82293cdc48SArtur Paszkiewicz }
83293cdc48SArtur Paszkiewicz
84293cdc48SArtur Paszkiewicz /* Initialize the step's argument */
85293cdc48SArtur Paszkiewicz if (desc->ctx_size) {
86293cdc48SArtur Paszkiewicz step->ctx = calloc(1, desc->ctx_size);
87293cdc48SArtur Paszkiewicz if (!step->ctx) {
88293cdc48SArtur Paszkiewicz free(step);
89293cdc48SArtur Paszkiewicz return -ENOMEM;
90293cdc48SArtur Paszkiewicz }
91293cdc48SArtur Paszkiewicz }
92293cdc48SArtur Paszkiewicz step->desc = desc;
93293cdc48SArtur Paszkiewicz TAILQ_INSERT_TAIL(&mngt->action_queue_todo, step, action.entry);
94293cdc48SArtur Paszkiewicz
95293cdc48SArtur Paszkiewicz return 0;
96293cdc48SArtur Paszkiewicz }
97293cdc48SArtur Paszkiewicz
98293cdc48SArtur Paszkiewicz static void
free_mngt(struct ftl_mngt_process * mngt)99293cdc48SArtur Paszkiewicz free_mngt(struct ftl_mngt_process *mngt)
100293cdc48SArtur Paszkiewicz {
101293cdc48SArtur Paszkiewicz TAILQ_HEAD(, ftl_mngt_step) steps;
102293cdc48SArtur Paszkiewicz
103293cdc48SArtur Paszkiewicz if (!mngt) {
104293cdc48SArtur Paszkiewicz return;
105293cdc48SArtur Paszkiewicz }
106293cdc48SArtur Paszkiewicz
107293cdc48SArtur Paszkiewicz TAILQ_INIT(&steps);
108293cdc48SArtur Paszkiewicz TAILQ_CONCAT(&steps, &mngt->action_queue_todo, action.entry);
109293cdc48SArtur Paszkiewicz TAILQ_CONCAT(&steps, &mngt->action_queue_done, action.entry);
110293cdc48SArtur Paszkiewicz
111293cdc48SArtur Paszkiewicz while (!TAILQ_EMPTY(&steps)) {
112293cdc48SArtur Paszkiewicz struct ftl_mngt_step *step = TAILQ_FIRST(&steps);
113293cdc48SArtur Paszkiewicz TAILQ_REMOVE(&steps, step, action.entry);
114293cdc48SArtur Paszkiewicz
115293cdc48SArtur Paszkiewicz free(step->ctx);
116293cdc48SArtur Paszkiewicz free(step);
117293cdc48SArtur Paszkiewicz }
118293cdc48SArtur Paszkiewicz
119293cdc48SArtur Paszkiewicz free(mngt->ctx);
120293cdc48SArtur Paszkiewicz free(mngt);
121293cdc48SArtur Paszkiewicz }
122293cdc48SArtur Paszkiewicz
123293cdc48SArtur Paszkiewicz static struct ftl_mngt_process *
allocate_mngt(struct spdk_ftl_dev * dev,const struct ftl_mngt_process_desc * pdesc,ftl_mngt_completion cb,void * cb_ctx,bool silent)124b71eebd8SArtur Paszkiewicz allocate_mngt(struct spdk_ftl_dev *dev, const struct ftl_mngt_process_desc *pdesc,
125b71eebd8SArtur Paszkiewicz ftl_mngt_completion cb, void *cb_ctx, bool silent)
126293cdc48SArtur Paszkiewicz {
127293cdc48SArtur Paszkiewicz struct ftl_mngt_process *mngt;
128293cdc48SArtur Paszkiewicz
129293cdc48SArtur Paszkiewicz /* Initialize management process */
130293cdc48SArtur Paszkiewicz mngt = calloc(1, sizeof(*mngt));
131293cdc48SArtur Paszkiewicz if (!mngt) {
132293cdc48SArtur Paszkiewicz goto error;
133293cdc48SArtur Paszkiewicz }
134293cdc48SArtur Paszkiewicz mngt->dev = dev;
135b71eebd8SArtur Paszkiewicz mngt->silent = silent;
136293cdc48SArtur Paszkiewicz mngt->caller.cb = cb;
137293cdc48SArtur Paszkiewicz mngt->caller.cb_ctx = cb_ctx;
138293cdc48SArtur Paszkiewicz mngt->caller.thread = spdk_get_thread();
139293cdc48SArtur Paszkiewicz
140293cdc48SArtur Paszkiewicz /* Initialize process context */
141293cdc48SArtur Paszkiewicz if (pdesc->ctx_size) {
142293cdc48SArtur Paszkiewicz mngt->ctx = calloc(1, pdesc->ctx_size);
143293cdc48SArtur Paszkiewicz if (!mngt->ctx) {
144293cdc48SArtur Paszkiewicz goto error;
145293cdc48SArtur Paszkiewicz }
146293cdc48SArtur Paszkiewicz }
147293cdc48SArtur Paszkiewicz mngt->tsc_start = spdk_get_ticks();
148293cdc48SArtur Paszkiewicz mngt->desc = pdesc;
149293cdc48SArtur Paszkiewicz TAILQ_INIT(&mngt->action_queue_todo);
150293cdc48SArtur Paszkiewicz TAILQ_INIT(&mngt->action_queue_done);
151293cdc48SArtur Paszkiewicz TAILQ_INIT(&mngt->rollback_queue_todo);
152293cdc48SArtur Paszkiewicz TAILQ_INIT(&mngt->rollback_queue_done);
153293cdc48SArtur Paszkiewicz
154293cdc48SArtur Paszkiewicz return mngt;
155293cdc48SArtur Paszkiewicz error:
156293cdc48SArtur Paszkiewicz free_mngt(mngt);
157293cdc48SArtur Paszkiewicz return NULL;
158293cdc48SArtur Paszkiewicz }
159293cdc48SArtur Paszkiewicz
160b71eebd8SArtur Paszkiewicz static int
invoke_init_handler(struct spdk_ftl_dev * dev,struct ftl_mngt_process * mngt,const struct ftl_mngt_process_desc * pdesc,void * init_ctx)1619452abe6SMateusz Kozlowski invoke_init_handler(struct spdk_ftl_dev *dev, struct ftl_mngt_process *mngt,
1629452abe6SMateusz Kozlowski const struct ftl_mngt_process_desc *pdesc, void *init_ctx)
1639452abe6SMateusz Kozlowski {
1649452abe6SMateusz Kozlowski int rc = 0;
1659452abe6SMateusz Kozlowski
1669452abe6SMateusz Kozlowski if (init_ctx || pdesc->init_handler) {
1679452abe6SMateusz Kozlowski ftl_bug(!init_ctx);
1689452abe6SMateusz Kozlowski ftl_bug(!pdesc->init_handler);
1699452abe6SMateusz Kozlowski rc = pdesc->init_handler(dev, mngt, init_ctx);
1709452abe6SMateusz Kozlowski }
1719452abe6SMateusz Kozlowski
1729452abe6SMateusz Kozlowski return rc;
1739452abe6SMateusz Kozlowski }
1749452abe6SMateusz Kozlowski
1759452abe6SMateusz Kozlowski static int
_ftl_mngt_process_execute(struct spdk_ftl_dev * dev,const struct ftl_mngt_process_desc * pdesc,ftl_mngt_completion cb,void * cb_ctx,bool silent,void * init_ctx)176b71eebd8SArtur Paszkiewicz _ftl_mngt_process_execute(struct spdk_ftl_dev *dev, const struct ftl_mngt_process_desc *pdesc,
1779452abe6SMateusz Kozlowski ftl_mngt_completion cb, void *cb_ctx, bool silent, void *init_ctx)
178293cdc48SArtur Paszkiewicz {
179293cdc48SArtur Paszkiewicz const struct ftl_mngt_step_desc *sdesc;
180293cdc48SArtur Paszkiewicz struct ftl_mngt_process *mngt;
181293cdc48SArtur Paszkiewicz int rc = 0;
182293cdc48SArtur Paszkiewicz
183b71eebd8SArtur Paszkiewicz mngt = allocate_mngt(dev, pdesc, cb, cb_ctx, silent);
184293cdc48SArtur Paszkiewicz if (!mngt) {
185293cdc48SArtur Paszkiewicz rc = -ENOMEM;
186293cdc48SArtur Paszkiewicz goto error;
187293cdc48SArtur Paszkiewicz }
188293cdc48SArtur Paszkiewicz
189293cdc48SArtur Paszkiewicz if (pdesc->error_handler) {
190293cdc48SArtur Paszkiewicz /* Initialize a step for error handler */
191293cdc48SArtur Paszkiewicz mngt->cleanup.step.desc = &mngt->cleanup.desc;
192293cdc48SArtur Paszkiewicz mngt->cleanup.desc.name = "Handle ERROR";
193293cdc48SArtur Paszkiewicz mngt->cleanup.desc.cleanup = pdesc->error_handler;
194293cdc48SArtur Paszkiewicz
195293cdc48SArtur Paszkiewicz /* Queue error handler to the rollback queue, it will be executed at the end */
196293cdc48SArtur Paszkiewicz TAILQ_INSERT_HEAD(&mngt->rollback_queue_todo, &mngt->cleanup.step,
197293cdc48SArtur Paszkiewicz rollback.entry);
198293cdc48SArtur Paszkiewicz }
199293cdc48SArtur Paszkiewicz
200293cdc48SArtur Paszkiewicz /* Initialize steps */
201293cdc48SArtur Paszkiewicz sdesc = mngt->desc->steps;
202293cdc48SArtur Paszkiewicz while (sdesc->action) {
203293cdc48SArtur Paszkiewicz rc = init_step(mngt, sdesc);
204293cdc48SArtur Paszkiewicz if (rc) {
205293cdc48SArtur Paszkiewicz goto error;
206293cdc48SArtur Paszkiewicz }
207293cdc48SArtur Paszkiewicz sdesc++;
208293cdc48SArtur Paszkiewicz }
209293cdc48SArtur Paszkiewicz
2109452abe6SMateusz Kozlowski rc = invoke_init_handler(dev, mngt, pdesc, init_ctx);
2119452abe6SMateusz Kozlowski if (rc) {
2129452abe6SMateusz Kozlowski goto error;
2139452abe6SMateusz Kozlowski }
2149452abe6SMateusz Kozlowski
215293cdc48SArtur Paszkiewicz action_execute(mngt);
216293cdc48SArtur Paszkiewicz return 0;
217293cdc48SArtur Paszkiewicz error:
218293cdc48SArtur Paszkiewicz free_mngt(mngt);
219293cdc48SArtur Paszkiewicz return rc;
220293cdc48SArtur Paszkiewicz }
221293cdc48SArtur Paszkiewicz
222293cdc48SArtur Paszkiewicz int
ftl_mngt_process_execute(struct spdk_ftl_dev * dev,const struct ftl_mngt_process_desc * pdesc,ftl_mngt_completion cb,void * cb_ctx)223b71eebd8SArtur Paszkiewicz ftl_mngt_process_execute(struct spdk_ftl_dev *dev, const struct ftl_mngt_process_desc *pdesc,
224b71eebd8SArtur Paszkiewicz ftl_mngt_completion cb, void *cb_ctx)
225b71eebd8SArtur Paszkiewicz {
2269452abe6SMateusz Kozlowski return _ftl_mngt_process_execute(dev, pdesc, cb, cb_ctx, false, NULL);
227b71eebd8SArtur Paszkiewicz }
228b71eebd8SArtur Paszkiewicz
229b71eebd8SArtur Paszkiewicz int
ftl_mngt_process_rollback(struct spdk_ftl_dev * dev,const struct ftl_mngt_process_desc * pdesc,ftl_mngt_completion cb,void * cb_ctx)230b71eebd8SArtur Paszkiewicz ftl_mngt_process_rollback(struct spdk_ftl_dev *dev, const struct ftl_mngt_process_desc *pdesc,
231b71eebd8SArtur Paszkiewicz ftl_mngt_completion cb, void *cb_ctx)
232293cdc48SArtur Paszkiewicz {
233293cdc48SArtur Paszkiewicz const struct ftl_mngt_step_desc *sdesc;
234293cdc48SArtur Paszkiewicz struct ftl_mngt_process *mngt;
235293cdc48SArtur Paszkiewicz int rc = 0;
236293cdc48SArtur Paszkiewicz
237b71eebd8SArtur Paszkiewicz mngt = allocate_mngt(dev, pdesc, cb, cb_ctx, true);
238293cdc48SArtur Paszkiewicz if (!mngt) {
239293cdc48SArtur Paszkiewicz rc = -ENOMEM;
240293cdc48SArtur Paszkiewicz goto error;
241293cdc48SArtur Paszkiewicz }
242293cdc48SArtur Paszkiewicz
243293cdc48SArtur Paszkiewicz /* Initialize steps for rollback */
244293cdc48SArtur Paszkiewicz sdesc = mngt->desc->steps;
245293cdc48SArtur Paszkiewicz while (sdesc->action) {
246293cdc48SArtur Paszkiewicz if (!sdesc->cleanup) {
247293cdc48SArtur Paszkiewicz sdesc++;
248293cdc48SArtur Paszkiewicz continue;
249293cdc48SArtur Paszkiewicz }
250293cdc48SArtur Paszkiewicz rc = init_step(mngt, sdesc);
251293cdc48SArtur Paszkiewicz if (rc) {
252293cdc48SArtur Paszkiewicz goto error;
253293cdc48SArtur Paszkiewicz }
254293cdc48SArtur Paszkiewicz sdesc++;
255293cdc48SArtur Paszkiewicz }
256293cdc48SArtur Paszkiewicz
257293cdc48SArtur Paszkiewicz /* Build rollback list */
258293cdc48SArtur Paszkiewicz struct ftl_mngt_step *step;
259293cdc48SArtur Paszkiewicz TAILQ_FOREACH(step, &mngt->action_queue_todo, action.entry) {
260293cdc48SArtur Paszkiewicz step->action.silent = true;
261293cdc48SArtur Paszkiewicz TAILQ_INSERT_HEAD(&mngt->rollback_queue_todo, step,
262293cdc48SArtur Paszkiewicz rollback.entry);
263293cdc48SArtur Paszkiewicz }
264293cdc48SArtur Paszkiewicz
265293cdc48SArtur Paszkiewicz mngt->rollback = true;
266293cdc48SArtur Paszkiewicz rollback_execute(mngt);
267293cdc48SArtur Paszkiewicz return 0;
268293cdc48SArtur Paszkiewicz error:
269293cdc48SArtur Paszkiewicz free_mngt(mngt);
270293cdc48SArtur Paszkiewicz return rc;
271293cdc48SArtur Paszkiewicz }
272293cdc48SArtur Paszkiewicz
273293cdc48SArtur Paszkiewicz struct spdk_ftl_dev *
ftl_mngt_get_dev(struct ftl_mngt_process * mngt)274293cdc48SArtur Paszkiewicz ftl_mngt_get_dev(struct ftl_mngt_process *mngt)
275293cdc48SArtur Paszkiewicz {
276293cdc48SArtur Paszkiewicz return mngt->dev;
277293cdc48SArtur Paszkiewicz }
278293cdc48SArtur Paszkiewicz
279293cdc48SArtur Paszkiewicz int
ftl_mngt_alloc_step_ctx(struct ftl_mngt_process * mngt,size_t size)280293cdc48SArtur Paszkiewicz ftl_mngt_alloc_step_ctx(struct ftl_mngt_process *mngt, size_t size)
281293cdc48SArtur Paszkiewicz {
282293cdc48SArtur Paszkiewicz struct ftl_mngt_step *step = get_current_step(mngt);
283293cdc48SArtur Paszkiewicz void *arg = calloc(1, size);
284293cdc48SArtur Paszkiewicz
285293cdc48SArtur Paszkiewicz if (!arg) {
286293cdc48SArtur Paszkiewicz return -ENOMEM;
287293cdc48SArtur Paszkiewicz }
288293cdc48SArtur Paszkiewicz
289293cdc48SArtur Paszkiewicz free(step->ctx);
290293cdc48SArtur Paszkiewicz step->ctx = arg;
291293cdc48SArtur Paszkiewicz
292293cdc48SArtur Paszkiewicz return 0;
293293cdc48SArtur Paszkiewicz }
294293cdc48SArtur Paszkiewicz
295293cdc48SArtur Paszkiewicz void *
ftl_mngt_get_step_ctx(struct ftl_mngt_process * mngt)296293cdc48SArtur Paszkiewicz ftl_mngt_get_step_ctx(struct ftl_mngt_process *mngt)
297293cdc48SArtur Paszkiewicz {
298293cdc48SArtur Paszkiewicz return get_current_step(mngt)->ctx;
299293cdc48SArtur Paszkiewicz }
300293cdc48SArtur Paszkiewicz
301293cdc48SArtur Paszkiewicz void *
ftl_mngt_get_process_ctx(struct ftl_mngt_process * mngt)302293cdc48SArtur Paszkiewicz ftl_mngt_get_process_ctx(struct ftl_mngt_process *mngt)
303293cdc48SArtur Paszkiewicz {
304293cdc48SArtur Paszkiewicz return mngt->ctx;
305293cdc48SArtur Paszkiewicz }
306293cdc48SArtur Paszkiewicz
307293cdc48SArtur Paszkiewicz void *
ftl_mngt_get_caller_ctx(struct ftl_mngt_process * mngt)308293cdc48SArtur Paszkiewicz ftl_mngt_get_caller_ctx(struct ftl_mngt_process *mngt)
309293cdc48SArtur Paszkiewicz {
310293cdc48SArtur Paszkiewicz return mngt->caller.cb_ctx;
311293cdc48SArtur Paszkiewicz }
312293cdc48SArtur Paszkiewicz
313293cdc48SArtur Paszkiewicz void
ftl_mngt_next_step(struct ftl_mngt_process * mngt)314293cdc48SArtur Paszkiewicz ftl_mngt_next_step(struct ftl_mngt_process *mngt)
315293cdc48SArtur Paszkiewicz {
316293cdc48SArtur Paszkiewicz if (false == mngt->rollback) {
317293cdc48SArtur Paszkiewicz action_next(mngt);
318293cdc48SArtur Paszkiewicz } else {
319293cdc48SArtur Paszkiewicz rollback_next(mngt);
320293cdc48SArtur Paszkiewicz }
321293cdc48SArtur Paszkiewicz }
322293cdc48SArtur Paszkiewicz
323293cdc48SArtur Paszkiewicz void
ftl_mngt_skip_step(struct ftl_mngt_process * mngt)324293cdc48SArtur Paszkiewicz ftl_mngt_skip_step(struct ftl_mngt_process *mngt)
325293cdc48SArtur Paszkiewicz {
326293cdc48SArtur Paszkiewicz if (mngt->rollback) {
327293cdc48SArtur Paszkiewicz get_current_step(mngt)->rollback.silent = true;
328293cdc48SArtur Paszkiewicz } else {
329293cdc48SArtur Paszkiewicz get_current_step(mngt)->action.silent = true;
330293cdc48SArtur Paszkiewicz }
331293cdc48SArtur Paszkiewicz ftl_mngt_next_step(mngt);
332293cdc48SArtur Paszkiewicz }
333293cdc48SArtur Paszkiewicz
334293cdc48SArtur Paszkiewicz void
ftl_mngt_continue_step(struct ftl_mngt_process * mngt)335293cdc48SArtur Paszkiewicz ftl_mngt_continue_step(struct ftl_mngt_process *mngt)
336293cdc48SArtur Paszkiewicz {
337293cdc48SArtur Paszkiewicz
338293cdc48SArtur Paszkiewicz if (!mngt->continuing) {
339293cdc48SArtur Paszkiewicz if (false == mngt->rollback) {
340293cdc48SArtur Paszkiewicz action_execute(mngt);
341293cdc48SArtur Paszkiewicz } else {
342293cdc48SArtur Paszkiewicz rollback_execute(mngt);
343293cdc48SArtur Paszkiewicz }
344293cdc48SArtur Paszkiewicz }
345293cdc48SArtur Paszkiewicz
346293cdc48SArtur Paszkiewicz mngt->continuing = true;
347293cdc48SArtur Paszkiewicz }
348293cdc48SArtur Paszkiewicz
349293cdc48SArtur Paszkiewicz static void
child_cb(struct spdk_ftl_dev * dev,void * ctx,int status)350b71eebd8SArtur Paszkiewicz child_cb(struct spdk_ftl_dev *dev, void *ctx, int status)
351293cdc48SArtur Paszkiewicz {
352b71eebd8SArtur Paszkiewicz struct ftl_mngt_process *parent = ctx;
353293cdc48SArtur Paszkiewicz
354293cdc48SArtur Paszkiewicz if (status) {
355293cdc48SArtur Paszkiewicz ftl_mngt_fail_step(parent);
356293cdc48SArtur Paszkiewicz } else {
357293cdc48SArtur Paszkiewicz ftl_mngt_next_step(parent);
358293cdc48SArtur Paszkiewicz }
359293cdc48SArtur Paszkiewicz }
360293cdc48SArtur Paszkiewicz
361293cdc48SArtur Paszkiewicz void
ftl_mngt_call_process(struct ftl_mngt_process * mngt,const struct ftl_mngt_process_desc * pdesc,void * init_ctx)362293cdc48SArtur Paszkiewicz ftl_mngt_call_process(struct ftl_mngt_process *mngt,
3639452abe6SMateusz Kozlowski const struct ftl_mngt_process_desc *pdesc,
3649452abe6SMateusz Kozlowski void *init_ctx)
365293cdc48SArtur Paszkiewicz {
3669452abe6SMateusz Kozlowski if (_ftl_mngt_process_execute(mngt->dev, pdesc, child_cb, mngt, true, init_ctx)) {
367293cdc48SArtur Paszkiewicz ftl_mngt_fail_step(mngt);
368293cdc48SArtur Paszkiewicz } else {
369293cdc48SArtur Paszkiewicz if (mngt->rollback) {
370293cdc48SArtur Paszkiewicz get_current_step(mngt)->rollback.silent = true;
371293cdc48SArtur Paszkiewicz } else {
372293cdc48SArtur Paszkiewicz get_current_step(mngt)->action.silent = true;
373293cdc48SArtur Paszkiewicz }
374293cdc48SArtur Paszkiewicz }
375293cdc48SArtur Paszkiewicz }
376293cdc48SArtur Paszkiewicz
377293cdc48SArtur Paszkiewicz void
ftl_mngt_call_process_rollback(struct ftl_mngt_process * mngt,const struct ftl_mngt_process_desc * pdesc)378293cdc48SArtur Paszkiewicz ftl_mngt_call_process_rollback(struct ftl_mngt_process *mngt,
379293cdc48SArtur Paszkiewicz const struct ftl_mngt_process_desc *pdesc)
380293cdc48SArtur Paszkiewicz {
381293cdc48SArtur Paszkiewicz if (ftl_mngt_process_rollback(mngt->dev, pdesc, child_cb, mngt)) {
382293cdc48SArtur Paszkiewicz ftl_mngt_fail_step(mngt);
383293cdc48SArtur Paszkiewicz } else {
384293cdc48SArtur Paszkiewicz if (mngt->rollback) {
385293cdc48SArtur Paszkiewicz get_current_step(mngt)->rollback.silent = true;
386293cdc48SArtur Paszkiewicz } else {
387293cdc48SArtur Paszkiewicz get_current_step(mngt)->action.silent = true;
388293cdc48SArtur Paszkiewicz }
389293cdc48SArtur Paszkiewicz }
390293cdc48SArtur Paszkiewicz }
391293cdc48SArtur Paszkiewicz
392293cdc48SArtur Paszkiewicz void
ftl_mngt_fail_step(struct ftl_mngt_process * mngt)393293cdc48SArtur Paszkiewicz ftl_mngt_fail_step(struct ftl_mngt_process *mngt)
394293cdc48SArtur Paszkiewicz {
395293cdc48SArtur Paszkiewicz mngt->status = -1;
396293cdc48SArtur Paszkiewicz
397293cdc48SArtur Paszkiewicz if (false == mngt->rollback) {
398293cdc48SArtur Paszkiewicz action_done(mngt, -1);
399293cdc48SArtur Paszkiewicz } else {
400293cdc48SArtur Paszkiewicz rollback_done(mngt, -1);
401293cdc48SArtur Paszkiewicz }
402293cdc48SArtur Paszkiewicz
403293cdc48SArtur Paszkiewicz mngt->rollback = true;
404293cdc48SArtur Paszkiewicz rollback_execute(mngt);
405293cdc48SArtur Paszkiewicz }
406293cdc48SArtur Paszkiewicz
407293cdc48SArtur Paszkiewicz static inline float
tsc_to_ms(uint64_t tsc)408293cdc48SArtur Paszkiewicz tsc_to_ms(uint64_t tsc)
409293cdc48SArtur Paszkiewicz {
410293cdc48SArtur Paszkiewicz float ms = tsc;
411293cdc48SArtur Paszkiewicz ms /= (float)spdk_get_ticks_hz();
412293cdc48SArtur Paszkiewicz ms *= 1000.0;
413293cdc48SArtur Paszkiewicz return ms;
414293cdc48SArtur Paszkiewicz }
415293cdc48SArtur Paszkiewicz
416293cdc48SArtur Paszkiewicz static void
trace_step(struct spdk_ftl_dev * dev,struct ftl_mngt_step * step,bool rollback)417293cdc48SArtur Paszkiewicz trace_step(struct spdk_ftl_dev *dev, struct ftl_mngt_step *step, bool rollback)
418293cdc48SArtur Paszkiewicz {
419293cdc48SArtur Paszkiewicz uint64_t duration;
420293cdc48SArtur Paszkiewicz const char *what = rollback ? "Rollback" : "Action";
421293cdc48SArtur Paszkiewicz int silent = rollback ? step->rollback.silent : step->action.silent;
422293cdc48SArtur Paszkiewicz
423293cdc48SArtur Paszkiewicz if (silent) {
424293cdc48SArtur Paszkiewicz return;
425293cdc48SArtur Paszkiewicz }
426293cdc48SArtur Paszkiewicz
427293cdc48SArtur Paszkiewicz FTL_NOTICELOG(dev, "%s\n", what);
428293cdc48SArtur Paszkiewicz FTL_NOTICELOG(dev, "\t name: %s\n", step->desc->name);
429293cdc48SArtur Paszkiewicz duration = step->action.stop - step->action.start;
430293cdc48SArtur Paszkiewicz FTL_NOTICELOG(dev, "\t duration: %.3f ms\n", tsc_to_ms(duration));
431293cdc48SArtur Paszkiewicz FTL_NOTICELOG(dev, "\t status: %d\n", step->action.status);
432293cdc48SArtur Paszkiewicz }
433293cdc48SArtur Paszkiewicz
434293cdc48SArtur Paszkiewicz static void
finish_msg(void * ctx)435293cdc48SArtur Paszkiewicz finish_msg(void *ctx)
436293cdc48SArtur Paszkiewicz {
437293cdc48SArtur Paszkiewicz struct ftl_mngt_process *mngt = ctx;
438e49ccfc8SArtur Paszkiewicz char *devname = NULL;
439e49ccfc8SArtur Paszkiewicz
440e49ccfc8SArtur Paszkiewicz if (!mngt->silent && mngt->dev->conf.name) {
441e49ccfc8SArtur Paszkiewicz /* the callback below can free the device so make a temp copy of the name */
442e49ccfc8SArtur Paszkiewicz devname = strdup(mngt->dev->conf.name);
443e49ccfc8SArtur Paszkiewicz }
444293cdc48SArtur Paszkiewicz
445b71eebd8SArtur Paszkiewicz mngt->caller.cb(mngt->dev, mngt->caller.cb_ctx, mngt->status);
446e49ccfc8SArtur Paszkiewicz
447*5d89ebb7SMateusz Kozlowski if (mngt->desc->deinit_handler) {
448*5d89ebb7SMateusz Kozlowski mngt->desc->deinit_handler(mngt->dev, mngt);
449*5d89ebb7SMateusz Kozlowski }
450*5d89ebb7SMateusz Kozlowski
451e49ccfc8SArtur Paszkiewicz if (!mngt->silent) {
452e49ccfc8SArtur Paszkiewicz /* TODO: refactor the logging macros to pass just the name instead of device */
453e49ccfc8SArtur Paszkiewicz struct spdk_ftl_dev tmpdev = {
454e49ccfc8SArtur Paszkiewicz .conf = {
455e49ccfc8SArtur Paszkiewicz .name = devname
456e49ccfc8SArtur Paszkiewicz }
457e49ccfc8SArtur Paszkiewicz };
458e49ccfc8SArtur Paszkiewicz
459e49ccfc8SArtur Paszkiewicz FTL_NOTICELOG(&tmpdev, "Management process finished, name '%s', duration = %.3f ms, result %d\n",
460e49ccfc8SArtur Paszkiewicz mngt->desc->name,
461e49ccfc8SArtur Paszkiewicz tsc_to_ms(mngt->tsc_stop - mngt->tsc_start),
462e49ccfc8SArtur Paszkiewicz mngt->status);
463e49ccfc8SArtur Paszkiewicz }
464293cdc48SArtur Paszkiewicz free_mngt(mngt);
465e49ccfc8SArtur Paszkiewicz free(devname);
466293cdc48SArtur Paszkiewicz }
467293cdc48SArtur Paszkiewicz
468293cdc48SArtur Paszkiewicz void
ftl_mngt_finish(struct ftl_mngt_process * mngt)469293cdc48SArtur Paszkiewicz ftl_mngt_finish(struct ftl_mngt_process *mngt)
470293cdc48SArtur Paszkiewicz {
471293cdc48SArtur Paszkiewicz mngt->tsc_stop = spdk_get_ticks();
472293cdc48SArtur Paszkiewicz spdk_thread_send_msg(mngt->caller.thread, finish_msg, mngt);
473293cdc48SArtur Paszkiewicz }
474293cdc48SArtur Paszkiewicz
475293cdc48SArtur Paszkiewicz /*
476293cdc48SArtur Paszkiewicz * Actions
477293cdc48SArtur Paszkiewicz */
478293cdc48SArtur Paszkiewicz static void
action_next(struct ftl_mngt_process * mngt)479293cdc48SArtur Paszkiewicz action_next(struct ftl_mngt_process *mngt)
480293cdc48SArtur Paszkiewicz {
481293cdc48SArtur Paszkiewicz if (TAILQ_EMPTY(&mngt->action_queue_todo)) {
482293cdc48SArtur Paszkiewicz /* Nothing to do, finish the management process */
483293cdc48SArtur Paszkiewicz ftl_mngt_finish(mngt);
484293cdc48SArtur Paszkiewicz return;
485293cdc48SArtur Paszkiewicz } else {
486293cdc48SArtur Paszkiewicz action_done(mngt, 0);
487293cdc48SArtur Paszkiewicz action_execute(mngt);
488293cdc48SArtur Paszkiewicz }
489293cdc48SArtur Paszkiewicz }
490293cdc48SArtur Paszkiewicz
491293cdc48SArtur Paszkiewicz static void
action_msg(void * ctx)492293cdc48SArtur Paszkiewicz action_msg(void *ctx)
493293cdc48SArtur Paszkiewicz {
494293cdc48SArtur Paszkiewicz struct ftl_mngt_process *mngt = ctx;
495293cdc48SArtur Paszkiewicz struct ftl_mngt_step *step;
496293cdc48SArtur Paszkiewicz
497293cdc48SArtur Paszkiewicz mngt->continuing = false;
498293cdc48SArtur Paszkiewicz
499293cdc48SArtur Paszkiewicz if (TAILQ_EMPTY(&mngt->action_queue_todo)) {
500293cdc48SArtur Paszkiewicz ftl_mngt_finish(mngt);
501293cdc48SArtur Paszkiewicz return;
502293cdc48SArtur Paszkiewicz }
503293cdc48SArtur Paszkiewicz
504293cdc48SArtur Paszkiewicz step = TAILQ_FIRST(&mngt->action_queue_todo);
505293cdc48SArtur Paszkiewicz if (!step->action.start) {
506293cdc48SArtur Paszkiewicz step->action.start = spdk_get_ticks();
507293cdc48SArtur Paszkiewicz }
508293cdc48SArtur Paszkiewicz step->desc->action(mngt->dev, mngt);
509293cdc48SArtur Paszkiewicz }
510293cdc48SArtur Paszkiewicz
511293cdc48SArtur Paszkiewicz static void
action_execute(struct ftl_mngt_process * mngt)512293cdc48SArtur Paszkiewicz action_execute(struct ftl_mngt_process *mngt)
513293cdc48SArtur Paszkiewicz {
514293cdc48SArtur Paszkiewicz spdk_thread_send_msg(mngt->dev->core_thread, action_msg, mngt);
515293cdc48SArtur Paszkiewicz }
516293cdc48SArtur Paszkiewicz
517293cdc48SArtur Paszkiewicz static void
action_done(struct ftl_mngt_process * mngt,int status)518293cdc48SArtur Paszkiewicz action_done(struct ftl_mngt_process *mngt, int status)
519293cdc48SArtur Paszkiewicz {
520293cdc48SArtur Paszkiewicz struct ftl_mngt_step *step;
521293cdc48SArtur Paszkiewicz
522293cdc48SArtur Paszkiewicz assert(!TAILQ_EMPTY(&mngt->action_queue_todo));
523293cdc48SArtur Paszkiewicz step = TAILQ_FIRST(&mngt->action_queue_todo);
524293cdc48SArtur Paszkiewicz TAILQ_REMOVE(&mngt->action_queue_todo, step, action.entry);
525293cdc48SArtur Paszkiewicz
526293cdc48SArtur Paszkiewicz TAILQ_INSERT_TAIL(&mngt->action_queue_done, step, action.entry);
527293cdc48SArtur Paszkiewicz if (step->desc->cleanup) {
528293cdc48SArtur Paszkiewicz TAILQ_INSERT_HEAD(&mngt->rollback_queue_todo, step,
529293cdc48SArtur Paszkiewicz rollback.entry);
530293cdc48SArtur Paszkiewicz }
531293cdc48SArtur Paszkiewicz
532293cdc48SArtur Paszkiewicz step->action.stop = spdk_get_ticks();
533293cdc48SArtur Paszkiewicz step->action.status = status;
534293cdc48SArtur Paszkiewicz
535293cdc48SArtur Paszkiewicz trace_step(mngt->dev, step, false);
536293cdc48SArtur Paszkiewicz }
537293cdc48SArtur Paszkiewicz
538293cdc48SArtur Paszkiewicz /*
539293cdc48SArtur Paszkiewicz * Rollback
540293cdc48SArtur Paszkiewicz */
541293cdc48SArtur Paszkiewicz static void
rollback_next(struct ftl_mngt_process * mngt)542293cdc48SArtur Paszkiewicz rollback_next(struct ftl_mngt_process *mngt)
543293cdc48SArtur Paszkiewicz {
544293cdc48SArtur Paszkiewicz if (TAILQ_EMPTY(&mngt->rollback_queue_todo)) {
545293cdc48SArtur Paszkiewicz /* Nothing to do, finish the management process */
546293cdc48SArtur Paszkiewicz ftl_mngt_finish(mngt);
547293cdc48SArtur Paszkiewicz return;
548293cdc48SArtur Paszkiewicz } else {
549293cdc48SArtur Paszkiewicz rollback_done(mngt, 0);
550293cdc48SArtur Paszkiewicz rollback_execute(mngt);
551293cdc48SArtur Paszkiewicz }
552293cdc48SArtur Paszkiewicz }
553293cdc48SArtur Paszkiewicz
554293cdc48SArtur Paszkiewicz static void
rollback_msg(void * ctx)555293cdc48SArtur Paszkiewicz rollback_msg(void *ctx)
556293cdc48SArtur Paszkiewicz {
557293cdc48SArtur Paszkiewicz struct ftl_mngt_process *mngt = ctx;
558293cdc48SArtur Paszkiewicz struct ftl_mngt_step *step;
559293cdc48SArtur Paszkiewicz
560293cdc48SArtur Paszkiewicz mngt->continuing = false;
561293cdc48SArtur Paszkiewicz
562293cdc48SArtur Paszkiewicz if (TAILQ_EMPTY(&mngt->rollback_queue_todo)) {
563293cdc48SArtur Paszkiewicz ftl_mngt_finish(mngt);
564293cdc48SArtur Paszkiewicz return;
565293cdc48SArtur Paszkiewicz }
566293cdc48SArtur Paszkiewicz
567293cdc48SArtur Paszkiewicz step = TAILQ_FIRST(&mngt->rollback_queue_todo);
568293cdc48SArtur Paszkiewicz if (!step->rollback.start) {
569293cdc48SArtur Paszkiewicz step->rollback.start = spdk_get_ticks();
570293cdc48SArtur Paszkiewicz }
571293cdc48SArtur Paszkiewicz step->desc->cleanup(mngt->dev, mngt);
572293cdc48SArtur Paszkiewicz }
573293cdc48SArtur Paszkiewicz
574293cdc48SArtur Paszkiewicz static void
rollback_execute(struct ftl_mngt_process * mngt)575293cdc48SArtur Paszkiewicz rollback_execute(struct ftl_mngt_process *mngt)
576293cdc48SArtur Paszkiewicz {
577293cdc48SArtur Paszkiewicz spdk_thread_send_msg(mngt->dev->core_thread, rollback_msg, mngt);
578293cdc48SArtur Paszkiewicz }
579293cdc48SArtur Paszkiewicz
580293cdc48SArtur Paszkiewicz void
rollback_done(struct ftl_mngt_process * mngt,int status)581293cdc48SArtur Paszkiewicz rollback_done(struct ftl_mngt_process *mngt, int status)
582293cdc48SArtur Paszkiewicz {
583293cdc48SArtur Paszkiewicz struct ftl_mngt_step *step;
584293cdc48SArtur Paszkiewicz
585293cdc48SArtur Paszkiewicz assert(!TAILQ_EMPTY(&mngt->rollback_queue_todo));
586293cdc48SArtur Paszkiewicz step = TAILQ_FIRST(&mngt->rollback_queue_todo);
587293cdc48SArtur Paszkiewicz TAILQ_REMOVE(&mngt->rollback_queue_todo, step, rollback.entry);
588293cdc48SArtur Paszkiewicz TAILQ_INSERT_TAIL(&mngt->rollback_queue_done, step, rollback.entry);
589293cdc48SArtur Paszkiewicz
590293cdc48SArtur Paszkiewicz step->rollback.stop = spdk_get_ticks();
591293cdc48SArtur Paszkiewicz step->rollback.status = status;
592293cdc48SArtur Paszkiewicz
593293cdc48SArtur Paszkiewicz trace_step(mngt->dev, step, true);
594293cdc48SArtur Paszkiewicz }
595