1*a70f355bSandvar /* $NetBSD: dm_target.c,v 1.42 2021/08/21 22:23:33 andvar Exp $ */
2c9d0c62aShaad
3c9d0c62aShaad /*
4c9d0c62aShaad * Copyright (c) 2008 The NetBSD Foundation, Inc.
5c9d0c62aShaad * All rights reserved.
6c9d0c62aShaad *
7c9d0c62aShaad * This code is derived from software contributed to The NetBSD Foundation
8c9d0c62aShaad * by Adam Hamsik.
9c9d0c62aShaad *
10c9d0c62aShaad * Redistribution and use in source and binary forms, with or without
11c9d0c62aShaad * modification, are permitted provided that the following conditions
12c9d0c62aShaad * are met:
13c9d0c62aShaad * 1. Redistributions of source code Must retain the above copyright
14c9d0c62aShaad * notice, this list of conditions and the following disclaimer.
15c9d0c62aShaad * 2. Redistributions in binary form must reproduce the above copyright
16c9d0c62aShaad * notice, this list of conditions and the following disclaimer in the
17c9d0c62aShaad * documentation and/or other materials provided with the distribution.
18c9d0c62aShaad *
19c9d0c62aShaad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20c9d0c62aShaad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21c9d0c62aShaad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22c9d0c62aShaad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23c9d0c62aShaad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24c9d0c62aShaad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25c9d0c62aShaad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26c9d0c62aShaad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27c9d0c62aShaad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28c9d0c62aShaad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29c9d0c62aShaad * POSSIBILITY OF SUCH DAMAGE.
30c9d0c62aShaad */
31249cf593Schristos #include <sys/cdefs.h>
32*a70f355bSandvar __KERNEL_RCSID(0, "$NetBSD: dm_target.c,v 1.42 2021/08/21 22:23:33 andvar Exp $");
33c9d0c62aShaad
34c9d0c62aShaad #include <sys/types.h>
35c9d0c62aShaad #include <sys/param.h>
36c9d0c62aShaad #include <sys/kmem.h>
3717599f37Shaad #include <sys/module.h>
3817599f37Shaad
39c9d0c62aShaad #include "netbsd-dm.h"
40c9d0c62aShaad #include "dm.h"
41c9d0c62aShaad
4278284dcaShaad static dm_target_t *dm_target_lookup_name(const char *);
43c9d0c62aShaad
44c9d0c62aShaad TAILQ_HEAD(dm_target_head, dm_target);
45c9d0c62aShaad
46c9d0c62aShaad static struct dm_target_head dm_target_list =
47c9d0c62aShaad TAILQ_HEAD_INITIALIZER(dm_target_list);
48c9d0c62aShaad
496664a499Stkusumi static kmutex_t dm_target_mutex;
5078284dcaShaad
5178284dcaShaad /*
5283723a32Syamt * Called indirectly from dm_table_load_ioctl to mark target as used.
5378284dcaShaad */
5478284dcaShaad void
dm_target_busy(dm_target_t * target)5578284dcaShaad dm_target_busy(dm_target_t *target)
5678284dcaShaad {
5746f14759Stkusumi
5817599f37Shaad atomic_inc_32(&target->ref_cnt);
5978284dcaShaad }
60249cf593Schristos
6117599f37Shaad /*
6217599f37Shaad * Release reference counter on target.
6317599f37Shaad */
6478284dcaShaad void
dm_target_unbusy(dm_target_t * target)6578284dcaShaad dm_target_unbusy(dm_target_t *target)
6678284dcaShaad {
6746f14759Stkusumi
6817599f37Shaad KASSERT(target->ref_cnt > 0);
6917599f37Shaad atomic_dec_32(&target->ref_cnt);
7078284dcaShaad }
71249cf593Schristos
7217599f37Shaad /*
7317599f37Shaad * Try to autoload target module if it was not found in current
7417599f37Shaad * target list.
7517599f37Shaad */
7617599f37Shaad dm_target_t *
dm_target_autoload(const char * dm_target_name)7717599f37Shaad dm_target_autoload(const char *dm_target_name)
7817599f37Shaad {
79d624725aShaad char name[30];
80d2a47630Stkusumi unsigned int gen;
8117599f37Shaad dm_target_t *dmt;
8217599f37Shaad
83d624725aShaad snprintf(name, sizeof(name), "dm_target_%s", dm_target_name);
84d624725aShaad name[29] = '\0';
85d624725aShaad
8617599f37Shaad do {
8717599f37Shaad gen = module_gen;
8817599f37Shaad
8917599f37Shaad /* Try to autoload target module */
90d9c59a05Stkusumi module_autoload(name, MODULE_CLASS_MISC);
9117599f37Shaad } while (gen != module_gen);
9217599f37Shaad
9317599f37Shaad mutex_enter(&dm_target_mutex);
9417599f37Shaad dmt = dm_target_lookup_name(dm_target_name);
95e654dd3dShaad if (dmt != NULL)
9617599f37Shaad dm_target_busy(dmt);
97e654dd3dShaad mutex_exit(&dm_target_mutex);
9817599f37Shaad
9917599f37Shaad return dmt;
10017599f37Shaad }
101249cf593Schristos
10217599f37Shaad /*
10317599f37Shaad * Lookup for target in global target list.
10417599f37Shaad */
10578284dcaShaad dm_target_t *
dm_target_lookup(const char * dm_target_name)10678284dcaShaad dm_target_lookup(const char *dm_target_name)
10778284dcaShaad {
10878284dcaShaad dm_target_t *dmt;
10978284dcaShaad
11017599f37Shaad if (dm_target_name == NULL)
11117599f37Shaad return NULL;
11217599f37Shaad
11378284dcaShaad mutex_enter(&dm_target_mutex);
11478284dcaShaad
11578284dcaShaad dmt = dm_target_lookup_name(dm_target_name);
11678284dcaShaad if (dmt != NULL)
11778284dcaShaad dm_target_busy(dmt);
11878284dcaShaad
11978284dcaShaad mutex_exit(&dm_target_mutex);
12078284dcaShaad
12178284dcaShaad return dmt;
12278284dcaShaad }
123249cf593Schristos
124c9d0c62aShaad /*
125*a70f355bSandvar * Search for name in TAIL and return appropriate pointer.
126c9d0c62aShaad */
12778284dcaShaad static dm_target_t *
dm_target_lookup_name(const char * dm_target_name)128c9d0c62aShaad dm_target_lookup_name(const char *dm_target_name)
129c9d0c62aShaad {
130c9d0c62aShaad dm_target_t *dm_target;
131249cf593Schristos size_t dlen;
132249cf593Schristos size_t slen;
133c9d0c62aShaad
134c9d0c62aShaad slen = strlen(dm_target_name) + 1;
135c9d0c62aShaad
136c9d0c62aShaad TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) {
137c9d0c62aShaad dlen = strlen(dm_target->name) + 1;
138c9d0c62aShaad if (dlen != slen)
139c9d0c62aShaad continue;
140c9d0c62aShaad
14117599f37Shaad if (strncmp(dm_target_name, dm_target->name, slen) == 0)
142c9d0c62aShaad return dm_target;
143c9d0c62aShaad }
144c9d0c62aShaad
145c9d0c62aShaad return NULL;
146c9d0c62aShaad }
147249cf593Schristos
148c9d0c62aShaad /*
149c9d0c62aShaad * Insert new target struct into the TAIL.
150c9d0c62aShaad * dm_target
151*a70f355bSandvar * contains name, version, function pointer to specific target functions.
152c9d0c62aShaad */
153c9d0c62aShaad int
dm_target_insert(dm_target_t * dm_target)154c9d0c62aShaad dm_target_insert(dm_target_t *dm_target)
155c9d0c62aShaad {
156c9d0c62aShaad dm_target_t *dmt;
157c9d0c62aShaad
1587cc36507Sahoka /* Sanity check for any missing function */
1599a83c98bStkusumi if (dm_target->init == NULL) {
1609a83c98bStkusumi printf("%s missing init\n", dm_target->name);
1619a83c98bStkusumi return EINVAL;
1629a83c98bStkusumi }
1639a83c98bStkusumi if (dm_target->strategy == NULL) {
1649a83c98bStkusumi printf("%s missing strategy\n", dm_target->name);
1659a83c98bStkusumi return EINVAL;
1669a83c98bStkusumi }
1679a83c98bStkusumi if (dm_target->destroy == NULL) {
1689a83c98bStkusumi printf("%s missing destroy\n", dm_target->name);
1699a83c98bStkusumi return EINVAL;
1709a83c98bStkusumi }
17167de4a93Stkusumi #if 0
1729a83c98bStkusumi if (dm_target->upcall == NULL) {
1739a83c98bStkusumi printf("%s missing upcall\n", dm_target->name);
1749a83c98bStkusumi return EINVAL;
1759a83c98bStkusumi }
17667de4a93Stkusumi #endif
1777cc36507Sahoka
17878284dcaShaad mutex_enter(&dm_target_mutex);
179c9d0c62aShaad
18078284dcaShaad dmt = dm_target_lookup_name(dm_target->name);
18178284dcaShaad if (dmt != NULL) {
18278284dcaShaad mutex_exit(&dm_target_mutex);
183c9d0c62aShaad return EEXIST;
18478284dcaShaad }
185c9d0c62aShaad TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next);
186c9d0c62aShaad
18778284dcaShaad mutex_exit(&dm_target_mutex);
18878284dcaShaad
189c9d0c62aShaad return 0;
190c9d0c62aShaad }
191c9d0c62aShaad
192c9d0c62aShaad /*
193f0a7346dSsnj * Remove target from TAIL, target is selected with its name.
194c9d0c62aShaad */
195c9d0c62aShaad int
dm_target_rem(const char * dm_target_name)1961c486dc6Stkusumi dm_target_rem(const char *dm_target_name)
197c9d0c62aShaad {
19878284dcaShaad dm_target_t *dmt;
199c9d0c62aShaad
200c9d0c62aShaad KASSERT(dm_target_name != NULL);
201c9d0c62aShaad
20278284dcaShaad mutex_enter(&dm_target_mutex);
20378284dcaShaad
20478284dcaShaad dmt = dm_target_lookup_name(dm_target_name);
20578284dcaShaad if (dmt == NULL) {
20678284dcaShaad mutex_exit(&dm_target_mutex);
207c9d0c62aShaad return ENOENT;
20878284dcaShaad }
20978284dcaShaad if (dmt->ref_cnt > 0) {
21078284dcaShaad mutex_exit(&dm_target_mutex);
21178284dcaShaad return EBUSY;
21278284dcaShaad }
2139dea6936Stkusumi TAILQ_REMOVE(&dm_target_list, dmt, dm_target_next);
214c9d0c62aShaad
21578284dcaShaad mutex_exit(&dm_target_mutex);
21678284dcaShaad
217d9c59a05Stkusumi kmem_free(dmt, sizeof(dm_target_t));
218c9d0c62aShaad
219c9d0c62aShaad return 0;
220c9d0c62aShaad }
221249cf593Schristos
222c9d0c62aShaad /*
223c9d0c62aShaad * Destroy all targets and remove them from queue.
224c9d0c62aShaad * This routine is called from dm_detach, before module
225c9d0c62aShaad * is unloaded.
226c9d0c62aShaad */
227c9d0c62aShaad int
dm_target_destroy(void)228c9d0c62aShaad dm_target_destroy(void)
229c9d0c62aShaad {
230c9d0c62aShaad dm_target_t *dm_target;
231c9d0c62aShaad
23278284dcaShaad mutex_enter(&dm_target_mutex);
233c9d0c62aShaad
234312beb09Stkusumi while ((dm_target = TAILQ_FIRST(&dm_target_list)) != NULL) {
235312beb09Stkusumi TAILQ_REMOVE(&dm_target_list, dm_target, dm_target_next);
236d9c59a05Stkusumi kmem_free(dm_target, sizeof(dm_target_t));
237c9d0c62aShaad }
238312beb09Stkusumi KASSERT(TAILQ_EMPTY(&dm_target_list));
239312beb09Stkusumi
24078284dcaShaad mutex_exit(&dm_target_mutex);
241c9d0c62aShaad
242cca8fb31Shaad mutex_destroy(&dm_target_mutex);
243ea24dc8dStkusumi #if 0
244ea24dc8dStkusumi /* Target specific module destroy routine. */
245ea24dc8dStkusumi dm_target_delay_pool_destroy();
246ea24dc8dStkusumi #endif
247c9d0c62aShaad return 0;
248c9d0c62aShaad }
249249cf593Schristos
250c9d0c62aShaad /*
251c9d0c62aShaad * Allocate new target entry.
252c9d0c62aShaad */
253c9d0c62aShaad dm_target_t *
dm_target_alloc(const char * name)254c9d0c62aShaad dm_target_alloc(const char *name)
255c9d0c62aShaad {
256592bc735Stkusumi dm_target_t *dmt;
257592bc735Stkusumi
258592bc735Stkusumi dmt = kmem_zalloc(sizeof(dm_target_t), KM_SLEEP);
259592bc735Stkusumi if (dmt == NULL)
260592bc735Stkusumi return NULL;
261592bc735Stkusumi
262592bc735Stkusumi if (name)
263592bc735Stkusumi strlcpy(dmt->name, name, sizeof(dmt->name));
264592bc735Stkusumi
265592bc735Stkusumi return dmt;
266c9d0c62aShaad }
267249cf593Schristos
268c9d0c62aShaad /*
269c9d0c62aShaad * Return prop_array of dm_target dictionaries.
270c9d0c62aShaad */
271c9d0c62aShaad prop_array_t
dm_target_prop_list(void)272c9d0c62aShaad dm_target_prop_list(void)
273c9d0c62aShaad {
27446f14759Stkusumi prop_array_t target_array;
275c9d0c62aShaad dm_target_t *dm_target;
276c9d0c62aShaad
277c9d0c62aShaad target_array = prop_array_create();
278c9d0c62aShaad
27978284dcaShaad mutex_enter(&dm_target_mutex);
28078284dcaShaad
281c9d0c62aShaad TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) {
28246f14759Stkusumi prop_array_t ver;
28346f14759Stkusumi prop_dictionary_t target_dict;
28446f14759Stkusumi int i;
28546f14759Stkusumi
286c9d0c62aShaad target_dict = prop_dictionary_create();
287c9d0c62aShaad ver = prop_array_create();
288b5a91dc2Sthorpej prop_dictionary_set_string(target_dict, DM_TARGETS_NAME,
289c9d0c62aShaad dm_target->name);
290c9d0c62aShaad
291c9d0c62aShaad for (i = 0; i < 3; i++)
292c9d0c62aShaad prop_array_add_uint32(ver, dm_target->version[i]);
293c9d0c62aShaad
294c9d0c62aShaad prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver);
295c9d0c62aShaad prop_array_add(target_array, target_dict);
296c9d0c62aShaad
297c9d0c62aShaad prop_object_release(ver);
298c9d0c62aShaad prop_object_release(target_dict);
299c9d0c62aShaad }
300c9d0c62aShaad
30178284dcaShaad mutex_exit(&dm_target_mutex);
30278284dcaShaad
303c9d0c62aShaad return target_array;
304c9d0c62aShaad }
305249cf593Schristos
30646f14759Stkusumi /*
30746f14759Stkusumi * Initialize dm_target subsystem.
30846f14759Stkusumi */
309c9d0c62aShaad int
dm_target_init(void)310c9d0c62aShaad dm_target_init(void)
311c9d0c62aShaad {
31284d45206Stkusumi dm_target_t *dmt;
313c9d0c62aShaad
31478284dcaShaad mutex_init(&dm_target_mutex, MUTEX_DEFAULT, IPL_NONE);
31578284dcaShaad
316c9d0c62aShaad dmt = dm_target_alloc("linear");
317c9d0c62aShaad dmt->version[0] = 1;
318c9d0c62aShaad dmt->version[1] = 0;
319c9d0c62aShaad dmt->version[2] = 2;
320c9d0c62aShaad dmt->init = &dm_target_linear_init;
3218026110eStkusumi dmt->table = &dm_target_linear_table;
322c9d0c62aShaad dmt->strategy = &dm_target_linear_strategy;
323fb8751abShaad dmt->sync = &dm_target_linear_sync;
324c9d0c62aShaad dmt->destroy = &dm_target_linear_destroy;
32567de4a93Stkusumi //dmt->upcall = &dm_target_linear_upcall;
32675268cffSmlelstv dmt->secsize = &dm_target_linear_secsize;
32784d45206Stkusumi if (dm_target_insert(dmt))
32884d45206Stkusumi printf("Failed to insert linear\n");
329c9d0c62aShaad
33084d45206Stkusumi dmt = dm_target_alloc("striped");
33184d45206Stkusumi dmt->version[0] = 1;
33284d45206Stkusumi dmt->version[1] = 0;
33384d45206Stkusumi dmt->version[2] = 3;
33484d45206Stkusumi dmt->init = &dm_target_stripe_init;
335c2813277Stkusumi dmt->info = &dm_target_stripe_info;
33684d45206Stkusumi dmt->table = &dm_target_stripe_table;
33784d45206Stkusumi dmt->strategy = &dm_target_stripe_strategy;
33884d45206Stkusumi dmt->sync = &dm_target_stripe_sync;
33984d45206Stkusumi dmt->destroy = &dm_target_stripe_destroy;
34067de4a93Stkusumi //dmt->upcall = &dm_target_stripe_upcall;
34184d45206Stkusumi dmt->secsize = &dm_target_stripe_secsize;
34284d45206Stkusumi if (dm_target_insert(dmt))
34384d45206Stkusumi printf("Failed to insert striped\n");
344c9d0c62aShaad
34584d45206Stkusumi dmt = dm_target_alloc("error");
34684d45206Stkusumi dmt->version[0] = 1;
34784d45206Stkusumi dmt->version[1] = 0;
34884d45206Stkusumi dmt->version[2] = 0;
34984d45206Stkusumi dmt->init = &dm_target_error_init;
35084d45206Stkusumi dmt->strategy = &dm_target_error_strategy;
35184d45206Stkusumi dmt->destroy = &dm_target_error_destroy;
35267de4a93Stkusumi //dmt->upcall = &dm_target_error_upcall;
35384d45206Stkusumi if (dm_target_insert(dmt))
35484d45206Stkusumi printf("Failed to insert error\n");
355c9d0c62aShaad
35684d45206Stkusumi dmt = dm_target_alloc("zero");
35784d45206Stkusumi dmt->version[0] = 1;
35884d45206Stkusumi dmt->version[1] = 0;
35984d45206Stkusumi dmt->version[2] = 0;
36084d45206Stkusumi dmt->init = &dm_target_zero_init;
36184d45206Stkusumi dmt->strategy = &dm_target_zero_strategy;
36284d45206Stkusumi dmt->destroy = &dm_target_zero_destroy;
36367de4a93Stkusumi //dmt->upcall = &dm_target_zero_upcall;
36484d45206Stkusumi if (dm_target_insert(dmt))
36584d45206Stkusumi printf("Failed to insert zero\n");
3668dab45b6Stkusumi #if 0
367ea24dc8dStkusumi dmt = dm_target_alloc("delay");
368ea24dc8dStkusumi dmt->version[0] = 1;
369ea24dc8dStkusumi dmt->version[1] = 0;
370ea24dc8dStkusumi dmt->version[2] = 0;
371ea24dc8dStkusumi dmt->init = &dm_target_delay_init;
372ea24dc8dStkusumi dmt->info = &dm_target_delay_info;
373ea24dc8dStkusumi dmt->table = &dm_target_delay_table;
374ea24dc8dStkusumi dmt->strategy = &dm_target_delay_strategy;
375ea24dc8dStkusumi dmt->sync = &dm_target_delay_sync;
376ea24dc8dStkusumi dmt->destroy = &dm_target_delay_destroy;
37767de4a93Stkusumi //dmt->upcall = &dm_target_delay_upcall;
378ea24dc8dStkusumi dmt->secsize = &dm_target_delay_secsize;
379ea24dc8dStkusumi if (dm_target_insert(dmt))
380ea24dc8dStkusumi printf("Failed to insert delay\n");
381ea24dc8dStkusumi dm_target_delay_pool_create();
382ea24dc8dStkusumi
3838dab45b6Stkusumi dmt = dm_target_alloc("flakey");
3848dab45b6Stkusumi dmt->version[0] = 1;
3858dab45b6Stkusumi dmt->version[1] = 0;
3868dab45b6Stkusumi dmt->version[2] = 0;
3878dab45b6Stkusumi dmt->init = &dm_target_flakey_init;
3888dab45b6Stkusumi dmt->table = &dm_target_flakey_table;
3898dab45b6Stkusumi dmt->strategy = &dm_target_flakey_strategy;
3908dab45b6Stkusumi dmt->sync = &dm_target_flakey_sync;
3918dab45b6Stkusumi dmt->destroy = &dm_target_flakey_destroy;
39267de4a93Stkusumi //dmt->upcall = &dm_target_flakey_upcall;
3938dab45b6Stkusumi dmt->secsize = &dm_target_flakey_secsize;
3948dab45b6Stkusumi if (dm_target_insert(dmt))
3958dab45b6Stkusumi printf("Failed to insert flakey\n");
3968dab45b6Stkusumi #endif
39784d45206Stkusumi return 0;
398c9d0c62aShaad }
399