1b7d3956bSstephh /* 2b7d3956bSstephh * 3b7d3956bSstephh * CDDL HEADER START 4b7d3956bSstephh * 5b7d3956bSstephh * The contents of this file are subject to the terms of the 6b7d3956bSstephh * Common Development and Distribution License (the "License"). 7b7d3956bSstephh * You may not use this file except in compliance with the License. 8b7d3956bSstephh * 9b7d3956bSstephh * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10b7d3956bSstephh * or http://www.opensolaris.org/os/licensing. 11b7d3956bSstephh * See the License for the specific language governing permissions 12b7d3956bSstephh * and limitations under the License. 13b7d3956bSstephh * 14b7d3956bSstephh * When distributing Covered Code, include this CDDL HEADER in each 15b7d3956bSstephh * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16b7d3956bSstephh * If applicable, add the following below this CDDL HEADER, with the 17b7d3956bSstephh * fields enclosed by brackets "[]" replaced with your own identifying 18b7d3956bSstephh * information: Portions Copyright [yyyy] [name of copyright owner] 19b7d3956bSstephh * 20b7d3956bSstephh * CDDL HEADER END 21b7d3956bSstephh */ 22b7d3956bSstephh 23b7d3956bSstephh /* 24f6e214c7SGavin Maltby * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 25*2227b8adSAlek Pinchuk * Copyright 2013 Nexenta Systems, Inc. All rights reserved. 26b7d3956bSstephh */ 27b7d3956bSstephh 28b7d3956bSstephh #include <stdio.h> 29b7d3956bSstephh #include <stdlib.h> 30b7d3956bSstephh #include <string.h> 31b7d3956bSstephh #include <errno.h> 32b7d3956bSstephh #include <ctype.h> 33b7d3956bSstephh #include <alloca.h> 34b7d3956bSstephh #include <limits.h> 35b7d3956bSstephh #include <fm/topo_mod.h> 36b7d3956bSstephh #include <sys/param.h> 37b7d3956bSstephh #include <sys/systeminfo.h> 38b7d3956bSstephh #include <sys/fm/protocol.h> 39b7d3956bSstephh #include <sys/stat.h> 40b7d3956bSstephh 41b7d3956bSstephh #include <topo_method.h> 42b7d3956bSstephh #include <topo_subr.h> 43b7d3956bSstephh #include <libzfs.h> 44b7d3956bSstephh #include <zfs.h> 45*2227b8adSAlek Pinchuk #include <pthread.h> 46b7d3956bSstephh 47b7d3956bSstephh static int zfs_enum(topo_mod_t *, tnode_t *, const char *, topo_instance_t, 48b7d3956bSstephh topo_instance_t, void *, void *); 49842727c2SChris Kirby static void zfs_rele(topo_mod_t *, tnode_t *); 50b7d3956bSstephh static int zfs_fmri_nvl2str(topo_mod_t *, tnode_t *, topo_version_t, 51b7d3956bSstephh nvlist_t *, nvlist_t **); 52b7d3956bSstephh 53b7d3956bSstephh const topo_method_t zfs_methods[] = { 54b7d3956bSstephh { TOPO_METH_NVL2STR, TOPO_METH_NVL2STR_DESC, TOPO_METH_NVL2STR_VERSION, 55b7d3956bSstephh TOPO_STABILITY_INTERNAL, zfs_fmri_nvl2str }, 56b7d3956bSstephh { NULL } 57b7d3956bSstephh }; 58b7d3956bSstephh 59b7d3956bSstephh static const topo_modops_t zfs_ops = 60842727c2SChris Kirby { zfs_enum, zfs_rele }; 61b7d3956bSstephh static const topo_modinfo_t zfs_info = 62b7d3956bSstephh { ZFS, FM_FMRI_SCHEME_ZFS, ZFS_VERSION, &zfs_ops }; 63b7d3956bSstephh 64*2227b8adSAlek Pinchuk static libzfs_handle_t *g_zfs = NULL; 65*2227b8adSAlek Pinchuk static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER; 66*2227b8adSAlek Pinchuk static int g_refcount = 0; 67d5b8f72dSStephen Hanson 68b7d3956bSstephh int 69b7d3956bSstephh zfs_init(topo_mod_t *mod, topo_version_t version) 70b7d3956bSstephh { 71b7d3956bSstephh /* 72b7d3956bSstephh * Turn on module debugging output 73b7d3956bSstephh */ 74b7d3956bSstephh if (getenv("TOPOZFSDEBUG")) 75b7d3956bSstephh topo_mod_setdebug(mod); 76b7d3956bSstephh 77b7d3956bSstephh topo_mod_dprintf(mod, "initializing zfs builtin\n"); 78b7d3956bSstephh 79b7d3956bSstephh if (version != ZFS_VERSION) 80b7d3956bSstephh return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 81b7d3956bSstephh 82b7d3956bSstephh if (topo_mod_register(mod, &zfs_info, TOPO_VERSION) != 0) { 83b7d3956bSstephh topo_mod_dprintf(mod, "failed to register zfs: " 84b7d3956bSstephh "%s\n", topo_mod_errmsg(mod)); 85b7d3956bSstephh return (-1); /* mod errno already set */ 86b7d3956bSstephh } 87*2227b8adSAlek Pinchuk 88*2227b8adSAlek Pinchuk (void) pthread_mutex_lock(&g_lock); 89*2227b8adSAlek Pinchuk if (g_refcount == 0) { 90*2227b8adSAlek Pinchuk if ((g_zfs = libzfs_init()) == NULL) { 91*2227b8adSAlek Pinchuk (void) pthread_mutex_unlock(&g_lock); 92*2227b8adSAlek Pinchuk topo_mod_dprintf(mod, "libzfs_init() failed"); 93*2227b8adSAlek Pinchuk topo_mod_unregister(mod); 94*2227b8adSAlek Pinchuk return (topo_mod_seterrno(mod, EMOD_UNKNOWN)); 95*2227b8adSAlek Pinchuk } 96*2227b8adSAlek Pinchuk } 97*2227b8adSAlek Pinchuk g_refcount++; 98*2227b8adSAlek Pinchuk (void) pthread_mutex_unlock(&g_lock); 99b7d3956bSstephh 100b7d3956bSstephh return (0); 101b7d3956bSstephh } 102b7d3956bSstephh 103b7d3956bSstephh void 104b7d3956bSstephh zfs_fini(topo_mod_t *mod) 105b7d3956bSstephh { 106*2227b8adSAlek Pinchuk (void) pthread_mutex_lock(&g_lock); 107*2227b8adSAlek Pinchuk g_refcount--; 108*2227b8adSAlek Pinchuk if (g_refcount == 0) { 109d5b8f72dSStephen Hanson libzfs_fini(g_zfs); 110d5b8f72dSStephen Hanson g_zfs = NULL; 111ede7616dSStephen Hanson } 112*2227b8adSAlek Pinchuk (void) pthread_mutex_unlock(&g_lock); 113b7d3956bSstephh topo_mod_unregister(mod); 114b7d3956bSstephh } 115b7d3956bSstephh 116b7d3956bSstephh 117b7d3956bSstephh /*ARGSUSED*/ 118b7d3956bSstephh int 119b7d3956bSstephh zfs_enum(topo_mod_t *mod, tnode_t *pnode, const char *name, topo_instance_t min, 120b7d3956bSstephh topo_instance_t max, void *notused1, void *notused2) 121b7d3956bSstephh { 122f6e214c7SGavin Maltby /* 123f6e214c7SGavin Maltby * Methods are registered, but there is no enumeration. Should 124f6e214c7SGavin Maltby * enumeration be added be sure to cater for global vs non-global 125f6e214c7SGavin Maltby * zones. 126f6e214c7SGavin Maltby */ 127b7d3956bSstephh (void) topo_method_register(mod, pnode, zfs_methods); 128b7d3956bSstephh return (0); 129b7d3956bSstephh } 130b7d3956bSstephh 131b7d3956bSstephh /*ARGSUSED*/ 132b7d3956bSstephh static void 133842727c2SChris Kirby zfs_rele(topo_mod_t *mp, tnode_t *node) 134b7d3956bSstephh { 135b7d3956bSstephh topo_method_unregister_all(mp, node); 136b7d3956bSstephh } 137b7d3956bSstephh 138b7d3956bSstephh typedef struct cbdata { 139b7d3956bSstephh uint64_t cb_guid; 140b7d3956bSstephh zpool_handle_t *cb_pool; 141b7d3956bSstephh } cbdata_t; 142b7d3956bSstephh 143b7d3956bSstephh static int 144b7d3956bSstephh find_pool(zpool_handle_t *zhp, void *data) 145b7d3956bSstephh { 146b7d3956bSstephh cbdata_t *cbp = data; 147b7d3956bSstephh 148b7d3956bSstephh if (zpool_get_prop_int(zhp, ZPOOL_PROP_GUID, NULL) == cbp->cb_guid) { 149b7d3956bSstephh cbp->cb_pool = zhp; 150b7d3956bSstephh return (1); 151b7d3956bSstephh } 152b7d3956bSstephh 153b7d3956bSstephh zpool_close(zhp); 154b7d3956bSstephh 155b7d3956bSstephh return (0); 156b7d3956bSstephh } 157b7d3956bSstephh 158b7d3956bSstephh static ssize_t 159b7d3956bSstephh fmri_nvl2str(nvlist_t *nvl, char *buf, size_t buflen) 160b7d3956bSstephh { 161b7d3956bSstephh uint64_t pool_guid, vdev_guid; 162b7d3956bSstephh cbdata_t cb; 163b7d3956bSstephh ssize_t len; 164b7d3956bSstephh const char *name; 165b7d3956bSstephh char guidbuf[64]; 166b7d3956bSstephh 167b7d3956bSstephh (void) nvlist_lookup_uint64(nvl, FM_FMRI_ZFS_POOL, &pool_guid); 168b7d3956bSstephh 169b7d3956bSstephh /* 170b7d3956bSstephh * Attempt to convert the pool guid to a name. 171b7d3956bSstephh */ 172b7d3956bSstephh cb.cb_guid = pool_guid; 173b7d3956bSstephh cb.cb_pool = NULL; 174b7d3956bSstephh 175*2227b8adSAlek Pinchuk if (zpool_iter(g_zfs, find_pool, &cb) == 1) { 176b7d3956bSstephh name = zpool_get_name(cb.cb_pool); 177b7d3956bSstephh } else { 178b7d3956bSstephh (void) snprintf(guidbuf, sizeof (guidbuf), "%llx", pool_guid); 179b7d3956bSstephh name = guidbuf; 180b7d3956bSstephh } 181b7d3956bSstephh 182b7d3956bSstephh if (nvlist_lookup_uint64(nvl, FM_FMRI_ZFS_VDEV, &vdev_guid) == 0) 183b7d3956bSstephh len = snprintf(buf, buflen, "%s://pool=%s/vdev=%llx", 184b7d3956bSstephh FM_FMRI_SCHEME_ZFS, name, vdev_guid); 185b7d3956bSstephh else 186b7d3956bSstephh len = snprintf(buf, buflen, "%s://pool=%s", 187b7d3956bSstephh FM_FMRI_SCHEME_ZFS, name); 188b7d3956bSstephh 189b7d3956bSstephh if (cb.cb_pool) 190b7d3956bSstephh zpool_close(cb.cb_pool); 191b7d3956bSstephh 192b7d3956bSstephh return (len); 193b7d3956bSstephh } 194b7d3956bSstephh 195b7d3956bSstephh /*ARGSUSED*/ 196b7d3956bSstephh static int 197b7d3956bSstephh zfs_fmri_nvl2str(topo_mod_t *mod, tnode_t *node, topo_version_t version, 198b7d3956bSstephh nvlist_t *nvl, nvlist_t **out) 199b7d3956bSstephh { 200b7d3956bSstephh ssize_t len; 201b7d3956bSstephh char *name = NULL; 202b7d3956bSstephh nvlist_t *fmristr; 203b7d3956bSstephh 204b7d3956bSstephh if (version > TOPO_METH_NVL2STR_VERSION) 205b7d3956bSstephh return (topo_mod_seterrno(mod, EMOD_VER_NEW)); 206b7d3956bSstephh 207b7d3956bSstephh if ((len = fmri_nvl2str(nvl, NULL, 0)) == 0 || 208b7d3956bSstephh (name = topo_mod_alloc(mod, len + 1)) == NULL || 209b7d3956bSstephh fmri_nvl2str(nvl, name, len + 1) == 0) { 210b7d3956bSstephh if (name != NULL) 211b7d3956bSstephh topo_mod_free(mod, name, len + 1); 212b7d3956bSstephh return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 213b7d3956bSstephh } 214b7d3956bSstephh 215b7d3956bSstephh if (topo_mod_nvalloc(mod, &fmristr, NV_UNIQUE_NAME) != 0) { 216b7d3956bSstephh topo_mod_free(mod, name, len + 1); 217b7d3956bSstephh return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 218b7d3956bSstephh } 219b7d3956bSstephh if (nvlist_add_string(fmristr, "fmri-string", name) != 0) { 220b7d3956bSstephh topo_mod_free(mod, name, len + 1); 221b7d3956bSstephh nvlist_free(fmristr); 222b7d3956bSstephh return (topo_mod_seterrno(mod, EMOD_FMRI_NVL)); 223b7d3956bSstephh } 224b7d3956bSstephh topo_mod_free(mod, name, len + 1); 225b7d3956bSstephh *out = fmristr; 226b7d3956bSstephh 227b7d3956bSstephh return (0); 228b7d3956bSstephh } 229