xref: /spdk/module/bdev/raid/bdev_raid.c (revision c51db5661936b51edfbfec945fd73c3c5d067789)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2018 Intel Corporation.
307fe6a43SSeth Howell  *   All rights reserved.
4be440c01SAlexey Marchuk  *   Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
507fe6a43SSeth Howell  */
607fe6a43SSeth Howell 
707fe6a43SSeth Howell #include "bdev_raid.h"
807fe6a43SSeth Howell #include "spdk/env.h"
98e05b15cSDarek Stojaczyk #include "spdk/thread.h"
104e8e97c8STomasz Zawadzki #include "spdk/log.h"
1107fe6a43SSeth Howell #include "spdk/string.h"
1207fe6a43SSeth Howell #include "spdk/util.h"
1307fe6a43SSeth Howell #include "spdk/json.h"
1407fe6a43SSeth Howell 
1507fe6a43SSeth Howell static bool g_shutdown_started = false;
1607fe6a43SSeth Howell 
1707fe6a43SSeth Howell /* List of all raid bdevs */
1807fe6a43SSeth Howell struct raid_all_tailq g_raid_bdev_list = TAILQ_HEAD_INITIALIZER(g_raid_bdev_list);
1907fe6a43SSeth Howell 
20706029d5SArtur Paszkiewicz static TAILQ_HEAD(, raid_bdev_module) g_raid_modules = TAILQ_HEAD_INITIALIZER(g_raid_modules);
21706029d5SArtur Paszkiewicz 
228dd1cd21SBen Walker static struct raid_bdev_module *
238dd1cd21SBen Walker raid_bdev_module_find(enum raid_level level)
24706029d5SArtur Paszkiewicz {
25706029d5SArtur Paszkiewicz 	struct raid_bdev_module *raid_module;
26706029d5SArtur Paszkiewicz 
27706029d5SArtur Paszkiewicz 	TAILQ_FOREACH(raid_module, &g_raid_modules, link) {
28706029d5SArtur Paszkiewicz 		if (raid_module->level == level) {
29706029d5SArtur Paszkiewicz 			return raid_module;
30706029d5SArtur Paszkiewicz 		}
31706029d5SArtur Paszkiewicz 	}
32706029d5SArtur Paszkiewicz 
33706029d5SArtur Paszkiewicz 	return NULL;
34706029d5SArtur Paszkiewicz }
35706029d5SArtur Paszkiewicz 
368dd1cd21SBen Walker void
378dd1cd21SBen Walker raid_bdev_module_list_add(struct raid_bdev_module *raid_module)
38706029d5SArtur Paszkiewicz {
39706029d5SArtur Paszkiewicz 	if (raid_bdev_module_find(raid_module->level) != NULL) {
40706029d5SArtur Paszkiewicz 		SPDK_ERRLOG("module for raid level '%s' already registered.\n",
41706029d5SArtur Paszkiewicz 			    raid_bdev_level_to_str(raid_module->level));
42706029d5SArtur Paszkiewicz 		assert(false);
43706029d5SArtur Paszkiewicz 	} else {
44706029d5SArtur Paszkiewicz 		TAILQ_INSERT_TAIL(&g_raid_modules, raid_module, link);
45706029d5SArtur Paszkiewicz 	}
46706029d5SArtur Paszkiewicz }
47706029d5SArtur Paszkiewicz 
4807fe6a43SSeth Howell /* Function declarations */
4907fe6a43SSeth Howell static void	raid_bdev_examine(struct spdk_bdev *bdev);
5007fe6a43SSeth Howell static int	raid_bdev_init(void);
5107fe6a43SSeth Howell static void	raid_bdev_deconfigure(struct raid_bdev *raid_bdev,
5207fe6a43SSeth Howell 				      raid_bdev_destruct_cb cb_fn, void *cb_arg);
5307fe6a43SSeth Howell 
5407fe6a43SSeth Howell /*
5507fe6a43SSeth Howell  * brief:
5607fe6a43SSeth Howell  * raid_bdev_create_cb function is a cb function for raid bdev which creates the
5707fe6a43SSeth Howell  * hierarchy from raid bdev to base bdev io channels. It will be called per core
5807fe6a43SSeth Howell  * params:
5907fe6a43SSeth Howell  * io_device - pointer to raid bdev io device represented by raid_bdev
6007fe6a43SSeth Howell  * ctx_buf - pointer to context buffer for raid bdev io channel
6107fe6a43SSeth Howell  * returns:
6207fe6a43SSeth Howell  * 0 - success
6307fe6a43SSeth Howell  * non zero - failure
6407fe6a43SSeth Howell  */
6507fe6a43SSeth Howell static int
6607fe6a43SSeth Howell raid_bdev_create_cb(void *io_device, void *ctx_buf)
6707fe6a43SSeth Howell {
6807fe6a43SSeth Howell 	struct raid_bdev            *raid_bdev = io_device;
6907fe6a43SSeth Howell 	struct raid_bdev_io_channel *raid_ch = ctx_buf;
709d94e1f5SArtur Paszkiewicz 	uint8_t i;
71c89e2008SArtur Paszkiewicz 	int ret = 0;
7207fe6a43SSeth Howell 
732172c432STomasz Zawadzki 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_create_cb, %p\n", raid_ch);
7407fe6a43SSeth Howell 
7507fe6a43SSeth Howell 	assert(raid_bdev != NULL);
7607fe6a43SSeth Howell 	assert(raid_bdev->state == RAID_BDEV_STATE_ONLINE);
7707fe6a43SSeth Howell 
7807fe6a43SSeth Howell 	raid_ch->num_channels = raid_bdev->num_base_bdevs;
7907fe6a43SSeth Howell 
8007fe6a43SSeth Howell 	raid_ch->base_channel = calloc(raid_ch->num_channels,
8107fe6a43SSeth Howell 				       sizeof(struct spdk_io_channel *));
8207fe6a43SSeth Howell 	if (!raid_ch->base_channel) {
8307fe6a43SSeth Howell 		SPDK_ERRLOG("Unable to allocate base bdevs io channel\n");
8407fe6a43SSeth Howell 		return -ENOMEM;
8507fe6a43SSeth Howell 	}
86b42cb0e5SArtur Paszkiewicz 
87b42cb0e5SArtur Paszkiewicz 	spdk_spin_lock(&raid_bdev->base_bdev_lock);
889d94e1f5SArtur Paszkiewicz 	for (i = 0; i < raid_ch->num_channels; i++) {
8907fe6a43SSeth Howell 		/*
9007fe6a43SSeth Howell 		 * Get the spdk_io_channel for all the base bdevs. This is used during
9107fe6a43SSeth Howell 		 * split logic to send the respective child bdev ios to respective base
9207fe6a43SSeth Howell 		 * bdev io channel.
9307fe6a43SSeth Howell 		 */
94b42cb0e5SArtur Paszkiewicz 		if (raid_bdev->base_bdev_info[i].desc == NULL) {
95b42cb0e5SArtur Paszkiewicz 			continue;
96b42cb0e5SArtur Paszkiewicz 		}
9707fe6a43SSeth Howell 		raid_ch->base_channel[i] = spdk_bdev_get_io_channel(
9807fe6a43SSeth Howell 						   raid_bdev->base_bdev_info[i].desc);
9907fe6a43SSeth Howell 		if (!raid_ch->base_channel[i]) {
100c89e2008SArtur Paszkiewicz 			SPDK_ERRLOG("Unable to create io channel for base bdev\n");
101c89e2008SArtur Paszkiewicz 			ret = -ENOMEM;
102c89e2008SArtur Paszkiewicz 			break;
103c89e2008SArtur Paszkiewicz 		}
104c89e2008SArtur Paszkiewicz 	}
105b42cb0e5SArtur Paszkiewicz 	spdk_spin_unlock(&raid_bdev->base_bdev_lock);
106c89e2008SArtur Paszkiewicz 
107c89e2008SArtur Paszkiewicz 	if (!ret && raid_bdev->module->get_io_channel) {
108c89e2008SArtur Paszkiewicz 		raid_ch->module_channel = raid_bdev->module->get_io_channel(raid_bdev);
109c89e2008SArtur Paszkiewicz 		if (!raid_ch->module_channel) {
110c89e2008SArtur Paszkiewicz 			SPDK_ERRLOG("Unable to create io channel for raid module\n");
111c89e2008SArtur Paszkiewicz 			ret = -ENOMEM;
112c89e2008SArtur Paszkiewicz 		}
113c89e2008SArtur Paszkiewicz 	}
114c89e2008SArtur Paszkiewicz 
115c89e2008SArtur Paszkiewicz 	if (ret) {
116b42cb0e5SArtur Paszkiewicz 		for (i = 0; i < raid_ch->num_channels; i++) {
117b42cb0e5SArtur Paszkiewicz 			if (raid_ch->base_channel[i] != NULL) {
118b42cb0e5SArtur Paszkiewicz 				spdk_put_io_channel(raid_ch->base_channel[i]);
119b42cb0e5SArtur Paszkiewicz 			}
12007fe6a43SSeth Howell 		}
12107fe6a43SSeth Howell 		free(raid_ch->base_channel);
12207fe6a43SSeth Howell 		raid_ch->base_channel = NULL;
12307fe6a43SSeth Howell 	}
124c89e2008SArtur Paszkiewicz 	return ret;
12507fe6a43SSeth Howell }
12607fe6a43SSeth Howell 
12707fe6a43SSeth Howell /*
12807fe6a43SSeth Howell  * brief:
12907fe6a43SSeth Howell  * raid_bdev_destroy_cb function is a cb function for raid bdev which deletes the
13007fe6a43SSeth Howell  * hierarchy from raid bdev to base bdev io channels. It will be called per core
13107fe6a43SSeth Howell  * params:
13207fe6a43SSeth Howell  * io_device - pointer to raid bdev io device represented by raid_bdev
13307fe6a43SSeth Howell  * ctx_buf - pointer to context buffer for raid bdev io channel
13407fe6a43SSeth Howell  * returns:
13507fe6a43SSeth Howell  * none
13607fe6a43SSeth Howell  */
13707fe6a43SSeth Howell static void
13807fe6a43SSeth Howell raid_bdev_destroy_cb(void *io_device, void *ctx_buf)
13907fe6a43SSeth Howell {
14007fe6a43SSeth Howell 	struct raid_bdev_io_channel *raid_ch = ctx_buf;
1419d94e1f5SArtur Paszkiewicz 	uint8_t i;
14207fe6a43SSeth Howell 
1432172c432STomasz Zawadzki 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_destroy_cb\n");
14407fe6a43SSeth Howell 
14507fe6a43SSeth Howell 	assert(raid_ch != NULL);
14607fe6a43SSeth Howell 	assert(raid_ch->base_channel);
147c89e2008SArtur Paszkiewicz 
148c89e2008SArtur Paszkiewicz 	if (raid_ch->module_channel) {
149c89e2008SArtur Paszkiewicz 		spdk_put_io_channel(raid_ch->module_channel);
150c89e2008SArtur Paszkiewicz 	}
151c89e2008SArtur Paszkiewicz 
1529d94e1f5SArtur Paszkiewicz 	for (i = 0; i < raid_ch->num_channels; i++) {
15307fe6a43SSeth Howell 		/* Free base bdev channels */
154b42cb0e5SArtur Paszkiewicz 		if (raid_ch->base_channel[i] != NULL) {
15507fe6a43SSeth Howell 			spdk_put_io_channel(raid_ch->base_channel[i]);
15607fe6a43SSeth Howell 		}
157b42cb0e5SArtur Paszkiewicz 	}
15807fe6a43SSeth Howell 	free(raid_ch->base_channel);
15907fe6a43SSeth Howell 	raid_ch->base_channel = NULL;
16007fe6a43SSeth Howell }
16107fe6a43SSeth Howell 
16207fe6a43SSeth Howell /*
16307fe6a43SSeth Howell  * brief:
16495a04949SArtur Paszkiewicz  * raid_bdev_cleanup is used to cleanup raid_bdev related data
16507fe6a43SSeth Howell  * structures.
16607fe6a43SSeth Howell  * params:
16707fe6a43SSeth Howell  * raid_bdev - pointer to raid_bdev
16807fe6a43SSeth Howell  * returns:
16907fe6a43SSeth Howell  * none
17007fe6a43SSeth Howell  */
17107fe6a43SSeth Howell static void
17207fe6a43SSeth Howell raid_bdev_cleanup(struct raid_bdev *raid_bdev)
17307fe6a43SSeth Howell {
174dccdd1e5SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
175dccdd1e5SArtur Paszkiewicz 
17646ff15a6SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_cleanup, %p name %s, state %s\n",
17746ff15a6SArtur Paszkiewicz 		      raid_bdev, raid_bdev->bdev.name, raid_bdev_state_to_str(raid_bdev->state));
17812ed89acSArtur Paszkiewicz 	assert(raid_bdev->state != RAID_BDEV_STATE_ONLINE);
1794dd2a0d3SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
180dccdd1e5SArtur Paszkiewicz 
181dccdd1e5SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
182dccdd1e5SArtur Paszkiewicz 		assert(base_info->desc == NULL);
183dccdd1e5SArtur Paszkiewicz 		free(base_info->name);
184dccdd1e5SArtur Paszkiewicz 	}
185dccdd1e5SArtur Paszkiewicz 
18607fe6a43SSeth Howell 	TAILQ_REMOVE(&g_raid_bdev_list, raid_bdev, global_link);
18795a04949SArtur Paszkiewicz }
18895a04949SArtur Paszkiewicz 
18995a04949SArtur Paszkiewicz static void
19095a04949SArtur Paszkiewicz raid_bdev_free(struct raid_bdev *raid_bdev)
19195a04949SArtur Paszkiewicz {
19277b8f7b6SArtur Paszkiewicz 	spdk_dma_free(raid_bdev->sb);
193b42cb0e5SArtur Paszkiewicz 	spdk_spin_destroy(&raid_bdev->base_bdev_lock);
194fbdb05f0SArtur Paszkiewicz 	free(raid_bdev->base_bdev_info);
19595a04949SArtur Paszkiewicz 	free(raid_bdev->bdev.name);
19607fe6a43SSeth Howell 	free(raid_bdev);
19707fe6a43SSeth Howell }
19807fe6a43SSeth Howell 
19995a04949SArtur Paszkiewicz static void
20095a04949SArtur Paszkiewicz raid_bdev_cleanup_and_free(struct raid_bdev *raid_bdev)
20195a04949SArtur Paszkiewicz {
20295a04949SArtur Paszkiewicz 	raid_bdev_cleanup(raid_bdev);
20395a04949SArtur Paszkiewicz 	raid_bdev_free(raid_bdev);
20495a04949SArtur Paszkiewicz }
20595a04949SArtur Paszkiewicz 
20607fe6a43SSeth Howell /*
20707fe6a43SSeth Howell  * brief:
20807fe6a43SSeth Howell  * free resource of base bdev for raid bdev
20907fe6a43SSeth Howell  * params:
210a193dcb8SArtur Paszkiewicz  * base_info - raid base bdev info
21107fe6a43SSeth Howell  * returns:
21277b8f7b6SArtur Paszkiewicz  * none
21307fe6a43SSeth Howell  */
21407fe6a43SSeth Howell static void
21526861b70SArtur Paszkiewicz raid_bdev_free_base_bdev_resource(struct raid_base_bdev_info *base_info)
21607fe6a43SSeth Howell {
21726861b70SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
21826861b70SArtur Paszkiewicz 
2194dd2a0d3SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
2204dd2a0d3SArtur Paszkiewicz 
221dccdd1e5SArtur Paszkiewicz 	free(base_info->name);
222dccdd1e5SArtur Paszkiewicz 	base_info->name = NULL;
2238a6bb6a8SArtur Paszkiewicz 	if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING) {
2248a6bb6a8SArtur Paszkiewicz 		spdk_uuid_set_null(&base_info->uuid);
2258a6bb6a8SArtur Paszkiewicz 	}
226dccdd1e5SArtur Paszkiewicz 
2278d1993a5SArtur Paszkiewicz 	if (base_info->desc == NULL) {
228dccdd1e5SArtur Paszkiewicz 		return;
229dccdd1e5SArtur Paszkiewicz 	}
230dccdd1e5SArtur Paszkiewicz 
2318d1993a5SArtur Paszkiewicz 	spdk_bdev_module_release_bdev(spdk_bdev_desc_get_bdev(base_info->desc));
232a193dcb8SArtur Paszkiewicz 	spdk_bdev_close(base_info->desc);
233a193dcb8SArtur Paszkiewicz 	base_info->desc = NULL;
23477b8f7b6SArtur Paszkiewicz 	spdk_put_io_channel(base_info->app_thread_ch);
23577b8f7b6SArtur Paszkiewicz 	base_info->app_thread_ch = NULL;
23607fe6a43SSeth Howell 
2379222ff97SArtur Paszkiewicz 	if (base_info->is_configured) {
23807fe6a43SSeth Howell 		assert(raid_bdev->num_base_bdevs_discovered);
23907fe6a43SSeth Howell 		raid_bdev->num_base_bdevs_discovered--;
2409222ff97SArtur Paszkiewicz 		base_info->is_configured = false;
2419222ff97SArtur Paszkiewicz 	}
24207fe6a43SSeth Howell }
24307fe6a43SSeth Howell 
24495a04949SArtur Paszkiewicz static void
24595a04949SArtur Paszkiewicz raid_bdev_io_device_unregister_cb(void *io_device)
24695a04949SArtur Paszkiewicz {
24795a04949SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = io_device;
24895a04949SArtur Paszkiewicz 
24995a04949SArtur Paszkiewicz 	if (raid_bdev->num_base_bdevs_discovered == 0) {
25095a04949SArtur Paszkiewicz 		/* Free raid_bdev when there are no base bdevs left */
25195a04949SArtur Paszkiewicz 		SPDK_DEBUGLOG(bdev_raid, "raid bdev base bdevs is 0, going to free all in destruct\n");
25295a04949SArtur Paszkiewicz 		raid_bdev_cleanup(raid_bdev);
25395a04949SArtur Paszkiewicz 		spdk_bdev_destruct_done(&raid_bdev->bdev, 0);
25495a04949SArtur Paszkiewicz 		raid_bdev_free(raid_bdev);
25595a04949SArtur Paszkiewicz 	} else {
25695a04949SArtur Paszkiewicz 		spdk_bdev_destruct_done(&raid_bdev->bdev, 0);
25795a04949SArtur Paszkiewicz 	}
25895a04949SArtur Paszkiewicz }
25995a04949SArtur Paszkiewicz 
2609cf1ab5bSArtur Paszkiewicz void
2619cf1ab5bSArtur Paszkiewicz raid_bdev_module_stop_done(struct raid_bdev *raid_bdev)
2629cf1ab5bSArtur Paszkiewicz {
2639cf1ab5bSArtur Paszkiewicz 	if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING) {
2649cf1ab5bSArtur Paszkiewicz 		spdk_io_device_unregister(raid_bdev, raid_bdev_io_device_unregister_cb);
2659cf1ab5bSArtur Paszkiewicz 	}
2669cf1ab5bSArtur Paszkiewicz }
2679cf1ab5bSArtur Paszkiewicz 
2684dd2a0d3SArtur Paszkiewicz static void
2694dd2a0d3SArtur Paszkiewicz _raid_bdev_destruct(void *ctxt)
27007fe6a43SSeth Howell {
27107fe6a43SSeth Howell 	struct raid_bdev *raid_bdev = ctxt;
272a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
27307fe6a43SSeth Howell 
2742172c432STomasz Zawadzki 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_destruct\n");
27507fe6a43SSeth Howell 
276a193dcb8SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
27707fe6a43SSeth Howell 		/*
27807fe6a43SSeth Howell 		 * Close all base bdev descriptors for which call has come from below
27907fe6a43SSeth Howell 		 * layers.  Also close the descriptors if we have started shutdown.
28007fe6a43SSeth Howell 		 */
281dccdd1e5SArtur Paszkiewicz 		if (g_shutdown_started || base_info->remove_scheduled == true) {
28226861b70SArtur Paszkiewicz 			raid_bdev_free_base_bdev_resource(base_info);
28307fe6a43SSeth Howell 		}
28407fe6a43SSeth Howell 	}
28507fe6a43SSeth Howell 
28607fe6a43SSeth Howell 	if (g_shutdown_started) {
28707fe6a43SSeth Howell 		raid_bdev->state = RAID_BDEV_STATE_OFFLINE;
28807fe6a43SSeth Howell 	}
28907fe6a43SSeth Howell 
290df80e8ffSyupeng 	if (raid_bdev->module->stop != NULL) {
2919cf1ab5bSArtur Paszkiewicz 		if (raid_bdev->module->stop(raid_bdev) == false) {
2924dd2a0d3SArtur Paszkiewicz 			return;
2939cf1ab5bSArtur Paszkiewicz 		}
294df80e8ffSyupeng 	}
295df80e8ffSyupeng 
2969cf1ab5bSArtur Paszkiewicz 	raid_bdev_module_stop_done(raid_bdev);
2974dd2a0d3SArtur Paszkiewicz }
2984dd2a0d3SArtur Paszkiewicz 
2994dd2a0d3SArtur Paszkiewicz static int
3004dd2a0d3SArtur Paszkiewicz raid_bdev_destruct(void *ctx)
3014dd2a0d3SArtur Paszkiewicz {
3024dd2a0d3SArtur Paszkiewicz 	spdk_thread_exec_msg(spdk_thread_get_app_thread(), _raid_bdev_destruct, ctx);
30307fe6a43SSeth Howell 
30495a04949SArtur Paszkiewicz 	return 1;
30507fe6a43SSeth Howell }
30607fe6a43SSeth Howell 
3076ba11b19SArtur Paszkiewicz void
3086ba11b19SArtur Paszkiewicz raid_bdev_io_complete(struct raid_bdev_io *raid_io, enum spdk_bdev_io_status status)
3096ba11b19SArtur Paszkiewicz {
3106ba11b19SArtur Paszkiewicz 	struct spdk_bdev_io *bdev_io = spdk_bdev_io_from_ctx(raid_io);
3116ba11b19SArtur Paszkiewicz 
3126ba11b19SArtur Paszkiewicz 	spdk_bdev_io_complete(bdev_io, status);
3136ba11b19SArtur Paszkiewicz }
3146ba11b19SArtur Paszkiewicz 
31507fe6a43SSeth Howell /*
31607fe6a43SSeth Howell  * brief:
3172efe6d92SArtur Paszkiewicz  * raid_bdev_io_complete_part - signal the completion of a part of the expected
3182efe6d92SArtur Paszkiewicz  * base bdev IOs and complete the raid_io if this is the final expected IO.
3192efe6d92SArtur Paszkiewicz  * The caller should first set raid_io->base_bdev_io_remaining. This function
3202efe6d92SArtur Paszkiewicz  * will decrement this counter by the value of the 'completed' parameter and
3212efe6d92SArtur Paszkiewicz  * complete the raid_io if the counter reaches 0. The caller is free to
3222efe6d92SArtur Paszkiewicz  * interpret the 'base_bdev_io_remaining' and 'completed' values as needed,
3232efe6d92SArtur Paszkiewicz  * it can represent e.g. blocks or IOs.
324a5d9d778Spaul luse  * params:
3252efe6d92SArtur Paszkiewicz  * raid_io - pointer to raid_bdev_io
3262efe6d92SArtur Paszkiewicz  * completed - the part of the raid_io that has been completed
3272efe6d92SArtur Paszkiewicz  * status - status of the base IO
328a5d9d778Spaul luse  * returns:
3292efe6d92SArtur Paszkiewicz  * true - if the raid_io is completed
3302efe6d92SArtur Paszkiewicz  * false - otherwise
331a5d9d778Spaul luse  */
3322efe6d92SArtur Paszkiewicz bool
3332efe6d92SArtur Paszkiewicz raid_bdev_io_complete_part(struct raid_bdev_io *raid_io, uint64_t completed,
3342efe6d92SArtur Paszkiewicz 			   enum spdk_bdev_io_status status)
335a5d9d778Spaul luse {
3362efe6d92SArtur Paszkiewicz 	assert(raid_io->base_bdev_io_remaining >= completed);
3372efe6d92SArtur Paszkiewicz 	raid_io->base_bdev_io_remaining -= completed;
338a5d9d778Spaul luse 
3392efe6d92SArtur Paszkiewicz 	if (status != SPDK_BDEV_IO_STATUS_SUCCESS) {
3402efe6d92SArtur Paszkiewicz 		raid_io->base_bdev_io_status = status;
341a5d9d778Spaul luse 	}
342a5d9d778Spaul luse 
3432efe6d92SArtur Paszkiewicz 	if (raid_io->base_bdev_io_remaining == 0) {
3446ba11b19SArtur Paszkiewicz 		raid_bdev_io_complete(raid_io, raid_io->base_bdev_io_status);
3452efe6d92SArtur Paszkiewicz 		return true;
3462efe6d92SArtur Paszkiewicz 	} else {
3472efe6d92SArtur Paszkiewicz 		return false;
348a5d9d778Spaul luse 	}
349a5d9d778Spaul luse }
350a5d9d778Spaul luse 
35107fe6a43SSeth Howell /*
35207fe6a43SSeth Howell  * brief:
3531d246e97SArtur Paszkiewicz  * raid_bdev_queue_io_wait function processes the IO which failed to submit.
3541d246e97SArtur Paszkiewicz  * It will try to queue the IOs after storing the context to bdev wait queue logic.
35507fe6a43SSeth Howell  * params:
356ae70d6a4SArtur Paszkiewicz  * raid_io - pointer to raid_bdev_io
357ae70d6a4SArtur Paszkiewicz  * bdev - the block device that the IO is submitted to
358ae70d6a4SArtur Paszkiewicz  * ch - io channel
359ae70d6a4SArtur Paszkiewicz  * cb_fn - callback when the spdk_bdev_io for bdev becomes available
36007fe6a43SSeth Howell  * returns:
36107fe6a43SSeth Howell  * none
36207fe6a43SSeth Howell  */
363fc9ca1d0SArtur Paszkiewicz void
364ae70d6a4SArtur Paszkiewicz raid_bdev_queue_io_wait(struct raid_bdev_io *raid_io, struct spdk_bdev *bdev,
365ae70d6a4SArtur Paszkiewicz 			struct spdk_io_channel *ch, spdk_bdev_io_wait_cb cb_fn)
36607fe6a43SSeth Howell {
367ae70d6a4SArtur Paszkiewicz 	raid_io->waitq_entry.bdev = bdev;
36807fe6a43SSeth Howell 	raid_io->waitq_entry.cb_fn = cb_fn;
369ae70d6a4SArtur Paszkiewicz 	raid_io->waitq_entry.cb_arg = raid_io;
370ae70d6a4SArtur Paszkiewicz 	spdk_bdev_queue_io_wait(bdev, ch, &raid_io->waitq_entry);
37107fe6a43SSeth Howell }
37207fe6a43SSeth Howell 
3730ae5a89dSArtur Paszkiewicz static void
3742efe6d92SArtur Paszkiewicz raid_base_bdev_reset_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
3752efe6d92SArtur Paszkiewicz {
3762efe6d92SArtur Paszkiewicz 	struct raid_bdev_io *raid_io = cb_arg;
3772efe6d92SArtur Paszkiewicz 
3782efe6d92SArtur Paszkiewicz 	spdk_bdev_free_io(bdev_io);
3792efe6d92SArtur Paszkiewicz 
3802efe6d92SArtur Paszkiewicz 	raid_bdev_io_complete_part(raid_io, 1, success ?
3812efe6d92SArtur Paszkiewicz 				   SPDK_BDEV_IO_STATUS_SUCCESS :
3822efe6d92SArtur Paszkiewicz 				   SPDK_BDEV_IO_STATUS_FAILED);
3832efe6d92SArtur Paszkiewicz }
3842efe6d92SArtur Paszkiewicz 
3858dd1cd21SBen Walker static void raid_bdev_submit_reset_request(struct raid_bdev_io *raid_io);
3860ae5a89dSArtur Paszkiewicz 
3870ae5a89dSArtur Paszkiewicz static void
388ae70d6a4SArtur Paszkiewicz _raid_bdev_submit_reset_request(void *_raid_io)
3890ae5a89dSArtur Paszkiewicz {
390ae70d6a4SArtur Paszkiewicz 	struct raid_bdev_io *raid_io = _raid_io;
3910ae5a89dSArtur Paszkiewicz 
3920ae5a89dSArtur Paszkiewicz 	raid_bdev_submit_reset_request(raid_io);
3930ae5a89dSArtur Paszkiewicz }
3940ae5a89dSArtur Paszkiewicz 
39507fe6a43SSeth Howell /*
39607fe6a43SSeth Howell  * brief:
3970ae5a89dSArtur Paszkiewicz  * raid_bdev_submit_reset_request function submits reset requests
39807fe6a43SSeth Howell  * to member disks; it will submit as many as possible unless a reset fails with -ENOMEM, in
39907fe6a43SSeth Howell  * which case it will queue it for later submission
40007fe6a43SSeth Howell  * params:
4010ae5a89dSArtur Paszkiewicz  * raid_io
40207fe6a43SSeth Howell  * returns:
40307fe6a43SSeth Howell  * none
40407fe6a43SSeth Howell  */
40507fe6a43SSeth Howell static void
4060ae5a89dSArtur Paszkiewicz raid_bdev_submit_reset_request(struct raid_bdev_io *raid_io)
40707fe6a43SSeth Howell {
40807fe6a43SSeth Howell 	struct raid_bdev		*raid_bdev;
40907fe6a43SSeth Howell 	int				ret;
41007fe6a43SSeth Howell 	uint8_t				i;
411235cc2c9SArtur Paszkiewicz 	struct raid_base_bdev_info	*base_info;
412235cc2c9SArtur Paszkiewicz 	struct spdk_io_channel		*base_ch;
41307fe6a43SSeth Howell 
414cb8dbf17SArtur Paszkiewicz 	raid_bdev = raid_io->raid_bdev;
41507fe6a43SSeth Howell 
4162efe6d92SArtur Paszkiewicz 	if (raid_io->base_bdev_io_remaining == 0) {
4172efe6d92SArtur Paszkiewicz 		raid_io->base_bdev_io_remaining = raid_bdev->num_base_bdevs;
4182efe6d92SArtur Paszkiewicz 	}
41977b8618eSArtur Paszkiewicz 
420fe7932a5SArtur Paszkiewicz 	for (i = raid_io->base_bdev_io_submitted; i < raid_bdev->num_base_bdevs; i++) {
421235cc2c9SArtur Paszkiewicz 		base_info = &raid_bdev->base_bdev_info[i];
422235cc2c9SArtur Paszkiewicz 		base_ch = raid_io->raid_ch->base_channel[i];
423b42cb0e5SArtur Paszkiewicz 		if (base_ch == NULL) {
424b42cb0e5SArtur Paszkiewicz 			raid_io->base_bdev_io_submitted++;
425b42cb0e5SArtur Paszkiewicz 			raid_bdev_io_complete_part(raid_io, 1, SPDK_BDEV_IO_STATUS_SUCCESS);
426b42cb0e5SArtur Paszkiewicz 			continue;
427b42cb0e5SArtur Paszkiewicz 		}
428235cc2c9SArtur Paszkiewicz 		ret = spdk_bdev_reset(base_info->desc, base_ch,
4292efe6d92SArtur Paszkiewicz 				      raid_base_bdev_reset_complete, raid_io);
43007fe6a43SSeth Howell 		if (ret == 0) {
43107fe6a43SSeth Howell 			raid_io->base_bdev_io_submitted++;
432d3a04643SArtur Paszkiewicz 		} else if (ret == -ENOMEM) {
4338d1993a5SArtur Paszkiewicz 			raid_bdev_queue_io_wait(raid_io, spdk_bdev_desc_get_bdev(base_info->desc),
4348d1993a5SArtur Paszkiewicz 						base_ch, _raid_bdev_submit_reset_request);
435d3a04643SArtur Paszkiewicz 			return;
436d3a04643SArtur Paszkiewicz 		} else {
437d3a04643SArtur Paszkiewicz 			SPDK_ERRLOG("bdev io submit error not due to ENOMEM, it should not happen\n");
438d3a04643SArtur Paszkiewicz 			assert(false);
4396ba11b19SArtur Paszkiewicz 			raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED);
44007fe6a43SSeth Howell 			return;
44107fe6a43SSeth Howell 		}
44207fe6a43SSeth Howell 	}
44307fe6a43SSeth Howell }
44407fe6a43SSeth Howell 
44507fe6a43SSeth Howell /*
44607fe6a43SSeth Howell  * brief:
44707fe6a43SSeth Howell  * Callback function to spdk_bdev_io_get_buf.
44807fe6a43SSeth Howell  * params:
44907fe6a43SSeth Howell  * ch - pointer to raid bdev io channel
45007fe6a43SSeth Howell  * bdev_io - pointer to parent bdev_io on raid bdev device
45107fe6a43SSeth Howell  * success - True if buffer is allocated or false otherwise.
45207fe6a43SSeth Howell  * returns:
45307fe6a43SSeth Howell  * none
45407fe6a43SSeth Howell  */
45507fe6a43SSeth Howell static void
45607fe6a43SSeth Howell raid_bdev_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
45707fe6a43SSeth Howell 		     bool success)
45807fe6a43SSeth Howell {
4590ae5a89dSArtur Paszkiewicz 	struct raid_bdev_io *raid_io = (struct raid_bdev_io *)bdev_io->driver_ctx;
4600ae5a89dSArtur Paszkiewicz 
46107fe6a43SSeth Howell 	if (!success) {
4626ba11b19SArtur Paszkiewicz 		raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED);
46307fe6a43SSeth Howell 		return;
46407fe6a43SSeth Howell 	}
46507fe6a43SSeth Howell 
466182278c0SArtur Paszkiewicz 	raid_io->raid_bdev->module->submit_rw_request(raid_io);
46707fe6a43SSeth Howell }
46807fe6a43SSeth Howell 
46907fe6a43SSeth Howell /*
47007fe6a43SSeth Howell  * brief:
47107fe6a43SSeth Howell  * raid_bdev_submit_request function is the submit_request function pointer of
47207fe6a43SSeth Howell  * raid bdev function table. This is used to submit the io on raid_bdev to below
47307fe6a43SSeth Howell  * layers.
47407fe6a43SSeth Howell  * params:
47507fe6a43SSeth Howell  * ch - pointer to raid bdev io channel
47607fe6a43SSeth Howell  * bdev_io - pointer to parent bdev_io on raid bdev device
47707fe6a43SSeth Howell  * returns:
47807fe6a43SSeth Howell  * none
47907fe6a43SSeth Howell  */
48007fe6a43SSeth Howell static void
48107fe6a43SSeth Howell raid_bdev_submit_request(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io)
48207fe6a43SSeth Howell {
483485c7912SArtur Paszkiewicz 	struct raid_bdev_io *raid_io = (struct raid_bdev_io *)bdev_io->driver_ctx;
484485c7912SArtur Paszkiewicz 
485cb8dbf17SArtur Paszkiewicz 	raid_io->raid_bdev = bdev_io->bdev->ctxt;
486485c7912SArtur Paszkiewicz 	raid_io->raid_ch = spdk_io_channel_get_ctx(ch);
4872efe6d92SArtur Paszkiewicz 	raid_io->base_bdev_io_remaining = 0;
488485c7912SArtur Paszkiewicz 	raid_io->base_bdev_io_submitted = 0;
489485c7912SArtur Paszkiewicz 	raid_io->base_bdev_io_status = SPDK_BDEV_IO_STATUS_SUCCESS;
490485c7912SArtur Paszkiewicz 
49107fe6a43SSeth Howell 	switch (bdev_io->type) {
49207fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_READ:
49307fe6a43SSeth Howell 		spdk_bdev_io_get_buf(bdev_io, raid_bdev_get_buf_cb,
49407fe6a43SSeth Howell 				     bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
49507fe6a43SSeth Howell 		break;
49607fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_WRITE:
497182278c0SArtur Paszkiewicz 		raid_io->raid_bdev->module->submit_rw_request(raid_io);
49807fe6a43SSeth Howell 		break;
49907fe6a43SSeth Howell 
50007fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_RESET:
5010ae5a89dSArtur Paszkiewicz 		raid_bdev_submit_reset_request(raid_io);
50207fe6a43SSeth Howell 		break;
50307fe6a43SSeth Howell 
50407fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_FLUSH:
50507fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_UNMAP:
506182278c0SArtur Paszkiewicz 		raid_io->raid_bdev->module->submit_null_payload_request(raid_io);
50707fe6a43SSeth Howell 		break;
50807fe6a43SSeth Howell 
50907fe6a43SSeth Howell 	default:
51007fe6a43SSeth Howell 		SPDK_ERRLOG("submit request, invalid io type %u\n", bdev_io->type);
5116ba11b19SArtur Paszkiewicz 		raid_bdev_io_complete(raid_io, SPDK_BDEV_IO_STATUS_FAILED);
51207fe6a43SSeth Howell 		break;
51307fe6a43SSeth Howell 	}
51407fe6a43SSeth Howell }
51507fe6a43SSeth Howell 
51607fe6a43SSeth Howell /*
51707fe6a43SSeth Howell  * brief:
51807fe6a43SSeth Howell  * _raid_bdev_io_type_supported checks whether io_type is supported in
51907fe6a43SSeth Howell  * all base bdev modules of raid bdev module. If anyone among the base_bdevs
52007fe6a43SSeth Howell  * doesn't support, the raid device doesn't supports.
52107fe6a43SSeth Howell  *
52207fe6a43SSeth Howell  * params:
52307fe6a43SSeth Howell  * raid_bdev - pointer to raid bdev context
52407fe6a43SSeth Howell  * io_type - io type
52507fe6a43SSeth Howell  * returns:
52607fe6a43SSeth Howell  * true - io_type is supported
52707fe6a43SSeth Howell  * false - io_type is not supported
52807fe6a43SSeth Howell  */
52907fe6a43SSeth Howell inline static bool
53007fe6a43SSeth Howell _raid_bdev_io_type_supported(struct raid_bdev *raid_bdev, enum spdk_bdev_io_type io_type)
53107fe6a43SSeth Howell {
532a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
53307fe6a43SSeth Howell 
5341d3ca5c4SArtur Paszkiewicz 	if (io_type == SPDK_BDEV_IO_TYPE_FLUSH ||
5351d3ca5c4SArtur Paszkiewicz 	    io_type == SPDK_BDEV_IO_TYPE_UNMAP) {
5361d3ca5c4SArtur Paszkiewicz 		if (raid_bdev->module->submit_null_payload_request == NULL) {
5371d3ca5c4SArtur Paszkiewicz 			return false;
5381d3ca5c4SArtur Paszkiewicz 		}
5391d3ca5c4SArtur Paszkiewicz 	}
5401d3ca5c4SArtur Paszkiewicz 
541a193dcb8SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
5428d1993a5SArtur Paszkiewicz 		if (base_info->desc == NULL) {
54307fe6a43SSeth Howell 			continue;
54407fe6a43SSeth Howell 		}
54507fe6a43SSeth Howell 
5468d1993a5SArtur Paszkiewicz 		if (spdk_bdev_io_type_supported(spdk_bdev_desc_get_bdev(base_info->desc), io_type) == false) {
54707fe6a43SSeth Howell 			return false;
54807fe6a43SSeth Howell 		}
54907fe6a43SSeth Howell 	}
55007fe6a43SSeth Howell 
55107fe6a43SSeth Howell 	return true;
55207fe6a43SSeth Howell }
55307fe6a43SSeth Howell 
55407fe6a43SSeth Howell /*
55507fe6a43SSeth Howell  * brief:
55607fe6a43SSeth Howell  * raid_bdev_io_type_supported is the io_supported function for bdev function
55707fe6a43SSeth Howell  * table which returns whether the particular io type is supported or not by
55807fe6a43SSeth Howell  * raid bdev module
55907fe6a43SSeth Howell  * params:
56007fe6a43SSeth Howell  * ctx - pointer to raid bdev context
56107fe6a43SSeth Howell  * type - io type
56207fe6a43SSeth Howell  * returns:
56307fe6a43SSeth Howell  * true - io_type is supported
56407fe6a43SSeth Howell  * false - io_type is not supported
56507fe6a43SSeth Howell  */
56607fe6a43SSeth Howell static bool
56707fe6a43SSeth Howell raid_bdev_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
56807fe6a43SSeth Howell {
56907fe6a43SSeth Howell 	switch (io_type) {
57007fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_READ:
57107fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_WRITE:
57207fe6a43SSeth Howell 		return true;
57307fe6a43SSeth Howell 
57407fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_FLUSH:
57507fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_RESET:
57607fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_UNMAP:
57707fe6a43SSeth Howell 		return _raid_bdev_io_type_supported(ctx, io_type);
57807fe6a43SSeth Howell 
57907fe6a43SSeth Howell 	default:
58007fe6a43SSeth Howell 		return false;
58107fe6a43SSeth Howell 	}
58207fe6a43SSeth Howell 
58307fe6a43SSeth Howell 	return false;
58407fe6a43SSeth Howell }
58507fe6a43SSeth Howell 
58607fe6a43SSeth Howell /*
58707fe6a43SSeth Howell  * brief:
58807fe6a43SSeth Howell  * raid_bdev_get_io_channel is the get_io_channel function table pointer for
58907fe6a43SSeth Howell  * raid bdev. This is used to return the io channel for this raid bdev
59007fe6a43SSeth Howell  * params:
59107fe6a43SSeth Howell  * ctxt - pointer to raid_bdev
59207fe6a43SSeth Howell  * returns:
59307fe6a43SSeth Howell  * pointer to io channel for raid bdev
59407fe6a43SSeth Howell  */
59507fe6a43SSeth Howell static struct spdk_io_channel *
59607fe6a43SSeth Howell raid_bdev_get_io_channel(void *ctxt)
59707fe6a43SSeth Howell {
59807fe6a43SSeth Howell 	struct raid_bdev *raid_bdev = ctxt;
59907fe6a43SSeth Howell 
60007fe6a43SSeth Howell 	return spdk_get_io_channel(raid_bdev);
60107fe6a43SSeth Howell }
60207fe6a43SSeth Howell 
603ec6d94b6SArtur Paszkiewicz void
604ec6d94b6SArtur Paszkiewicz raid_bdev_write_info_json(struct raid_bdev *raid_bdev, struct spdk_json_write_ctx *w)
60507fe6a43SSeth Howell {
606a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
607b9792a95SArtur Paszkiewicz 	char uuid_str[SPDK_UUID_STRING_LEN];
60807fe6a43SSeth Howell 
60907fe6a43SSeth Howell 	assert(raid_bdev != NULL);
6104dd2a0d3SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
61107fe6a43SSeth Howell 
612b9792a95SArtur Paszkiewicz 	spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &raid_bdev->bdev.uuid);
613b9792a95SArtur Paszkiewicz 	spdk_json_write_named_string(w, "uuid", uuid_str);
61407fe6a43SSeth Howell 	spdk_json_write_named_uint32(w, "strip_size_kb", raid_bdev->strip_size_kb);
61546ff15a6SArtur Paszkiewicz 	spdk_json_write_named_string(w, "state", raid_bdev_state_to_str(raid_bdev->state));
616445e667fSArtur Paszkiewicz 	spdk_json_write_named_string(w, "raid_level", raid_bdev_level_to_str(raid_bdev->level));
61777b8f7b6SArtur Paszkiewicz 	spdk_json_write_named_bool(w, "superblock", raid_bdev->sb != NULL);
61807fe6a43SSeth Howell 	spdk_json_write_named_uint32(w, "num_base_bdevs", raid_bdev->num_base_bdevs);
61907fe6a43SSeth Howell 	spdk_json_write_named_uint32(w, "num_base_bdevs_discovered", raid_bdev->num_base_bdevs_discovered);
62007fe6a43SSeth Howell 	spdk_json_write_name(w, "base_bdevs_list");
62107fe6a43SSeth Howell 	spdk_json_write_array_begin(w);
622a193dcb8SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
623*c51db566SArtur Paszkiewicz 		spdk_json_write_object_begin(w);
624*c51db566SArtur Paszkiewicz 		spdk_json_write_name(w, "name");
625*c51db566SArtur Paszkiewicz 		if (base_info->name) {
626*c51db566SArtur Paszkiewicz 			spdk_json_write_string(w, base_info->name);
62707fe6a43SSeth Howell 		} else {
62807fe6a43SSeth Howell 			spdk_json_write_null(w);
62907fe6a43SSeth Howell 		}
630*c51db566SArtur Paszkiewicz 		spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &base_info->uuid);
631*c51db566SArtur Paszkiewicz 		spdk_json_write_named_string(w, "uuid", uuid_str);
632*c51db566SArtur Paszkiewicz 		spdk_json_write_named_bool(w, "is_configured", base_info->is_configured);
633*c51db566SArtur Paszkiewicz 		spdk_json_write_named_uint64(w, "data_offset", base_info->data_offset);
634*c51db566SArtur Paszkiewicz 		spdk_json_write_named_uint64(w, "data_size", base_info->data_size);
635*c51db566SArtur Paszkiewicz 		spdk_json_write_object_end(w);
63607fe6a43SSeth Howell 	}
63707fe6a43SSeth Howell 	spdk_json_write_array_end(w);
638ec6d94b6SArtur Paszkiewicz }
639ec6d94b6SArtur Paszkiewicz 
640ec6d94b6SArtur Paszkiewicz /*
641ec6d94b6SArtur Paszkiewicz  * brief:
642ec6d94b6SArtur Paszkiewicz  * raid_bdev_dump_info_json is the function table pointer for raid bdev
643ec6d94b6SArtur Paszkiewicz  * params:
644ec6d94b6SArtur Paszkiewicz  * ctx - pointer to raid_bdev
645ec6d94b6SArtur Paszkiewicz  * w - pointer to json context
646ec6d94b6SArtur Paszkiewicz  * returns:
647ec6d94b6SArtur Paszkiewicz  * 0 - success
648ec6d94b6SArtur Paszkiewicz  * non zero - failure
649ec6d94b6SArtur Paszkiewicz  */
650ec6d94b6SArtur Paszkiewicz static int
651ec6d94b6SArtur Paszkiewicz raid_bdev_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
652ec6d94b6SArtur Paszkiewicz {
653ec6d94b6SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = ctx;
654ec6d94b6SArtur Paszkiewicz 
655ec6d94b6SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_dump_config_json\n");
656ec6d94b6SArtur Paszkiewicz 
657ec6d94b6SArtur Paszkiewicz 	/* Dump the raid bdev configuration related information */
658ec6d94b6SArtur Paszkiewicz 	spdk_json_write_named_object_begin(w, "raid");
659ec6d94b6SArtur Paszkiewicz 	raid_bdev_write_info_json(raid_bdev, w);
66007fe6a43SSeth Howell 	spdk_json_write_object_end(w);
66107fe6a43SSeth Howell 
66207fe6a43SSeth Howell 	return 0;
66307fe6a43SSeth Howell }
66407fe6a43SSeth Howell 
66507fe6a43SSeth Howell /*
66607fe6a43SSeth Howell  * brief:
66707fe6a43SSeth Howell  * raid_bdev_write_config_json is the function table pointer for raid bdev
66807fe6a43SSeth Howell  * params:
66907fe6a43SSeth Howell  * bdev - pointer to spdk_bdev
67007fe6a43SSeth Howell  * w - pointer to json context
67107fe6a43SSeth Howell  * returns:
67207fe6a43SSeth Howell  * none
67307fe6a43SSeth Howell  */
67407fe6a43SSeth Howell static void
67507fe6a43SSeth Howell raid_bdev_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
67607fe6a43SSeth Howell {
67707fe6a43SSeth Howell 	struct raid_bdev *raid_bdev = bdev->ctxt;
678a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
679b9792a95SArtur Paszkiewicz 	char uuid_str[SPDK_UUID_STRING_LEN];
68007fe6a43SSeth Howell 
6814dd2a0d3SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
6824dd2a0d3SArtur Paszkiewicz 
68377b8f7b6SArtur Paszkiewicz 	if (raid_bdev->sb != NULL) {
684deed7d2fSArtur Paszkiewicz 		/* raid bdev configuration is stored in the superblock */
685deed7d2fSArtur Paszkiewicz 		return;
686deed7d2fSArtur Paszkiewicz 	}
687deed7d2fSArtur Paszkiewicz 
68807fe6a43SSeth Howell 	spdk_json_write_object_begin(w);
68907fe6a43SSeth Howell 
690f0731534SMaciej Wawryk 	spdk_json_write_named_string(w, "method", "bdev_raid_create");
69107fe6a43SSeth Howell 
69207fe6a43SSeth Howell 	spdk_json_write_named_object_begin(w, "params");
69307fe6a43SSeth Howell 	spdk_json_write_named_string(w, "name", bdev->name);
694b9792a95SArtur Paszkiewicz 	spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &raid_bdev->bdev.uuid);
695b9792a95SArtur Paszkiewicz 	spdk_json_write_named_string(w, "uuid", uuid_str);
696af4fa148SWANGHAILIANG 	spdk_json_write_named_uint32(w, "strip_size_kb", raid_bdev->strip_size_kb);
697445e667fSArtur Paszkiewicz 	spdk_json_write_named_string(w, "raid_level", raid_bdev_level_to_str(raid_bdev->level));
69877b8f7b6SArtur Paszkiewicz 	spdk_json_write_named_bool(w, "superblock", raid_bdev->sb != NULL);
69907fe6a43SSeth Howell 
70007fe6a43SSeth Howell 	spdk_json_write_named_array_begin(w, "base_bdevs");
701a193dcb8SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
7028d1993a5SArtur Paszkiewicz 		if (base_info->desc) {
7038d1993a5SArtur Paszkiewicz 			spdk_json_write_string(w, spdk_bdev_desc_get_bdev(base_info->desc)->name);
70407fe6a43SSeth Howell 		}
70507fe6a43SSeth Howell 	}
70607fe6a43SSeth Howell 	spdk_json_write_array_end(w);
70707fe6a43SSeth Howell 	spdk_json_write_object_end(w);
70807fe6a43SSeth Howell 
70907fe6a43SSeth Howell 	spdk_json_write_object_end(w);
71007fe6a43SSeth Howell }
71107fe6a43SSeth Howell 
712be440c01SAlexey Marchuk static int
713be440c01SAlexey Marchuk raid_bdev_get_memory_domains(void *ctx, struct spdk_memory_domain **domains, int array_size)
714be440c01SAlexey Marchuk {
715be440c01SAlexey Marchuk 	struct raid_bdev *raid_bdev = ctx;
716973b0d62SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
717b42cb0e5SArtur Paszkiewicz 	int domains_count = 0, rc = 0;
718be440c01SAlexey Marchuk 
71972672d49SArtur Paszkiewicz 	if (raid_bdev->module->memory_domains_supported == false) {
72072672d49SArtur Paszkiewicz 		return 0;
72172672d49SArtur Paszkiewicz 	}
72272672d49SArtur Paszkiewicz 
723b42cb0e5SArtur Paszkiewicz 	spdk_spin_lock(&raid_bdev->base_bdev_lock);
724b42cb0e5SArtur Paszkiewicz 
725be440c01SAlexey Marchuk 	/* First loop to get the number of memory domains */
726973b0d62SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
7278d1993a5SArtur Paszkiewicz 		if (base_info->desc == NULL) {
728b42cb0e5SArtur Paszkiewicz 			continue;
729b42cb0e5SArtur Paszkiewicz 		}
7308d1993a5SArtur Paszkiewicz 		rc = spdk_bdev_get_memory_domains(spdk_bdev_desc_get_bdev(base_info->desc), NULL, 0);
731be440c01SAlexey Marchuk 		if (rc < 0) {
732b42cb0e5SArtur Paszkiewicz 			goto out;
733be440c01SAlexey Marchuk 		}
734be440c01SAlexey Marchuk 		domains_count += rc;
735be440c01SAlexey Marchuk 	}
736be440c01SAlexey Marchuk 
737be440c01SAlexey Marchuk 	if (!domains || array_size < domains_count) {
738b42cb0e5SArtur Paszkiewicz 		goto out;
739be440c01SAlexey Marchuk 	}
740be440c01SAlexey Marchuk 
741973b0d62SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
7428d1993a5SArtur Paszkiewicz 		if (base_info->desc == NULL) {
743b42cb0e5SArtur Paszkiewicz 			continue;
744b42cb0e5SArtur Paszkiewicz 		}
7458d1993a5SArtur Paszkiewicz 		rc = spdk_bdev_get_memory_domains(spdk_bdev_desc_get_bdev(base_info->desc), domains, array_size);
746be440c01SAlexey Marchuk 		if (rc < 0) {
747b42cb0e5SArtur Paszkiewicz 			goto out;
748be440c01SAlexey Marchuk 		}
749be440c01SAlexey Marchuk 		domains += rc;
750be440c01SAlexey Marchuk 		array_size -= rc;
751be440c01SAlexey Marchuk 	}
752b42cb0e5SArtur Paszkiewicz out:
753b42cb0e5SArtur Paszkiewicz 	spdk_spin_unlock(&raid_bdev->base_bdev_lock);
754b42cb0e5SArtur Paszkiewicz 
755b42cb0e5SArtur Paszkiewicz 	if (rc < 0) {
756b42cb0e5SArtur Paszkiewicz 		return rc;
757b42cb0e5SArtur Paszkiewicz 	}
758be440c01SAlexey Marchuk 
759be440c01SAlexey Marchuk 	return domains_count;
760be440c01SAlexey Marchuk }
761be440c01SAlexey Marchuk 
76207fe6a43SSeth Howell /* g_raid_bdev_fn_table is the function table for raid bdev */
76307fe6a43SSeth Howell static const struct spdk_bdev_fn_table g_raid_bdev_fn_table = {
76407fe6a43SSeth Howell 	.destruct		= raid_bdev_destruct,
76507fe6a43SSeth Howell 	.submit_request		= raid_bdev_submit_request,
76607fe6a43SSeth Howell 	.io_type_supported	= raid_bdev_io_type_supported,
76707fe6a43SSeth Howell 	.get_io_channel		= raid_bdev_get_io_channel,
76807fe6a43SSeth Howell 	.dump_info_json		= raid_bdev_dump_info_json,
76907fe6a43SSeth Howell 	.write_config_json	= raid_bdev_write_config_json,
770be440c01SAlexey Marchuk 	.get_memory_domains	= raid_bdev_get_memory_domains,
77107fe6a43SSeth Howell };
77207fe6a43SSeth Howell 
773dccdd1e5SArtur Paszkiewicz struct raid_bdev *
774dccdd1e5SArtur Paszkiewicz raid_bdev_find_by_name(const char *name)
77507fe6a43SSeth Howell {
776dccdd1e5SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
77707fe6a43SSeth Howell 
778dccdd1e5SArtur Paszkiewicz 	TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) {
779dccdd1e5SArtur Paszkiewicz 		if (strcmp(raid_bdev->bdev.name, name) == 0) {
780dccdd1e5SArtur Paszkiewicz 			return raid_bdev;
78107fe6a43SSeth Howell 		}
78207fe6a43SSeth Howell 	}
78307fe6a43SSeth Howell 
784dccdd1e5SArtur Paszkiewicz 	return NULL;
78507fe6a43SSeth Howell }
786445e667fSArtur Paszkiewicz 
787445e667fSArtur Paszkiewicz static struct {
788445e667fSArtur Paszkiewicz 	const char *name;
789445e667fSArtur Paszkiewicz 	enum raid_level value;
790445e667fSArtur Paszkiewicz } g_raid_level_names[] = {
791445e667fSArtur Paszkiewicz 	{ "raid0", RAID0 },
792445e667fSArtur Paszkiewicz 	{ "0", RAID0 },
793208f21cdSKrzysztof Smolinski 	{ "raid1", RAID1 },
794208f21cdSKrzysztof Smolinski 	{ "1", RAID1 },
79583a4b155SArtur Paszkiewicz 	{ "raid5f", RAID5F },
79683a4b155SArtur Paszkiewicz 	{ "5f", RAID5F },
79764eebbd1Syupeng 	{ "concat", CONCAT },
798445e667fSArtur Paszkiewicz 	{ }
799445e667fSArtur Paszkiewicz };
800445e667fSArtur Paszkiewicz 
80146ff15a6SArtur Paszkiewicz static struct {
80246ff15a6SArtur Paszkiewicz 	const char *name;
80346ff15a6SArtur Paszkiewicz 	enum raid_bdev_state value;
80446ff15a6SArtur Paszkiewicz } g_raid_state_names[] = {
80546ff15a6SArtur Paszkiewicz 	{ "online", RAID_BDEV_STATE_ONLINE },
80646ff15a6SArtur Paszkiewicz 	{ "configuring", RAID_BDEV_STATE_CONFIGURING },
80746ff15a6SArtur Paszkiewicz 	{ "offline", RAID_BDEV_STATE_OFFLINE },
80846ff15a6SArtur Paszkiewicz 	{ }
80946ff15a6SArtur Paszkiewicz };
81046ff15a6SArtur Paszkiewicz 
8118dd1cd21SBen Walker /* We have to use the typedef in the function declaration to appease astyle. */
8128dd1cd21SBen Walker typedef enum raid_level raid_level_t;
81346ff15a6SArtur Paszkiewicz typedef enum raid_bdev_state raid_bdev_state_t;
8148dd1cd21SBen Walker 
8158dd1cd21SBen Walker raid_level_t
81646ff15a6SArtur Paszkiewicz raid_bdev_str_to_level(const char *str)
817445e667fSArtur Paszkiewicz {
818445e667fSArtur Paszkiewicz 	unsigned int i;
819445e667fSArtur Paszkiewicz 
820a2606d4bSMaciej Szwed 	assert(str != NULL);
821a2606d4bSMaciej Szwed 
822445e667fSArtur Paszkiewicz 	for (i = 0; g_raid_level_names[i].name != NULL; i++) {
823445e667fSArtur Paszkiewicz 		if (strcasecmp(g_raid_level_names[i].name, str) == 0) {
824445e667fSArtur Paszkiewicz 			return g_raid_level_names[i].value;
825445e667fSArtur Paszkiewicz 		}
826445e667fSArtur Paszkiewicz 	}
827445e667fSArtur Paszkiewicz 
828445e667fSArtur Paszkiewicz 	return INVALID_RAID_LEVEL;
829445e667fSArtur Paszkiewicz }
830445e667fSArtur Paszkiewicz 
831445e667fSArtur Paszkiewicz const char *
832445e667fSArtur Paszkiewicz raid_bdev_level_to_str(enum raid_level level)
833445e667fSArtur Paszkiewicz {
834445e667fSArtur Paszkiewicz 	unsigned int i;
835445e667fSArtur Paszkiewicz 
836445e667fSArtur Paszkiewicz 	for (i = 0; g_raid_level_names[i].name != NULL; i++) {
837445e667fSArtur Paszkiewicz 		if (g_raid_level_names[i].value == level) {
838445e667fSArtur Paszkiewicz 			return g_raid_level_names[i].name;
839445e667fSArtur Paszkiewicz 		}
840445e667fSArtur Paszkiewicz 	}
841445e667fSArtur Paszkiewicz 
842445e667fSArtur Paszkiewicz 	return "";
843445e667fSArtur Paszkiewicz }
844445e667fSArtur Paszkiewicz 
84546ff15a6SArtur Paszkiewicz raid_bdev_state_t
84646ff15a6SArtur Paszkiewicz raid_bdev_str_to_state(const char *str)
84746ff15a6SArtur Paszkiewicz {
84846ff15a6SArtur Paszkiewicz 	unsigned int i;
84946ff15a6SArtur Paszkiewicz 
85046ff15a6SArtur Paszkiewicz 	assert(str != NULL);
85146ff15a6SArtur Paszkiewicz 
85246ff15a6SArtur Paszkiewicz 	for (i = 0; g_raid_state_names[i].name != NULL; i++) {
85346ff15a6SArtur Paszkiewicz 		if (strcasecmp(g_raid_state_names[i].name, str) == 0) {
85446ff15a6SArtur Paszkiewicz 			return g_raid_state_names[i].value;
85546ff15a6SArtur Paszkiewicz 		}
85646ff15a6SArtur Paszkiewicz 	}
85746ff15a6SArtur Paszkiewicz 
85846ff15a6SArtur Paszkiewicz 	return RAID_BDEV_STATE_MAX;
85946ff15a6SArtur Paszkiewicz }
86046ff15a6SArtur Paszkiewicz 
86146ff15a6SArtur Paszkiewicz const char *
86246ff15a6SArtur Paszkiewicz raid_bdev_state_to_str(enum raid_bdev_state state)
86346ff15a6SArtur Paszkiewicz {
86446ff15a6SArtur Paszkiewicz 	unsigned int i;
86546ff15a6SArtur Paszkiewicz 
86646ff15a6SArtur Paszkiewicz 	for (i = 0; g_raid_state_names[i].name != NULL; i++) {
86746ff15a6SArtur Paszkiewicz 		if (g_raid_state_names[i].value == state) {
86846ff15a6SArtur Paszkiewicz 			return g_raid_state_names[i].name;
86946ff15a6SArtur Paszkiewicz 		}
87046ff15a6SArtur Paszkiewicz 	}
87146ff15a6SArtur Paszkiewicz 
87246ff15a6SArtur Paszkiewicz 	assert(false);
87346ff15a6SArtur Paszkiewicz 	return "";
87446ff15a6SArtur Paszkiewicz }
87546ff15a6SArtur Paszkiewicz 
87607fe6a43SSeth Howell /*
87707fe6a43SSeth Howell  * brief:
87807fe6a43SSeth Howell  * raid_bdev_fini_start is called when bdev layer is starting the
87907fe6a43SSeth Howell  * shutdown process
88007fe6a43SSeth Howell  * params:
88107fe6a43SSeth Howell  * none
88207fe6a43SSeth Howell  * returns:
88307fe6a43SSeth Howell  * none
88407fe6a43SSeth Howell  */
88507fe6a43SSeth Howell static void
88607fe6a43SSeth Howell raid_bdev_fini_start(void)
88707fe6a43SSeth Howell {
8882172c432STomasz Zawadzki 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_fini_start\n");
88907fe6a43SSeth Howell 	g_shutdown_started = true;
89007fe6a43SSeth Howell }
89107fe6a43SSeth Howell 
89207fe6a43SSeth Howell /*
89307fe6a43SSeth Howell  * brief:
89407fe6a43SSeth Howell  * raid_bdev_exit is called on raid bdev module exit time by bdev layer
89507fe6a43SSeth Howell  * params:
89607fe6a43SSeth Howell  * none
89707fe6a43SSeth Howell  * returns:
89807fe6a43SSeth Howell  * none
89907fe6a43SSeth Howell  */
90007fe6a43SSeth Howell static void
90107fe6a43SSeth Howell raid_bdev_exit(void)
90207fe6a43SSeth Howell {
903dccdd1e5SArtur Paszkiewicz 	struct raid_bdev *raid_bdev, *tmp;
90495a04949SArtur Paszkiewicz 
9052172c432STomasz Zawadzki 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_exit\n");
906dccdd1e5SArtur Paszkiewicz 
907dccdd1e5SArtur Paszkiewicz 	TAILQ_FOREACH_SAFE(raid_bdev, &g_raid_bdev_list, global_link, tmp) {
908dccdd1e5SArtur Paszkiewicz 		raid_bdev_cleanup_and_free(raid_bdev);
90995a04949SArtur Paszkiewicz 	}
91007fe6a43SSeth Howell }
91107fe6a43SSeth Howell 
91207fe6a43SSeth Howell /*
91307fe6a43SSeth Howell  * brief:
91407fe6a43SSeth Howell  * raid_bdev_get_ctx_size is used to return the context size of bdev_io for raid
91507fe6a43SSeth Howell  * module
91607fe6a43SSeth Howell  * params:
91707fe6a43SSeth Howell  * none
91807fe6a43SSeth Howell  * returns:
91907fe6a43SSeth Howell  * size of spdk_bdev_io context for raid
92007fe6a43SSeth Howell  */
92107fe6a43SSeth Howell static int
92207fe6a43SSeth Howell raid_bdev_get_ctx_size(void)
92307fe6a43SSeth Howell {
9242172c432STomasz Zawadzki 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_get_ctx_size\n");
92507fe6a43SSeth Howell 	return sizeof(struct raid_bdev_io);
92607fe6a43SSeth Howell }
92707fe6a43SSeth Howell 
92807fe6a43SSeth Howell static struct spdk_bdev_module g_raid_if = {
92907fe6a43SSeth Howell 	.name = "raid",
93007fe6a43SSeth Howell 	.module_init = raid_bdev_init,
93107fe6a43SSeth Howell 	.fini_start = raid_bdev_fini_start,
93207fe6a43SSeth Howell 	.module_fini = raid_bdev_exit,
93307fe6a43SSeth Howell 	.get_ctx_size = raid_bdev_get_ctx_size,
9348a6bb6a8SArtur Paszkiewicz 	.examine_disk = raid_bdev_examine,
93507fe6a43SSeth Howell 	.async_init = false,
93607fe6a43SSeth Howell 	.async_fini = false,
93707fe6a43SSeth Howell };
93807fe6a43SSeth Howell SPDK_BDEV_MODULE_REGISTER(raid, &g_raid_if)
93907fe6a43SSeth Howell 
94007fe6a43SSeth Howell /*
94107fe6a43SSeth Howell  * brief:
94207fe6a43SSeth Howell  * raid_bdev_init is the initialization function for raid bdev module
94307fe6a43SSeth Howell  * params:
94407fe6a43SSeth Howell  * none
94507fe6a43SSeth Howell  * returns:
94607fe6a43SSeth Howell  * 0 - success
94707fe6a43SSeth Howell  * non zero - failure
94807fe6a43SSeth Howell  */
94907fe6a43SSeth Howell static int
95007fe6a43SSeth Howell raid_bdev_init(void)
95107fe6a43SSeth Howell {
95207fe6a43SSeth Howell 	return 0;
95307fe6a43SSeth Howell }
95407fe6a43SSeth Howell 
95577b8f7b6SArtur Paszkiewicz static int
95677b8f7b6SArtur Paszkiewicz _raid_bdev_create(const char *name, uint32_t strip_size, uint8_t num_base_bdevs,
957deed7d2fSArtur Paszkiewicz 		  enum raid_level level, bool superblock_enabled, const struct spdk_uuid *uuid,
958deed7d2fSArtur Paszkiewicz 		  struct raid_bdev **raid_bdev_out)
95907fe6a43SSeth Howell {
96007fe6a43SSeth Howell 	struct raid_bdev *raid_bdev;
96107fe6a43SSeth Howell 	struct spdk_bdev *raid_bdev_gen;
9620a5194faSArtur Paszkiewicz 	struct raid_bdev_module *module;
96326861b70SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
964ad94094fSKrzysztof Smolinski 	uint8_t min_operational;
9650a5194faSArtur Paszkiewicz 
96677b8f7b6SArtur Paszkiewicz 	if (strnlen(name, RAID_BDEV_SB_NAME_SIZE) == RAID_BDEV_SB_NAME_SIZE) {
96777b8f7b6SArtur Paszkiewicz 		SPDK_ERRLOG("Raid bdev name '%s' exceeds %d characters\n", name, RAID_BDEV_SB_NAME_SIZE - 1);
96877b8f7b6SArtur Paszkiewicz 		return -EINVAL;
96977b8f7b6SArtur Paszkiewicz 	}
97077b8f7b6SArtur Paszkiewicz 
971dccdd1e5SArtur Paszkiewicz 	if (raid_bdev_find_by_name(name) != NULL) {
972dccdd1e5SArtur Paszkiewicz 		SPDK_ERRLOG("Duplicate raid bdev name found: %s\n", name);
973dccdd1e5SArtur Paszkiewicz 		return -EEXIST;
974dccdd1e5SArtur Paszkiewicz 	}
975dccdd1e5SArtur Paszkiewicz 
976208f21cdSKrzysztof Smolinski 	if (level == RAID1) {
977208f21cdSKrzysztof Smolinski 		if (strip_size != 0) {
978208f21cdSKrzysztof Smolinski 			SPDK_ERRLOG("Strip size is not supported by raid1\n");
979208f21cdSKrzysztof Smolinski 			return -EINVAL;
980208f21cdSKrzysztof Smolinski 		}
981208f21cdSKrzysztof Smolinski 	} else if (spdk_u32_is_pow2(strip_size) == false) {
982dccdd1e5SArtur Paszkiewicz 		SPDK_ERRLOG("Invalid strip size %" PRIu32 "\n", strip_size);
983dccdd1e5SArtur Paszkiewicz 		return -EINVAL;
984dccdd1e5SArtur Paszkiewicz 	}
985dccdd1e5SArtur Paszkiewicz 
986dccdd1e5SArtur Paszkiewicz 	module = raid_bdev_module_find(level);
9870a5194faSArtur Paszkiewicz 	if (module == NULL) {
988dccdd1e5SArtur Paszkiewicz 		SPDK_ERRLOG("Unsupported raid level '%d'\n", level);
9890a5194faSArtur Paszkiewicz 		return -EINVAL;
9900a5194faSArtur Paszkiewicz 	}
9910a5194faSArtur Paszkiewicz 
9920a5194faSArtur Paszkiewicz 	assert(module->base_bdevs_min != 0);
993dccdd1e5SArtur Paszkiewicz 	if (num_base_bdevs < module->base_bdevs_min) {
9940a5194faSArtur Paszkiewicz 		SPDK_ERRLOG("At least %u base devices required for %s\n",
9950a5194faSArtur Paszkiewicz 			    module->base_bdevs_min,
996dccdd1e5SArtur Paszkiewicz 			    raid_bdev_level_to_str(level));
9970a5194faSArtur Paszkiewicz 		return -EINVAL;
9980a5194faSArtur Paszkiewicz 	}
99907fe6a43SSeth Howell 
1000ad94094fSKrzysztof Smolinski 	switch (module->base_bdevs_constraint.type) {
1001ad94094fSKrzysztof Smolinski 	case CONSTRAINT_MAX_BASE_BDEVS_REMOVED:
1002ad94094fSKrzysztof Smolinski 		min_operational = num_base_bdevs - module->base_bdevs_constraint.value;
1003ad94094fSKrzysztof Smolinski 		break;
1004ad94094fSKrzysztof Smolinski 	case CONSTRAINT_MIN_BASE_BDEVS_OPERATIONAL:
1005ad94094fSKrzysztof Smolinski 		min_operational = module->base_bdevs_constraint.value;
1006ad94094fSKrzysztof Smolinski 		break;
1007ad94094fSKrzysztof Smolinski 	case CONSTRAINT_UNSET:
1008ad94094fSKrzysztof Smolinski 		if (module->base_bdevs_constraint.value != 0) {
1009ad94094fSKrzysztof Smolinski 			SPDK_ERRLOG("Unexpected constraint value '%u' provided for raid bdev '%s'.\n",
1010ad94094fSKrzysztof Smolinski 				    (uint8_t)module->base_bdevs_constraint.value, name);
1011ad94094fSKrzysztof Smolinski 			return -EINVAL;
1012ad94094fSKrzysztof Smolinski 		}
1013ad94094fSKrzysztof Smolinski 		min_operational = num_base_bdevs;
1014ad94094fSKrzysztof Smolinski 		break;
1015ad94094fSKrzysztof Smolinski 	default:
1016ad94094fSKrzysztof Smolinski 		SPDK_ERRLOG("Unrecognised constraint type '%u' in module for raid level '%s'.\n",
1017ad94094fSKrzysztof Smolinski 			    (uint8_t)module->base_bdevs_constraint.type,
1018ad94094fSKrzysztof Smolinski 			    raid_bdev_level_to_str(module->level));
1019ad94094fSKrzysztof Smolinski 		return -EINVAL;
1020ad94094fSKrzysztof Smolinski 	};
1021ad94094fSKrzysztof Smolinski 
1022ad94094fSKrzysztof Smolinski 	if (min_operational == 0 || min_operational > num_base_bdevs) {
1023ad94094fSKrzysztof Smolinski 		SPDK_ERRLOG("Wrong constraint value for raid level '%s'.\n",
1024ad94094fSKrzysztof Smolinski 			    raid_bdev_level_to_str(module->level));
1025ad94094fSKrzysztof Smolinski 		return -EINVAL;
1026ad94094fSKrzysztof Smolinski 	}
1027ad94094fSKrzysztof Smolinski 
102807fe6a43SSeth Howell 	raid_bdev = calloc(1, sizeof(*raid_bdev));
102907fe6a43SSeth Howell 	if (!raid_bdev) {
103007fe6a43SSeth Howell 		SPDK_ERRLOG("Unable to allocate memory for raid bdev\n");
103107fe6a43SSeth Howell 		return -ENOMEM;
103207fe6a43SSeth Howell 	}
103307fe6a43SSeth Howell 
1034fbdb05f0SArtur Paszkiewicz 	spdk_spin_init(&raid_bdev->base_bdev_lock);
10350a5194faSArtur Paszkiewicz 	raid_bdev->module = module;
1036dccdd1e5SArtur Paszkiewicz 	raid_bdev->num_base_bdevs = num_base_bdevs;
103707fe6a43SSeth Howell 	raid_bdev->base_bdev_info = calloc(raid_bdev->num_base_bdevs,
103807fe6a43SSeth Howell 					   sizeof(struct raid_base_bdev_info));
103907fe6a43SSeth Howell 	if (!raid_bdev->base_bdev_info) {
104007fe6a43SSeth Howell 		SPDK_ERRLOG("Unable able to allocate base bdev info\n");
1041fbdb05f0SArtur Paszkiewicz 		raid_bdev_free(raid_bdev);
104207fe6a43SSeth Howell 		return -ENOMEM;
104307fe6a43SSeth Howell 	}
104407fe6a43SSeth Howell 
104526861b70SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
104626861b70SArtur Paszkiewicz 		base_info->raid_bdev = raid_bdev;
104726861b70SArtur Paszkiewicz 	}
104826861b70SArtur Paszkiewicz 
104907fe6a43SSeth Howell 	/* strip_size_kb is from the rpc param.  strip_size is in blocks and used
105017f7cf9bSpaul luse 	 * internally and set later.
105107fe6a43SSeth Howell 	 */
105207fe6a43SSeth Howell 	raid_bdev->strip_size = 0;
1053dccdd1e5SArtur Paszkiewicz 	raid_bdev->strip_size_kb = strip_size;
105407fe6a43SSeth Howell 	raid_bdev->state = RAID_BDEV_STATE_CONFIGURING;
1055dccdd1e5SArtur Paszkiewicz 	raid_bdev->level = level;
1056ad94094fSKrzysztof Smolinski 	raid_bdev->min_base_bdevs_operational = min_operational;
105777b8f7b6SArtur Paszkiewicz 
105877b8f7b6SArtur Paszkiewicz 	if (superblock_enabled) {
105977b8f7b6SArtur Paszkiewicz 		raid_bdev->sb = spdk_dma_zmalloc(RAID_BDEV_SB_MAX_LENGTH, 0x1000, NULL);
106077b8f7b6SArtur Paszkiewicz 		if (!raid_bdev->sb) {
106177b8f7b6SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to allocate raid bdev sb buffer\n");
106277b8f7b6SArtur Paszkiewicz 			raid_bdev_free(raid_bdev);
106377b8f7b6SArtur Paszkiewicz 			return -ENOMEM;
106477b8f7b6SArtur Paszkiewicz 		}
106577b8f7b6SArtur Paszkiewicz 	}
1066576729edSpaul luse 
106707fe6a43SSeth Howell 	raid_bdev_gen = &raid_bdev->bdev;
106807fe6a43SSeth Howell 
1069dccdd1e5SArtur Paszkiewicz 	raid_bdev_gen->name = strdup(name);
107007fe6a43SSeth Howell 	if (!raid_bdev_gen->name) {
107107fe6a43SSeth Howell 		SPDK_ERRLOG("Unable to allocate name for raid\n");
1072fbdb05f0SArtur Paszkiewicz 		raid_bdev_free(raid_bdev);
107307fe6a43SSeth Howell 		return -ENOMEM;
107407fe6a43SSeth Howell 	}
107507fe6a43SSeth Howell 
107607fe6a43SSeth Howell 	raid_bdev_gen->product_name = "Raid Volume";
107707fe6a43SSeth Howell 	raid_bdev_gen->ctxt = raid_bdev;
107807fe6a43SSeth Howell 	raid_bdev_gen->fn_table = &g_raid_bdev_fn_table;
107907fe6a43SSeth Howell 	raid_bdev_gen->module = &g_raid_if;
108007fe6a43SSeth Howell 	raid_bdev_gen->write_cache = 0;
10811db41324SKrzysztof Karas 	spdk_uuid_copy(&raid_bdev_gen->uuid, uuid);
10821db41324SKrzysztof Karas 
108307fe6a43SSeth Howell 	TAILQ_INSERT_TAIL(&g_raid_bdev_list, raid_bdev, global_link);
108407fe6a43SSeth Howell 
1085dccdd1e5SArtur Paszkiewicz 	*raid_bdev_out = raid_bdev;
108607fe6a43SSeth Howell 
108707fe6a43SSeth Howell 	return 0;
108807fe6a43SSeth Howell }
108907fe6a43SSeth Howell 
109007fe6a43SSeth Howell /*
109107fe6a43SSeth Howell  * brief:
109277b8f7b6SArtur Paszkiewicz  * raid_bdev_create allocates raid bdev based on passed configuration
109377b8f7b6SArtur Paszkiewicz  * params:
109477b8f7b6SArtur Paszkiewicz  * name - name for raid bdev
109577b8f7b6SArtur Paszkiewicz  * strip_size - strip size in KB
109677b8f7b6SArtur Paszkiewicz  * num_base_bdevs - number of base bdevs
109777b8f7b6SArtur Paszkiewicz  * level - raid level
109877b8f7b6SArtur Paszkiewicz  * superblock_enabled - true if raid should have superblock
109977b8f7b6SArtur Paszkiewicz  * uuid - uuid to set for the bdev
110077b8f7b6SArtur Paszkiewicz  * raid_bdev_out - the created raid bdev
110177b8f7b6SArtur Paszkiewicz  * returns:
110277b8f7b6SArtur Paszkiewicz  * 0 - success
110377b8f7b6SArtur Paszkiewicz  * non zero - failure
110477b8f7b6SArtur Paszkiewicz  */
110577b8f7b6SArtur Paszkiewicz int
110677b8f7b6SArtur Paszkiewicz raid_bdev_create(const char *name, uint32_t strip_size, uint8_t num_base_bdevs,
110777b8f7b6SArtur Paszkiewicz 		 enum raid_level level, bool superblock_enabled, const struct spdk_uuid *uuid,
110877b8f7b6SArtur Paszkiewicz 		 struct raid_bdev **raid_bdev_out)
110977b8f7b6SArtur Paszkiewicz {
111077b8f7b6SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
111177b8f7b6SArtur Paszkiewicz 	int rc;
111277b8f7b6SArtur Paszkiewicz 
111377b8f7b6SArtur Paszkiewicz 	assert(uuid != NULL);
111477b8f7b6SArtur Paszkiewicz 
111577b8f7b6SArtur Paszkiewicz 	rc = _raid_bdev_create(name, strip_size, num_base_bdevs, level, superblock_enabled, uuid,
111677b8f7b6SArtur Paszkiewicz 			       &raid_bdev);
111777b8f7b6SArtur Paszkiewicz 	if (rc != 0) {
111877b8f7b6SArtur Paszkiewicz 		return rc;
111977b8f7b6SArtur Paszkiewicz 	}
112077b8f7b6SArtur Paszkiewicz 
112177b8f7b6SArtur Paszkiewicz 	if (superblock_enabled && spdk_uuid_is_null(uuid)) {
112277b8f7b6SArtur Paszkiewicz 		/* we need to have the uuid to store in the superblock before the bdev is registered */
112377b8f7b6SArtur Paszkiewicz 		spdk_uuid_generate(&raid_bdev->bdev.uuid);
112477b8f7b6SArtur Paszkiewicz 	}
112577b8f7b6SArtur Paszkiewicz 
112677b8f7b6SArtur Paszkiewicz 	*raid_bdev_out = raid_bdev;
112777b8f7b6SArtur Paszkiewicz 
112877b8f7b6SArtur Paszkiewicz 	return 0;
112977b8f7b6SArtur Paszkiewicz }
113077b8f7b6SArtur Paszkiewicz 
113177b8f7b6SArtur Paszkiewicz /*
113277b8f7b6SArtur Paszkiewicz  * brief:
1133357c038cSKrzysztof Smolinski  * Check underlying block devices against support for metadata. Do not configure
1134357c038cSKrzysztof Smolinski  * md support when parameters from block devices are inconsistent.
1135357c038cSKrzysztof Smolinski  * params:
1136357c038cSKrzysztof Smolinski  * raid_bdev - pointer to raid bdev
1137357c038cSKrzysztof Smolinski  * returns:
1138357c038cSKrzysztof Smolinski  * 0 - The raid bdev md parameters were successfully configured.
1139357c038cSKrzysztof Smolinski  * non zero - Failed to configure md.
1140357c038cSKrzysztof Smolinski  */
1141357c038cSKrzysztof Smolinski static int
1142357c038cSKrzysztof Smolinski raid_bdev_configure_md(struct raid_bdev *raid_bdev)
1143357c038cSKrzysztof Smolinski {
1144357c038cSKrzysztof Smolinski 	struct spdk_bdev *base_bdev;
1145357c038cSKrzysztof Smolinski 	uint8_t i;
1146357c038cSKrzysztof Smolinski 
1147357c038cSKrzysztof Smolinski 	for (i = 0; i < raid_bdev->num_base_bdevs; i++) {
11488d1993a5SArtur Paszkiewicz 		base_bdev = spdk_bdev_desc_get_bdev(raid_bdev->base_bdev_info[i].desc);
1149357c038cSKrzysztof Smolinski 
1150c91f8b18SSlawomir Ptak 		/* Currently, RAID bdevs do not support DIF or DIX, so a RAID bdev cannot
1151c91f8b18SSlawomir Ptak 		 * be created on top of any bdev which supports it */
1152c91f8b18SSlawomir Ptak 		if (spdk_bdev_get_dif_type(base_bdev) != SPDK_DIF_DISABLE) {
1153c91f8b18SSlawomir Ptak 			SPDK_ERRLOG("at least one base bdev has DIF or DIX enabled "
1154c91f8b18SSlawomir Ptak 				    "- unsupported RAID configuration\n");
1155c91f8b18SSlawomir Ptak 			return -EPERM;
1156c91f8b18SSlawomir Ptak 		}
1157c91f8b18SSlawomir Ptak 
1158357c038cSKrzysztof Smolinski 		if (i == 0) {
1159357c038cSKrzysztof Smolinski 			raid_bdev->bdev.md_len = spdk_bdev_get_md_size(base_bdev);
1160357c038cSKrzysztof Smolinski 			raid_bdev->bdev.md_interleave = spdk_bdev_is_md_interleaved(base_bdev);
1161357c038cSKrzysztof Smolinski 			continue;
1162357c038cSKrzysztof Smolinski 		}
1163357c038cSKrzysztof Smolinski 
1164357c038cSKrzysztof Smolinski 		if (raid_bdev->bdev.md_len != spdk_bdev_get_md_size(base_bdev) ||
1165c91f8b18SSlawomir Ptak 		    raid_bdev->bdev.md_interleave != spdk_bdev_is_md_interleaved(base_bdev)) {
1166357c038cSKrzysztof Smolinski 			SPDK_ERRLOG("base bdevs are configured with different metadata formats\n");
1167357c038cSKrzysztof Smolinski 			return -EPERM;
1168357c038cSKrzysztof Smolinski 		}
1169357c038cSKrzysztof Smolinski 	}
1170357c038cSKrzysztof Smolinski 
1171357c038cSKrzysztof Smolinski 	return 0;
1172357c038cSKrzysztof Smolinski }
1173357c038cSKrzysztof Smolinski 
117477b8f7b6SArtur Paszkiewicz static void
117577b8f7b6SArtur Paszkiewicz raid_bdev_configure_cont(struct raid_bdev *raid_bdev)
117677b8f7b6SArtur Paszkiewicz {
117777b8f7b6SArtur Paszkiewicz 	struct spdk_bdev *raid_bdev_gen = &raid_bdev->bdev;
117877b8f7b6SArtur Paszkiewicz 	int rc;
117977b8f7b6SArtur Paszkiewicz 
118077b8f7b6SArtur Paszkiewicz 	raid_bdev->state = RAID_BDEV_STATE_ONLINE;
118177b8f7b6SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "io device register %p\n", raid_bdev);
118277b8f7b6SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "blockcnt %" PRIu64 ", blocklen %u\n",
118377b8f7b6SArtur Paszkiewicz 		      raid_bdev_gen->blockcnt, raid_bdev_gen->blocklen);
118477b8f7b6SArtur Paszkiewicz 	spdk_io_device_register(raid_bdev, raid_bdev_create_cb, raid_bdev_destroy_cb,
118577b8f7b6SArtur Paszkiewicz 				sizeof(struct raid_bdev_io_channel),
118677b8f7b6SArtur Paszkiewicz 				raid_bdev_gen->name);
118777b8f7b6SArtur Paszkiewicz 	rc = spdk_bdev_register(raid_bdev_gen);
118877b8f7b6SArtur Paszkiewicz 	if (rc != 0) {
118977b8f7b6SArtur Paszkiewicz 		SPDK_ERRLOG("Unable to register raid bdev and stay at configuring state\n");
119077b8f7b6SArtur Paszkiewicz 		if (raid_bdev->module->stop != NULL) {
119177b8f7b6SArtur Paszkiewicz 			raid_bdev->module->stop(raid_bdev);
119277b8f7b6SArtur Paszkiewicz 		}
119377b8f7b6SArtur Paszkiewicz 		spdk_io_device_unregister(raid_bdev, NULL);
119477b8f7b6SArtur Paszkiewicz 		raid_bdev->state = RAID_BDEV_STATE_CONFIGURING;
119577b8f7b6SArtur Paszkiewicz 		return;
119677b8f7b6SArtur Paszkiewicz 	}
119777b8f7b6SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "raid bdev generic %p\n", raid_bdev_gen);
119877b8f7b6SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "raid bdev is created with name %s, raid_bdev %p\n",
119977b8f7b6SArtur Paszkiewicz 		      raid_bdev_gen->name, raid_bdev);
120077b8f7b6SArtur Paszkiewicz }
120177b8f7b6SArtur Paszkiewicz 
120277b8f7b6SArtur Paszkiewicz static void
120377b8f7b6SArtur Paszkiewicz raid_bdev_configure_write_sb_cb(int status, struct raid_bdev *raid_bdev, void *ctx)
120477b8f7b6SArtur Paszkiewicz {
120577b8f7b6SArtur Paszkiewicz 	if (status == 0) {
120677b8f7b6SArtur Paszkiewicz 		raid_bdev_configure_cont(raid_bdev);
120777b8f7b6SArtur Paszkiewicz 	} else {
120877b8f7b6SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to write raid bdev '%s' superblock: %s\n",
120977b8f7b6SArtur Paszkiewicz 			    raid_bdev->bdev.name, spdk_strerror(-status));
121077b8f7b6SArtur Paszkiewicz 		if (raid_bdev->module->stop != NULL) {
121177b8f7b6SArtur Paszkiewicz 			raid_bdev->module->stop(raid_bdev);
121277b8f7b6SArtur Paszkiewicz 		}
121377b8f7b6SArtur Paszkiewicz 	}
121477b8f7b6SArtur Paszkiewicz }
121577b8f7b6SArtur Paszkiewicz 
1216357c038cSKrzysztof Smolinski /*
1217357c038cSKrzysztof Smolinski  * brief:
121807fe6a43SSeth Howell  * If raid bdev config is complete, then only register the raid bdev to
121907fe6a43SSeth Howell  * bdev layer and remove this raid bdev from configuring list and
122007fe6a43SSeth Howell  * insert the raid bdev to configured list
122107fe6a43SSeth Howell  * params:
122207fe6a43SSeth Howell  * raid_bdev - pointer to raid bdev
122307fe6a43SSeth Howell  * returns:
122407fe6a43SSeth Howell  * 0 - success
122507fe6a43SSeth Howell  * non zero - failure
122607fe6a43SSeth Howell  */
122707fe6a43SSeth Howell static int
122807fe6a43SSeth Howell raid_bdev_configure(struct raid_bdev *raid_bdev)
122907fe6a43SSeth Howell {
1230a193dcb8SArtur Paszkiewicz 	uint32_t blocklen = 0;
1231a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
12328d1993a5SArtur Paszkiewicz 	struct spdk_bdev *base_bdev;
123307fe6a43SSeth Howell 	int rc = 0;
123407fe6a43SSeth Howell 
123594ea8754SArtur Paszkiewicz 	assert(raid_bdev->state == RAID_BDEV_STATE_CONFIGURING);
123694ea8754SArtur Paszkiewicz 	assert(raid_bdev->num_base_bdevs_discovered == raid_bdev->num_base_bdevs);
123794ea8754SArtur Paszkiewicz 
1238a193dcb8SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
12398d1993a5SArtur Paszkiewicz 		assert(base_info->desc != NULL);
12408d1993a5SArtur Paszkiewicz 		base_bdev = spdk_bdev_desc_get_bdev(base_info->desc);
124107fe6a43SSeth Howell 		/* Check blocklen for all base bdevs that it should be same */
1242a193dcb8SArtur Paszkiewicz 		if (blocklen == 0) {
12438d1993a5SArtur Paszkiewicz 			blocklen = base_bdev->blocklen;
12448d1993a5SArtur Paszkiewicz 		} else if (blocklen != base_bdev->blocklen) {
124507fe6a43SSeth Howell 			/*
124607fe6a43SSeth Howell 			 * Assumption is that all the base bdevs for any raid bdev should
124707fe6a43SSeth Howell 			 * have same blocklen
124807fe6a43SSeth Howell 			 */
124907fe6a43SSeth Howell 			SPDK_ERRLOG("Blocklen of various bdevs not matching\n");
125007fe6a43SSeth Howell 			return -EINVAL;
125107fe6a43SSeth Howell 		}
125207fe6a43SSeth Howell 	}
125379bde4d3SArtur Paszkiewicz 	assert(blocklen > 0);
125407fe6a43SSeth Howell 
125507fe6a43SSeth Howell 	/* The strip_size_kb is read in from user in KB. Convert to blocks here for
125607fe6a43SSeth Howell 	 * internal use.
125707fe6a43SSeth Howell 	 */
125807fe6a43SSeth Howell 	raid_bdev->strip_size = (raid_bdev->strip_size_kb * 1024) / blocklen;
125931ce6cd8SArtur Paszkiewicz 	if (raid_bdev->strip_size == 0 && raid_bdev->level != RAID1) {
126031ce6cd8SArtur Paszkiewicz 		SPDK_ERRLOG("Strip size cannot be smaller than the device block size\n");
126131ce6cd8SArtur Paszkiewicz 		return -EINVAL;
126231ce6cd8SArtur Paszkiewicz 	}
126307fe6a43SSeth Howell 	raid_bdev->strip_size_shift = spdk_u32log2(raid_bdev->strip_size);
126407fe6a43SSeth Howell 	raid_bdev->blocklen_shift = spdk_u32log2(blocklen);
126577b8f7b6SArtur Paszkiewicz 	raid_bdev->bdev.blocklen = blocklen;
12660b4ca522SArtur Paszkiewicz 
1267357c038cSKrzysztof Smolinski 	rc = raid_bdev_configure_md(raid_bdev);
1268357c038cSKrzysztof Smolinski 	if (rc != 0) {
1269357c038cSKrzysztof Smolinski 		SPDK_ERRLOG("raid metadata configuration failed\n");
1270357c038cSKrzysztof Smolinski 		return rc;
1271357c038cSKrzysztof Smolinski 	}
1272357c038cSKrzysztof Smolinski 
12730b4ca522SArtur Paszkiewicz 	rc = raid_bdev->module->start(raid_bdev);
12740b4ca522SArtur Paszkiewicz 	if (rc != 0) {
12750b4ca522SArtur Paszkiewicz 		SPDK_ERRLOG("raid module startup callback failed\n");
12760b4ca522SArtur Paszkiewicz 		return rc;
127707fe6a43SSeth Howell 	}
127877b8f7b6SArtur Paszkiewicz 
127977b8f7b6SArtur Paszkiewicz 	if (raid_bdev->sb != NULL) {
12808a6bb6a8SArtur Paszkiewicz 		if (spdk_uuid_is_null(&raid_bdev->sb->uuid)) {
12818a6bb6a8SArtur Paszkiewicz 			/* NULL UUID is not valid in the sb so it means that we are creating a new
12828a6bb6a8SArtur Paszkiewicz 			 * raid bdev and should initialize the superblock.
12838a6bb6a8SArtur Paszkiewicz 			 */
128477b8f7b6SArtur Paszkiewicz 			raid_bdev_init_superblock(raid_bdev);
12858a6bb6a8SArtur Paszkiewicz 		} else {
12868a6bb6a8SArtur Paszkiewicz 			assert(spdk_uuid_compare(&raid_bdev->sb->uuid, &raid_bdev->bdev.uuid) == 0);
12878a6bb6a8SArtur Paszkiewicz 			if (raid_bdev->sb->block_size != blocklen) {
12888a6bb6a8SArtur Paszkiewicz 				SPDK_ERRLOG("blocklen does not match value in superblock\n");
12898a6bb6a8SArtur Paszkiewicz 				rc = -EINVAL;
12908a6bb6a8SArtur Paszkiewicz 			}
12918a6bb6a8SArtur Paszkiewicz 			if (raid_bdev->sb->raid_size != raid_bdev->bdev.blockcnt) {
12928a6bb6a8SArtur Paszkiewicz 				SPDK_ERRLOG("blockcnt does not match value in superblock\n");
12938a6bb6a8SArtur Paszkiewicz 				rc = -EINVAL;
12948a6bb6a8SArtur Paszkiewicz 			}
12958a6bb6a8SArtur Paszkiewicz 			if (rc != 0) {
12968a6bb6a8SArtur Paszkiewicz 				if (raid_bdev->module->stop != NULL) {
12978a6bb6a8SArtur Paszkiewicz 					raid_bdev->module->stop(raid_bdev);
12988a6bb6a8SArtur Paszkiewicz 				}
12998a6bb6a8SArtur Paszkiewicz 				return rc;
13008a6bb6a8SArtur Paszkiewicz 			}
13018a6bb6a8SArtur Paszkiewicz 		}
13028a6bb6a8SArtur Paszkiewicz 
130377b8f7b6SArtur Paszkiewicz 		raid_bdev_write_superblock(raid_bdev, raid_bdev_configure_write_sb_cb, NULL);
130477b8f7b6SArtur Paszkiewicz 	} else {
130577b8f7b6SArtur Paszkiewicz 		raid_bdev_configure_cont(raid_bdev);
13060b4ca522SArtur Paszkiewicz 	}
130707fe6a43SSeth Howell 
130807fe6a43SSeth Howell 	return 0;
130907fe6a43SSeth Howell }
131007fe6a43SSeth Howell 
131107fe6a43SSeth Howell /*
131207fe6a43SSeth Howell  * brief:
131307fe6a43SSeth Howell  * If raid bdev is online and registered, change the bdev state to
131407fe6a43SSeth Howell  * configuring and unregister this raid device. Queue this raid device
131507fe6a43SSeth Howell  * in configuring list
131607fe6a43SSeth Howell  * params:
131707fe6a43SSeth Howell  * raid_bdev - pointer to raid bdev
131807fe6a43SSeth Howell  * cb_fn - callback function
131907fe6a43SSeth Howell  * cb_arg - argument to callback function
132007fe6a43SSeth Howell  * returns:
132107fe6a43SSeth Howell  * none
132207fe6a43SSeth Howell  */
132307fe6a43SSeth Howell static void
132407fe6a43SSeth Howell raid_bdev_deconfigure(struct raid_bdev *raid_bdev, raid_bdev_destruct_cb cb_fn,
132507fe6a43SSeth Howell 		      void *cb_arg)
132607fe6a43SSeth Howell {
132707fe6a43SSeth Howell 	if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) {
132807fe6a43SSeth Howell 		if (cb_fn) {
132907fe6a43SSeth Howell 			cb_fn(cb_arg, 0);
133007fe6a43SSeth Howell 		}
133107fe6a43SSeth Howell 		return;
133207fe6a43SSeth Howell 	}
133307fe6a43SSeth Howell 
133407fe6a43SSeth Howell 	raid_bdev->state = RAID_BDEV_STATE_OFFLINE;
133507fe6a43SSeth Howell 	assert(raid_bdev->num_base_bdevs_discovered);
13361960ef16SJosh Soref 	SPDK_DEBUGLOG(bdev_raid, "raid bdev state changing from online to offline\n");
133707fe6a43SSeth Howell 
133807fe6a43SSeth Howell 	spdk_bdev_unregister(&raid_bdev->bdev, cb_fn, cb_arg);
133907fe6a43SSeth Howell }
134007fe6a43SSeth Howell 
134107fe6a43SSeth Howell /*
134207fe6a43SSeth Howell  * brief:
134326861b70SArtur Paszkiewicz  * raid_bdev_find_base_info_by_bdev function finds the base bdev info by bdev.
134407fe6a43SSeth Howell  * params:
134526861b70SArtur Paszkiewicz  * base_bdev - pointer to base bdev
134607fe6a43SSeth Howell  * returns:
134726861b70SArtur Paszkiewicz  * base bdev info if found, otherwise NULL.
134807fe6a43SSeth Howell  */
134926861b70SArtur Paszkiewicz static struct raid_base_bdev_info *
135026861b70SArtur Paszkiewicz raid_bdev_find_base_info_by_bdev(struct spdk_bdev *base_bdev)
135107fe6a43SSeth Howell {
135207fe6a43SSeth Howell 	struct raid_bdev *raid_bdev;
1353a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
135407fe6a43SSeth Howell 
135507fe6a43SSeth Howell 	TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) {
1356a193dcb8SArtur Paszkiewicz 		RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
13578d1993a5SArtur Paszkiewicz 			if (base_info->desc != NULL &&
13588d1993a5SArtur Paszkiewicz 			    spdk_bdev_desc_get_bdev(base_info->desc) == base_bdev) {
135926861b70SArtur Paszkiewicz 				return base_info;
136007fe6a43SSeth Howell 			}
136107fe6a43SSeth Howell 		}
136207fe6a43SSeth Howell 	}
136307fe6a43SSeth Howell 
136426861b70SArtur Paszkiewicz 	return NULL;
136507fe6a43SSeth Howell }
136607fe6a43SSeth Howell 
1367b42cb0e5SArtur Paszkiewicz static void
1368b42cb0e5SArtur Paszkiewicz raid_bdev_remove_base_bdev_on_unquiesced(void *ctx, int status)
1369b42cb0e5SArtur Paszkiewicz {
1370b42cb0e5SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = ctx;
1371b42cb0e5SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
1372b42cb0e5SArtur Paszkiewicz 
1373b42cb0e5SArtur Paszkiewicz 	base_info->remove_scheduled = false;
1374b42cb0e5SArtur Paszkiewicz 
1375b42cb0e5SArtur Paszkiewicz 	if (status != 0) {
1376b42cb0e5SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to unquiesce raid bdev %s: %s\n",
1377b42cb0e5SArtur Paszkiewicz 			    raid_bdev->bdev.name, spdk_strerror(-status));
137823850b03SKrzysztof Smolinski 		goto out;
1379b42cb0e5SArtur Paszkiewicz 	}
1380b42cb0e5SArtur Paszkiewicz 
1381b42cb0e5SArtur Paszkiewicz 	spdk_spin_lock(&raid_bdev->base_bdev_lock);
1382b42cb0e5SArtur Paszkiewicz 	raid_bdev_free_base_bdev_resource(base_info);
1383b42cb0e5SArtur Paszkiewicz 	spdk_spin_unlock(&raid_bdev->base_bdev_lock);
138423850b03SKrzysztof Smolinski out:
138523850b03SKrzysztof Smolinski 	if (base_info->remove_cb != NULL) {
138623850b03SKrzysztof Smolinski 		base_info->remove_cb(base_info->remove_cb_ctx, status);
138723850b03SKrzysztof Smolinski 	}
1388b42cb0e5SArtur Paszkiewicz }
1389b42cb0e5SArtur Paszkiewicz 
1390b42cb0e5SArtur Paszkiewicz static void
1391b42cb0e5SArtur Paszkiewicz raid_bdev_channel_remove_base_bdev(struct spdk_io_channel_iter *i)
1392b42cb0e5SArtur Paszkiewicz {
1393b42cb0e5SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = spdk_io_channel_iter_get_ctx(i);
1394b42cb0e5SArtur Paszkiewicz 	struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
1395b42cb0e5SArtur Paszkiewicz 	struct raid_bdev_io_channel *raid_ch = spdk_io_channel_get_ctx(ch);
1396b42cb0e5SArtur Paszkiewicz 	uint8_t idx = base_info - base_info->raid_bdev->base_bdev_info;
1397b42cb0e5SArtur Paszkiewicz 
1398b42cb0e5SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "slot: %u raid_ch: %p\n", idx, raid_ch);
1399b42cb0e5SArtur Paszkiewicz 
1400b42cb0e5SArtur Paszkiewicz 	if (raid_ch->base_channel[idx] != NULL) {
1401b42cb0e5SArtur Paszkiewicz 		spdk_put_io_channel(raid_ch->base_channel[idx]);
1402b42cb0e5SArtur Paszkiewicz 		raid_ch->base_channel[idx] = NULL;
1403b42cb0e5SArtur Paszkiewicz 	}
1404b42cb0e5SArtur Paszkiewicz 
1405b42cb0e5SArtur Paszkiewicz 	spdk_for_each_channel_continue(i, 0);
1406b42cb0e5SArtur Paszkiewicz }
1407b42cb0e5SArtur Paszkiewicz 
1408b42cb0e5SArtur Paszkiewicz static void
1409b42cb0e5SArtur Paszkiewicz raid_bdev_channels_remove_base_bdev_done(struct spdk_io_channel_iter *i, int status)
1410b42cb0e5SArtur Paszkiewicz {
1411b42cb0e5SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = spdk_io_channel_iter_get_ctx(i);
1412b42cb0e5SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
1413b42cb0e5SArtur Paszkiewicz 
1414b42cb0e5SArtur Paszkiewicz 	spdk_bdev_unquiesce(&raid_bdev->bdev, &g_raid_if, raid_bdev_remove_base_bdev_on_unquiesced,
1415b42cb0e5SArtur Paszkiewicz 			    base_info);
1416b42cb0e5SArtur Paszkiewicz }
1417b42cb0e5SArtur Paszkiewicz 
1418b42cb0e5SArtur Paszkiewicz static void
1419b42cb0e5SArtur Paszkiewicz raid_bdev_remove_base_bdev_on_quiesced(void *ctx, int status)
1420b42cb0e5SArtur Paszkiewicz {
1421b42cb0e5SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = ctx;
1422b42cb0e5SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
1423b42cb0e5SArtur Paszkiewicz 
1424b42cb0e5SArtur Paszkiewicz 	if (status != 0) {
1425b42cb0e5SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to quiesce raid bdev %s: %s\n",
1426b42cb0e5SArtur Paszkiewicz 			    raid_bdev->bdev.name, spdk_strerror(-status));
1427b42cb0e5SArtur Paszkiewicz 		base_info->remove_scheduled = false;
142823850b03SKrzysztof Smolinski 		if (base_info->remove_cb != NULL) {
142923850b03SKrzysztof Smolinski 			base_info->remove_cb(base_info->remove_cb_ctx, status);
143023850b03SKrzysztof Smolinski 		}
1431b42cb0e5SArtur Paszkiewicz 		return;
1432b42cb0e5SArtur Paszkiewicz 	}
1433b42cb0e5SArtur Paszkiewicz 
1434b42cb0e5SArtur Paszkiewicz 	spdk_for_each_channel(raid_bdev, raid_bdev_channel_remove_base_bdev, base_info,
1435b42cb0e5SArtur Paszkiewicz 			      raid_bdev_channels_remove_base_bdev_done);
1436b42cb0e5SArtur Paszkiewicz }
1437b42cb0e5SArtur Paszkiewicz 
143807fe6a43SSeth Howell /*
143907fe6a43SSeth Howell  * brief:
144007fe6a43SSeth Howell  * raid_bdev_remove_base_bdev function is called by below layers when base_bdev
144107fe6a43SSeth Howell  * is removed. This function checks if this base bdev is part of any raid bdev
144207fe6a43SSeth Howell  * or not. If yes, it takes necessary action on that particular raid bdev.
144307fe6a43SSeth Howell  * params:
1444c9224e26SShuhei Matsumoto  * base_bdev - pointer to base bdev which got removed
144523850b03SKrzysztof Smolinski  * cb_fn - callback function
144623850b03SKrzysztof Smolinski  * cb_arg - argument to callback function
144707fe6a43SSeth Howell  * returns:
1448b42cb0e5SArtur Paszkiewicz  * 0 - success
1449b42cb0e5SArtur Paszkiewicz  * non zero - failure
145007fe6a43SSeth Howell  */
145123850b03SKrzysztof Smolinski int
145223850b03SKrzysztof Smolinski raid_bdev_remove_base_bdev(struct spdk_bdev *base_bdev, raid_bdev_remove_base_bdev_cb cb_fn,
145323850b03SKrzysztof Smolinski 			   void *cb_ctx)
145407fe6a43SSeth Howell {
145526861b70SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
1456a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
145707fe6a43SSeth Howell 
1458b42cb0e5SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "%s\n", base_bdev->name);
145907fe6a43SSeth Howell 
146007fe6a43SSeth Howell 	/* Find the raid_bdev which has claimed this base_bdev */
146126861b70SArtur Paszkiewicz 	base_info = raid_bdev_find_base_info_by_bdev(base_bdev);
146226861b70SArtur Paszkiewicz 	if (!base_info) {
146307fe6a43SSeth Howell 		SPDK_ERRLOG("bdev to remove '%s' not found\n", base_bdev->name);
1464b42cb0e5SArtur Paszkiewicz 		return -ENODEV;
146507fe6a43SSeth Howell 	}
146626861b70SArtur Paszkiewicz 	raid_bdev = base_info->raid_bdev;
146707fe6a43SSeth Howell 
14684dd2a0d3SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
14694dd2a0d3SArtur Paszkiewicz 
1470b42cb0e5SArtur Paszkiewicz 	if (base_info->remove_scheduled) {
1471b42cb0e5SArtur Paszkiewicz 		return 0;
1472b42cb0e5SArtur Paszkiewicz 	}
1473b42cb0e5SArtur Paszkiewicz 
1474a193dcb8SArtur Paszkiewicz 	assert(base_info->desc);
1475a193dcb8SArtur Paszkiewicz 	base_info->remove_scheduled = true;
147623850b03SKrzysztof Smolinski 	base_info->remove_cb = cb_fn;
147723850b03SKrzysztof Smolinski 	base_info->remove_cb_ctx = cb_ctx;
147807fe6a43SSeth Howell 
14794ad1ac90SArtur Paszkiewicz 	if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) {
148007fe6a43SSeth Howell 		/*
148107fe6a43SSeth Howell 		 * As raid bdev is not registered yet or already unregistered,
148207fe6a43SSeth Howell 		 * so cleanup should be done here itself.
148307fe6a43SSeth Howell 		 */
148426861b70SArtur Paszkiewicz 		raid_bdev_free_base_bdev_resource(base_info);
148507fe6a43SSeth Howell 		if (raid_bdev->num_base_bdevs_discovered == 0) {
148607fe6a43SSeth Howell 			/* There is no base bdev for this raid, so free the raid device. */
148795a04949SArtur Paszkiewicz 			raid_bdev_cleanup_and_free(raid_bdev);
1488b42cb0e5SArtur Paszkiewicz 		}
1489b42cb0e5SArtur Paszkiewicz 	} else if (raid_bdev->num_base_bdevs_discovered == raid_bdev->min_base_bdevs_operational) {
1490b42cb0e5SArtur Paszkiewicz 		/*
1491b42cb0e5SArtur Paszkiewicz 		 * After this base bdev is removed there will not be enough base bdevs
1492b42cb0e5SArtur Paszkiewicz 		 * to keep the raid bdev operational.
1493b42cb0e5SArtur Paszkiewicz 		 */
149423850b03SKrzysztof Smolinski 		raid_bdev_deconfigure(raid_bdev, cb_fn, cb_ctx);
1495b42cb0e5SArtur Paszkiewicz 	} else {
1496b42cb0e5SArtur Paszkiewicz 		int ret;
1497b42cb0e5SArtur Paszkiewicz 
1498b42cb0e5SArtur Paszkiewicz 		ret = spdk_bdev_quiesce(&raid_bdev->bdev, &g_raid_if,
1499b42cb0e5SArtur Paszkiewicz 					raid_bdev_remove_base_bdev_on_quiesced, base_info);
1500b42cb0e5SArtur Paszkiewicz 		if (ret != 0) {
1501b42cb0e5SArtur Paszkiewicz 			base_info->remove_scheduled = false;
150207fe6a43SSeth Howell 		}
150307fe6a43SSeth Howell 	}
150407fe6a43SSeth Howell 
1505b42cb0e5SArtur Paszkiewicz 	return 0;
150607fe6a43SSeth Howell }
150707fe6a43SSeth Howell 
150807fe6a43SSeth Howell /*
150907fe6a43SSeth Howell  * brief:
1510c9224e26SShuhei Matsumoto  * raid_bdev_resize_base_bdev function is called by below layers when base_bdev
1511c9224e26SShuhei Matsumoto  * is resized. This function checks if the smallest size of the base_bdevs is changed.
1512c9224e26SShuhei Matsumoto  * If yes, call module handler to resize the raid_bdev if implemented.
1513c9224e26SShuhei Matsumoto  * params:
1514c9224e26SShuhei Matsumoto  * base_bdev - pointer to base bdev which got resized.
1515c9224e26SShuhei Matsumoto  * returns:
1516c9224e26SShuhei Matsumoto  * none
1517c9224e26SShuhei Matsumoto  */
1518c9224e26SShuhei Matsumoto static void
1519c9224e26SShuhei Matsumoto raid_bdev_resize_base_bdev(struct spdk_bdev *base_bdev)
1520c9224e26SShuhei Matsumoto {
152126861b70SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
1522c9224e26SShuhei Matsumoto 	struct raid_base_bdev_info *base_info;
1523c9224e26SShuhei Matsumoto 
1524c9224e26SShuhei Matsumoto 	SPDK_DEBUGLOG(bdev_raid, "raid_bdev_resize_base_bdev\n");
1525c9224e26SShuhei Matsumoto 
152626861b70SArtur Paszkiewicz 	base_info = raid_bdev_find_base_info_by_bdev(base_bdev);
152726861b70SArtur Paszkiewicz 
1528c9224e26SShuhei Matsumoto 	/* Find the raid_bdev which has claimed this base_bdev */
152926861b70SArtur Paszkiewicz 	if (!base_info) {
1530c9224e26SShuhei Matsumoto 		SPDK_ERRLOG("raid_bdev whose base_bdev '%s' not found\n", base_bdev->name);
1531c9224e26SShuhei Matsumoto 		return;
1532c9224e26SShuhei Matsumoto 	}
153326861b70SArtur Paszkiewicz 	raid_bdev = base_info->raid_bdev;
1534c9224e26SShuhei Matsumoto 
1535c9224e26SShuhei Matsumoto 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
1536c9224e26SShuhei Matsumoto 
1537c9224e26SShuhei Matsumoto 	SPDK_NOTICELOG("base_bdev '%s' was resized: old size %" PRIu64 ", new size %" PRIu64 "\n",
1538c9224e26SShuhei Matsumoto 		       base_bdev->name, base_info->blockcnt, base_bdev->blockcnt);
1539c9224e26SShuhei Matsumoto 
1540c9224e26SShuhei Matsumoto 	if (raid_bdev->module->resize) {
1541c9224e26SShuhei Matsumoto 		raid_bdev->module->resize(raid_bdev);
1542c9224e26SShuhei Matsumoto 	}
1543c9224e26SShuhei Matsumoto }
1544c9224e26SShuhei Matsumoto 
1545c9224e26SShuhei Matsumoto /*
1546c9224e26SShuhei Matsumoto  * brief:
1547d8a18924SShuhei Matsumoto  * raid_bdev_event_base_bdev function is called by below layers when base_bdev
1548d8a18924SShuhei Matsumoto  * triggers asynchronous event.
1549d8a18924SShuhei Matsumoto  * params:
1550d8a18924SShuhei Matsumoto  * type - event details.
1551d8a18924SShuhei Matsumoto  * bdev - bdev that triggered event.
1552d8a18924SShuhei Matsumoto  * event_ctx - context for event.
1553d8a18924SShuhei Matsumoto  * returns:
1554d8a18924SShuhei Matsumoto  * none
1555d8a18924SShuhei Matsumoto  */
1556d8a18924SShuhei Matsumoto static void
1557d8a18924SShuhei Matsumoto raid_bdev_event_base_bdev(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
1558d8a18924SShuhei Matsumoto 			  void *event_ctx)
1559d8a18924SShuhei Matsumoto {
1560b42cb0e5SArtur Paszkiewicz 	int rc;
1561b42cb0e5SArtur Paszkiewicz 
1562d8a18924SShuhei Matsumoto 	switch (type) {
1563d8a18924SShuhei Matsumoto 	case SPDK_BDEV_EVENT_REMOVE:
156423850b03SKrzysztof Smolinski 		rc = raid_bdev_remove_base_bdev(bdev, NULL, NULL);
1565b42cb0e5SArtur Paszkiewicz 		if (rc != 0) {
1566b42cb0e5SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to remove base bdev %s: %s\n",
1567b42cb0e5SArtur Paszkiewicz 				    spdk_bdev_get_name(bdev), spdk_strerror(-rc));
1568b42cb0e5SArtur Paszkiewicz 		}
1569d8a18924SShuhei Matsumoto 		break;
1570c9224e26SShuhei Matsumoto 	case SPDK_BDEV_EVENT_RESIZE:
1571c9224e26SShuhei Matsumoto 		raid_bdev_resize_base_bdev(bdev);
1572c9224e26SShuhei Matsumoto 		break;
1573d8a18924SShuhei Matsumoto 	default:
1574d8a18924SShuhei Matsumoto 		SPDK_NOTICELOG("Unsupported bdev event: type %d\n", type);
1575d8a18924SShuhei Matsumoto 		break;
1576d8a18924SShuhei Matsumoto 	}
1577d8a18924SShuhei Matsumoto }
1578d8a18924SShuhei Matsumoto 
1579d8a18924SShuhei Matsumoto /*
1580d8a18924SShuhei Matsumoto  * brief:
1581dccdd1e5SArtur Paszkiewicz  * Deletes the specified raid bdev
158207fe6a43SSeth Howell  * params:
1583dccdd1e5SArtur Paszkiewicz  * raid_bdev - pointer to raid bdev
158407fe6a43SSeth Howell  * cb_fn - callback function
1585dccdd1e5SArtur Paszkiewicz  * cb_arg - argument to callback function
158607fe6a43SSeth Howell  */
158707fe6a43SSeth Howell void
1588dccdd1e5SArtur Paszkiewicz raid_bdev_delete(struct raid_bdev *raid_bdev, raid_bdev_destruct_cb cb_fn, void *cb_arg)
158907fe6a43SSeth Howell {
1590a193dcb8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
159107fe6a43SSeth Howell 
1592dccdd1e5SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "delete raid bdev: %s\n", raid_bdev->bdev.name);
159307fe6a43SSeth Howell 
159407fe6a43SSeth Howell 	if (raid_bdev->destroy_started) {
15952172c432STomasz Zawadzki 		SPDK_DEBUGLOG(bdev_raid, "destroying raid bdev %s is already started\n",
1596dccdd1e5SArtur Paszkiewicz 			      raid_bdev->bdev.name);
159707fe6a43SSeth Howell 		if (cb_fn) {
159807fe6a43SSeth Howell 			cb_fn(cb_arg, -EALREADY);
159907fe6a43SSeth Howell 		}
160007fe6a43SSeth Howell 		return;
160107fe6a43SSeth Howell 	}
160207fe6a43SSeth Howell 
160307fe6a43SSeth Howell 	raid_bdev->destroy_started = true;
160407fe6a43SSeth Howell 
1605a193dcb8SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
1606a193dcb8SArtur Paszkiewicz 		base_info->remove_scheduled = true;
160707fe6a43SSeth Howell 
16084ad1ac90SArtur Paszkiewicz 		if (raid_bdev->state != RAID_BDEV_STATE_ONLINE) {
160907fe6a43SSeth Howell 			/*
161007fe6a43SSeth Howell 			 * As raid bdev is not registered yet or already unregistered,
161107fe6a43SSeth Howell 			 * so cleanup should be done here itself.
161207fe6a43SSeth Howell 			 */
161326861b70SArtur Paszkiewicz 			raid_bdev_free_base_bdev_resource(base_info);
1614df1e07e9SGangCao 		}
1615df1e07e9SGangCao 	}
1616df1e07e9SGangCao 
161707fe6a43SSeth Howell 	if (raid_bdev->num_base_bdevs_discovered == 0) {
161807fe6a43SSeth Howell 		/* There is no base bdev for this raid, so free the raid device. */
161995a04949SArtur Paszkiewicz 		raid_bdev_cleanup_and_free(raid_bdev);
162007fe6a43SSeth Howell 		if (cb_fn) {
162107fe6a43SSeth Howell 			cb_fn(cb_arg, 0);
162207fe6a43SSeth Howell 		}
1623df1e07e9SGangCao 	} else {
162407fe6a43SSeth Howell 		raid_bdev_deconfigure(raid_bdev, cb_fn, cb_arg);
162507fe6a43SSeth Howell 	}
1626df1e07e9SGangCao }
162707fe6a43SSeth Howell 
16289222ff97SArtur Paszkiewicz static void
16299222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_cont(struct raid_base_bdev_info *base_info)
16309222ff97SArtur Paszkiewicz {
16319222ff97SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
16329222ff97SArtur Paszkiewicz 	int rc;
16339222ff97SArtur Paszkiewicz 
16349222ff97SArtur Paszkiewicz 	base_info->is_configured = true;
16359222ff97SArtur Paszkiewicz 
16369222ff97SArtur Paszkiewicz 	raid_bdev->num_base_bdevs_discovered++;
16379222ff97SArtur Paszkiewicz 	assert(raid_bdev->num_base_bdevs_discovered <= raid_bdev->num_base_bdevs);
16389222ff97SArtur Paszkiewicz 
16399222ff97SArtur Paszkiewicz 	if (raid_bdev->num_base_bdevs_discovered == raid_bdev->num_base_bdevs) {
16409222ff97SArtur Paszkiewicz 		rc = raid_bdev_configure(raid_bdev);
16419222ff97SArtur Paszkiewicz 		if (rc != 0) {
16429222ff97SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to configure raid bdev: %s\n", spdk_strerror(-rc));
16439222ff97SArtur Paszkiewicz 		}
16449222ff97SArtur Paszkiewicz 	}
16459222ff97SArtur Paszkiewicz }
16469222ff97SArtur Paszkiewicz 
16479222ff97SArtur Paszkiewicz static void
16489222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev_check_sb_cb(const struct raid_bdev_superblock *sb, int status,
16499222ff97SArtur Paszkiewicz 		void *ctx)
16509222ff97SArtur Paszkiewicz {
16519222ff97SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info = ctx;
16529222ff97SArtur Paszkiewicz 
16539222ff97SArtur Paszkiewicz 	switch (status) {
16549222ff97SArtur Paszkiewicz 	case 0:
16559222ff97SArtur Paszkiewicz 		/* valid superblock found */
16569222ff97SArtur Paszkiewicz 		SPDK_ERRLOG("Existing raid superblock found on bdev %s\n", base_info->name);
16579222ff97SArtur Paszkiewicz 		raid_bdev_free_base_bdev_resource(base_info);
16589222ff97SArtur Paszkiewicz 		break;
16599222ff97SArtur Paszkiewicz 	case -EINVAL:
16609222ff97SArtur Paszkiewicz 		/* no valid superblock */
16619222ff97SArtur Paszkiewicz 		raid_bdev_configure_base_bdev_cont(base_info);
16629222ff97SArtur Paszkiewicz 		break;
16639222ff97SArtur Paszkiewicz 	default:
16649222ff97SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to examine bdev %s: %s\n",
16659222ff97SArtur Paszkiewicz 			    base_info->name, spdk_strerror(-status));
16669222ff97SArtur Paszkiewicz 		break;
16679222ff97SArtur Paszkiewicz 	}
16689222ff97SArtur Paszkiewicz }
16699222ff97SArtur Paszkiewicz 
167007fe6a43SSeth Howell static int
16719222ff97SArtur Paszkiewicz raid_bdev_configure_base_bdev(struct raid_base_bdev_info *base_info, bool existing)
167207fe6a43SSeth Howell {
167326861b70SArtur Paszkiewicz 	struct raid_bdev *raid_bdev = base_info->raid_bdev;
1674dccdd1e5SArtur Paszkiewicz 	struct spdk_bdev_desc *desc;
1675dccdd1e5SArtur Paszkiewicz 	struct spdk_bdev *bdev;
16768a6bb6a8SArtur Paszkiewicz 	const struct spdk_uuid *bdev_uuid;
167707fe6a43SSeth Howell 	int rc;
167807fe6a43SSeth Howell 
16794dd2a0d3SArtur Paszkiewicz 	assert(spdk_get_thread() == spdk_thread_get_app_thread());
16808d1993a5SArtur Paszkiewicz 	assert(base_info->desc == NULL);
168107fe6a43SSeth Howell 
16828a6bb6a8SArtur Paszkiewicz 	/*
16838a6bb6a8SArtur Paszkiewicz 	 * Base bdev can be added by name or uuid. Here we assure both properties are set and valid
16848a6bb6a8SArtur Paszkiewicz 	 * before claiming the bdev.
16858a6bb6a8SArtur Paszkiewicz 	 */
16868a6bb6a8SArtur Paszkiewicz 
16878a6bb6a8SArtur Paszkiewicz 	if (!spdk_uuid_is_null(&base_info->uuid)) {
16888a6bb6a8SArtur Paszkiewicz 		char uuid_str[SPDK_UUID_STRING_LEN];
16898a6bb6a8SArtur Paszkiewicz 		const char *bdev_name;
16908a6bb6a8SArtur Paszkiewicz 
16918a6bb6a8SArtur Paszkiewicz 		spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &base_info->uuid);
16928a6bb6a8SArtur Paszkiewicz 
16938a6bb6a8SArtur Paszkiewicz 		/* UUID of a bdev is registered as its alias */
16948a6bb6a8SArtur Paszkiewicz 		bdev = spdk_bdev_get_by_name(uuid_str);
16958a6bb6a8SArtur Paszkiewicz 		if (bdev == NULL) {
16968a6bb6a8SArtur Paszkiewicz 			return -ENODEV;
16978a6bb6a8SArtur Paszkiewicz 		}
16988a6bb6a8SArtur Paszkiewicz 
16998a6bb6a8SArtur Paszkiewicz 		bdev_name = spdk_bdev_get_name(bdev);
17008a6bb6a8SArtur Paszkiewicz 
17018a6bb6a8SArtur Paszkiewicz 		if (base_info->name == NULL) {
17029222ff97SArtur Paszkiewicz 			assert(existing == true);
17038a6bb6a8SArtur Paszkiewicz 			base_info->name = strdup(bdev_name);
17048a6bb6a8SArtur Paszkiewicz 			if (base_info->name == NULL) {
17058a6bb6a8SArtur Paszkiewicz 				return -ENOMEM;
17068a6bb6a8SArtur Paszkiewicz 			}
17078a6bb6a8SArtur Paszkiewicz 		} else if (strcmp(base_info->name, bdev_name) != 0) {
17088a6bb6a8SArtur Paszkiewicz 			SPDK_ERRLOG("Name mismatch for base bdev '%s' - expected '%s'\n",
17098a6bb6a8SArtur Paszkiewicz 				    bdev_name, base_info->name);
17108a6bb6a8SArtur Paszkiewicz 			return -EINVAL;
17118a6bb6a8SArtur Paszkiewicz 		}
17128a6bb6a8SArtur Paszkiewicz 	}
17138a6bb6a8SArtur Paszkiewicz 
17148a6bb6a8SArtur Paszkiewicz 	assert(base_info->name != NULL);
17158a6bb6a8SArtur Paszkiewicz 
1716dccdd1e5SArtur Paszkiewicz 	rc = spdk_bdev_open_ext(base_info->name, true, raid_bdev_event_base_bdev, NULL, &desc);
171707fe6a43SSeth Howell 	if (rc != 0) {
1718bd190d88SShuhei Matsumoto 		if (rc != -ENODEV) {
1719dccdd1e5SArtur Paszkiewicz 			SPDK_ERRLOG("Unable to create desc on bdev '%s'\n", base_info->name);
1720bd190d88SShuhei Matsumoto 		}
172107fe6a43SSeth Howell 		return rc;
172207fe6a43SSeth Howell 	}
172307fe6a43SSeth Howell 
1724dccdd1e5SArtur Paszkiewicz 	bdev = spdk_bdev_desc_get_bdev(desc);
17258a6bb6a8SArtur Paszkiewicz 	bdev_uuid = spdk_bdev_get_uuid(bdev);
17268a6bb6a8SArtur Paszkiewicz 
17278a6bb6a8SArtur Paszkiewicz 	if (spdk_uuid_is_null(&base_info->uuid)) {
17288a6bb6a8SArtur Paszkiewicz 		spdk_uuid_copy(&base_info->uuid, bdev_uuid);
17298a6bb6a8SArtur Paszkiewicz 	} else if (spdk_uuid_compare(&base_info->uuid, bdev_uuid) != 0) {
17308a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("UUID mismatch for base bdev '%s'\n", base_info->name);
17318a6bb6a8SArtur Paszkiewicz 		spdk_bdev_close(desc);
17328a6bb6a8SArtur Paszkiewicz 		return -EINVAL;
17338a6bb6a8SArtur Paszkiewicz 	}
1734dccdd1e5SArtur Paszkiewicz 
1735dccdd1e5SArtur Paszkiewicz 	rc = spdk_bdev_module_claim_bdev(bdev, NULL, &g_raid_if);
1736dccdd1e5SArtur Paszkiewicz 	if (rc != 0) {
1737dccdd1e5SArtur Paszkiewicz 		SPDK_ERRLOG("Unable to claim this bdev as it is already claimed\n");
1738dccdd1e5SArtur Paszkiewicz 		spdk_bdev_close(desc);
1739dccdd1e5SArtur Paszkiewicz 		return rc;
1740dccdd1e5SArtur Paszkiewicz 	}
1741dccdd1e5SArtur Paszkiewicz 
1742dccdd1e5SArtur Paszkiewicz 	SPDK_DEBUGLOG(bdev_raid, "bdev %s is claimed\n", bdev->name);
1743dccdd1e5SArtur Paszkiewicz 
1744dccdd1e5SArtur Paszkiewicz 	assert(raid_bdev->state != RAID_BDEV_STATE_ONLINE);
1745dccdd1e5SArtur Paszkiewicz 
174677b8f7b6SArtur Paszkiewicz 	base_info->app_thread_ch = spdk_bdev_get_io_channel(desc);
174777b8f7b6SArtur Paszkiewicz 	if (base_info->app_thread_ch == NULL) {
174877b8f7b6SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to get io channel\n");
174977b8f7b6SArtur Paszkiewicz 		spdk_bdev_module_release_bdev(bdev);
175077b8f7b6SArtur Paszkiewicz 		spdk_bdev_close(desc);
175177b8f7b6SArtur Paszkiewicz 		return -ENOMEM;
175277b8f7b6SArtur Paszkiewicz 	}
175377b8f7b6SArtur Paszkiewicz 
1754dccdd1e5SArtur Paszkiewicz 	base_info->desc = desc;
1755c9224e26SShuhei Matsumoto 	base_info->blockcnt = bdev->blockcnt;
175607fe6a43SSeth Howell 
175777b8f7b6SArtur Paszkiewicz 	if (raid_bdev->sb != NULL) {
17588a6bb6a8SArtur Paszkiewicz 		uint64_t data_offset;
1759deed7d2fSArtur Paszkiewicz 
17608a6bb6a8SArtur Paszkiewicz 		if (base_info->data_offset == 0) {
17618a6bb6a8SArtur Paszkiewicz 			assert((RAID_BDEV_MIN_DATA_OFFSET_SIZE % bdev->blocklen) == 0);
17628a6bb6a8SArtur Paszkiewicz 			data_offset = RAID_BDEV_MIN_DATA_OFFSET_SIZE / bdev->blocklen;
17638a6bb6a8SArtur Paszkiewicz 		} else {
17648a6bb6a8SArtur Paszkiewicz 			data_offset = base_info->data_offset;
17658a6bb6a8SArtur Paszkiewicz 		}
17668a6bb6a8SArtur Paszkiewicz 
17678a6bb6a8SArtur Paszkiewicz 		if (bdev->optimal_io_boundary != 0) {
17688a6bb6a8SArtur Paszkiewicz 			data_offset = spdk_divide_round_up(data_offset,
1769deed7d2fSArtur Paszkiewicz 							   bdev->optimal_io_boundary) * bdev->optimal_io_boundary;
17708a6bb6a8SArtur Paszkiewicz 			if (base_info->data_offset != 0 && base_info->data_offset != data_offset) {
17718a6bb6a8SArtur Paszkiewicz 				SPDK_WARNLOG("Data offset %lu on bdev '%s' is different than optimal value %lu\n",
17728a6bb6a8SArtur Paszkiewicz 					     base_info->data_offset, base_info->name, data_offset);
17738a6bb6a8SArtur Paszkiewicz 				data_offset = base_info->data_offset;
17748a6bb6a8SArtur Paszkiewicz 			}
17758a6bb6a8SArtur Paszkiewicz 		}
17768a6bb6a8SArtur Paszkiewicz 
17778a6bb6a8SArtur Paszkiewicz 		base_info->data_offset = data_offset;
1778deed7d2fSArtur Paszkiewicz 	}
1779deed7d2fSArtur Paszkiewicz 
1780deed7d2fSArtur Paszkiewicz 	if (base_info->data_offset >= bdev->blockcnt) {
1781deed7d2fSArtur Paszkiewicz 		SPDK_ERRLOG("Data offset %lu exceeds base bdev capacity %lu on bdev '%s'\n",
1782deed7d2fSArtur Paszkiewicz 			    base_info->data_offset, bdev->blockcnt, base_info->name);
17838a6bb6a8SArtur Paszkiewicz 		rc = -EINVAL;
17848a6bb6a8SArtur Paszkiewicz 		goto out;
1785deed7d2fSArtur Paszkiewicz 	}
1786deed7d2fSArtur Paszkiewicz 
17878a6bb6a8SArtur Paszkiewicz 	if (base_info->data_size == 0) {
1788deed7d2fSArtur Paszkiewicz 		base_info->data_size = bdev->blockcnt - base_info->data_offset;
17898a6bb6a8SArtur Paszkiewicz 	} else if (base_info->data_offset + base_info->data_size > bdev->blockcnt) {
17908a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("Data offset and size exceeds base bdev capacity %lu on bdev '%s'\n",
17918a6bb6a8SArtur Paszkiewicz 			    bdev->blockcnt, base_info->name);
17928a6bb6a8SArtur Paszkiewicz 		rc = -EINVAL;
17938a6bb6a8SArtur Paszkiewicz 		goto out;
1794deed7d2fSArtur Paszkiewicz 	}
1795deed7d2fSArtur Paszkiewicz 
17969222ff97SArtur Paszkiewicz 	if (existing) {
17979222ff97SArtur Paszkiewicz 		raid_bdev_configure_base_bdev_cont(base_info);
17989222ff97SArtur Paszkiewicz 	} else {
17999222ff97SArtur Paszkiewicz 		/* check for existing superblock when using a new bdev */
18009222ff97SArtur Paszkiewicz 		rc = raid_bdev_load_base_bdev_superblock(desc, base_info->app_thread_ch,
18019222ff97SArtur Paszkiewicz 				raid_bdev_configure_base_bdev_check_sb_cb, base_info);
18029222ff97SArtur Paszkiewicz 		if (rc) {
18039222ff97SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to read bdev %s superblock: %s\n",
18049222ff97SArtur Paszkiewicz 				    bdev->name, spdk_strerror(-rc));
18058a6bb6a8SArtur Paszkiewicz 		}
18068a6bb6a8SArtur Paszkiewicz 	}
18078a6bb6a8SArtur Paszkiewicz out:
18088a6bb6a8SArtur Paszkiewicz 	if (rc != 0) {
18098a6bb6a8SArtur Paszkiewicz 		raid_bdev_free_base_bdev_resource(base_info);
18108a6bb6a8SArtur Paszkiewicz 	}
181107fe6a43SSeth Howell 	return rc;
181207fe6a43SSeth Howell }
181307fe6a43SSeth Howell 
181407fe6a43SSeth Howell /*
181507fe6a43SSeth Howell  * brief:
1816dccdd1e5SArtur Paszkiewicz  * raid_bdev_add_base_device function is the actual function which either adds
1817dccdd1e5SArtur Paszkiewicz  * the nvme base device to existing raid bdev or create a new raid bdev. It also claims
1818dccdd1e5SArtur Paszkiewicz  * the base device and keep the open descriptor.
181907fe6a43SSeth Howell  * params:
1820dccdd1e5SArtur Paszkiewicz  * raid_bdev - pointer to raid bdev
1821dccdd1e5SArtur Paszkiewicz  * name - name of the base bdev
1822dccdd1e5SArtur Paszkiewicz  * slot - position to add base bdev
182307fe6a43SSeth Howell  * returns:
1824dccdd1e5SArtur Paszkiewicz  * 0 - success
1825dccdd1e5SArtur Paszkiewicz  * non zero - failure
182607fe6a43SSeth Howell  */
182707fe6a43SSeth Howell int
1828dccdd1e5SArtur Paszkiewicz raid_bdev_add_base_device(struct raid_bdev *raid_bdev, const char *name, uint8_t slot)
182907fe6a43SSeth Howell {
1830dccdd1e5SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
1831dccdd1e5SArtur Paszkiewicz 	int rc;
183207fe6a43SSeth Howell 
1833dccdd1e5SArtur Paszkiewicz 	if (slot >= raid_bdev->num_base_bdevs) {
1834dccdd1e5SArtur Paszkiewicz 		return -EINVAL;
183507fe6a43SSeth Howell 	}
183607fe6a43SSeth Howell 
1837dccdd1e5SArtur Paszkiewicz 	base_info = &raid_bdev->base_bdev_info[slot];
1838dccdd1e5SArtur Paszkiewicz 
1839dccdd1e5SArtur Paszkiewicz 	if (base_info->name != NULL) {
1840dccdd1e5SArtur Paszkiewicz 		SPDK_ERRLOG("Slot %u on raid bdev '%s' already assigned to bdev '%s'\n",
1841dccdd1e5SArtur Paszkiewicz 			    slot, raid_bdev->bdev.name, base_info->name);
1842dccdd1e5SArtur Paszkiewicz 		return -EBUSY;
1843dccdd1e5SArtur Paszkiewicz 	}
1844dccdd1e5SArtur Paszkiewicz 
18458a6bb6a8SArtur Paszkiewicz 	if (!spdk_uuid_is_null(&base_info->uuid)) {
18468a6bb6a8SArtur Paszkiewicz 		char uuid_str[SPDK_UUID_STRING_LEN];
18478a6bb6a8SArtur Paszkiewicz 
18488a6bb6a8SArtur Paszkiewicz 		spdk_uuid_fmt_lower(uuid_str, sizeof(uuid_str), &base_info->uuid);
18498a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("Slot %u on raid bdev '%s' already assigned to bdev with uuid %s\n",
18508a6bb6a8SArtur Paszkiewicz 			    slot, raid_bdev->bdev.name, uuid_str);
18518a6bb6a8SArtur Paszkiewicz 		return -EBUSY;
18528a6bb6a8SArtur Paszkiewicz 	}
18538a6bb6a8SArtur Paszkiewicz 
1854dccdd1e5SArtur Paszkiewicz 	base_info->name = strdup(name);
1855dccdd1e5SArtur Paszkiewicz 	if (base_info->name == NULL) {
1856dccdd1e5SArtur Paszkiewicz 		return -ENOMEM;
1857dccdd1e5SArtur Paszkiewicz 	}
1858dccdd1e5SArtur Paszkiewicz 
18599222ff97SArtur Paszkiewicz 	rc = raid_bdev_configure_base_bdev(base_info, false);
1860dccdd1e5SArtur Paszkiewicz 	if (rc != 0) {
1861dccdd1e5SArtur Paszkiewicz 		if (rc != -ENODEV) {
1862dccdd1e5SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to allocate resource for bdev '%s'\n", name);
1863dccdd1e5SArtur Paszkiewicz 		}
186407fe6a43SSeth Howell 		return rc;
186507fe6a43SSeth Howell 	}
186607fe6a43SSeth Howell 
1867dccdd1e5SArtur Paszkiewicz 	return 0;
1868dccdd1e5SArtur Paszkiewicz }
1869dccdd1e5SArtur Paszkiewicz 
18708a6bb6a8SArtur Paszkiewicz static int
18718a6bb6a8SArtur Paszkiewicz raid_bdev_create_from_sb(const struct raid_bdev_superblock *sb, struct raid_bdev **raid_bdev_out)
18728a6bb6a8SArtur Paszkiewicz {
18738a6bb6a8SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
18748a6bb6a8SArtur Paszkiewicz 	uint8_t i;
18758a6bb6a8SArtur Paszkiewicz 	int rc;
18768a6bb6a8SArtur Paszkiewicz 
18778a6bb6a8SArtur Paszkiewicz 	rc = raid_bdev_create(sb->name, (sb->strip_size * sb->block_size) / 1024, sb->num_base_bdevs,
18788a6bb6a8SArtur Paszkiewicz 			      sb->level, true, &sb->uuid, &raid_bdev);
18798a6bb6a8SArtur Paszkiewicz 	if (rc != 0) {
18808a6bb6a8SArtur Paszkiewicz 		return rc;
18818a6bb6a8SArtur Paszkiewicz 	}
18828a6bb6a8SArtur Paszkiewicz 
18838a6bb6a8SArtur Paszkiewicz 	assert(sb->length <= RAID_BDEV_SB_MAX_LENGTH);
18848a6bb6a8SArtur Paszkiewicz 	memcpy(raid_bdev->sb, sb, sb->length);
18858a6bb6a8SArtur Paszkiewicz 
18868a6bb6a8SArtur Paszkiewicz 	for (i = 0; i < sb->base_bdevs_size; i++) {
18878a6bb6a8SArtur Paszkiewicz 		const struct raid_bdev_sb_base_bdev *sb_base_bdev = &sb->base_bdevs[i];
18888a6bb6a8SArtur Paszkiewicz 		struct raid_base_bdev_info *base_info = &raid_bdev->base_bdev_info[sb_base_bdev->slot];
18898a6bb6a8SArtur Paszkiewicz 
18908a6bb6a8SArtur Paszkiewicz 		if (sb_base_bdev->state == RAID_SB_BASE_BDEV_CONFIGURED) {
18918a6bb6a8SArtur Paszkiewicz 			spdk_uuid_copy(&base_info->uuid, &sb_base_bdev->uuid);
18928a6bb6a8SArtur Paszkiewicz 		}
18938a6bb6a8SArtur Paszkiewicz 
18948a6bb6a8SArtur Paszkiewicz 		base_info->data_offset = sb_base_bdev->data_offset;
18958a6bb6a8SArtur Paszkiewicz 		base_info->data_size = sb_base_bdev->data_size;
18968a6bb6a8SArtur Paszkiewicz 	}
18978a6bb6a8SArtur Paszkiewicz 
18988a6bb6a8SArtur Paszkiewicz 	*raid_bdev_out = raid_bdev;
18998a6bb6a8SArtur Paszkiewicz 	return 0;
19008a6bb6a8SArtur Paszkiewicz }
19018a6bb6a8SArtur Paszkiewicz 
19028a6bb6a8SArtur Paszkiewicz static void
19038a6bb6a8SArtur Paszkiewicz raid_bdev_examine_no_sb(struct spdk_bdev *bdev)
19048a6bb6a8SArtur Paszkiewicz {
19058a6bb6a8SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
19068a6bb6a8SArtur Paszkiewicz 	struct raid_base_bdev_info *base_info;
19078a6bb6a8SArtur Paszkiewicz 
19088a6bb6a8SArtur Paszkiewicz 	TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) {
19098a6bb6a8SArtur Paszkiewicz 		RAID_FOR_EACH_BASE_BDEV(raid_bdev, base_info) {
19108a6bb6a8SArtur Paszkiewicz 			if (base_info->desc == NULL && base_info->name != NULL &&
19118a6bb6a8SArtur Paszkiewicz 			    strcmp(bdev->name, base_info->name) == 0) {
19129222ff97SArtur Paszkiewicz 				raid_bdev_configure_base_bdev(base_info, true);
19138a6bb6a8SArtur Paszkiewicz 				break;
19148a6bb6a8SArtur Paszkiewicz 			}
19158a6bb6a8SArtur Paszkiewicz 		}
19168a6bb6a8SArtur Paszkiewicz 	}
19178a6bb6a8SArtur Paszkiewicz }
19188a6bb6a8SArtur Paszkiewicz 
19198a6bb6a8SArtur Paszkiewicz static void
19208a6bb6a8SArtur Paszkiewicz raid_bdev_examine_sb(const struct raid_bdev_superblock *sb, struct spdk_bdev *bdev)
19218a6bb6a8SArtur Paszkiewicz {
19228a6bb6a8SArtur Paszkiewicz 	const struct raid_bdev_sb_base_bdev *sb_base_bdev;
19238a6bb6a8SArtur Paszkiewicz 	struct raid_bdev *raid_bdev;
19248a6bb6a8SArtur Paszkiewicz 	struct raid_base_bdev_info *iter, *base_info;
19258a6bb6a8SArtur Paszkiewicz 	uint8_t i;
19268a6bb6a8SArtur Paszkiewicz 	int rc;
19278a6bb6a8SArtur Paszkiewicz 
19288a6bb6a8SArtur Paszkiewicz 	if (sb->block_size != bdev->blocklen) {
19298a6bb6a8SArtur Paszkiewicz 		SPDK_WARNLOG("Bdev %s block size (%u) does not match the value in superblock (%u)\n",
19308a6bb6a8SArtur Paszkiewicz 			     bdev->name, sb->block_size, bdev->blocklen);
19318a6bb6a8SArtur Paszkiewicz 		return;
19328a6bb6a8SArtur Paszkiewicz 	}
19338a6bb6a8SArtur Paszkiewicz 
19348a6bb6a8SArtur Paszkiewicz 	if (spdk_uuid_is_null(&sb->uuid)) {
19358a6bb6a8SArtur Paszkiewicz 		SPDK_WARNLOG("NULL raid bdev UUID in superblock on bdev %s\n", bdev->name);
19368a6bb6a8SArtur Paszkiewicz 		return;
19378a6bb6a8SArtur Paszkiewicz 	}
19388a6bb6a8SArtur Paszkiewicz 
19398a6bb6a8SArtur Paszkiewicz 	TAILQ_FOREACH(raid_bdev, &g_raid_bdev_list, global_link) {
19408a6bb6a8SArtur Paszkiewicz 		if (spdk_uuid_compare(&raid_bdev->bdev.uuid, &sb->uuid) == 0) {
19418a6bb6a8SArtur Paszkiewicz 			break;
19428a6bb6a8SArtur Paszkiewicz 		}
19438a6bb6a8SArtur Paszkiewicz 	}
19448a6bb6a8SArtur Paszkiewicz 
19458a6bb6a8SArtur Paszkiewicz 	if (raid_bdev) {
19468a6bb6a8SArtur Paszkiewicz 		if (sb->seq_number > raid_bdev->sb->seq_number) {
19478a6bb6a8SArtur Paszkiewicz 			SPDK_DEBUGLOG(bdev_raid,
19488a6bb6a8SArtur Paszkiewicz 				      "raid superblock seq_number on bdev %s (%lu) greater than existing raid bdev %s (%lu)\n",
19498a6bb6a8SArtur Paszkiewicz 				      bdev->name, sb->seq_number, raid_bdev->bdev.name, raid_bdev->sb->seq_number);
19508a6bb6a8SArtur Paszkiewicz 
19518a6bb6a8SArtur Paszkiewicz 			if (raid_bdev->state != RAID_BDEV_STATE_CONFIGURING) {
19528a6bb6a8SArtur Paszkiewicz 				SPDK_WARNLOG("Newer version of raid bdev %s superblock found on bdev %s but raid bdev is not in configuring state.\n",
19538a6bb6a8SArtur Paszkiewicz 					     raid_bdev->bdev.name, bdev->name);
19548a6bb6a8SArtur Paszkiewicz 				return;
19558a6bb6a8SArtur Paszkiewicz 			}
19568a6bb6a8SArtur Paszkiewicz 
19578a6bb6a8SArtur Paszkiewicz 			/* remove and then recreate the raid bdev using the newer superblock */
19588a6bb6a8SArtur Paszkiewicz 			raid_bdev_delete(raid_bdev, NULL, NULL);
19598a6bb6a8SArtur Paszkiewicz 			raid_bdev = NULL;
19608a6bb6a8SArtur Paszkiewicz 		} else if (sb->seq_number < raid_bdev->sb->seq_number) {
19618a6bb6a8SArtur Paszkiewicz 			SPDK_DEBUGLOG(bdev_raid,
19628a6bb6a8SArtur Paszkiewicz 				      "raid superblock seq_number on bdev %s (%lu) smaller than existing raid bdev %s (%lu)\n",
19638a6bb6a8SArtur Paszkiewicz 				      bdev->name, sb->seq_number, raid_bdev->bdev.name, raid_bdev->sb->seq_number);
19648a6bb6a8SArtur Paszkiewicz 			/* use the current raid bdev superblock */
19658a6bb6a8SArtur Paszkiewicz 			sb = raid_bdev->sb;
19668a6bb6a8SArtur Paszkiewicz 		}
19678a6bb6a8SArtur Paszkiewicz 	}
19688a6bb6a8SArtur Paszkiewicz 
19698a6bb6a8SArtur Paszkiewicz 	for (i = 0; i < sb->base_bdevs_size; i++) {
19708a6bb6a8SArtur Paszkiewicz 		sb_base_bdev = &sb->base_bdevs[i];
19718a6bb6a8SArtur Paszkiewicz 
19728a6bb6a8SArtur Paszkiewicz 		assert(spdk_uuid_is_null(&sb_base_bdev->uuid) == false);
19738a6bb6a8SArtur Paszkiewicz 
19748a6bb6a8SArtur Paszkiewicz 		if (spdk_uuid_compare(&sb_base_bdev->uuid, spdk_bdev_get_uuid(bdev)) == 0) {
19758a6bb6a8SArtur Paszkiewicz 			break;
19768a6bb6a8SArtur Paszkiewicz 		}
19778a6bb6a8SArtur Paszkiewicz 	}
19788a6bb6a8SArtur Paszkiewicz 
19798a6bb6a8SArtur Paszkiewicz 	if (i == sb->base_bdevs_size) {
19808a6bb6a8SArtur Paszkiewicz 		SPDK_DEBUGLOG(bdev_raid, "raid superblock does not contain this bdev's uuid\n");
19818a6bb6a8SArtur Paszkiewicz 		return;
19828a6bb6a8SArtur Paszkiewicz 	}
19838a6bb6a8SArtur Paszkiewicz 
19848a6bb6a8SArtur Paszkiewicz 	if (!raid_bdev) {
19858a6bb6a8SArtur Paszkiewicz 		rc = raid_bdev_create_from_sb(sb, &raid_bdev);
19868a6bb6a8SArtur Paszkiewicz 		if (rc != 0) {
19878a6bb6a8SArtur Paszkiewicz 			SPDK_ERRLOG("Failed to create raid bdev %s: %s\n",
19888a6bb6a8SArtur Paszkiewicz 				    sb->name, spdk_strerror(-rc));
19898a6bb6a8SArtur Paszkiewicz 		}
19908a6bb6a8SArtur Paszkiewicz 	}
19918a6bb6a8SArtur Paszkiewicz 
19928a6bb6a8SArtur Paszkiewicz 	if (sb_base_bdev->state != RAID_SB_BASE_BDEV_CONFIGURED) {
19938a6bb6a8SArtur Paszkiewicz 		SPDK_NOTICELOG("Bdev %s is not an active member of raid bdev %s. Ignoring.\n",
19948a6bb6a8SArtur Paszkiewicz 			       bdev->name, raid_bdev->bdev.name);
19958a6bb6a8SArtur Paszkiewicz 		return;
19968a6bb6a8SArtur Paszkiewicz 	}
19978a6bb6a8SArtur Paszkiewicz 
19988a6bb6a8SArtur Paszkiewicz 	base_info = NULL;
19998a6bb6a8SArtur Paszkiewicz 	RAID_FOR_EACH_BASE_BDEV(raid_bdev, iter) {
20008a6bb6a8SArtur Paszkiewicz 		if (spdk_uuid_compare(&iter->uuid, spdk_bdev_get_uuid(bdev)) == 0) {
20018a6bb6a8SArtur Paszkiewicz 			base_info = iter;
20028a6bb6a8SArtur Paszkiewicz 			break;
20038a6bb6a8SArtur Paszkiewicz 		}
20048a6bb6a8SArtur Paszkiewicz 	}
20058a6bb6a8SArtur Paszkiewicz 
20068a6bb6a8SArtur Paszkiewicz 	if (base_info == NULL) {
20078a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("Bdev %s is not a member of raid bdev %s\n",
20088a6bb6a8SArtur Paszkiewicz 			    bdev->name, raid_bdev->bdev.name);
20098a6bb6a8SArtur Paszkiewicz 		return;
20108a6bb6a8SArtur Paszkiewicz 	}
20118a6bb6a8SArtur Paszkiewicz 
20129222ff97SArtur Paszkiewicz 	rc = raid_bdev_configure_base_bdev(base_info, true);
20138a6bb6a8SArtur Paszkiewicz 	if (rc != 0) {
20148a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to configure bdev %s as base bdev of raid %s: %s\n",
20158a6bb6a8SArtur Paszkiewicz 			    bdev->name, raid_bdev->bdev.name, spdk_strerror(-rc));
20168a6bb6a8SArtur Paszkiewicz 	}
20178a6bb6a8SArtur Paszkiewicz }
20188a6bb6a8SArtur Paszkiewicz 
20198a6bb6a8SArtur Paszkiewicz struct raid_bdev_examine_ctx {
20208a6bb6a8SArtur Paszkiewicz 	struct spdk_bdev_desc *desc;
20218a6bb6a8SArtur Paszkiewicz 	struct spdk_io_channel *ch;
20228a6bb6a8SArtur Paszkiewicz };
20238a6bb6a8SArtur Paszkiewicz 
20248a6bb6a8SArtur Paszkiewicz static void
20258a6bb6a8SArtur Paszkiewicz raid_bdev_examine_ctx_free(struct raid_bdev_examine_ctx *ctx)
20268a6bb6a8SArtur Paszkiewicz {
20278a6bb6a8SArtur Paszkiewicz 	if (!ctx) {
20288a6bb6a8SArtur Paszkiewicz 		return;
20298a6bb6a8SArtur Paszkiewicz 	}
20308a6bb6a8SArtur Paszkiewicz 
20318a6bb6a8SArtur Paszkiewicz 	if (ctx->ch) {
20328a6bb6a8SArtur Paszkiewicz 		spdk_put_io_channel(ctx->ch);
20338a6bb6a8SArtur Paszkiewicz 	}
20348a6bb6a8SArtur Paszkiewicz 
20358a6bb6a8SArtur Paszkiewicz 	if (ctx->desc) {
20368a6bb6a8SArtur Paszkiewicz 		spdk_bdev_close(ctx->desc);
20378a6bb6a8SArtur Paszkiewicz 	}
20388a6bb6a8SArtur Paszkiewicz 
20398a6bb6a8SArtur Paszkiewicz 	free(ctx);
20408a6bb6a8SArtur Paszkiewicz }
20418a6bb6a8SArtur Paszkiewicz 
20428a6bb6a8SArtur Paszkiewicz static void
20438a6bb6a8SArtur Paszkiewicz raid_bdev_examine_load_sb_cb(const struct raid_bdev_superblock *sb, int status, void *_ctx)
20448a6bb6a8SArtur Paszkiewicz {
20458a6bb6a8SArtur Paszkiewicz 	struct raid_bdev_examine_ctx *ctx = _ctx;
20468a6bb6a8SArtur Paszkiewicz 	struct spdk_bdev *bdev = spdk_bdev_desc_get_bdev(ctx->desc);
20478a6bb6a8SArtur Paszkiewicz 
20488a6bb6a8SArtur Paszkiewicz 	switch (status) {
20498a6bb6a8SArtur Paszkiewicz 	case 0:
20508a6bb6a8SArtur Paszkiewicz 		/* valid superblock found */
20518a6bb6a8SArtur Paszkiewicz 		SPDK_DEBUGLOG(bdev_raid, "raid superblock found on bdev %s\n", bdev->name);
20528a6bb6a8SArtur Paszkiewicz 		raid_bdev_examine_sb(sb, bdev);
20538a6bb6a8SArtur Paszkiewicz 		break;
20548a6bb6a8SArtur Paszkiewicz 	case -EINVAL:
20558a6bb6a8SArtur Paszkiewicz 		/* no valid superblock, check if it can be claimed anyway */
20568a6bb6a8SArtur Paszkiewicz 		raid_bdev_examine_no_sb(bdev);
20578a6bb6a8SArtur Paszkiewicz 		break;
20588a6bb6a8SArtur Paszkiewicz 	default:
20598a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to examine bdev %s: %s\n",
20608a6bb6a8SArtur Paszkiewicz 			    bdev->name, spdk_strerror(-status));
20618a6bb6a8SArtur Paszkiewicz 		break;
20628a6bb6a8SArtur Paszkiewicz 	}
20638a6bb6a8SArtur Paszkiewicz 
20648a6bb6a8SArtur Paszkiewicz 	raid_bdev_examine_ctx_free(ctx);
20658a6bb6a8SArtur Paszkiewicz 	spdk_bdev_module_examine_done(&g_raid_if);
20668a6bb6a8SArtur Paszkiewicz }
20678a6bb6a8SArtur Paszkiewicz 
20688a6bb6a8SArtur Paszkiewicz static void
20698a6bb6a8SArtur Paszkiewicz raid_bdev_examine_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
20708a6bb6a8SArtur Paszkiewicz {
20718a6bb6a8SArtur Paszkiewicz }
20728a6bb6a8SArtur Paszkiewicz 
207307fe6a43SSeth Howell /*
207407fe6a43SSeth Howell  * brief:
207507fe6a43SSeth Howell  * raid_bdev_examine function is the examine function call by the below layers
207607fe6a43SSeth Howell  * like bdev_nvme layer. This function will check if this base bdev can be
207707fe6a43SSeth Howell  * claimed by this raid bdev or not.
207807fe6a43SSeth Howell  * params:
207907fe6a43SSeth Howell  * bdev - pointer to base bdev
208007fe6a43SSeth Howell  * returns:
208107fe6a43SSeth Howell  * none
208207fe6a43SSeth Howell  */
208307fe6a43SSeth Howell static void
208407fe6a43SSeth Howell raid_bdev_examine(struct spdk_bdev *bdev)
208507fe6a43SSeth Howell {
20868a6bb6a8SArtur Paszkiewicz 	struct raid_bdev_examine_ctx *ctx;
20878a6bb6a8SArtur Paszkiewicz 	int rc;
208807fe6a43SSeth Howell 
20898a6bb6a8SArtur Paszkiewicz 	ctx = calloc(1, sizeof(*ctx));
20908a6bb6a8SArtur Paszkiewicz 	if (!ctx) {
20918a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to examine bdev %s: %s\n",
20928a6bb6a8SArtur Paszkiewicz 			    bdev->name, spdk_strerror(ENOMEM));
20938a6bb6a8SArtur Paszkiewicz 		goto err;
209407fe6a43SSeth Howell 	}
209507fe6a43SSeth Howell 
20968a6bb6a8SArtur Paszkiewicz 	rc = spdk_bdev_open_ext(spdk_bdev_get_name(bdev), false, raid_bdev_examine_event_cb, NULL,
20978a6bb6a8SArtur Paszkiewicz 				&ctx->desc);
20988a6bb6a8SArtur Paszkiewicz 	if (rc) {
20998a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to open bdev %s: %s\n",
21008a6bb6a8SArtur Paszkiewicz 			    bdev->name, spdk_strerror(-rc));
21018a6bb6a8SArtur Paszkiewicz 		goto err;
21028a6bb6a8SArtur Paszkiewicz 	}
21038a6bb6a8SArtur Paszkiewicz 
21048a6bb6a8SArtur Paszkiewicz 	ctx->ch = spdk_bdev_get_io_channel(ctx->desc);
21058a6bb6a8SArtur Paszkiewicz 	if (!ctx->ch) {
21068a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to get io channel for bdev %s\n", bdev->name);
21078a6bb6a8SArtur Paszkiewicz 		goto err;
21088a6bb6a8SArtur Paszkiewicz 	}
21098a6bb6a8SArtur Paszkiewicz 
21108a6bb6a8SArtur Paszkiewicz 	rc = raid_bdev_load_base_bdev_superblock(ctx->desc, ctx->ch, raid_bdev_examine_load_sb_cb, ctx);
21118a6bb6a8SArtur Paszkiewicz 	if (rc) {
21128a6bb6a8SArtur Paszkiewicz 		SPDK_ERRLOG("Failed to read bdev %s superblock: %s\n",
21138a6bb6a8SArtur Paszkiewicz 			    bdev->name, spdk_strerror(-rc));
21148a6bb6a8SArtur Paszkiewicz 		goto err;
21158a6bb6a8SArtur Paszkiewicz 	}
21168a6bb6a8SArtur Paszkiewicz 
21178a6bb6a8SArtur Paszkiewicz 	return;
21188a6bb6a8SArtur Paszkiewicz err:
21198a6bb6a8SArtur Paszkiewicz 	raid_bdev_examine_ctx_free(ctx);
212007fe6a43SSeth Howell 	spdk_bdev_module_examine_done(&g_raid_if);
212107fe6a43SSeth Howell }
212207fe6a43SSeth Howell 
212307fe6a43SSeth Howell /* Log component for bdev raid bdev module */
21242172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(bdev_raid)
2125