1ff56536eSAlex Hornung /* $NetBSD: dm_target.c,v 1.12 2010/01/04 00:14:41 haad Exp $ */ 2ff56536eSAlex Hornung 3ff56536eSAlex Hornung /* 4ba2ce341SAlex Hornung * Copyright (c) 2010-2011 Alex Hornung <alex@alexhornung.com> 5ff56536eSAlex Hornung * Copyright (c) 2008 The NetBSD Foundation, Inc. 6ff56536eSAlex Hornung * All rights reserved. 7ff56536eSAlex Hornung * 8ff56536eSAlex Hornung * This code is derived from software contributed to The NetBSD Foundation 9ff56536eSAlex Hornung * by Adam Hamsik. 10ff56536eSAlex Hornung * 11ff56536eSAlex Hornung * Redistribution and use in source and binary forms, with or without 12ff56536eSAlex Hornung * modification, are permitted provided that the following conditions 13ff56536eSAlex Hornung * are met: 14ff56536eSAlex Hornung * 1. Redistributions of source code Must retain the above copyright 15ff56536eSAlex Hornung * notice, this list of conditions and the following disclaimer. 16ff56536eSAlex Hornung * 2. Redistributions in binary form must reproduce the above copyright 17ff56536eSAlex Hornung * notice, this list of conditions and the following disclaimer in the 18ff56536eSAlex Hornung * documentation and/or other materials provided with the distribution. 19ff56536eSAlex Hornung * 20ff56536eSAlex Hornung * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21ff56536eSAlex Hornung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22ff56536eSAlex Hornung * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23ff56536eSAlex Hornung * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24ff56536eSAlex Hornung * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25ff56536eSAlex Hornung * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26ff56536eSAlex Hornung * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27ff56536eSAlex Hornung * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28ff56536eSAlex Hornung * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29ff56536eSAlex Hornung * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30ff56536eSAlex Hornung * POSSIBILITY OF SUCH DAMAGE. 31ff56536eSAlex Hornung */ 32ff56536eSAlex Hornung 33ff56536eSAlex Hornung #include <sys/types.h> 345b279a20SAlex Hornung #include <sys/malloc.h> 35ff56536eSAlex Hornung #include <sys/module.h> 367115a22bSAlex Hornung #include <sys/linker.h> 37a84e173eSAlex Hornung #include <dev/disk/dm/dm.h> 38ff56536eSAlex Hornung 39ff56536eSAlex Hornung #include "netbsd-dm.h" 40ff56536eSAlex Hornung 41ff56536eSAlex Hornung static dm_target_t *dm_target_lookup_name(const char *); 42ff56536eSAlex Hornung 434e359672STomohiro Kusumi static TAILQ_HEAD(, dm_target) dm_target_list; 44ff56536eSAlex Hornung 45637b454aSTomohiro Kusumi static struct lock dm_target_mutex; 46ff56536eSAlex Hornung 47ff56536eSAlex Hornung void 48ff56536eSAlex Hornung dm_target_busy(dm_target_t *target) 49ff56536eSAlex Hornung { 505b279a20SAlex Hornung atomic_add_int(&target->ref_cnt, 1); 51ff56536eSAlex Hornung } 52*b7c11cdaSTomohiro Kusumi 53ff56536eSAlex Hornung /* 54ff56536eSAlex Hornung * Release reference counter on target. 55ff56536eSAlex Hornung */ 56ff56536eSAlex Hornung void 57ff56536eSAlex Hornung dm_target_unbusy(dm_target_t *target) 58ff56536eSAlex Hornung { 595b279a20SAlex Hornung KKASSERT(target->ref_cnt > 0); 605b279a20SAlex Hornung atomic_subtract_int(&target->ref_cnt, 1); 61ff56536eSAlex Hornung } 62ff56536eSAlex Hornung 63ff56536eSAlex Hornung /* 647115a22bSAlex Hornung * Try to autoload the module for the requested target. 657115a22bSAlex Hornung */ 667115a22bSAlex Hornung dm_target_t * 677115a22bSAlex Hornung dm_target_autoload(const char *dm_target_name) 687115a22bSAlex Hornung { 697115a22bSAlex Hornung char mod_name[128]; 707115a22bSAlex Hornung dm_target_t *dmt; 717115a22bSAlex Hornung linker_file_t linker_file; 727115a22bSAlex Hornung int error; 737115a22bSAlex Hornung 747115a22bSAlex Hornung ksnprintf(mod_name, sizeof(mod_name), "dm_target_%s", dm_target_name); 757115a22bSAlex Hornung error = linker_reference_module(mod_name, NULL, &linker_file); 767115a22bSAlex Hornung if (error != 0) { 777115a22bSAlex Hornung kprintf("dm: could not autoload module for target %s\n", 787115a22bSAlex Hornung dm_target_name); 797115a22bSAlex Hornung return NULL; 807115a22bSAlex Hornung } 817115a22bSAlex Hornung 827115a22bSAlex Hornung dmt = dm_target_lookup(dm_target_name); 837115a22bSAlex Hornung if (dmt == NULL) { 847115a22bSAlex Hornung linker_release_module(NULL, NULL, linker_file); 857115a22bSAlex Hornung return NULL; 867115a22bSAlex Hornung } 877115a22bSAlex Hornung 887115a22bSAlex Hornung /* XXX: extra-big hack to allow users to kldunload the module */ 897115a22bSAlex Hornung linker_file->userrefs = 1; 907115a22bSAlex Hornung 917115a22bSAlex Hornung return dmt; 927115a22bSAlex Hornung } 937115a22bSAlex Hornung 947115a22bSAlex Hornung /* 95ff56536eSAlex Hornung * Lookup for target in global target list. 96ff56536eSAlex Hornung */ 97ff56536eSAlex Hornung dm_target_t * 98ff56536eSAlex Hornung dm_target_lookup(const char *dm_target_name) 99ff56536eSAlex Hornung { 100ff56536eSAlex Hornung dm_target_t *dmt; 101ff56536eSAlex Hornung 102ff56536eSAlex Hornung dmt = NULL; 103ff56536eSAlex Hornung 104ff56536eSAlex Hornung if (dm_target_name == NULL) 105ff56536eSAlex Hornung return NULL; 106ff56536eSAlex Hornung 1075b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 108ff56536eSAlex Hornung 109ff56536eSAlex Hornung dmt = dm_target_lookup_name(dm_target_name); 110ff56536eSAlex Hornung if (dmt != NULL) 111ff56536eSAlex Hornung dm_target_busy(dmt); 112ff56536eSAlex Hornung 1135b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 114ff56536eSAlex Hornung 115ff56536eSAlex Hornung return dmt; 116ff56536eSAlex Hornung } 117*b7c11cdaSTomohiro Kusumi 118ff56536eSAlex Hornung /* 119*b7c11cdaSTomohiro Kusumi * Search for name in TAILQ and return apropriate pointer. 120ff56536eSAlex Hornung */ 121ff56536eSAlex Hornung static dm_target_t * 122ff56536eSAlex Hornung dm_target_lookup_name(const char *dm_target_name) 123ff56536eSAlex Hornung { 124ff56536eSAlex Hornung dm_target_t *dm_target; 125ff56536eSAlex Hornung 126ff56536eSAlex Hornung TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 1270d42d35bSAlex Hornung if (strcmp(dm_target_name, dm_target->name) == 0) 128ff56536eSAlex Hornung return dm_target; 129ff56536eSAlex Hornung } 130ff56536eSAlex Hornung 131ff56536eSAlex Hornung return NULL; 132ff56536eSAlex Hornung } 133*b7c11cdaSTomohiro Kusumi 134ff56536eSAlex Hornung /* 135*b7c11cdaSTomohiro Kusumi * Insert new target struct into the TAILQ. 136*b7c11cdaSTomohiro Kusumi * dm_target contains name, version, function pointer to specific target 137*b7c11cdaSTomohiro Kusumi * functions. 138ff56536eSAlex Hornung */ 139ff56536eSAlex Hornung int 140ff56536eSAlex Hornung dm_target_insert(dm_target_t *dm_target) 141ff56536eSAlex Hornung { 142ff56536eSAlex Hornung dm_target_t *dmt; 143ff56536eSAlex Hornung 144b4e97860STomohiro Kusumi if (dm_target->init == NULL) { 145b4e97860STomohiro Kusumi kprintf("dm: %s missing init\n", dm_target->name); 146b4e97860STomohiro Kusumi return EINVAL; 147b4e97860STomohiro Kusumi } 148b4e97860STomohiro Kusumi if (dm_target->destroy == NULL) { 149b4e97860STomohiro Kusumi kprintf("dm: %s missing destroy\n", dm_target->name); 150b4e97860STomohiro Kusumi return EINVAL; 151b4e97860STomohiro Kusumi } 152b4e97860STomohiro Kusumi if (dm_target->strategy == NULL) { 153b4e97860STomohiro Kusumi kprintf("dm: %s missing strategy\n", dm_target->name); 154b4e97860STomohiro Kusumi return EINVAL; 155b4e97860STomohiro Kusumi } 156b4e97860STomohiro Kusumi 1575b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 158ff56536eSAlex Hornung 159ff56536eSAlex Hornung dmt = dm_target_lookup_name(dm_target->name); 160ff56536eSAlex Hornung if (dmt != NULL) { 1615b279a20SAlex Hornung kprintf("uhoh, target_insert EEXIST\n"); 1625b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 163ff56536eSAlex Hornung return EEXIST; 164ff56536eSAlex Hornung } 165ff56536eSAlex Hornung TAILQ_INSERT_TAIL(&dm_target_list, dm_target, dm_target_next); 166ff56536eSAlex Hornung 1675b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 168ff56536eSAlex Hornung 169ff56536eSAlex Hornung return 0; 170ff56536eSAlex Hornung } 171ff56536eSAlex Hornung 172ff56536eSAlex Hornung /* 173*b7c11cdaSTomohiro Kusumi * Remove target from TAILQ, target is selected with it's name. 174ff56536eSAlex Hornung */ 175ff56536eSAlex Hornung int 176a6b470c8STomohiro Kusumi dm_target_remove(char *dm_target_name) 177ff56536eSAlex Hornung { 178ff56536eSAlex Hornung dm_target_t *dmt; 179ff56536eSAlex Hornung 1805b279a20SAlex Hornung KKASSERT(dm_target_name != NULL); 181ff56536eSAlex Hornung 1825b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 183ff56536eSAlex Hornung 184ff56536eSAlex Hornung dmt = dm_target_lookup_name(dm_target_name); 185ff56536eSAlex Hornung if (dmt == NULL) { 1865b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 187ff56536eSAlex Hornung return ENOENT; 188ff56536eSAlex Hornung } 189ff56536eSAlex Hornung if (dmt->ref_cnt > 0) { 1905b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 191ff56536eSAlex Hornung return EBUSY; 192ff56536eSAlex Hornung } 193*b7c11cdaSTomohiro Kusumi TAILQ_REMOVE(&dm_target_list, dmt, dm_target_next); 194ff56536eSAlex Hornung 1955b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 196ff56536eSAlex Hornung 197d880b9dfSTomohiro Kusumi dm_target_free(dmt); 198ff56536eSAlex Hornung 199ff56536eSAlex Hornung return 0; 200ff56536eSAlex Hornung } 201ff56536eSAlex Hornung 202ff56536eSAlex Hornung /* 203ff56536eSAlex Hornung * Allocate new target entry. 204ff56536eSAlex Hornung */ 205ff56536eSAlex Hornung dm_target_t * 206ff56536eSAlex Hornung dm_target_alloc(const char *name) 207ff56536eSAlex Hornung { 208efaf91a7STomohiro Kusumi dm_target_t *dmt; 209efaf91a7STomohiro Kusumi 210efaf91a7STomohiro Kusumi dmt = kmalloc(sizeof(*dmt), M_DM, M_WAITOK | M_ZERO); 211efaf91a7STomohiro Kusumi if (dmt == NULL) 212efaf91a7STomohiro Kusumi return NULL; 213efaf91a7STomohiro Kusumi 214efaf91a7STomohiro Kusumi if (name) 215efaf91a7STomohiro Kusumi strlcpy(dmt->name, name, sizeof(dmt->name)); 216efaf91a7STomohiro Kusumi 217efaf91a7STomohiro Kusumi return dmt; 218ff56536eSAlex Hornung } 219efaf91a7STomohiro Kusumi 220d880b9dfSTomohiro Kusumi int 221d880b9dfSTomohiro Kusumi dm_target_free(dm_target_t *dmt) 222d880b9dfSTomohiro Kusumi { 223d880b9dfSTomohiro Kusumi KKASSERT(dmt != NULL); 224d880b9dfSTomohiro Kusumi 225d880b9dfSTomohiro Kusumi kfree(dmt, M_DM); 226d880b9dfSTomohiro Kusumi 227d880b9dfSTomohiro Kusumi return 0; 228d880b9dfSTomohiro Kusumi } 229d880b9dfSTomohiro Kusumi 230ff56536eSAlex Hornung /* 231ff56536eSAlex Hornung * Return prop_array of dm_target dictionaries. 232ff56536eSAlex Hornung */ 233ff56536eSAlex Hornung prop_array_t 234ff56536eSAlex Hornung dm_target_prop_list(void) 235ff56536eSAlex Hornung { 236ff56536eSAlex Hornung prop_array_t target_array, ver; 237ff56536eSAlex Hornung prop_dictionary_t target_dict; 238ff56536eSAlex Hornung dm_target_t *dm_target; 239ff56536eSAlex Hornung 240ff56536eSAlex Hornung size_t i; 241ff56536eSAlex Hornung 242ff56536eSAlex Hornung target_array = prop_array_create(); 243ff56536eSAlex Hornung 2445b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 245ff56536eSAlex Hornung 246ff56536eSAlex Hornung TAILQ_FOREACH(dm_target, &dm_target_list, dm_target_next) { 247ff56536eSAlex Hornung 248ff56536eSAlex Hornung target_dict = prop_dictionary_create(); 249ff56536eSAlex Hornung ver = prop_array_create(); 250ff56536eSAlex Hornung prop_dictionary_set_cstring(target_dict, DM_TARGETS_NAME, 251ff56536eSAlex Hornung dm_target->name); 252ff56536eSAlex Hornung 253ff56536eSAlex Hornung for (i = 0; i < 3; i++) 254ff56536eSAlex Hornung prop_array_add_uint32(ver, dm_target->version[i]); 255ff56536eSAlex Hornung 256ff56536eSAlex Hornung prop_dictionary_set(target_dict, DM_TARGETS_VERSION, ver); 257ff56536eSAlex Hornung prop_array_add(target_array, target_dict); 258ff56536eSAlex Hornung 259ff56536eSAlex Hornung prop_object_release(ver); 260ff56536eSAlex Hornung prop_object_release(target_dict); 261ff56536eSAlex Hornung } 262ff56536eSAlex Hornung 2635b279a20SAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 264ff56536eSAlex Hornung 265ff56536eSAlex Hornung return target_array; 266ff56536eSAlex Hornung } 2675c411e8eSAlex Hornung 268*b7c11cdaSTomohiro Kusumi /* 269*b7c11cdaSTomohiro Kusumi * Initialize dm_target subsystem. 270*b7c11cdaSTomohiro Kusumi */ 271ff56536eSAlex Hornung int 272ff56536eSAlex Hornung dm_target_init(void) 273ff56536eSAlex Hornung { 2744e359672STomohiro Kusumi TAILQ_INIT(&dm_target_list); /* initialize global target list */ 2755b279a20SAlex Hornung lockinit(&dm_target_mutex, "dmtrgt", 0, LK_CANRECURSE); 276ff56536eSAlex Hornung 2775c411e8eSAlex Hornung return 0; 278ff56536eSAlex Hornung } 2799fada28aSAlex Hornung 2809fada28aSAlex Hornung /* 2819fada28aSAlex Hornung * Destroy all targets and remove them from queue. 2827350b8b6STomohiro Kusumi * This routine is called from dmdestroy, before module 2839fada28aSAlex Hornung * is unloaded. 2849fada28aSAlex Hornung */ 2859fada28aSAlex Hornung int 2869fada28aSAlex Hornung dm_target_uninit(void) 2879fada28aSAlex Hornung { 2889fada28aSAlex Hornung dm_target_t *dm_target; 2899fada28aSAlex Hornung 2909fada28aSAlex Hornung lockmgr(&dm_target_mutex, LK_EXCLUSIVE); 2919fada28aSAlex Hornung 29233b3a12eSTomohiro Kusumi while ((dm_target = TAILQ_FIRST(&dm_target_list)) != NULL) { 29333b3a12eSTomohiro Kusumi TAILQ_REMOVE(&dm_target_list, dm_target, dm_target_next); 294d880b9dfSTomohiro Kusumi dm_target_free(dm_target); 2959fada28aSAlex Hornung } 29633b3a12eSTomohiro Kusumi KKASSERT(TAILQ_EMPTY(&dm_target_list)); 29733b3a12eSTomohiro Kusumi 2989fada28aSAlex Hornung lockmgr(&dm_target_mutex, LK_RELEASE); 2999fada28aSAlex Hornung 3009fada28aSAlex Hornung lockuninit(&dm_target_mutex); 3019fada28aSAlex Hornung 3029fada28aSAlex Hornung return 0; 3039fada28aSAlex Hornung } 304