xref: /spdk/lib/ftl/mngt/ftl_mngt.c (revision 5d89ebb726114a1eb84e70bb7719b6c88439f7a7)
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