1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright (c) 2012, Joyent, Inc. All rights reserved. 29 * Copyright 2017 Nexenta Systems, Inc. 30 * Copyright 2024 Sebastian Wiedenroth 31 */ 32 33 #ifndef _LIBDISKMGT_H 34 #define _LIBDISKMGT_H 35 36 #ifdef __cplusplus 37 extern "C" { 38 #endif 39 40 #include <libnvpair.h> 41 #include <sys/swap.h> 42 43 44 /* 45 * Disk Management Library 46 * 47 * This library provides a common way to gather information about a system's 48 * disks, controllers, and related components. 49 * 50 * 51 * THREADS 52 * ------- 53 * 54 * In general all of the functions are thread safe, however there are some 55 * specific considerations for getting events. The dm_get_event function may 56 * block the calling thread if no event is currently available. If another 57 * thread calls dm_get_event while a thread is already blocked in this function, 58 * the second thread will also block. When an event arrives and multiple 59 * threads are waiting for events, it is undefined which thread will be 60 * unblocked and receive the event. If a callback is used for handling events, 61 * this is equivalent to the dm_get_event function, so mixing callbacks and 62 * dm_get_event is also nondeterministic. 63 * 64 * 65 * ERRORS 66 * ------ 67 * 68 * In general all of the functions take an errno pointer. This is an integer 69 * that will contain 0 if the function succeeded or contains an errno (see 70 * errno.h) if there was an error. If the function returns some data, that 71 * return data will generally be null if an error occured (see the API comment 72 * for the specific function for details). Many of the functions take a 73 * descriptor and provide more information for that descriptor. These functions 74 * may return an error if the object was removed between the call which obtained 75 * the descriptor and the call to get more information about the object (errno 76 * will be ENODEV). Only a few of the possible errno values will be returned; 77 * typically: 78 * EPERM not super-user 79 * ENOMEM not enough memory 80 * ENODEV no such device 81 * EINVAL invalid argument 82 * ENOENT no event queue has been created 83 * 84 * Many of the functions require the application to be running as root in order 85 * to get complete information. EPERM will be returned if the application is 86 * not running as root. However, not all of the functions have this requirement 87 * (i.e. event handling). 88 * 89 * It is possible for the system to run out of memory while receiving events. 90 * Since event receipt is asyncronous from the dm_get_event call there may not 91 * be a thread waiting when the event occurs and ENOMEM is detected. In this 92 * case the event will be lost. The first call to dm_get_event following this 93 * condition will immediately return ENOMEM, even if events are queued. 94 * Subsequent calls can return events. The dm_get_event call will clear the 95 * pending ENOMEM condition. There is no way to know how many events were lost 96 * when this situation occurs. If a thread is waiting when the event arrives 97 * and the ENOMEM condition occurs, the call will also return with ENOMEM. 98 * There is no way to determine if the system ran out of memory before the 99 * dm_get_event call or while the thread was blocked in the dm_get_event call 100 * since both conditions cause dm_get_event to return ENOMEM. 101 * 102 * 103 * MEMORY MANAGEMENT 104 * ----------------- 105 * 106 * Most of the functions that return data are returning memory that has been 107 * allocated and must be freed by the application when no longer needed. The 108 * application should call the proper free function to free the memory. Most of 109 * the functions return either a nvlist or an array of descriptors. The normal 110 * nvlist function (nvlist_free; see libnvpair(3LIB)) can be used to free the 111 * simple nvlists. Other functions are provided to free the more complex data 112 * structures. 113 * 114 * The following list shows the functions that return allocated memory and the 115 * corresponding function to free the memory: 116 * dm_get_descriptors dm_free_descriptors 117 * dm_get_associated_descriptors dm_free_descriptors 118 * dm_get_descriptor_by_name dm_free_descriptor 119 * dm_get_name dm_free_name 120 * dm_get_attributes nvlist_free 121 * dm_get_stats nvlist_free 122 * dm_get_event nvlist_free 123 * 124 * 125 * EVENTS 126 * ------ 127 * 128 * Event information is returned as a nvlist. It may be possible to return more 129 * information about events over time, especially information about what has 130 * changed. However, that may not always be the case, so by using an nvlist we 131 * have a very generic event indication. At a minimum the event will return the 132 * name of the device, the type of device (see dm_desc_type_t) and the type of 133 * event. The event type is a string which can currently be; add, remove, 134 * change. 135 * 136 * If a drive goes up or down this could be returned as event type "change". 137 * The application could get the drive information to see that the "status" 138 * attribute has changed value (ideally the event would include an attribute 139 * with the name of the changed attribute as the value). Although the API can 140 * return events for all drive related changes, events will not necessarily be 141 * delivered for all changes unless the system generates those events. 142 * 143 * 144 * Controller/HBAs 145 * --------------- 146 * 147 * In general the API means "the parent node of the drive in the device tree" 148 * where the word "controller" is used. This can actually be either the HBA or 149 * the drive controller depending on the type of the drive. 150 * 151 * Drives can be connected to their controller(s) in three different ways: 152 * single controller 153 * multiple controllers 154 * multiple controllers with mpxio 155 * These cases will lead to different information being available for the 156 * configuration. The two interesting cases are multi-path with and without 157 * mpxio. With mpxio the drive will have a unique name and a single controller 158 * (scsi_vhci). The physical controllers, the paths to the drive, can be 159 * obtained by calling dm_get_associated_descriptors with a drive descriptor and 160 * a type of DM_PATH. This will only return these physical paths when MPXIO, or 161 * possibly some future similar feature, is controlling the drive. 162 * 163 * Without mpxio the drive does not have a unique public name (in all cases the 164 * alias(es) of the drive can be determined by calling 165 * dm_get_associated_descriptors to get the DM_ALIAS descriptors. There will be 166 * more than one controller returned from dm_get_associated_descriptors when 167 * called with a type of DM_CONTROLLER. The controllers for each of the aliases 168 * will be returned in the same order as the aliases descriptors. For example, 169 * a drive with two paths has the aliases c5t3d2 and c7t1d0. There will be two 170 * controllers returned; the first corresponds to c5 and the second corresponds 171 * to c7. 172 * 173 * In the multi-path, non-mpxio case the drive has more than one alias. 174 * Although most of the drive attributes are represented on the drive (see 175 * dm_get_attributes) there can be some different attributes for the different 176 * aliases for the drive. Use dm_get_associated_descriptors to get the DM_ALIAS 177 * descriptors which can then be used to obtain these attributes. Use of this 178 * algorithm is not restricted to the multi-path, non-mpxio case. For example, 179 * it can be used to get the target/lun for a SCSI drive with a single path. 180 */ 181 182 /* 183 * Holds all the data regarding the device. 184 * Private to libdiskmgt. Must use dm_xxx functions to set/get data. 185 */ 186 typedef uint64_t dm_descriptor_t; 187 188 typedef enum { 189 DM_WHO_MKFS = 0, 190 DM_WHO_ZPOOL, 191 DM_WHO_ZPOOL_FORCE, 192 DM_WHO_FORMAT, 193 DM_WHO_SWAP, 194 DM_WHO_DUMP, 195 DM_WHO_ZPOOL_SPARE 196 } dm_who_type_t; 197 198 /* 199 * The API uses a "descriptor" to identify the managed objects such as drives, 200 * controllers, media, slices, partitions, paths and buses. The descriptors are 201 * opaque and are only returned or used as parameters to the other functions in 202 * the API. The descriptor definition is a typedef to dm_descriptor_t. 203 * 204 * Applications call either the dm_get_descriptors or 205 * dm_get_associated_descriptors function to obtain a list of descriptors of a 206 * specific type. The application specifies the desired type from the following 207 * enumeration: 208 */ 209 typedef enum { 210 DM_DRIVE = 0, 211 DM_CONTROLLER, 212 DM_MEDIA, 213 DM_SLICE, 214 DM_PARTITION, 215 DM_PATH, 216 DM_ALIAS, 217 DM_BUS 218 } dm_desc_type_t; 219 220 /* 221 * These descriptors are associated with each other in the following way: 222 * 223 * alias partition 224 * _ \ / | 225 * / \ \ / | 226 * \ / \ / | 227 * bus --- controller --- drive --- media | 228 * | / \ | 229 * | / \ | 230 * | / \ | 231 * path slice 232 * 233 * The dm_get_associated_descriptors function can be used get the descriptors 234 * associated with a given descriptor. The dm_get_associated_types function can 235 * be used to find the types that can be associated with a given type. 236 * 237 * The attributes and values for these objects are described using a list of 238 * name/value pairs (see libnvpair(3LIB) and the specific comments for each 239 * function in the API section of this document). 240 * 241 * Drives and media have a type which are defined as the following enumerations. 242 * There could be additional types added to these enumerations as new drive and 243 * media types are supported by the system. 244 */ 245 246 typedef enum { 247 DM_DT_UNKNOWN = 0, 248 DM_DT_FIXED, 249 DM_DT_ZIP, 250 DM_DT_JAZ, 251 DM_DT_FLOPPY, 252 DM_DT_MO_ERASABLE, 253 DM_DT_MO_WRITEONCE, 254 DM_DT_AS_MO, 255 DM_DT_CDROM, 256 DM_DT_CDR, 257 DM_DT_CDRW, 258 DM_DT_DVDROM, 259 DM_DT_DVDR, 260 DM_DT_DVDRAM, 261 DM_DT_DVDRW, 262 DM_DT_DDCDROM, 263 DM_DT_DDCDR, 264 DM_DT_DDCDRW 265 } dm_drive_type_t; 266 267 typedef enum { 268 DM_MT_UNKNOWN = 0, 269 DM_MT_FIXED, 270 DM_MT_FLOPPY, 271 DM_MT_CDROM, 272 DM_MT_ZIP, 273 DM_MT_JAZ, 274 DM_MT_CDR, 275 DM_MT_CDRW, 276 DM_MT_DVDROM, 277 DM_MT_DVDR, 278 DM_MT_DVDRAM, 279 DM_MT_MO_ERASABLE, 280 DM_MT_MO_WRITEONCE, 281 DM_MT_AS_MO 282 } dm_media_type_t; 283 284 #define DM_FILTER_END -1 285 286 /* 287 * The dm_get_stats function takes a stat_type argument for the specific sample 288 * to get for the descriptor. The following enums specify the drive and slice 289 * stat types. 290 */ 291 /* drive stat name */ 292 typedef enum { 293 DM_DRV_STAT_PERFORMANCE = 0, 294 DM_DRV_STAT_DIAGNOSTIC, 295 DM_DRV_STAT_TEMPERATURE 296 } dm_drive_stat_t; 297 298 /* slice stat name */ 299 typedef enum { 300 DM_SLICE_STAT_USE = 0 301 } dm_slice_stat_t; 302 303 /* partition type */ 304 typedef enum { 305 DM_PRIMARY = 0, 306 DM_EXTENDED, 307 DM_LOGICAL 308 } dm_partition_type_t; 309 310 /* attribute definitions */ 311 312 /* drive */ 313 #define DM_DISK_UP 1 314 #define DM_DISK_DOWN 0 315 316 #define DM_DRVTYPE "drvtype" 317 #define DM_FAILING "failing" 318 #define DM_LOADED "loaded" /* also in media */ 319 #define DM_NDNRERRS "ndevice_not_ready_errors" 320 #define DM_NBYTESREAD "nbytes_read" 321 #define DM_NBYTESWRITTEN "nbytes_written" 322 #define DM_NHARDERRS "nhard_errors" 323 #define DM_NILLREQERRS "nillegal_req_errors" 324 #define DM_NMEDIAERRS "nmedia_errors" 325 #define DM_NNODEVERRS "nno_dev_errors" 326 #define DM_NREADOPS "nread_ops" 327 #define DM_NRECOVERRS "nrecoverable_errors" 328 #define DM_NSOFTERRS "nsoft_errors" 329 #define DM_NTRANSERRS "ntransport_errors" 330 #define DM_NWRITEOPS "nwrite_ops" 331 #define DM_OPATH "opath" 332 #define DM_PRODUCT_ID "product_id" 333 #define DM_REMOVABLE "removable" /* also in media */ 334 #define DM_RPM "rpm" 335 #define DM_SERIAL "serial" 336 #define DM_SOLIDSTATE "solid_state" 337 #define DM_STATUS "status" 338 #define DM_SYNC_SPEED "sync_speed" 339 #define DM_TEMPERATURE "temperature" 340 #define DM_VENDOR_ID "vendor_id" 341 #define DM_WIDE "wide" /* also on controller */ 342 #define DM_WWN "wwn" 343 344 /* bus */ 345 #define DM_BTYPE "btype" 346 #define DM_CLOCK "clock" /* also on controller */ 347 #define DM_PNAME "pname" 348 349 /* controller */ 350 #define DM_FAST "fast" 351 #define DM_FAST20 "fast20" 352 #define DM_FAST40 "fast40" 353 #define DM_FAST80 "fast80" 354 #define DM_MULTIPLEX "multiplex" 355 #define DM_PATH_STATE "path_state" 356 357 #define DM_CTYPE_ATA "ata" 358 #define DM_CTYPE_FIBRE "fibre" 359 #define DM_CTYPE_LOFI "lofi" 360 #define DM_CTYPE_NVME "nvme" 361 #define DM_CTYPE_SATA "sata" 362 #define DM_CTYPE_SCSI "scsi" 363 #define DM_CTYPE_USB "usb" 364 #define DM_CTYPE_XEN "xen" 365 #define DM_CTYPE_UNKNOWN "unknown" 366 367 /* media */ 368 #define DM_BLOCKSIZE "blocksize" 369 #define DM_FDISK "fdisk" 370 #define DM_MTYPE "mtype" 371 #define DM_NACTUALCYLINDERS "nactual_cylinders" 372 #define DM_NALTCYLINDERS "nalt_cylinders" 373 #define DM_NCYLINDERS "ncylinders" 374 #define DM_NHEADS "nheads" 375 #define DM_NPHYSCYLINDERS "nphys_cylinders" 376 #define DM_NSECTORS "nsectors" /* also in partition */ 377 #define DM_SIZE "size" /* also in slice */ 378 #define DM_NACCESSIBLE "naccessible" 379 #define DM_LABEL "label" 380 381 /* partition */ 382 #define DM_BCYL "bcyl" 383 #define DM_BHEAD "bhead" 384 #define DM_BOOTID "bootid" 385 #define DM_BSECT "bsect" 386 #define DM_ECYL "ecyl" 387 #define DM_EHEAD "ehead" 388 #define DM_ESECT "esect" 389 #define DM_PTYPE "ptype" /* this references the partition id */ 390 #define DM_PARTITION_TYPE "part_type" /* primary, extended, logical */ 391 #define DM_RELSECT "relsect" 392 393 /* slice */ 394 #define DM_DEVICEID "deviceid" 395 #define DM_DEVT "devt" 396 #define DM_INDEX "index" 397 #define DM_EFI_NAME "name" 398 #define DM_MOUNTPOINT "mountpoint" 399 #define DM_LOCALNAME "localname" 400 #define DM_START "start" 401 #define DM_TAG "tag" 402 #define DM_FLAG "flag" 403 #define DM_EFI "efi" /* also on media */ 404 #define DM_USED_BY "used_by" 405 #define DM_USED_NAME "used_name" 406 #define DM_USE_MOUNT "mount" 407 #define DM_USE_LU "lu" 408 #define DM_USE_DUMP "dump" 409 #define DM_USE_VXVM "vxvm" 410 #define DM_USE_FS "fs" 411 #define DM_USE_VFSTAB "vfstab" 412 #define DM_USE_EXPORTED_ZPOOL "exported_zpool" 413 #define DM_USE_ACTIVE_ZPOOL "active_zpool" 414 #define DM_USE_SPARE_ZPOOL "spare_zpool" 415 #define DM_USE_L2CACHE_ZPOOL "l2cache_zpool" 416 417 /* event */ 418 #define DM_EV_NAME "name" 419 #define DM_EV_DTYPE "edtype" 420 #define DM_EV_TYPE "evtype" 421 #define DM_EV_TADD "add" 422 #define DM_EV_TREMOVE "remove" 423 #define DM_EV_TCHANGE "change" 424 425 /* findisks */ 426 #define DM_CTYPE "ctype" 427 #define DM_LUN "lun" 428 #define DM_TARGET "target" 429 430 #define NOINUSE_SET getenv("NOINUSE_CHECK") != NULL 431 432 void dm_free_descriptors(dm_descriptor_t *desc_list); 433 void dm_free_descriptor(dm_descriptor_t desc); 434 void dm_free_name(char *name); 435 void dm_free_swapentries(swaptbl_t *); 436 437 dm_descriptor_t *dm_get_descriptors(dm_desc_type_t type, int filter[], 438 int *errp); 439 dm_descriptor_t *dm_get_associated_descriptors(dm_descriptor_t desc, 440 dm_desc_type_t type, int *errp); 441 dm_desc_type_t *dm_get_associated_types(dm_desc_type_t type); 442 dm_descriptor_t dm_get_descriptor_by_name(dm_desc_type_t desc_type, 443 char *name, int *errp); 444 char *dm_get_name(dm_descriptor_t desc, int *errp); 445 dm_desc_type_t dm_get_type(dm_descriptor_t desc); 446 nvlist_t *dm_get_attributes(dm_descriptor_t desc, int *errp); 447 nvlist_t *dm_get_stats(dm_descriptor_t desc, int stat_type, 448 int *errp); 449 void dm_init_event_queue(void(*callback)(nvlist_t *, int), 450 int *errp); 451 nvlist_t *dm_get_event(int *errp); 452 void dm_get_slices(char *drive, dm_descriptor_t **slices, 453 int *errp); 454 void dm_get_slice_stats(char *slice, nvlist_t **dev_stats, 455 int *errp); 456 int dm_get_swapentries(swaptbl_t **, int *); 457 void dm_get_usage_string(char *who, char *data, char **msg); 458 int dm_inuse(char *dev_name, char **msg, dm_who_type_t who, 459 int *errp); 460 int dm_inuse_swap(const char *dev_name, int *errp); 461 int dm_isoverlapping(char *dev_name, char **msg, int *errp); 462 463 #ifdef __cplusplus 464 } 465 #endif 466 467 #endif /* _LIBDISKMGT_H */ 468