/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ #ifndef _LIBDISKMGT_H #define _LIBDISKMGT_H #ifdef __cplusplus extern "C" { #endif #include #include /* * Disk Management Library * * This library provides a common way to gather information about a system's * disks, controllers, and related components. * * * THREADS * ------- * * In general all of the functions are thread safe, however there are some * specific considerations for getting events. The dm_get_event function may * block the calling thread if no event is currently available. If another * thread calls dm_get_event while a thread is already blocked in this function, * the second thread will also block. When an event arrives and multiple * threads are waiting for events, it is undefined which thread will be * unblocked and receive the event. If a callback is used for handling events, * this is equivalent to the dm_get_event function, so mixing callbacks and * dm_get_event is also nondeterministic. * * * ERRORS * ------ * * In general all of the functions take an errno pointer. This is an integer * that will contain 0 if the function succeeded or contains an errno (see * errno.h) if there was an error. If the function returns some data, that * return data will generally be null if an error occured (see the API comment * for the specific function for details). Many of the functions take a * descriptor and provide more information for that descriptor. These functions * may return an error if the object was removed between the call which obtained * the descriptor and the call to get more information about the object (errno * will be ENODEV). Only a few of the possible errno values will be returned; * typically: * EPERM not super-user * ENOMEM not enough memory * ENODEV no such device * EINVAL invalid argument * ENOENT no event queue has been created * * Many of the functions require the application to be running as root in order * to get complete information. EPERM will be returned if the application is * not running as root. However, not all of the functions have this requirement * (i.e. event handling). * * It is possible for the system to run out of memory while receiving events. * Since event receipt is asyncronous from the dm_get_event call there may not * be a thread waiting when the event occurs and ENOMEM is detected. In this * case the event will be lost. The first call to dm_get_event following this * condition will immediately return ENOMEM, even if events are queued. * Subsequent calls can return events. The dm_get_event call will clear the * pending ENOMEM condition. There is no way to know how many events were lost * when this situation occurs. If a thread is waiting when the event arrives * and the ENOMEM condition occurs, the call will also return with ENOMEM. * There is no way to determine if the system ran out of memory before the * dm_get_event call or while the thread was blocked in the dm_get_event call * since both conditions cause dm_get_event to return ENOMEM. * * * MEMORY MANAGEMENT * ----------------- * * Most of the functions that return data are returning memory that has been * allocated and must be freed by the application when no longer needed. The * application should call the proper free function to free the memory. Most of * the functions return either a nvlist or an array of descriptors. The normal * nvlist function (nvlist_free; see libnvpair(3LIB)) can be used to free the * simple nvlists. Other functions are provided to free the more complex data * structures. * * The following list shows the functions that return allocated memory and the * corresponding function to free the memory: * dm_get_descriptors dm_free_descriptors * dm_get_associated_descriptors dm_free_descriptors * dm_get_descriptor_by_name dm_free_descriptor * dm_get_name dm_free_name * dm_get_attributes nvlist_free * dm_get_stats nvlist_free * dm_get_event nvlist_free * * * EVENTS * ------ * * Event information is returned as a nvlist. It may be possible to return more * information about events over time, especially information about what has * changed. However, that may not always be the case, so by using an nvlist we * have a very generic event indication. At a minimum the event will return the * name of the device, the type of device (see dm_desc_type_t) and the type of * event. The event type is a string which can currently be; add, remove, * change. * * If a drive goes up or down this could be returned as event type "change". * The application could get the drive information to see that the "status" * attribute has changed value (ideally the event would include an attribute * with the name of the changed attribute as the value). Although the API can * return events for all drive related changes, events will not necessarily be * delivered for all changes unless the system generates those events. * * * Controller/HBAs * --------------- * * In general the API means "the parent node of the drive in the device tree" * where the word "controller" is used. This can actually be either the HBA or * the drive controller depending on the type of the drive. * * Drives can be connected to their controller(s) in three different ways: * single controller * multiple controllers * multiple controllers with mpxio * These cases will lead to different information being available for the * configuration. The two interesting cases are multi-path with and without * mpxio. With mpxio the drive will have a unique name and a single controller * (scsi_vhci). The physical controllers, the paths to the drive, can be * obtained by calling dm_get_associated_descriptors with a drive descriptor and * a type of DM_PATH. This will only return these physical paths when MPXIO, or * possibly some future similar feature, is controlling the drive. * * Without mpxio the drive does not have a unique public name (in all cases the * alias(es) of the drive can be determined by calling * dm_get_associated_descriptors to get the DM_ALIAS descriptors. There will be * more than one controller returned from dm_get_associated_descriptors when * called with a type of DM_CONTROLLER. The controllers for each of the aliases * will be returned in the same order as the aliases descriptors. For example, * a drive with two paths has the aliases c5t3d2 and c7t1d0. There will be two * controllers returned; the first corresponds to c5 and the second corresponds * to c7. * * In the multi-path, non-mpxio case the drive has more than one alias. * Although most of the drive attributes are represented on the drive (see * dm_get_attributes) there can be some different attributes for the different * aliases for the drive. Use dm_get_associated_descriptors to get the DM_ALIAS * descriptors which can then be used to obtain these attributes. Use of this * algorithm is not restricted to the multi-path, non-mpxio case. For example, * it can be used to get the target/lun for a SCSI drive with a single path. */ /* * Holds all the data regarding the device. * Private to libdiskmgt. Must use dm_xxx functions to set/get data. */ typedef uint64_t dm_descriptor_t; typedef enum { DM_WHO_MKFS = 0, DM_WHO_ZPOOL, DM_WHO_ZPOOL_FORCE, DM_WHO_FORMAT, DM_WHO_SWAP, DM_WHO_DUMP, DM_WHO_ZPOOL_SPARE } dm_who_type_t; /* * The API uses a "descriptor" to identify the managed objects such as drives, * controllers, media, slices, partitions, paths and buses. The descriptors are * opaque and are only returned or used as parameters to the other functions in * the API. The descriptor definition is a typedef to dm_descriptor_t. * * Applications call either the dm_get_descriptors or * dm_get_associated_descriptors function to obtain a list of descriptors of a * specific type. The application specifies the desired type from the following * enumeration: */ typedef enum { DM_DRIVE = 0, DM_CONTROLLER, DM_MEDIA, DM_SLICE, DM_PARTITION, DM_PATH, DM_ALIAS, DM_BUS } dm_desc_type_t; /* * These descriptors are associated with each other in the following way: * * alias partition * _ \ / | * / \ \ / | * \ / \ / | * bus --- controller --- drive --- media | * | / \ | * | / \ | * | / \ | * path slice * * The dm_get_associated_descriptors function can be used get the descriptors * associated with a given descriptor. The dm_get_associated_types function can * be used to find the types that can be associated with a given type. * * The attributes and values for these objects are described using a list of * name/value pairs (see libnvpair(3LIB) and the specific comments for each * function in the API section of this document). * * Drives and media have a type which are defined as the following enumerations. * There could be additional types added to these enumerations as new drive and * media types are supported by the system. */ typedef enum { DM_DT_UNKNOWN = 0, DM_DT_FIXED, DM_DT_ZIP, DM_DT_JAZ, DM_DT_FLOPPY, DM_DT_MO_ERASABLE, DM_DT_MO_WRITEONCE, DM_DT_AS_MO, DM_DT_CDROM, DM_DT_CDR, DM_DT_CDRW, DM_DT_DVDROM, DM_DT_DVDR, DM_DT_DVDRAM, DM_DT_DVDRW, DM_DT_DDCDROM, DM_DT_DDCDR, DM_DT_DDCDRW } dm_drive_type_t; typedef enum { DM_MT_UNKNOWN = 0, DM_MT_FIXED, DM_MT_FLOPPY, DM_MT_CDROM, DM_MT_ZIP, DM_MT_JAZ, DM_MT_CDR, DM_MT_CDRW, DM_MT_DVDROM, DM_MT_DVDR, DM_MT_DVDRAM, DM_MT_MO_ERASABLE, DM_MT_MO_WRITEONCE, DM_MT_AS_MO } dm_media_type_t; #define DM_FILTER_END -1 /* * The dm_get_stats function takes a stat_type argument for the specific sample * to get for the descriptor. The following enums specify the drive and slice * stat types. */ /* drive stat name */ typedef enum { DM_DRV_STAT_PERFORMANCE = 0, DM_DRV_STAT_DIAGNOSTIC, DM_DRV_STAT_TEMPERATURE } dm_drive_stat_t; /* slice stat name */ typedef enum { DM_SLICE_STAT_USE = 0 } dm_slice_stat_t; /* partition type */ typedef enum { DM_PRIMARY = 0, DM_EXTENDED, DM_LOGICAL } dm_partition_type_t; /* attribute definitions */ /* drive */ #define DM_DISK_UP 1 #define DM_DISK_DOWN 0 #define DM_CLUSTERED "clustered" #define DM_DRVTYPE "drvtype" #define DM_FAILING "failing" #define DM_LOADED "loaded" /* also in media */ #define DM_NDNRERRS "ndevice_not_ready_errors" #define DM_NBYTESREAD "nbytes_read" #define DM_NBYTESWRITTEN "nbytes_written" #define DM_NHARDERRS "nhard_errors" #define DM_NILLREQERRS "nillegal_req_errors" #define DM_NMEDIAERRS "nmedia_errors" #define DM_NNODEVERRS "nno_dev_errors" #define DM_NREADOPS "nread_ops" #define DM_NRECOVERRS "nrecoverable_errors" #define DM_NSOFTERRS "nsoft_errors" #define DM_NTRANSERRS "ntransport_errors" #define DM_NWRITEOPS "nwrite_ops" #define DM_OPATH "opath" #define DM_PRODUCT_ID "product_id" #define DM_REMOVABLE "removable" /* also in media */ #define DM_RPM "rpm" #define DM_SOLIDSTATE "solid_state" #define DM_STATUS "status" #define DM_SYNC_SPEED "sync_speed" #define DM_TEMPERATURE "temperature" #define DM_VENDOR_ID "vendor_id" #define DM_WIDE "wide" /* also on controller */ #define DM_WWN "wwn" /* bus */ #define DM_BTYPE "btype" #define DM_CLOCK "clock" /* also on controller */ #define DM_PNAME "pname" /* controller */ #define DM_FAST "fast" #define DM_FAST20 "fast20" #define DM_FAST40 "fast40" #define DM_FAST80 "fast80" #define DM_MULTIPLEX "multiplex" #define DM_PATH_STATE "path_state" #define DM_CTYPE_ATA "ata" #define DM_CTYPE_SCSI "scsi" #define DM_CTYPE_FIBRE "fibre channel" #define DM_CTYPE_USB "usb" #define DM_CTYPE_UNKNOWN "unknown" /* media */ #define DM_BLOCKSIZE "blocksize" #define DM_FDISK "fdisk" #define DM_MTYPE "mtype" #define DM_NACTUALCYLINDERS "nactual_cylinders" #define DM_NALTCYLINDERS "nalt_cylinders" #define DM_NCYLINDERS "ncylinders" #define DM_NHEADS "nheads" #define DM_NPHYSCYLINDERS "nphys_cylinders" #define DM_NSECTORS "nsectors" /* also in partition */ #define DM_SIZE "size" /* also in slice */ #define DM_NACCESSIBLE "naccessible" #define DM_LABEL "label" /* partition */ #define DM_BCYL "bcyl" #define DM_BHEAD "bhead" #define DM_BOOTID "bootid" #define DM_BSECT "bsect" #define DM_ECYL "ecyl" #define DM_EHEAD "ehead" #define DM_ESECT "esect" #define DM_PTYPE "ptype" /* this references the partition id */ #define DM_PARTITION_TYPE "part_type" /* primary, extended, logical */ #define DM_RELSECT "relsect" /* slice */ #define DM_DEVICEID "deviceid" #define DM_DEVT "devt" #define DM_INDEX "index" #define DM_EFI_NAME "name" #define DM_MOUNTPOINT "mountpoint" #define DM_LOCALNAME "localname" #define DM_START "start" #define DM_TAG "tag" #define DM_FLAG "flag" #define DM_EFI "efi" /* also on media */ #define DM_USED_BY "used_by" #define DM_USED_NAME "used_name" #define DM_USE_MOUNT "mount" #define DM_USE_SVM "svm" #define DM_USE_LU "lu" #define DM_USE_DUMP "dump" #define DM_USE_VXVM "vxvm" #define DM_USE_FS "fs" #define DM_USE_VFSTAB "vfstab" #define DM_USE_EXPORTED_ZPOOL "exported_zpool" #define DM_USE_ACTIVE_ZPOOL "active_zpool" #define DM_USE_SPARE_ZPOOL "spare_zpool" #define DM_USE_L2CACHE_ZPOOL "l2cache_zpool" /* event */ #define DM_EV_NAME "name" #define DM_EV_DTYPE "edtype" #define DM_EV_TYPE "evtype" #define DM_EV_TADD "add" #define DM_EV_TREMOVE "remove" #define DM_EV_TCHANGE "change" /* findisks */ #define DM_CTYPE "ctype" #define DM_LUN "lun" #define DM_TARGET "target" #define NOINUSE_SET getenv("NOINUSE_CHECK") != NULL void dm_free_descriptors(dm_descriptor_t *desc_list); void dm_free_descriptor(dm_descriptor_t desc); void dm_free_name(char *name); void dm_free_swapentries(swaptbl_t *); dm_descriptor_t *dm_get_descriptors(dm_desc_type_t type, int filter[], int *errp); dm_descriptor_t *dm_get_associated_descriptors(dm_descriptor_t desc, dm_desc_type_t type, int *errp); dm_desc_type_t *dm_get_associated_types(dm_desc_type_t type); dm_descriptor_t dm_get_descriptor_by_name(dm_desc_type_t desc_type, char *name, int *errp); char *dm_get_name(dm_descriptor_t desc, int *errp); dm_desc_type_t dm_get_type(dm_descriptor_t desc); nvlist_t *dm_get_attributes(dm_descriptor_t desc, int *errp); nvlist_t *dm_get_stats(dm_descriptor_t desc, int stat_type, int *errp); void dm_init_event_queue(void(*callback)(nvlist_t *, int), int *errp); nvlist_t *dm_get_event(int *errp); void dm_get_slices(char *drive, dm_descriptor_t **slices, int *errp); void dm_get_slice_stats(char *slice, nvlist_t **dev_stats, int *errp); int dm_get_swapentries(swaptbl_t **, int *); void dm_get_usage_string(char *who, char *data, char **msg); int dm_inuse(char *dev_name, char **msg, dm_who_type_t who, int *errp); int dm_inuse_swap(const char *dev_name, int *errp); int dm_isoverlapping(char *dev_name, char **msg, int *errp); #ifdef __cplusplus } #endif #endif /* _LIBDISKMGT_H */