1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <assert.h> 30*0Sstevel@tonic-gate #include <string.h> 31*0Sstevel@tonic-gate #include <libintl.h> 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include "volume_error.h" 34*0Sstevel@tonic-gate #include "volume_defaults.h" 35*0Sstevel@tonic-gate #include "volume_dlist.h" 36*0Sstevel@tonic-gate #include "volume_output.h" 37*0Sstevel@tonic-gate #include "volume_request.h" 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #include "layout_device_cache.h" 40*0Sstevel@tonic-gate #include "layout_discovery.h" 41*0Sstevel@tonic-gate #include "layout_dlist_util.h" 42*0Sstevel@tonic-gate #include "layout_request.h" 43*0Sstevel@tonic-gate #include "layout_slice.h" 44*0Sstevel@tonic-gate #include "layout_validate.h" 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate #define _LAYOUT_REQUEST_C 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate static char *_request_diskset = NULL; 49*0Sstevel@tonic-gate static devconfig_t *_toplevel_request = NULL; 50*0Sstevel@tonic-gate static defaults_t *_defaults = NULL; 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate /* 53*0Sstevel@tonic-gate * This file contains code which handles various aspects of the 54*0Sstevel@tonic-gate * request and defaults devconfig_t structs passed to the layout 55*0Sstevel@tonic-gate * module. 56*0Sstevel@tonic-gate * 57*0Sstevel@tonic-gate * Functions are provided which determine what devices are available 58*0Sstevel@tonic-gate * for use by the various volume layout mechanisms. These are based 59*0Sstevel@tonic-gate * on the user specified available/unavailable devices included in 60*0Sstevel@tonic-gate * a request or in the defaults associated with the destination diskset. 61*0Sstevel@tonic-gate */ 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate /* 64*0Sstevel@tonic-gate * A struct to hold device "specifications" extracted from a user 65*0Sstevel@tonic-gate * specified device name. This struct is used to compare the user's 66*0Sstevel@tonic-gate * available and unavailable device specifications against physical 67*0Sstevel@tonic-gate * devices attached to the system. 68*0Sstevel@tonic-gate * 69*0Sstevel@tonic-gate * The spec struct holds one of two different specifications: if the 70*0Sstevel@tonic-gate * user supplied device name is parsable as a CTD name, it is parsed 71*0Sstevel@tonic-gate * into the component ids. Otherwise, it is stored as is. 72*0Sstevel@tonic-gate * 73*0Sstevel@tonic-gate * The CTD name space implies a device hierarchy and metassist 74*0Sstevel@tonic-gate * supports an implied wildcarding scheme for the CTD name space. 75*0Sstevel@tonic-gate * A CTD specification from the user is of the form cX, cXdX, 76*0Sstevel@tonic-gate * cXdXsX, cXtX, cXtXdX, or cXtXdXsX, so it may or may nor 77*0Sstevel@tonic-gate * correspond to an individual physical device depending on 78*0Sstevel@tonic-gate * the context. 79*0Sstevel@tonic-gate * 80*0Sstevel@tonic-gate * For example, "c1" can mean the controller/HBA with the 81*0Sstevel@tonic-gate * name "c1" or it can mean all devices attached to the 82*0Sstevel@tonic-gate * controller named "c1". 83*0Sstevel@tonic-gate * 84*0Sstevel@tonic-gate * The ctd specs make matching physical devices against a 85*0Sstevel@tonic-gate * user specification easier since the matching is based on 86*0Sstevel@tonic-gate * the numeric values extracted from the cXtXdXsX string 87*0Sstevel@tonic-gate * and not on the strings themselves. The strings are 88*0Sstevel@tonic-gate * troublesome because of situations like "c1" being 89*0Sstevel@tonic-gate * compared to "c11t1d0s0" and getting false matches. 90*0Sstevel@tonic-gate * 91*0Sstevel@tonic-gate * The ID_UNSPECIFIED value is used to flag components 92*0Sstevel@tonic-gate * that were not in the CTD name: 93*0Sstevel@tonic-gate * 94*0Sstevel@tonic-gate * "c3" -> { ctrl=3, target=ID_UNSPECIFIED, 95*0Sstevel@tonic-gate * lun=ID_UNSPECIFIED, slice=ID_UNSPECIFIED } 96*0Sstevel@tonic-gate * 97*0Sstevel@tonic-gate * "c3t2" -> { ctrl=3, target=2, 98*0Sstevel@tonic-gate * lun=ID_UNSPECIFIED, slice=ID_UNSPECIFIED } 99*0Sstevel@tonic-gate */ 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate #define ID_UNSPECIFIED -1 102*0Sstevel@tonic-gate typedef struct { 103*0Sstevel@tonic-gate int ctrl; 104*0Sstevel@tonic-gate int target; 105*0Sstevel@tonic-gate int lun; 106*0Sstevel@tonic-gate int slice; 107*0Sstevel@tonic-gate boolean_t is_ide; 108*0Sstevel@tonic-gate } ctd_spec_t; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate typedef enum { 111*0Sstevel@tonic-gate SPEC_TYPE_CTD = 0, 112*0Sstevel@tonic-gate SPEC_TYPE_RAW, 113*0Sstevel@tonic-gate SPEC_TYPE_OTHER 114*0Sstevel@tonic-gate } spec_type_t; 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate typedef struct { 117*0Sstevel@tonic-gate spec_type_t type; 118*0Sstevel@tonic-gate union { 119*0Sstevel@tonic-gate ctd_spec_t *ctd; 120*0Sstevel@tonic-gate char *raw; 121*0Sstevel@tonic-gate } data; 122*0Sstevel@tonic-gate } device_spec_t; 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate static int get_spec_for_name( 125*0Sstevel@tonic-gate char *name, 126*0Sstevel@tonic-gate device_spec_t **id); 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate static int create_device_spec( 129*0Sstevel@tonic-gate char *name, 130*0Sstevel@tonic-gate device_spec_t **spec); 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate static int create_device_ctd_spec( 133*0Sstevel@tonic-gate char *name, 134*0Sstevel@tonic-gate device_spec_t **spec); 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate static int create_device_raw_spec( 137*0Sstevel@tonic-gate char *name, 138*0Sstevel@tonic-gate device_spec_t **spec); 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate static void destroy_device_spec( 141*0Sstevel@tonic-gate device_spec_t *spec); 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gate static boolean_t ctd_spec_includes_device( 144*0Sstevel@tonic-gate device_spec_t *spec, 145*0Sstevel@tonic-gate device_spec_t *device); 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate static boolean_t raw_spec_includes_device( 148*0Sstevel@tonic-gate device_spec_t *spec, 149*0Sstevel@tonic-gate device_spec_t *device); 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate /* 152*0Sstevel@tonic-gate * get_spec_for_name builds up a cached mapping of device 153*0Sstevel@tonic-gate * names to the corresponding device_spec_t structs. 154*0Sstevel@tonic-gate * 155*0Sstevel@tonic-gate * This saves repeatedly converting the device names, which 156*0Sstevel@tonic-gate * could get expensive since devices are checked against the 157*0Sstevel@tonic-gate * user specified available/unavailable devices a lot. 158*0Sstevel@tonic-gate * 159*0Sstevel@tonic-gate * The cache is implemented as a list of these structs: 160*0Sstevel@tonic-gate */ 161*0Sstevel@tonic-gate typedef struct { 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate char *name; 164*0Sstevel@tonic-gate device_spec_t *device_spec; 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate } spec_cache_t; 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate static dlist_t *_spec_cache = NULL; 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate static int destroy_spec_cache(); 171*0Sstevel@tonic-gate static int compare_name_to_spec_cache_name( 172*0Sstevel@tonic-gate void *name, void *list_item); 173*0Sstevel@tonic-gate 174*0Sstevel@tonic-gate /* 175*0Sstevel@tonic-gate * The user specified available/unavailable devices are 176*0Sstevel@tonic-gate * accessed frequently during layout. To make this more 177*0Sstevel@tonic-gate * efficient, the char *arrays of available/unavailable 178*0Sstevel@tonic-gate * specifications for a request or defaults devconfig_t 179*0Sstevel@tonic-gate * object are converted to device_spec_ts the first time 180*0Sstevel@tonic-gate * they're accessed and then cached using this struct: 181*0Sstevel@tonic-gate */ 182*0Sstevel@tonic-gate typedef struct { 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate devconfig_t *request; 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate /* 187*0Sstevel@tonic-gate * avail_specs_list is a list of device spec_t 188*0Sstevel@tonic-gate * corresponding to available devices specified 189*0Sstevel@tonic-gate * in the request object 190*0Sstevel@tonic-gate */ 191*0Sstevel@tonic-gate dlist_t *avail_specs_list; 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate /* 194*0Sstevel@tonic-gate * unavail_specs_list is a list of device spec_t 195*0Sstevel@tonic-gate * corresponding to unavailable devices specified 196*0Sstevel@tonic-gate * in the request object 197*0Sstevel@tonic-gate */ 198*0Sstevel@tonic-gate dlist_t *unavail_specs_list; 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate } request_spec_list_t; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate dlist_t *_request_spec_list_cache = NULL; 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate static int destroy_request_spec_list_cache(); 205*0Sstevel@tonic-gate static void destroy_request_spec_list_entry(void *obj); 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate static int compare_request_to_request_spec_list_request( 208*0Sstevel@tonic-gate void *object, 209*0Sstevel@tonic-gate void *list_item); 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate static int convert_usernames_to_specs( 212*0Sstevel@tonic-gate char **specs, 213*0Sstevel@tonic-gate dlist_t **list); 214*0Sstevel@tonic-gate 215*0Sstevel@tonic-gate /* other private functions */ 216*0Sstevel@tonic-gate static int is_device_avail( 217*0Sstevel@tonic-gate dm_descriptor_t desc, 218*0Sstevel@tonic-gate devconfig_t *request, 219*0Sstevel@tonic-gate boolean_t *avail); 220*0Sstevel@tonic-gate 221*0Sstevel@tonic-gate static int is_named_device_avail( 222*0Sstevel@tonic-gate devconfig_t *request, 223*0Sstevel@tonic-gate char *device_name, 224*0Sstevel@tonic-gate boolean_t check_aliases, 225*0Sstevel@tonic-gate boolean_t *avail); 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gate static int avail_list_includes_device_name( 228*0Sstevel@tonic-gate dlist_t *list, 229*0Sstevel@tonic-gate char *device_name, 230*0Sstevel@tonic-gate boolean_t check_aliases, 231*0Sstevel@tonic-gate boolean_t *includes); 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate static int unavail_list_includes_device_name( 234*0Sstevel@tonic-gate dlist_t *list, 235*0Sstevel@tonic-gate char *device_name, 236*0Sstevel@tonic-gate boolean_t check_aliases, 237*0Sstevel@tonic-gate boolean_t *includes); 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate static int spec_includes_device_name( 240*0Sstevel@tonic-gate device_spec_t *spec, 241*0Sstevel@tonic-gate char *device_name, 242*0Sstevel@tonic-gate boolean_t check_aliases, 243*0Sstevel@tonic-gate boolean_t *includes); 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gate static boolean_t spec_includes_device( 246*0Sstevel@tonic-gate device_spec_t *spec, 247*0Sstevel@tonic-gate device_spec_t *device); 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate static int disk_get_avail_space( 250*0Sstevel@tonic-gate devconfig_t *request, 251*0Sstevel@tonic-gate dm_descriptor_t disk, 252*0Sstevel@tonic-gate uint64_t *avail); 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate static int compare_hba_n_avail_disks( 255*0Sstevel@tonic-gate void *obj1, 256*0Sstevel@tonic-gate void *obj2); 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate /* 259*0Sstevel@tonic-gate * FUNCTION: release_request_caches() 260*0Sstevel@tonic-gate * 261*0Sstevel@tonic-gate * RETURNS: 0 262*0Sstevel@tonic-gate * 263*0Sstevel@tonic-gate * PURPOSE: cleanup the module private caches. 264*0Sstevel@tonic-gate */ 265*0Sstevel@tonic-gate int 266*0Sstevel@tonic-gate release_request_caches() 267*0Sstevel@tonic-gate { 268*0Sstevel@tonic-gate (void) destroy_request_spec_list_cache(); 269*0Sstevel@tonic-gate (void) destroy_spec_cache(); 270*0Sstevel@tonic-gate 271*0Sstevel@tonic-gate return (0); 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate /* 274*0Sstevel@tonic-gate * FUNCTION: int set_request_diskset(char *) 275*0Sstevel@tonic-gate * 276*0Sstevel@tonic-gate * INPUT: char * - pointer to the diskset name 277*0Sstevel@tonic-gate * OUTPUT: 0 - success 278*0Sstevel@tonic-gate * !0 - validation failure 279*0Sstevel@tonic-gate * RETURNS: 280*0Sstevel@tonic-gate * 281*0Sstevel@tonic-gate * PURPOSE: set the module global diskset name. 282*0Sstevel@tonic-gate */ 283*0Sstevel@tonic-gate int 284*0Sstevel@tonic-gate set_request_diskset( 285*0Sstevel@tonic-gate char *dsname) 286*0Sstevel@tonic-gate { 287*0Sstevel@tonic-gate _request_diskset = dsname; 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate if (dsname == NULL || dsname[0] == '\0') { 290*0Sstevel@tonic-gate volume_set_error( 291*0Sstevel@tonic-gate gettext("No disk set specified in request\n")); 292*0Sstevel@tonic-gate return (-1); 293*0Sstevel@tonic-gate } 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate return (0); 296*0Sstevel@tonic-gate } 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate /* 299*0Sstevel@tonic-gate * FUNCTION: char *get_request_diskset() 300*0Sstevel@tonic-gate * 301*0Sstevel@tonic-gate * INPUT: none - 302*0Sstevel@tonic-gate * OUTPUT: none - 303*0Sstevel@tonic-gate * RETURNS: char * - pointer to the currently set diskset name 304*0Sstevel@tonic-gate * 305*0Sstevel@tonic-gate * PURPOSE: get the global name of the current diskset. 306*0Sstevel@tonic-gate */ 307*0Sstevel@tonic-gate char * 308*0Sstevel@tonic-gate get_request_diskset() 309*0Sstevel@tonic-gate { 310*0Sstevel@tonic-gate return (_request_diskset); 311*0Sstevel@tonic-gate } 312*0Sstevel@tonic-gate 313*0Sstevel@tonic-gate /* 314*0Sstevel@tonic-gate * FUNCTION: void unset_request_diskset() 315*0Sstevel@tonic-gate * 316*0Sstevel@tonic-gate * PURPOSE: unset the module global diskset name. 317*0Sstevel@tonic-gate */ 318*0Sstevel@tonic-gate void 319*0Sstevel@tonic-gate unset_request_diskset( 320*0Sstevel@tonic-gate char *dsname) 321*0Sstevel@tonic-gate { 322*0Sstevel@tonic-gate _request_diskset = NULL; 323*0Sstevel@tonic-gate } 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate /* 326*0Sstevel@tonic-gate * FUNCTION: int set_toplevel_request(devconfig_t *) 327*0Sstevel@tonic-gate * 328*0Sstevel@tonic-gate * INPUT: devconfig_t * - pointer to the diskset request 329*0Sstevel@tonic-gate * OUTPUT: 0 - success 330*0Sstevel@tonic-gate * !0 - validation failure 331*0Sstevel@tonic-gate * RETURNS: 332*0Sstevel@tonic-gate * 333*0Sstevel@tonic-gate * PURPOSE: set the module global toplevel request struct. 334*0Sstevel@tonic-gate * this will be set within the only public entry 335*0Sstevel@tonic-gate * point to the module -- get_layout() 336*0Sstevel@tonic-gate * 337*0Sstevel@tonic-gate * SIDEEFFECT: The devconfig_t's list of available and unavailable 338*0Sstevel@tonic-gate * devices will be validated. 339*0Sstevel@tonic-gate */ 340*0Sstevel@tonic-gate int 341*0Sstevel@tonic-gate set_toplevel_request( 342*0Sstevel@tonic-gate devconfig_t *req) 343*0Sstevel@tonic-gate { 344*0Sstevel@tonic-gate _toplevel_request = req; 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate return (validate_request_avail_unavail(req)); 347*0Sstevel@tonic-gate } 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate /* 350*0Sstevel@tonic-gate * FUNCTION: void unset_toplevel_request() 351*0Sstevel@tonic-gate * 352*0Sstevel@tonic-gate * PURPOSE: unset the layout module global toplevel request struct. 353*0Sstevel@tonic-gate * 354*0Sstevel@tonic-gate */ 355*0Sstevel@tonic-gate void 356*0Sstevel@tonic-gate unset_toplevel_request() 357*0Sstevel@tonic-gate { 358*0Sstevel@tonic-gate _toplevel_request = NULL; 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate /* 362*0Sstevel@tonic-gate * FUNCTION: int set_defaults(devconfig_t *) 363*0Sstevel@tonic-gate * 364*0Sstevel@tonic-gate * INPUT: devconfig_t * - pointer to the global defaults devconfig_t 365*0Sstevel@tonic-gate * OUTPUT: 0 - success 366*0Sstevel@tonic-gate * !0 - validation failure 367*0Sstevel@tonic-gate * RETURNS: 368*0Sstevel@tonic-gate * 369*0Sstevel@tonic-gate * PURPOSE: set the module global defaults struct. 370*0Sstevel@tonic-gate * this will be set within the only public entry 371*0Sstevel@tonic-gate * point to the module -- get_layout() 372*0Sstevel@tonic-gate * 373*0Sstevel@tonic-gate * SIDEEFFECT: The devconfig_t's list of available and unavailable 374*0Sstevel@tonic-gate * devices will be validated. 375*0Sstevel@tonic-gate */ 376*0Sstevel@tonic-gate int 377*0Sstevel@tonic-gate set_request_defaults( 378*0Sstevel@tonic-gate defaults_t *defaults) 379*0Sstevel@tonic-gate { 380*0Sstevel@tonic-gate int error = 0; 381*0Sstevel@tonic-gate devconfig_t *diskset = NULL; 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate _defaults = defaults; 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate if ((error = defaults_get_diskset_by_name( 386*0Sstevel@tonic-gate _defaults, get_request_diskset(), &diskset)) == 0) { 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gate error = validate_request_avail_unavail(diskset); 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate } else if (error == ENOENT) { 391*0Sstevel@tonic-gate /* no defaults to verify */ 392*0Sstevel@tonic-gate error = 0; 393*0Sstevel@tonic-gate } 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate return (error); 396*0Sstevel@tonic-gate } 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate /* 399*0Sstevel@tonic-gate * FUNCTION: void unset_request_defaults() 400*0Sstevel@tonic-gate * 401*0Sstevel@tonic-gate * PURPOSE: unset the layout module global defaults struct. 402*0Sstevel@tonic-gate * 403*0Sstevel@tonic-gate */ 404*0Sstevel@tonic-gate void 405*0Sstevel@tonic-gate unset_request_defaults() 406*0Sstevel@tonic-gate { 407*0Sstevel@tonic-gate _defaults = NULL; 408*0Sstevel@tonic-gate } 409*0Sstevel@tonic-gate 410*0Sstevel@tonic-gate /* 411*0Sstevel@tonic-gate * FUNCTION: get_stripe_min_comp(devconfig_t *req, uint16_t *val) 412*0Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request 413*0Sstevel@tonic-gate * val - pointer to a uint64_t to hold the result 414*0Sstevel@tonic-gate * 415*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 416*0Sstevel@tonic-gate * !0 - otherwise 417*0Sstevel@tonic-gate * 418*0Sstevel@tonic-gate * PURPOSE: helper which determines the minimum of components 419*0Sstevel@tonic-gate * for striped volumes satisfying the input request. 420*0Sstevel@tonic-gate * 421*0Sstevel@tonic-gate * The value to use is taken from the input request, the 422*0Sstevel@tonic-gate * toplevel diskset request, the diskset defaults or the 423*0Sstevel@tonic-gate * global defaults. 424*0Sstevel@tonic-gate */ 425*0Sstevel@tonic-gate int 426*0Sstevel@tonic-gate get_stripe_min_comp( 427*0Sstevel@tonic-gate devconfig_t *req, 428*0Sstevel@tonic-gate uint16_t *val) 429*0Sstevel@tonic-gate { 430*0Sstevel@tonic-gate int error = 0; 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate *val = 0; 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate if ((error = devconfig_get_stripe_mincomp(req, val)) != 0) { 435*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 436*0Sstevel@tonic-gate return (error); 437*0Sstevel@tonic-gate } 438*0Sstevel@tonic-gate } 439*0Sstevel@tonic-gate 440*0Sstevel@tonic-gate if (*val == 0) { 441*0Sstevel@tonic-gate if ((error = defaults_get_stripe_mincomp( 442*0Sstevel@tonic-gate _defaults, get_request_diskset(), val)) != 0) { 443*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 444*0Sstevel@tonic-gate return (error); 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate } 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate return (error); 450*0Sstevel@tonic-gate } 451*0Sstevel@tonic-gate 452*0Sstevel@tonic-gate /* 453*0Sstevel@tonic-gate * FUNCTION: get_stripe_max_comp(devconfig_t *req, uint16_t *val) 454*0Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request 455*0Sstevel@tonic-gate * val - pointer to a uint64_t to hold the result 456*0Sstevel@tonic-gate * 457*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 458*0Sstevel@tonic-gate * !0 - otherwise 459*0Sstevel@tonic-gate * 460*0Sstevel@tonic-gate * PURPOSE: helper which determines the maximum number of components 461*0Sstevel@tonic-gate * for striped volumes satisfying the input request. 462*0Sstevel@tonic-gate * 463*0Sstevel@tonic-gate * The value to use is taken from the input request, the 464*0Sstevel@tonic-gate * toplevel diskset request, the diskset defaults or the 465*0Sstevel@tonic-gate * global defaults. 466*0Sstevel@tonic-gate */ 467*0Sstevel@tonic-gate int 468*0Sstevel@tonic-gate get_stripe_max_comp( 469*0Sstevel@tonic-gate devconfig_t *req, 470*0Sstevel@tonic-gate uint16_t *val) 471*0Sstevel@tonic-gate { 472*0Sstevel@tonic-gate int error = 0; 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate *val = 0; 475*0Sstevel@tonic-gate 476*0Sstevel@tonic-gate if ((error = devconfig_get_stripe_maxcomp(req, val)) != 0) { 477*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 478*0Sstevel@tonic-gate return (error); 479*0Sstevel@tonic-gate } 480*0Sstevel@tonic-gate } 481*0Sstevel@tonic-gate 482*0Sstevel@tonic-gate if (*val == 0) { 483*0Sstevel@tonic-gate if ((error = defaults_get_stripe_maxcomp( 484*0Sstevel@tonic-gate _defaults, get_request_diskset(), val)) != 0) { 485*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 486*0Sstevel@tonic-gate return (error); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate } 489*0Sstevel@tonic-gate } 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate return (error); 492*0Sstevel@tonic-gate } 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate /* 495*0Sstevel@tonic-gate * FUNCTION: get_stripe_interlace(devconfig_t *req, uint64_t *val) 496*0Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request 497*0Sstevel@tonic-gate * val - pointer to a uint64_t to hold the result 498*0Sstevel@tonic-gate * 499*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 500*0Sstevel@tonic-gate * !0 - otherwise 501*0Sstevel@tonic-gate * 502*0Sstevel@tonic-gate * PURPOSE: helper which determines the interlace value for striped 503*0Sstevel@tonic-gate * volumes satisfying the input request. 504*0Sstevel@tonic-gate * 505*0Sstevel@tonic-gate * The value to use is taken from the input request, the 506*0Sstevel@tonic-gate * toplevel diskset request, the diskset defaults or the 507*0Sstevel@tonic-gate * global defaults. 508*0Sstevel@tonic-gate * 509*0Sstevel@tonic-gate * If no value is explictly specified, ERR_ATTR_UNSET is 510*0Sstevel@tonic-gate * returned. 511*0Sstevel@tonic-gate */ 512*0Sstevel@tonic-gate int 513*0Sstevel@tonic-gate get_stripe_interlace( 514*0Sstevel@tonic-gate devconfig_t *req, 515*0Sstevel@tonic-gate uint64_t *val) 516*0Sstevel@tonic-gate { 517*0Sstevel@tonic-gate int error = 0; 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate *val = 0; 520*0Sstevel@tonic-gate 521*0Sstevel@tonic-gate if ((error = devconfig_get_stripe_interlace(req, val)) != 0) { 522*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 523*0Sstevel@tonic-gate return (error); 524*0Sstevel@tonic-gate } 525*0Sstevel@tonic-gate error = 0; 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate if (*val == 0) { 529*0Sstevel@tonic-gate if ((error = defaults_get_stripe_interlace( 530*0Sstevel@tonic-gate _defaults, get_request_diskset(), val)) != 0) { 531*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 532*0Sstevel@tonic-gate return (error); 533*0Sstevel@tonic-gate } 534*0Sstevel@tonic-gate } 535*0Sstevel@tonic-gate } 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate return (error); 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate /* 541*0Sstevel@tonic-gate * FUNCTION: get_mirror_read_strategy(devconfig_t *req, 542*0Sstevel@tonic-gate * mirror_read_strategy_t *val) 543*0Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request 544*0Sstevel@tonic-gate * val - pointer to a mirror_read_strategy_t to hold the result 545*0Sstevel@tonic-gate * 546*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 547*0Sstevel@tonic-gate * !0 - otherwise 548*0Sstevel@tonic-gate * 549*0Sstevel@tonic-gate * PURPOSE: helper which determines the write strategy mirrored volumes 550*0Sstevel@tonic-gate * should have for volumes satisfying the input request. 551*0Sstevel@tonic-gate * 552*0Sstevel@tonic-gate * The value to use is taken from the input request, the 553*0Sstevel@tonic-gate * toplevel diskset request, the diskset defaults or the 554*0Sstevel@tonic-gate * global defaults. 555*0Sstevel@tonic-gate * 556*0Sstevel@tonic-gate * If no value is explictly specified, ERR_ATTR_UNSET is 557*0Sstevel@tonic-gate * returned. 558*0Sstevel@tonic-gate */ 559*0Sstevel@tonic-gate int 560*0Sstevel@tonic-gate get_mirror_read_strategy( 561*0Sstevel@tonic-gate devconfig_t *req, 562*0Sstevel@tonic-gate mirror_read_strategy_t *val) 563*0Sstevel@tonic-gate { 564*0Sstevel@tonic-gate int error = 0; 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate *val = 0; 567*0Sstevel@tonic-gate 568*0Sstevel@tonic-gate if ((error = devconfig_get_mirror_read(req, val)) != 0) { 569*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 570*0Sstevel@tonic-gate return (error); 571*0Sstevel@tonic-gate } 572*0Sstevel@tonic-gate } 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate if (*val == 0) { 575*0Sstevel@tonic-gate if ((error = defaults_get_mirror_read( 576*0Sstevel@tonic-gate _defaults, get_request_diskset(), val)) != 0) { 577*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 578*0Sstevel@tonic-gate return (error); 579*0Sstevel@tonic-gate } 580*0Sstevel@tonic-gate } 581*0Sstevel@tonic-gate } 582*0Sstevel@tonic-gate 583*0Sstevel@tonic-gate return (error); 584*0Sstevel@tonic-gate } 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate /* 587*0Sstevel@tonic-gate * FUNCTION: get_mirror_write_strategy(devconfig_t *req, 588*0Sstevel@tonic-gate * mirror_write_strategy_t *val) 589*0Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request 590*0Sstevel@tonic-gate * val - pointer to a mirror_write_strategy_t to hold result 591*0Sstevel@tonic-gate * 592*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 593*0Sstevel@tonic-gate * !0 - otherwise 594*0Sstevel@tonic-gate * 595*0Sstevel@tonic-gate * PURPOSE: helper which determines the write strategy mirrored volumes 596*0Sstevel@tonic-gate * should have for volumes satisfying the input request. 597*0Sstevel@tonic-gate * 598*0Sstevel@tonic-gate * The value to use is taken from the input request, the 599*0Sstevel@tonic-gate * toplevel diskset request, the diskset defaults or the 600*0Sstevel@tonic-gate * global defaults. 601*0Sstevel@tonic-gate * 602*0Sstevel@tonic-gate * If no value is explictly specified, ERR_ATTR_UNSET is 603*0Sstevel@tonic-gate * returned. 604*0Sstevel@tonic-gate */ 605*0Sstevel@tonic-gate int 606*0Sstevel@tonic-gate get_mirror_write_strategy( 607*0Sstevel@tonic-gate devconfig_t *req, 608*0Sstevel@tonic-gate mirror_write_strategy_t *val) 609*0Sstevel@tonic-gate { 610*0Sstevel@tonic-gate int error = 0; 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate *val = 0; 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate if ((error = devconfig_get_mirror_write(req, val)) != 0) { 615*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 616*0Sstevel@tonic-gate return (error); 617*0Sstevel@tonic-gate } 618*0Sstevel@tonic-gate } 619*0Sstevel@tonic-gate 620*0Sstevel@tonic-gate if (*val == 0) { 621*0Sstevel@tonic-gate if ((error = defaults_get_mirror_write( 622*0Sstevel@tonic-gate _defaults, get_request_diskset(), val)) != 0) { 623*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 624*0Sstevel@tonic-gate return (error); 625*0Sstevel@tonic-gate } 626*0Sstevel@tonic-gate } 627*0Sstevel@tonic-gate } 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate return (error); 630*0Sstevel@tonic-gate } 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate /* 633*0Sstevel@tonic-gate * FUNCTION: get_mirror_pass(devconfig_t *req, uint16_t *val) 634*0Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request 635*0Sstevel@tonic-gate * val - pointer to a uint16_t to hold the result 636*0Sstevel@tonic-gate * 637*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 638*0Sstevel@tonic-gate * !0 - otherwise 639*0Sstevel@tonic-gate * 640*0Sstevel@tonic-gate * PURPOSE: helper which determines the resync pass mirrored volumes 641*0Sstevel@tonic-gate * should have for volumes satisfying the input request. 642*0Sstevel@tonic-gate * 643*0Sstevel@tonic-gate * The value to use is taken from the input request, the 644*0Sstevel@tonic-gate * toplevel diskset request, the diskset defaults or the 645*0Sstevel@tonic-gate * global defaults. 646*0Sstevel@tonic-gate * 647*0Sstevel@tonic-gate * If no value is explictly specified, ERR_ATTR_UNSET is 648*0Sstevel@tonic-gate * returned. 649*0Sstevel@tonic-gate */ 650*0Sstevel@tonic-gate int 651*0Sstevel@tonic-gate get_mirror_pass( 652*0Sstevel@tonic-gate devconfig_t *req, 653*0Sstevel@tonic-gate uint16_t *val) 654*0Sstevel@tonic-gate { 655*0Sstevel@tonic-gate int error = 0; 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate *val = 0; 658*0Sstevel@tonic-gate 659*0Sstevel@tonic-gate if ((error = devconfig_get_mirror_pass(req, val)) != 0) { 660*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 661*0Sstevel@tonic-gate return (error); 662*0Sstevel@tonic-gate } 663*0Sstevel@tonic-gate } 664*0Sstevel@tonic-gate 665*0Sstevel@tonic-gate if (*val == 0) { 666*0Sstevel@tonic-gate if ((error = defaults_get_mirror_pass( 667*0Sstevel@tonic-gate _defaults, get_request_diskset(), val)) != 0) { 668*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 669*0Sstevel@tonic-gate return (error); 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate } 672*0Sstevel@tonic-gate } 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate return (error); 675*0Sstevel@tonic-gate } 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate /* 678*0Sstevel@tonic-gate * FUNCTION: get_mirror_nsubs(devconfig_t *req, uint16_t *val) 679*0Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request 680*0Sstevel@tonic-gate * val - pointer to a uint16_t to hold the result 681*0Sstevel@tonic-gate * 682*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 683*0Sstevel@tonic-gate * !0 - otherwise 684*0Sstevel@tonic-gate * 685*0Sstevel@tonic-gate * PURPOSE: helper which determines how many submirrors mirrored 686*0Sstevel@tonic-gate * volumes should have for volumes satisfying the input 687*0Sstevel@tonic-gate * request. 688*0Sstevel@tonic-gate * 689*0Sstevel@tonic-gate * The value to use is taken from the input request, the 690*0Sstevel@tonic-gate * toplevel diskset request, the diskset defaults or the 691*0Sstevel@tonic-gate * global defaults. 692*0Sstevel@tonic-gate */ 693*0Sstevel@tonic-gate int 694*0Sstevel@tonic-gate get_mirror_nsubs( 695*0Sstevel@tonic-gate devconfig_t *req, 696*0Sstevel@tonic-gate uint16_t *val) 697*0Sstevel@tonic-gate { 698*0Sstevel@tonic-gate int error = 0; 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate *val = 0; 701*0Sstevel@tonic-gate 702*0Sstevel@tonic-gate if ((error = devconfig_get_mirror_nsubs(req, val)) != 0) { 703*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 704*0Sstevel@tonic-gate return (error); 705*0Sstevel@tonic-gate } 706*0Sstevel@tonic-gate } 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate if (*val == 0) { 709*0Sstevel@tonic-gate if ((error = defaults_get_mirror_nsubs( 710*0Sstevel@tonic-gate _defaults, get_request_diskset(), val)) != 0) { 711*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 712*0Sstevel@tonic-gate return (error); 713*0Sstevel@tonic-gate } 714*0Sstevel@tonic-gate } 715*0Sstevel@tonic-gate } 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate return (error); 718*0Sstevel@tonic-gate } 719*0Sstevel@tonic-gate 720*0Sstevel@tonic-gate /* 721*0Sstevel@tonic-gate * FUNCTION: get_volume_faultrecov(devconfig_t *req, boolean_t *val) 722*0Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request 723*0Sstevel@tonic-gate * val - pointer to a boolean_t to hold the result 724*0Sstevel@tonic-gate * 725*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 726*0Sstevel@tonic-gate * !0 - otherwise 727*0Sstevel@tonic-gate * 728*0Sstevel@tonic-gate * PURPOSE: helper which determines whether data redundant volumes 729*0Sstevel@tonic-gate * should also have fault recovery (e.g., HSPs) for volumes 730*0Sstevel@tonic-gate * satisfying the input request. 731*0Sstevel@tonic-gate * 732*0Sstevel@tonic-gate * The value to use is taken from the input request, the 733*0Sstevel@tonic-gate * toplevel diskset request, the diskset defaults or the 734*0Sstevel@tonic-gate * global defaults. 735*0Sstevel@tonic-gate */ 736*0Sstevel@tonic-gate int 737*0Sstevel@tonic-gate get_volume_faultrecov( 738*0Sstevel@tonic-gate devconfig_t *req, 739*0Sstevel@tonic-gate boolean_t *val) 740*0Sstevel@tonic-gate { 741*0Sstevel@tonic-gate int error = 0; 742*0Sstevel@tonic-gate 743*0Sstevel@tonic-gate *val = B_FALSE; 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate if ((error = devconfig_get_volume_usehsp(req, val)) != 0) { 746*0Sstevel@tonic-gate if (error == ERR_ATTR_UNSET) { 747*0Sstevel@tonic-gate component_type_t type = TYPE_UNKNOWN; 748*0Sstevel@tonic-gate (void) devconfig_get_type(req, &type); 749*0Sstevel@tonic-gate 750*0Sstevel@tonic-gate switch (type) { 751*0Sstevel@tonic-gate case TYPE_MIRROR: 752*0Sstevel@tonic-gate error = defaults_get_mirror_usehsp( 753*0Sstevel@tonic-gate _defaults, get_request_diskset(), val); 754*0Sstevel@tonic-gate break; 755*0Sstevel@tonic-gate 756*0Sstevel@tonic-gate case TYPE_STRIPE: 757*0Sstevel@tonic-gate error = defaults_get_stripe_usehsp( 758*0Sstevel@tonic-gate _defaults, get_request_diskset(), val); 759*0Sstevel@tonic-gate break; 760*0Sstevel@tonic-gate 761*0Sstevel@tonic-gate case TYPE_CONCAT: 762*0Sstevel@tonic-gate error = defaults_get_concat_usehsp( 763*0Sstevel@tonic-gate _defaults, get_request_diskset(), val); 764*0Sstevel@tonic-gate break; 765*0Sstevel@tonic-gate 766*0Sstevel@tonic-gate case TYPE_VOLUME: 767*0Sstevel@tonic-gate error = defaults_get_volume_usehsp( 768*0Sstevel@tonic-gate _defaults, get_request_diskset(), val); 769*0Sstevel@tonic-gate break; 770*0Sstevel@tonic-gate } 771*0Sstevel@tonic-gate } 772*0Sstevel@tonic-gate } 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate return (error); 775*0Sstevel@tonic-gate } 776*0Sstevel@tonic-gate 777*0Sstevel@tonic-gate /* 778*0Sstevel@tonic-gate * FUNCTION: get_volume_redundancy_level(devconfig_t *req, uint16_t val) 779*0Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request 780*0Sstevel@tonic-gate * val - pointer to a uint16-t to hold the result 781*0Sstevel@tonic-gate * 782*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 783*0Sstevel@tonic-gate * !0 - otherwise 784*0Sstevel@tonic-gate * 785*0Sstevel@tonic-gate * PURPOSE: helper which determines the appropriate level of data 786*0Sstevel@tonic-gate * redundancy a volume should have for volumes satisfying 787*0Sstevel@tonic-gate * the input request. 788*0Sstevel@tonic-gate * 789*0Sstevel@tonic-gate * The value to use is taken from the input request, the 790*0Sstevel@tonic-gate * toplevel diskset request, the diskset defaults or the 791*0Sstevel@tonic-gate * global defaults. 792*0Sstevel@tonic-gate */ 793*0Sstevel@tonic-gate int 794*0Sstevel@tonic-gate get_volume_redundancy_level( 795*0Sstevel@tonic-gate devconfig_t *req, 796*0Sstevel@tonic-gate uint16_t *val) 797*0Sstevel@tonic-gate { 798*0Sstevel@tonic-gate int error = 0; 799*0Sstevel@tonic-gate 800*0Sstevel@tonic-gate *val = 0; 801*0Sstevel@tonic-gate 802*0Sstevel@tonic-gate if ((error = devconfig_get_volume_redundancy_level(req, val)) != 0) { 803*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 804*0Sstevel@tonic-gate return (error); 805*0Sstevel@tonic-gate } 806*0Sstevel@tonic-gate } 807*0Sstevel@tonic-gate 808*0Sstevel@tonic-gate if (*val == 0) { 809*0Sstevel@tonic-gate if ((error = defaults_get_volume_redundancy_level( 810*0Sstevel@tonic-gate _defaults, get_request_diskset(), val)) != 0) { 811*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 812*0Sstevel@tonic-gate return (error); 813*0Sstevel@tonic-gate } 814*0Sstevel@tonic-gate } 815*0Sstevel@tonic-gate } 816*0Sstevel@tonic-gate 817*0Sstevel@tonic-gate return (error); 818*0Sstevel@tonic-gate } 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate /* 821*0Sstevel@tonic-gate * FUNCTION: get_volume_npaths(devconfig_t *req, uint16_t val) 822*0Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request 823*0Sstevel@tonic-gate * val - pointer to a uint16-t to hold the result 824*0Sstevel@tonic-gate * 825*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 826*0Sstevel@tonic-gate * !0 - otherwise 827*0Sstevel@tonic-gate * 828*0Sstevel@tonic-gate * PURPOSE: helper which determines the appropriate level of datapath 829*0Sstevel@tonic-gate * redundancy a slice component should have for volumes 830*0Sstevel@tonic-gate * satisfying the input request. 831*0Sstevel@tonic-gate * 832*0Sstevel@tonic-gate * The value to use is taken from the input request, the 833*0Sstevel@tonic-gate * toplevel diskset request, the diskset defaults or the 834*0Sstevel@tonic-gate * global defaults. 835*0Sstevel@tonic-gate */ 836*0Sstevel@tonic-gate int 837*0Sstevel@tonic-gate get_volume_npaths( 838*0Sstevel@tonic-gate devconfig_t *req, 839*0Sstevel@tonic-gate uint16_t *val) 840*0Sstevel@tonic-gate { 841*0Sstevel@tonic-gate int error = 0; 842*0Sstevel@tonic-gate 843*0Sstevel@tonic-gate *val = 0; 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate if ((error = devconfig_get_volume_npaths(req, val)) != 0) { 846*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 847*0Sstevel@tonic-gate return (error); 848*0Sstevel@tonic-gate } 849*0Sstevel@tonic-gate } 850*0Sstevel@tonic-gate 851*0Sstevel@tonic-gate if (*val == 0) { 852*0Sstevel@tonic-gate if ((error = defaults_get_volume_npaths( 853*0Sstevel@tonic-gate _defaults, get_request_diskset(), val)) != 0) { 854*0Sstevel@tonic-gate if (error != ERR_ATTR_UNSET) { 855*0Sstevel@tonic-gate return (error); 856*0Sstevel@tonic-gate } 857*0Sstevel@tonic-gate } 858*0Sstevel@tonic-gate } 859*0Sstevel@tonic-gate 860*0Sstevel@tonic-gate return (error); 861*0Sstevel@tonic-gate } 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate /* 864*0Sstevel@tonic-gate * FUNCTION: get_default_hsp_name(devconfig_t *req, char **hspname) 865*0Sstevel@tonic-gate * INPUT: req - a devconfig_t pointer to the current request 866*0Sstevel@tonic-gate * hspname - pointer to a char * to hold the result, if any 867*0Sstevel@tonic-gate * 868*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 869*0Sstevel@tonic-gate * !0 - otherwise 870*0Sstevel@tonic-gate * 871*0Sstevel@tonic-gate * PURPOSE: helper which determines the default HSP name for the 872*0Sstevel@tonic-gate * input request. 873*0Sstevel@tonic-gate * 874*0Sstevel@tonic-gate * The value to use is taken from the input request, the 875*0Sstevel@tonic-gate * toplevel diskset request, the diskset defaults or the 876*0Sstevel@tonic-gate * global defaults. 877*0Sstevel@tonic-gate */ 878*0Sstevel@tonic-gate int 879*0Sstevel@tonic-gate get_default_hsp_name( 880*0Sstevel@tonic-gate devconfig_t *req, 881*0Sstevel@tonic-gate char **name) 882*0Sstevel@tonic-gate { 883*0Sstevel@tonic-gate int error = 0; 884*0Sstevel@tonic-gate 885*0Sstevel@tonic-gate *name = NULL; 886*0Sstevel@tonic-gate 887*0Sstevel@tonic-gate if ((error = defaults_get_hsp_name(_defaults, 888*0Sstevel@tonic-gate get_request_diskset(), name)) != 0) { 889*0Sstevel@tonic-gate if (error != ENOENT) { 890*0Sstevel@tonic-gate return (error); 891*0Sstevel@tonic-gate } 892*0Sstevel@tonic-gate error = 0; 893*0Sstevel@tonic-gate } 894*0Sstevel@tonic-gate 895*0Sstevel@tonic-gate return (error); 896*0Sstevel@tonic-gate } 897*0Sstevel@tonic-gate 898*0Sstevel@tonic-gate /* 899*0Sstevel@tonic-gate * FUNCTION: slice_is_available(char *sname, devconfig_t *request, 900*0Sstevel@tonic-gate * boolean_t bool) 901*0Sstevel@tonic-gate * INPUT: sname - a slice name 902*0Sstevel@tonic-gate * request - pointer to a devconfig_t struct representing 903*0Sstevel@tonic-gate * the current layout request being processed 904*0Sstevel@tonic-gate * bool - pointer to a boolean to hold the result 905*0Sstevel@tonic-gate * 906*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 907*0Sstevel@tonic-gate * !0 - otherwise 908*0Sstevel@tonic-gate * 909*0Sstevel@tonic-gate * PURPOSE: Validation helper which determines if the named slice can 910*0Sstevel@tonic-gate * be used as a volume component when satisfying the input 911*0Sstevel@tonic-gate * request. 912*0Sstevel@tonic-gate * 913*0Sstevel@tonic-gate * Check if the slice appears in the known slice list, 914*0Sstevel@tonic-gate * then check the request's available and unavailable 915*0Sstevel@tonic-gate * device specifications. 916*0Sstevel@tonic-gate */ 917*0Sstevel@tonic-gate int 918*0Sstevel@tonic-gate slice_is_available( 919*0Sstevel@tonic-gate char *sname, 920*0Sstevel@tonic-gate devconfig_t *request, 921*0Sstevel@tonic-gate boolean_t *bool) 922*0Sstevel@tonic-gate { 923*0Sstevel@tonic-gate dm_descriptor_t slice = (dm_descriptor_t)0; 924*0Sstevel@tonic-gate int error = 0; 925*0Sstevel@tonic-gate 926*0Sstevel@tonic-gate *bool = B_FALSE; 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate if ((error = slice_get_by_name(sname, &slice)) != 0) { 929*0Sstevel@tonic-gate return (error); 930*0Sstevel@tonic-gate } 931*0Sstevel@tonic-gate 932*0Sstevel@tonic-gate if (slice == (dm_descriptor_t)0) { 933*0Sstevel@tonic-gate /* no slice found */ 934*0Sstevel@tonic-gate return (ENODEV); 935*0Sstevel@tonic-gate } 936*0Sstevel@tonic-gate 937*0Sstevel@tonic-gate if (error == 0) { 938*0Sstevel@tonic-gate error = is_named_device_avail(request, sname, B_TRUE, bool); 939*0Sstevel@tonic-gate } 940*0Sstevel@tonic-gate 941*0Sstevel@tonic-gate return (error); 942*0Sstevel@tonic-gate } 943*0Sstevel@tonic-gate 944*0Sstevel@tonic-gate /* 945*0Sstevel@tonic-gate * FUNCTION: get_disks_for_target(char *name, dlist_t **disks) 946*0Sstevel@tonic-gate * 947*0Sstevel@tonic-gate * INPUT: name - a char* device CTD name 948*0Sstevel@tonic-gate * 949*0Sstevel@tonic-gate * OUTPUT: disks - disks matching the input target name 950*0Sstevel@tonic-gate * 951*0Sstevel@tonic-gate * RETURNS: int - 0 on success 952*0Sstevel@tonic-gate * !0 otherwise 953*0Sstevel@tonic-gate * 954*0Sstevel@tonic-gate * PURPOSE: Validation helper function which finds all disks "on" the 955*0Sstevel@tonic-gate * input target. 956*0Sstevel@tonic-gate * 957*0Sstevel@tonic-gate * The input name is assumed to be a target name, cXtX, and 958*0Sstevel@tonic-gate * the list of known disks is searched to find any disk that 959*0Sstevel@tonic-gate * looks to be "on" that target. 960*0Sstevel@tonic-gate * 961*0Sstevel@tonic-gate * "On" is determined by comparing a disk's name and 962*0Sstevel@tonic-gate * aliases to the target to see if they match. 963*0Sstevel@tonic-gate */ 964*0Sstevel@tonic-gate int 965*0Sstevel@tonic-gate get_disks_for_target( 966*0Sstevel@tonic-gate char *name, 967*0Sstevel@tonic-gate dlist_t **disks) 968*0Sstevel@tonic-gate { 969*0Sstevel@tonic-gate int error = 0; 970*0Sstevel@tonic-gate device_spec_t *targetid = NULL; 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate error = get_spec_for_name(name, &targetid); 973*0Sstevel@tonic-gate if (error == 0) { 974*0Sstevel@tonic-gate dlist_t *known_disks = NULL; 975*0Sstevel@tonic-gate dlist_t *iter = NULL; 976*0Sstevel@tonic-gate 977*0Sstevel@tonic-gate get_known_disks(&known_disks); 978*0Sstevel@tonic-gate for (iter = known_disks; 979*0Sstevel@tonic-gate (iter != NULL) && (error == 0); 980*0Sstevel@tonic-gate iter = iter->next) { 981*0Sstevel@tonic-gate 982*0Sstevel@tonic-gate dm_descriptor_t disk = (uintptr_t)iter->obj; 983*0Sstevel@tonic-gate device_spec_t *diskid = NULL; 984*0Sstevel@tonic-gate char *diskname = NULL; 985*0Sstevel@tonic-gate dlist_t *diskaliases = NULL; 986*0Sstevel@tonic-gate dlist_t *item; 987*0Sstevel@tonic-gate 988*0Sstevel@tonic-gate ((error = get_display_name(disk, &diskname)) != 0) || 989*0Sstevel@tonic-gate (error = get_aliases(disk, &diskaliases)) || 990*0Sstevel@tonic-gate (error = get_spec_for_name(diskname, &diskid)); 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate if (error == 0) { 993*0Sstevel@tonic-gate if (spec_includes_device(targetid, diskid) == B_TRUE) { 994*0Sstevel@tonic-gate /* add disk */ 995*0Sstevel@tonic-gate if ((item = dlist_new_item((void *)disk)) == NULL) { 996*0Sstevel@tonic-gate error = ENOMEM; 997*0Sstevel@tonic-gate } else { 998*0Sstevel@tonic-gate *disks = dlist_append(item, *disks, AT_HEAD); 999*0Sstevel@tonic-gate } 1000*0Sstevel@tonic-gate } else { 1001*0Sstevel@tonic-gate /* check disk's aliases */ 1002*0Sstevel@tonic-gate dlist_t *iter2; 1003*0Sstevel@tonic-gate for (iter2 = diskaliases; 1004*0Sstevel@tonic-gate (iter2 != NULL) && (error == 0); 1005*0Sstevel@tonic-gate iter2 = iter2->next) { 1006*0Sstevel@tonic-gate 1007*0Sstevel@tonic-gate char *aliasname = NULL; 1008*0Sstevel@tonic-gate device_spec_t *aliasid = NULL; 1009*0Sstevel@tonic-gate error = get_display_name(disk, &aliasname); 1010*0Sstevel@tonic-gate error = get_spec_for_name(aliasname, &aliasid); 1011*0Sstevel@tonic-gate 1012*0Sstevel@tonic-gate if (spec_includes_device( 1013*0Sstevel@tonic-gate targetid, aliasid) == B_TRUE) { 1014*0Sstevel@tonic-gate 1015*0Sstevel@tonic-gate /* alias matched, add disk */ 1016*0Sstevel@tonic-gate item = dlist_new_item((void *)disk); 1017*0Sstevel@tonic-gate if (item == NULL) { 1018*0Sstevel@tonic-gate error = ENOMEM; 1019*0Sstevel@tonic-gate } else { 1020*0Sstevel@tonic-gate *disks = 1021*0Sstevel@tonic-gate dlist_append(item, *disks, AT_HEAD); 1022*0Sstevel@tonic-gate } 1023*0Sstevel@tonic-gate } 1024*0Sstevel@tonic-gate } 1025*0Sstevel@tonic-gate } 1026*0Sstevel@tonic-gate } 1027*0Sstevel@tonic-gate } 1028*0Sstevel@tonic-gate } 1029*0Sstevel@tonic-gate 1030*0Sstevel@tonic-gate return (error); 1031*0Sstevel@tonic-gate } 1032*0Sstevel@tonic-gate 1033*0Sstevel@tonic-gate /* 1034*0Sstevel@tonic-gate * FUNCTION: select_hbas_with_n_disks(devconfig_t *request, 1035*0Sstevel@tonic-gate * dlist_t *hbas, int mindisks, dlist_t **selhbas, 1036*0Sstevel@tonic-gate * dlist_t **seldisks) 1037*0Sstevel@tonic-gate * 1038*0Sstevel@tonic-gate * INPUT: request - pointer to a devconfig_t struct representing 1039*0Sstevel@tonic-gate * the current layout request being processed 1040*0Sstevel@tonic-gate * hbas - pointer to a list of HBAs 1041*0Sstevel@tonic-gate * mindisks - minimum number of disks required on the HBAs 1042*0Sstevel@tonic-gate * 1043*0Sstevel@tonic-gate * OUTPUT: selhbas - pointer to a list containing the HBAs with at 1044*0Sstevel@tonic-gate * least mindisks available disks. 1045*0Sstevel@tonic-gate * seldisks - pointer to a list containing the available disks 1046*0Sstevel@tonic-gate * for the HBAs in selhbas 1047*0Sstevel@tonic-gate * 1048*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 1049*0Sstevel@tonic-gate * !0 - otherwise 1050*0Sstevel@tonic-gate * 1051*0Sstevel@tonic-gate * PURPOSE: helper which counts the number of available disks associated 1052*0Sstevel@tonic-gate * with each of the input HBAs and adds those that have at 1053*0Sstevel@tonic-gate * least mindisks to the output list. 1054*0Sstevel@tonic-gate * 1055*0Sstevel@tonic-gate * Only available disks that have available space are counted. 1056*0Sstevel@tonic-gate * 1057*0Sstevel@tonic-gate * Disks connected thru multiple HBAs are only counted for 1058*0Sstevel@tonic-gate * the first HBA they're accessed through. 1059*0Sstevel@tonic-gate * 1060*0Sstevel@tonic-gate * The list of HBAs returned will be in descending order, 1061*0Sstevel@tonic-gate * i.e., HBAs with more disks come before those with fewer. 1062*0Sstevel@tonic-gate * 1063*0Sstevel@tonic-gate * The returned lists of HBAs and disks must be passed to 1064*0Sstevel@tonic-gate * dlist_free_items() to recover the space allocated to hold 1065*0Sstevel@tonic-gate * each list item. 1066*0Sstevel@tonic-gate * 1067*0Sstevel@tonic-gate * for (each HBA) { 1068*0Sstevel@tonic-gate * 1069*0Sstevel@tonic-gate * select HBA 1070*0Sstevel@tonic-gate * get available disks on HBA 1071*0Sstevel@tonic-gate * 1072*0Sstevel@tonic-gate * for (each disk) { 1073*0Sstevel@tonic-gate * if (disk is not in selected disk list) 1074*0Sstevel@tonic-gate * add it to the list 1075*0Sstevel@tonic-gate * else 1076*0Sstevel@tonic-gate * count it as a distinct disk on this HBA 1077*0Sstevel@tonic-gate * } 1078*0Sstevel@tonic-gate * 1079*0Sstevel@tonic-gate * if (this HBA has >= mindisks distinct disks) 1080*0Sstevel@tonic-gate * add this HBA to the list of returned HBAs 1081*0Sstevel@tonic-gate * 1082*0Sstevel@tonic-gate * } 1083*0Sstevel@tonic-gate */ 1084*0Sstevel@tonic-gate int 1085*0Sstevel@tonic-gate select_hbas_with_n_disks( 1086*0Sstevel@tonic-gate devconfig_t *request, 1087*0Sstevel@tonic-gate dlist_t *hbas, 1088*0Sstevel@tonic-gate int mindisks, 1089*0Sstevel@tonic-gate dlist_t **selhbas, 1090*0Sstevel@tonic-gate dlist_t **seldisks) 1091*0Sstevel@tonic-gate { 1092*0Sstevel@tonic-gate dlist_t *iter = NULL; 1093*0Sstevel@tonic-gate int error = 0; 1094*0Sstevel@tonic-gate 1095*0Sstevel@tonic-gate *selhbas = NULL; 1096*0Sstevel@tonic-gate *seldisks = NULL; 1097*0Sstevel@tonic-gate 1098*0Sstevel@tonic-gate /* for each input HBA */ 1099*0Sstevel@tonic-gate for (iter = hbas; (error == 0) && (iter != NULL); iter = iter->next) { 1100*0Sstevel@tonic-gate 1101*0Sstevel@tonic-gate dm_descriptor_t hba = (uintptr_t)iter->obj; 1102*0Sstevel@tonic-gate dlist_t *iter2 = NULL; 1103*0Sstevel@tonic-gate dlist_t *disks = NULL; 1104*0Sstevel@tonic-gate uint64_t space = 0; 1105*0Sstevel@tonic-gate uint16_t ndistinct = 0; 1106*0Sstevel@tonic-gate 1107*0Sstevel@tonic-gate error = hba_get_avail_disks_and_space(request, hba, &disks, &space); 1108*0Sstevel@tonic-gate 1109*0Sstevel@tonic-gate /* for each of this HBA's disks */ 1110*0Sstevel@tonic-gate for (iter2 = disks; 1111*0Sstevel@tonic-gate (iter2 != NULL) && (error == 0); 1112*0Sstevel@tonic-gate iter2 = iter2->next) { 1113*0Sstevel@tonic-gate 1114*0Sstevel@tonic-gate dm_descriptor_t disk = (uintptr_t)iter2->obj; 1115*0Sstevel@tonic-gate 1116*0Sstevel@tonic-gate /* unique disk? has it been seen thru some other HBA? */ 1117*0Sstevel@tonic-gate if (dlist_contains(*seldisks, (void *)disk, 1118*0Sstevel@tonic-gate compare_descriptor_names) != B_TRUE) { 1119*0Sstevel@tonic-gate 1120*0Sstevel@tonic-gate /* distinct, add to list of all_distinct */ 1121*0Sstevel@tonic-gate dlist_t *item = dlist_new_item((void *)disk); 1122*0Sstevel@tonic-gate if (item == NULL) { 1123*0Sstevel@tonic-gate error = ENOMEM; 1124*0Sstevel@tonic-gate } else { 1125*0Sstevel@tonic-gate 1126*0Sstevel@tonic-gate *seldisks = 1127*0Sstevel@tonic-gate dlist_append(item, *seldisks, AT_HEAD); 1128*0Sstevel@tonic-gate 1129*0Sstevel@tonic-gate /* increment this HBA's distinct disk count */ 1130*0Sstevel@tonic-gate ++ndistinct; 1131*0Sstevel@tonic-gate } 1132*0Sstevel@tonic-gate } 1133*0Sstevel@tonic-gate } 1134*0Sstevel@tonic-gate 1135*0Sstevel@tonic-gate if (ndistinct >= mindisks) { 1136*0Sstevel@tonic-gate 1137*0Sstevel@tonic-gate /* this HBA has minimum # of disks, add to output list */ 1138*0Sstevel@tonic-gate dlist_t *item = dlist_new_item((void *)hba); 1139*0Sstevel@tonic-gate if (item == NULL) { 1140*0Sstevel@tonic-gate error = ENOMEM; 1141*0Sstevel@tonic-gate } else { 1142*0Sstevel@tonic-gate *selhbas = 1143*0Sstevel@tonic-gate dlist_insert_ordered( 1144*0Sstevel@tonic-gate item, *selhbas, DESCENDING, 1145*0Sstevel@tonic-gate compare_hba_n_avail_disks); 1146*0Sstevel@tonic-gate 1147*0Sstevel@tonic-gate /* save # of disks for ordering the list */ 1148*0Sstevel@tonic-gate hba_set_n_avail_disks(hba, ndistinct); 1149*0Sstevel@tonic-gate } 1150*0Sstevel@tonic-gate } 1151*0Sstevel@tonic-gate 1152*0Sstevel@tonic-gate dlist_free_items(disks, NULL); 1153*0Sstevel@tonic-gate } 1154*0Sstevel@tonic-gate 1155*0Sstevel@tonic-gate if (error != 0) { 1156*0Sstevel@tonic-gate oprintf(OUTPUT_TERSE, 1157*0Sstevel@tonic-gate gettext("failed selecting HBAs with n disks: %d\n"), 1158*0Sstevel@tonic-gate error); 1159*0Sstevel@tonic-gate 1160*0Sstevel@tonic-gate dlist_free_items(*selhbas, NULL); 1161*0Sstevel@tonic-gate *selhbas = NULL; 1162*0Sstevel@tonic-gate dlist_free_items(*seldisks, NULL); 1163*0Sstevel@tonic-gate *seldisks = NULL; 1164*0Sstevel@tonic-gate } 1165*0Sstevel@tonic-gate 1166*0Sstevel@tonic-gate return (error); 1167*0Sstevel@tonic-gate } 1168*0Sstevel@tonic-gate 1169*0Sstevel@tonic-gate /* 1170*0Sstevel@tonic-gate * FUNCTION: hba_get_avail_disks_and_space(devconfig_t *request, 1171*0Sstevel@tonic-gate * dm_descriptor_t hba, dlist_t **disks, uint64_t *space) 1172*0Sstevel@tonic-gate * 1173*0Sstevel@tonic-gate * INPUT: request - pointer to a devconfig_t struct representing 1174*0Sstevel@tonic-gate * the current layout request being processed 1175*0Sstevel@tonic-gate * hba - dm_descriptor_t handle for an HBA 1176*0Sstevel@tonic-gate * 1177*0Sstevel@tonic-gate * OUTPUT: disks - pointer to a list to hold the computed available 1178*0Sstevel@tonic-gate * disks 1179*0Sstevel@tonic-gate * avail - pointer to a uint64_t to hold the aggregate 1180*0Sstevel@tonic-gate * available space on the available disks 1181*0Sstevel@tonic-gate * 1182*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 1183*0Sstevel@tonic-gate * !0 - otherwise 1184*0Sstevel@tonic-gate * 1185*0Sstevel@tonic-gate * PURPOSE: helper which examines the disks associated with the 1186*0Sstevel@tonic-gate * input HBA and assembles a list of those that are available. 1187*0Sstevel@tonic-gate * 1188*0Sstevel@tonic-gate * Available is defined as being in the usable list, having 1189*0Sstevel@tonic-gate * unused space and not specifically excluded by the request's 1190*0Sstevel@tonic-gate * list of unavailable devices. 1191*0Sstevel@tonic-gate * 1192*0Sstevel@tonic-gate * The returned list must be passed to dlist_free_items() 1193*0Sstevel@tonic-gate * to recover the memory allocated to hold each list item. 1194*0Sstevel@tonic-gate */ 1195*0Sstevel@tonic-gate int 1196*0Sstevel@tonic-gate hba_get_avail_disks_and_space( 1197*0Sstevel@tonic-gate devconfig_t *request, 1198*0Sstevel@tonic-gate dm_descriptor_t hba, 1199*0Sstevel@tonic-gate dlist_t **disks, 1200*0Sstevel@tonic-gate uint64_t *space) 1201*0Sstevel@tonic-gate { 1202*0Sstevel@tonic-gate dlist_t *usable_disks = NULL; 1203*0Sstevel@tonic-gate dlist_t *iter = NULL; 1204*0Sstevel@tonic-gate int error = 0; 1205*0Sstevel@tonic-gate 1206*0Sstevel@tonic-gate *disks = NULL; 1207*0Sstevel@tonic-gate 1208*0Sstevel@tonic-gate /* for each usable disk */ 1209*0Sstevel@tonic-gate error = get_usable_disks(&usable_disks); 1210*0Sstevel@tonic-gate for (iter = usable_disks; 1211*0Sstevel@tonic-gate (error == 0) && (iter != NULL); 1212*0Sstevel@tonic-gate iter = iter->next) { 1213*0Sstevel@tonic-gate 1214*0Sstevel@tonic-gate dm_descriptor_t disk = (uintptr_t)iter->obj; 1215*0Sstevel@tonic-gate boolean_t avail = B_FALSE; 1216*0Sstevel@tonic-gate dlist_t *hbas = NULL; 1217*0Sstevel@tonic-gate 1218*0Sstevel@tonic-gate /* is disk attached to HBA in question? */ 1219*0Sstevel@tonic-gate error = disk_get_hbas(disk, &hbas); 1220*0Sstevel@tonic-gate if (error != 0) { 1221*0Sstevel@tonic-gate continue; 1222*0Sstevel@tonic-gate } 1223*0Sstevel@tonic-gate 1224*0Sstevel@tonic-gate if (dlist_contains(hbas, (void *)hba, 1225*0Sstevel@tonic-gate compare_descriptor_names) == B_TRUE) { 1226*0Sstevel@tonic-gate 1227*0Sstevel@tonic-gate /* is disk available? */ 1228*0Sstevel@tonic-gate error = is_device_avail(disk, request, &avail); 1229*0Sstevel@tonic-gate if ((error == 0) && (avail == B_TRUE)) { 1230*0Sstevel@tonic-gate uint64_t disk_space = 0; 1231*0Sstevel@tonic-gate 1232*0Sstevel@tonic-gate /* does disk have available space? */ 1233*0Sstevel@tonic-gate error = disk_get_avail_space(request, disk, &disk_space); 1234*0Sstevel@tonic-gate if ((error == 0) && (disk_space > 0)) { 1235*0Sstevel@tonic-gate 1236*0Sstevel@tonic-gate dlist_t *item = dlist_new_item((void *)disk); 1237*0Sstevel@tonic-gate if (item == NULL) { 1238*0Sstevel@tonic-gate error = ENOMEM; 1239*0Sstevel@tonic-gate } else { 1240*0Sstevel@tonic-gate *disks = dlist_append(item, *disks, AT_HEAD); 1241*0Sstevel@tonic-gate } 1242*0Sstevel@tonic-gate 1243*0Sstevel@tonic-gate *space += disk_space; 1244*0Sstevel@tonic-gate } 1245*0Sstevel@tonic-gate } 1246*0Sstevel@tonic-gate } 1247*0Sstevel@tonic-gate 1248*0Sstevel@tonic-gate dlist_free_items(hbas, NULL); 1249*0Sstevel@tonic-gate } 1250*0Sstevel@tonic-gate 1251*0Sstevel@tonic-gate if (error != 0) { 1252*0Sstevel@tonic-gate dlist_free_items(*disks, NULL); 1253*0Sstevel@tonic-gate *disks = NULL; 1254*0Sstevel@tonic-gate } 1255*0Sstevel@tonic-gate 1256*0Sstevel@tonic-gate return (error); 1257*0Sstevel@tonic-gate } 1258*0Sstevel@tonic-gate 1259*0Sstevel@tonic-gate /* 1260*0Sstevel@tonic-gate * FUNCTION: disk_get_avail_space(devconfig_t *request, 1261*0Sstevel@tonic-gate * dlist_t *disks, uint64_t space) 1262*0Sstevel@tonic-gate * 1263*0Sstevel@tonic-gate * INPUT: request - pointer to a devconfig_t struct representing 1264*0Sstevel@tonic-gate * the current layout request being processed 1265*0Sstevel@tonic-gate * disks - pointer to a list of disks 1266*0Sstevel@tonic-gate * space - pointer to a uint64_t to hold the computed available 1267*0Sstevel@tonic-gate * space 1268*0Sstevel@tonic-gate * 1269*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 1270*0Sstevel@tonic-gate * !0 - otherwise 1271*0Sstevel@tonic-gate * 1272*0Sstevel@tonic-gate * PURPOSE: helper which iterates the input list of disks and determines 1273*0Sstevel@tonic-gate * the aggregate amount of available space they represent. 1274*0Sstevel@tonic-gate * 1275*0Sstevel@tonic-gate * Only disk slices that are in the usable slice list and not 1276*0Sstevel@tonic-gate * specifically excluded by the request's list of unavailable 1277*0Sstevel@tonic-gate * devices will contribute to the aggregate space computation. 1278*0Sstevel@tonic-gate */ 1279*0Sstevel@tonic-gate static int 1280*0Sstevel@tonic-gate disk_get_avail_space( 1281*0Sstevel@tonic-gate devconfig_t *request, 1282*0Sstevel@tonic-gate dm_descriptor_t disk, 1283*0Sstevel@tonic-gate uint64_t *space) 1284*0Sstevel@tonic-gate { 1285*0Sstevel@tonic-gate dlist_t *usable_slices = NULL; 1286*0Sstevel@tonic-gate dlist_t *iter = NULL; 1287*0Sstevel@tonic-gate int error = 0; 1288*0Sstevel@tonic-gate 1289*0Sstevel@tonic-gate *space = 0; 1290*0Sstevel@tonic-gate 1291*0Sstevel@tonic-gate /* for each usable slice */ 1292*0Sstevel@tonic-gate error = get_usable_slices(&usable_slices); 1293*0Sstevel@tonic-gate for (iter = usable_slices; 1294*0Sstevel@tonic-gate (error == 0) && (iter != NULL); 1295*0Sstevel@tonic-gate iter = iter->next) { 1296*0Sstevel@tonic-gate 1297*0Sstevel@tonic-gate dm_descriptor_t slice = (uintptr_t)iter->obj; 1298*0Sstevel@tonic-gate dm_descriptor_t slice_disk; 1299*0Sstevel@tonic-gate boolean_t avail = B_FALSE; 1300*0Sstevel@tonic-gate boolean_t reserved = B_FALSE; 1301*0Sstevel@tonic-gate boolean_t used = B_FALSE; 1302*0Sstevel@tonic-gate 1303*0Sstevel@tonic-gate /* is slice on disk in question? */ 1304*0Sstevel@tonic-gate if (((error = slice_get_disk(slice, &slice_disk)) != 0) || 1305*0Sstevel@tonic-gate (compare_descriptor_names((void *)slice_disk, 1306*0Sstevel@tonic-gate (void *)disk) != 0)) { 1307*0Sstevel@tonic-gate continue; 1308*0Sstevel@tonic-gate } 1309*0Sstevel@tonic-gate 1310*0Sstevel@tonic-gate /* is slice reserved by an explicit layout request? */ 1311*0Sstevel@tonic-gate if (((error = is_reserved_slice(slice, &reserved)) != 0) || 1312*0Sstevel@tonic-gate (reserved == B_TRUE)) { 1313*0Sstevel@tonic-gate continue; 1314*0Sstevel@tonic-gate } 1315*0Sstevel@tonic-gate 1316*0Sstevel@tonic-gate /* is slice used by a pending layout request? */ 1317*0Sstevel@tonic-gate if (((error = is_used_slice(slice, &used)) != 0) || 1318*0Sstevel@tonic-gate (used == B_TRUE)) { 1319*0Sstevel@tonic-gate continue; 1320*0Sstevel@tonic-gate } 1321*0Sstevel@tonic-gate 1322*0Sstevel@tonic-gate /* is slice available? */ 1323*0Sstevel@tonic-gate if (((error = is_device_avail(slice, request, &avail)) == 0) && 1324*0Sstevel@tonic-gate (avail == B_TRUE)) { 1325*0Sstevel@tonic-gate 1326*0Sstevel@tonic-gate /* does slice have usable space? */ 1327*0Sstevel@tonic-gate uint64_t size = 0; 1328*0Sstevel@tonic-gate if ((error = slice_get_size(slice, &size)) == 0) { 1329*0Sstevel@tonic-gate *space += size; 1330*0Sstevel@tonic-gate } 1331*0Sstevel@tonic-gate } 1332*0Sstevel@tonic-gate } 1333*0Sstevel@tonic-gate 1334*0Sstevel@tonic-gate return (error); 1335*0Sstevel@tonic-gate } 1336*0Sstevel@tonic-gate 1337*0Sstevel@tonic-gate /* 1338*0Sstevel@tonic-gate * FUNCTION: disks_get_avail_slices(devconfig_t *request, 1339*0Sstevel@tonic-gate * dlist_t *disks, dlist_t **slices) 1340*0Sstevel@tonic-gate * 1341*0Sstevel@tonic-gate * INPUT: request - pointer to a devconfig_t struct representing 1342*0Sstevel@tonic-gate * the current layout request being processed 1343*0Sstevel@tonic-gate * disks - pointer to a list of disks 1344*0Sstevel@tonic-gate * slices - pointer to an output list of disks 1345*0Sstevel@tonic-gate * 1346*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 1347*0Sstevel@tonic-gate * !0 - otherwise 1348*0Sstevel@tonic-gate * 1349*0Sstevel@tonic-gate * PURPOSE: helper which iterates the input list of disks and builds a 1350*0Sstevel@tonic-gate * new list which contains disks that are determined to be 1351*0Sstevel@tonic-gate * available for satisfying the input request. 1352*0Sstevel@tonic-gate * 1353*0Sstevel@tonic-gate * A disk must contain at least one slice in the available 1354*0Sstevel@tonic-gate * slice list as well as have available space in order 1355*0Sstevel@tonic-gate * to be available. 1356*0Sstevel@tonic-gate */ 1357*0Sstevel@tonic-gate int 1358*0Sstevel@tonic-gate disks_get_avail_slices( 1359*0Sstevel@tonic-gate devconfig_t *request, 1360*0Sstevel@tonic-gate dlist_t *disks, 1361*0Sstevel@tonic-gate dlist_t **slices) 1362*0Sstevel@tonic-gate { 1363*0Sstevel@tonic-gate dlist_t *usable_slices = NULL; 1364*0Sstevel@tonic-gate dlist_t *iter = NULL; 1365*0Sstevel@tonic-gate int error = 0; 1366*0Sstevel@tonic-gate 1367*0Sstevel@tonic-gate *slices = NULL; 1368*0Sstevel@tonic-gate 1369*0Sstevel@tonic-gate /* for each usable slice */ 1370*0Sstevel@tonic-gate error = get_usable_slices(&usable_slices); 1371*0Sstevel@tonic-gate for (iter = usable_slices; 1372*0Sstevel@tonic-gate (error == 0) && (iter != NULL); 1373*0Sstevel@tonic-gate iter = iter->next) { 1374*0Sstevel@tonic-gate 1375*0Sstevel@tonic-gate dm_descriptor_t slice = (uintptr_t)iter->obj; 1376*0Sstevel@tonic-gate dm_descriptor_t disk = (dm_descriptor_t)0; 1377*0Sstevel@tonic-gate boolean_t avail = B_FALSE; 1378*0Sstevel@tonic-gate boolean_t reserved = B_FALSE; 1379*0Sstevel@tonic-gate boolean_t used = B_FALSE; 1380*0Sstevel@tonic-gate 1381*0Sstevel@tonic-gate /* is slice on a disk in the input list? */ 1382*0Sstevel@tonic-gate if (((error = slice_get_disk(slice, &disk)) != 0) || 1383*0Sstevel@tonic-gate (dlist_contains(disks, (void *)disk, 1384*0Sstevel@tonic-gate compare_descriptor_names) != B_TRUE)) { 1385*0Sstevel@tonic-gate continue; 1386*0Sstevel@tonic-gate } 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate /* is slice reserved by an explicit layout request? */ 1389*0Sstevel@tonic-gate if (((error = is_reserved_slice(slice, &reserved)) != 0) || 1390*0Sstevel@tonic-gate (reserved == B_TRUE)) { 1391*0Sstevel@tonic-gate continue; 1392*0Sstevel@tonic-gate } 1393*0Sstevel@tonic-gate 1394*0Sstevel@tonic-gate /* is slice used by a pending layout request? */ 1395*0Sstevel@tonic-gate if (((error = is_used_slice(slice, &used)) != 0) || 1396*0Sstevel@tonic-gate (used == B_TRUE)) { 1397*0Sstevel@tonic-gate continue; 1398*0Sstevel@tonic-gate } 1399*0Sstevel@tonic-gate 1400*0Sstevel@tonic-gate /* is slice available? */ 1401*0Sstevel@tonic-gate if (((error = is_device_avail(slice, request, &avail)) == 0) && 1402*0Sstevel@tonic-gate (avail == B_TRUE)) { 1403*0Sstevel@tonic-gate 1404*0Sstevel@tonic-gate /* does slice have available space? */ 1405*0Sstevel@tonic-gate uint64_t size = 0; 1406*0Sstevel@tonic-gate error = slice_get_size(slice, &size); 1407*0Sstevel@tonic-gate if ((error == 0) && (size > 0)) { 1408*0Sstevel@tonic-gate dlist_t *item = dlist_new_item((void *)slice); 1409*0Sstevel@tonic-gate if (item == NULL) { 1410*0Sstevel@tonic-gate error = ENOMEM; 1411*0Sstevel@tonic-gate } else { 1412*0Sstevel@tonic-gate *slices = dlist_append(item, *slices, AT_TAIL); 1413*0Sstevel@tonic-gate } 1414*0Sstevel@tonic-gate } 1415*0Sstevel@tonic-gate } 1416*0Sstevel@tonic-gate } 1417*0Sstevel@tonic-gate 1418*0Sstevel@tonic-gate if (error != 0) { 1419*0Sstevel@tonic-gate dlist_free_items(*slices, NULL); 1420*0Sstevel@tonic-gate *slices = NULL; 1421*0Sstevel@tonic-gate } 1422*0Sstevel@tonic-gate 1423*0Sstevel@tonic-gate return (error); 1424*0Sstevel@tonic-gate } 1425*0Sstevel@tonic-gate 1426*0Sstevel@tonic-gate 1427*0Sstevel@tonic-gate /* 1428*0Sstevel@tonic-gate * FUNCTION: get_hbas_and_disks_used_by_volumes(dlist_t *volumes, 1429*0Sstevel@tonic-gate * dlist_t **hbas, dlist_t **disks) 1430*0Sstevel@tonic-gate * 1431*0Sstevel@tonic-gate * INPUT: volumes - pointer to a list of devconfig_t volumes 1432*0Sstevel@tonic-gate * 1433*0Sstevel@tonic-gate * OUTPUT: hbas - a list of HBAs utilized by the input volumes 1434*0Sstevel@tonic-gate * disks - a list of disks utilized by the input volumes 1435*0Sstevel@tonic-gate * 1436*0Sstevel@tonic-gate * RETURNS: int - 0 on success 1437*0Sstevel@tonic-gate * !0 otherwise 1438*0Sstevel@tonic-gate * 1439*0Sstevel@tonic-gate * PURPOSE: An aggregate list of HBAs and disks used by the input volumes 1440*0Sstevel@tonic-gate * is built up by iterating the list of volumes and calling 1441*0Sstevel@tonic-gate * get_hbas_disks_used_by_volume() to determine the HBAs and disk 1442*0Sstevel@tonic-gate * used by each volume. 1443*0Sstevel@tonic-gate * 1444*0Sstevel@tonic-gate * The returned lists of HBAs and disks may contain duplicates. 1445*0Sstevel@tonic-gate */ 1446*0Sstevel@tonic-gate int 1447*0Sstevel@tonic-gate get_hbas_and_disks_used_by_volumes( 1448*0Sstevel@tonic-gate dlist_t *volumes, 1449*0Sstevel@tonic-gate dlist_t **hbas, 1450*0Sstevel@tonic-gate dlist_t **disks) 1451*0Sstevel@tonic-gate { 1452*0Sstevel@tonic-gate dlist_t *iter = NULL; 1453*0Sstevel@tonic-gate int error = 0; 1454*0Sstevel@tonic-gate 1455*0Sstevel@tonic-gate for (iter = volumes; 1456*0Sstevel@tonic-gate (iter != NULL) && (error == 0); 1457*0Sstevel@tonic-gate iter = iter->next) { 1458*0Sstevel@tonic-gate error = get_hbas_and_disks_used_by_volume( 1459*0Sstevel@tonic-gate (devconfig_t *)iter->obj, hbas, disks); 1460*0Sstevel@tonic-gate } 1461*0Sstevel@tonic-gate 1462*0Sstevel@tonic-gate return (error); 1463*0Sstevel@tonic-gate } 1464*0Sstevel@tonic-gate 1465*0Sstevel@tonic-gate /* 1466*0Sstevel@tonic-gate * FUNCTION: get_hbas_and_disks_used_by_volume(devconfig_t *volume, 1467*0Sstevel@tonic-gate * dlist_t **hbas, dlist_t **disks) 1468*0Sstevel@tonic-gate * 1469*0Sstevel@tonic-gate * INPUT: volume - pointer to a devconfig_t volume 1470*0Sstevel@tonic-gate * 1471*0Sstevel@tonic-gate * OUTPUT: hbas - a list of HBAs updated to include those utilized 1472*0Sstevel@tonic-gate * by the input volume 1473*0Sstevel@tonic-gate * disks - a list of disks updated to inlclude those utilized 1474*0Sstevel@tonic-gate * by the input volume 1475*0Sstevel@tonic-gate * 1476*0Sstevel@tonic-gate * RETURNS: int - 0 on success 1477*0Sstevel@tonic-gate * !0 otherwise 1478*0Sstevel@tonic-gate * 1479*0Sstevel@tonic-gate * PURPOSE: The volume's components are iterated and the disks and HBAs 1480*0Sstevel@tonic-gate * for each component are determined and appended to the input 1481*0Sstevel@tonic-gate * lists of HBAs and disks. 1482*0Sstevel@tonic-gate * 1483*0Sstevel@tonic-gate * The returned lists of HBAs and disks may contain duplicates. 1484*0Sstevel@tonic-gate */ 1485*0Sstevel@tonic-gate int 1486*0Sstevel@tonic-gate get_hbas_and_disks_used_by_volume( 1487*0Sstevel@tonic-gate devconfig_t *volume, 1488*0Sstevel@tonic-gate dlist_t **hbas, 1489*0Sstevel@tonic-gate dlist_t **disks) 1490*0Sstevel@tonic-gate { 1491*0Sstevel@tonic-gate dlist_t *iter = NULL; 1492*0Sstevel@tonic-gate int error = 0; 1493*0Sstevel@tonic-gate 1494*0Sstevel@tonic-gate for (iter = devconfig_get_components(volume); 1495*0Sstevel@tonic-gate (iter != NULL) && (error == 0); 1496*0Sstevel@tonic-gate iter = iter->next) { 1497*0Sstevel@tonic-gate 1498*0Sstevel@tonic-gate devconfig_t *dev = (devconfig_t *)iter->obj; 1499*0Sstevel@tonic-gate if (devconfig_isA(dev, TYPE_SLICE)) { 1500*0Sstevel@tonic-gate 1501*0Sstevel@tonic-gate dm_descriptor_t disk = NULL; 1502*0Sstevel@tonic-gate char *name = NULL; 1503*0Sstevel@tonic-gate 1504*0Sstevel@tonic-gate /* get disk for component slice */ 1505*0Sstevel@tonic-gate ((error = devconfig_get_name(dev, &name)) != 0) || 1506*0Sstevel@tonic-gate (error = get_disk_for_named_slice(name, &disk)); 1507*0Sstevel@tonic-gate if (error == 0) { 1508*0Sstevel@tonic-gate dlist_t *item = dlist_new_item((void *)disk); 1509*0Sstevel@tonic-gate if (item == NULL) { 1510*0Sstevel@tonic-gate error = ENOMEM; 1511*0Sstevel@tonic-gate } else { 1512*0Sstevel@tonic-gate *disks = dlist_append(item, *disks, AT_HEAD); 1513*0Sstevel@tonic-gate } 1514*0Sstevel@tonic-gate } 1515*0Sstevel@tonic-gate 1516*0Sstevel@tonic-gate /* get HBAs for disk */ 1517*0Sstevel@tonic-gate if (error == 0) { 1518*0Sstevel@tonic-gate dlist_t *disk_hbas = NULL; 1519*0Sstevel@tonic-gate if ((error = disk_get_hbas(disk, &disk_hbas)) == 0) { 1520*0Sstevel@tonic-gate /* the hba list may contain dups, but that's ok */ 1521*0Sstevel@tonic-gate *hbas = dlist_append(disk_hbas, *hbas, AT_HEAD); 1522*0Sstevel@tonic-gate } 1523*0Sstevel@tonic-gate } 1524*0Sstevel@tonic-gate 1525*0Sstevel@tonic-gate } else if (devconfig_isA(dev, TYPE_MIRROR)) { 1526*0Sstevel@tonic-gate 1527*0Sstevel@tonic-gate /* collect info for submirrors */ 1528*0Sstevel@tonic-gate dlist_t *iter1; 1529*0Sstevel@tonic-gate for (iter1 = devconfig_get_components(dev); 1530*0Sstevel@tonic-gate (iter1 != NULL) && (error == 0); 1531*0Sstevel@tonic-gate iter1 = iter1->next) { 1532*0Sstevel@tonic-gate error = get_hbas_and_disks_used_by_volume( 1533*0Sstevel@tonic-gate (devconfig_t *)iter1->obj, hbas, disks); 1534*0Sstevel@tonic-gate } 1535*0Sstevel@tonic-gate 1536*0Sstevel@tonic-gate } 1537*0Sstevel@tonic-gate } 1538*0Sstevel@tonic-gate 1539*0Sstevel@tonic-gate return (error); 1540*0Sstevel@tonic-gate } 1541*0Sstevel@tonic-gate 1542*0Sstevel@tonic-gate /* 1543*0Sstevel@tonic-gate * FUNCTION: compare_hba_n_avail_disks(void *obj1, void *obj2) 1544*0Sstevel@tonic-gate * 1545*0Sstevel@tonic-gate * INPUT: obj1 - opaque pointer 1546*0Sstevel@tonic-gate * obj2 - opaque pointer 1547*0Sstevel@tonic-gate * 1548*0Sstevel@tonic-gate * RETURNS: int - <0 - if obj1 has fewer available disks than obj2 1549*0Sstevel@tonic-gate * 0 - if obj1 has the same # of available disks as obj2 1550*0Sstevel@tonic-gate * >0 - if obj1 has more available disks than obj2 1551*0Sstevel@tonic-gate * 1552*0Sstevel@tonic-gate * PURPOSE: dlist_t helper which compares the number of available disks 1553*0Sstevel@tonic-gate * for two HBAs represented as dm_descriptor_t handles. 1554*0Sstevel@tonic-gate * 1555*0Sstevel@tonic-gate * Both input objects are assumed to be dm_descriptor_t handles. 1556*0Sstevel@tonic-gate * 1557*0Sstevel@tonic-gate * The number of available disks associated with the HBAs was 1558*0Sstevel@tonic-gate * computed and saved in select_hbas_with_n_disks(), this 1559*0Sstevel@tonic-gate * function just checks the saved values. 1560*0Sstevel@tonic-gate */ 1561*0Sstevel@tonic-gate static int 1562*0Sstevel@tonic-gate compare_hba_n_avail_disks( 1563*0Sstevel@tonic-gate void *obj1, 1564*0Sstevel@tonic-gate void *obj2) 1565*0Sstevel@tonic-gate { 1566*0Sstevel@tonic-gate uint16_t n1 = 0; 1567*0Sstevel@tonic-gate uint16_t n2 = 0; 1568*0Sstevel@tonic-gate 1569*0Sstevel@tonic-gate assert(obj1 != NULL); 1570*0Sstevel@tonic-gate assert(obj2 != NULL); 1571*0Sstevel@tonic-gate 1572*0Sstevel@tonic-gate (void) hba_get_n_avail_disks((uintptr_t)obj1, &n1); 1573*0Sstevel@tonic-gate (void) hba_get_n_avail_disks((uintptr_t)obj2, &n2); 1574*0Sstevel@tonic-gate 1575*0Sstevel@tonic-gate return ((int)n1 - n2); 1576*0Sstevel@tonic-gate } 1577*0Sstevel@tonic-gate 1578*0Sstevel@tonic-gate /* 1579*0Sstevel@tonic-gate * FUNCTION: is_device_avail(dm_descriptor_t desc, 1580*0Sstevel@tonic-gate * devconfig_t *request, boolean_t *avail) 1581*0Sstevel@tonic-gate * 1582*0Sstevel@tonic-gate * INPUT: desc - a dm_descriptor_t device handle 1583*0Sstevel@tonic-gate * request - pointer to a devconfig_t struct representing 1584*0Sstevel@tonic-gate * the current layout request being processed 1585*0Sstevel@tonic-gate * avail - pointer to a boolean to hold the result 1586*0Sstevel@tonic-gate * 1587*0Sstevel@tonic-gate * RETURNS: int - 0 - on success 1588*0Sstevel@tonic-gate * !0 - otherwise 1589*0Sstevel@tonic-gate * 1590*0Sstevel@tonic-gate * PURPOSE: Internal helper which determines if the input device can 1591*0Sstevel@tonic-gate * be used as a volume component when satisfying the input 1592*0Sstevel@tonic-gate * request. 1593*0Sstevel@tonic-gate * 1594*0Sstevel@tonic-gate * The device is assumed to be a known valid device. 1595*0Sstevel@tonic-gate * 1596*0Sstevel@tonic-gate * The function checks if the device passes the request's 1597*0Sstevel@tonic-gate * available and unavailable device specifications. 1598*0Sstevel@tonic-gate * 1599*0Sstevel@tonic-gate * The input device name may be either a DID name or a CTD 1600*0Sstevel@tonic-gate * name. All name comparisons are done using the CTD name. 1601*0Sstevel@tonic-gate */ 1602*0Sstevel@tonic-gate static int 1603*0Sstevel@tonic-gate is_device_avail( 1604*0Sstevel@tonic-gate dm_descriptor_t desc, 1605*0Sstevel@tonic-gate devconfig_t *request, 1606*0Sstevel@tonic-gate boolean_t *avail) 1607*0Sstevel@tonic-gate { 1608*0Sstevel@tonic-gate char *name = NULL; 1609*0Sstevel@tonic-gate int error = 0; 1610*0Sstevel@tonic-gate 1611*0Sstevel@tonic-gate *avail = B_FALSE; 1612*0Sstevel@tonic-gate 1613*0Sstevel@tonic-gate if ((error = get_display_name(desc, &name)) == 0) { 1614*0Sstevel@tonic-gate error = is_named_device_avail(request, name, B_TRUE, avail); 1615*0Sstevel@tonic-gate } 1616*0Sstevel@tonic-gate 1617*0Sstevel@tonic-gate return (error); 1618*0Sstevel@tonic-gate } 1619*0Sstevel@tonic-gate 1620*0Sstevel@tonic-gate /* 1621*0Sstevel@tonic-gate * FUNCTION: compare_request_to_request_spec_list_request( 1622*0Sstevel@tonic-gate * void *request, void *list_item) 1623*0Sstevel@tonic-gate * 1624*0Sstevel@tonic-gate * INPUT: request - opaque pointer to a devconfig_t 1625*0Sstevel@tonic-gate * list_item - opaque pointer to a request_spec_list_t 1626*0Sstevel@tonic-gate * 1627*0Sstevel@tonic-gate * RETURNS: int - 0 - if request is the same as list_item->request 1628*0Sstevel@tonic-gate * !0 - otherwise 1629*0Sstevel@tonic-gate * 1630*0Sstevel@tonic-gate * PURPOSE: dlist_t helper which compares the input request pointer 1631*0Sstevel@tonic-gate * to the list_item's request pointer for equality. 1632*0Sstevel@tonic-gate * 1633*0Sstevel@tonic-gate * This function is the lookup mechanism for the lists of 1634*0Sstevel@tonic-gate * cached device_spec_ts representing available/unavailable 1635*0Sstevel@tonic-gate * devices for a given defaults_t request/defaults struct. 1636*0Sstevel@tonic-gate * 1637*0Sstevel@tonic-gate * The defaults_t struct pointer is the lookup key. 1638*0Sstevel@tonic-gate */ 1639*0Sstevel@tonic-gate static int 1640*0Sstevel@tonic-gate compare_request_to_request_spec_list_request( 1641*0Sstevel@tonic-gate void *request, 1642*0Sstevel@tonic-gate void *list_item) 1643*0Sstevel@tonic-gate { 1644*0Sstevel@tonic-gate request_spec_list_t *entry = 1645*0Sstevel@tonic-gate (request_spec_list_t *)list_item; 1646*0Sstevel@tonic-gate 1647*0Sstevel@tonic-gate assert(request != NULL); 1648*0Sstevel@tonic-gate assert(entry != NULL); 1649*0Sstevel@tonic-gate 1650*0Sstevel@tonic-gate /* compare two devconfig_t pointers, if identical, return 0 */ 1651*0Sstevel@tonic-gate return ((devconfig_t *)request != entry->request); 1652*0Sstevel@tonic-gate } 1653*0Sstevel@tonic-gate 1654*0Sstevel@tonic-gate /* 1655*0Sstevel@tonic-gate * FUNCTION: compare_device_spec_specificity(void *spec1, void *spec2) 1656*0Sstevel@tonic-gate * 1657*0Sstevel@tonic-gate * INPUT: spec1 - opaque pointer to a device_spec_t 1658*0Sstevel@tonic-gate * spec2 - opaque pointer to a device_spec_t 1659*0Sstevel@tonic-gate * 1660*0Sstevel@tonic-gate * RETURNS: int - <0 - if spec1 is less specific than spec2 1661*0Sstevel@tonic-gate * 0 - if spec1 is as specific than spec2 1662*0Sstevel@tonic-gate * >0 - if spec1 is more specific than spec2 1663*0Sstevel@tonic-gate * 1664*0Sstevel@tonic-gate * PURPOSE: dlist_t helper which compares the level of specificity 1665*0Sstevel@tonic-gate * in the two input device_spec_t structs. The one 1666*0Sstevel@tonic-gate * which specifies more "components" of a cXtXdXsX device 1667*0Sstevel@tonic-gate * name is considered more specific. 1668*0Sstevel@tonic-gate */ 1669*0Sstevel@tonic-gate static int 1670*0Sstevel@tonic-gate compare_device_spec_specificity( 1671*0Sstevel@tonic-gate void *spec1, 1672*0Sstevel@tonic-gate void *spec2) 1673*0Sstevel@tonic-gate { 1674*0Sstevel@tonic-gate if (spec1 == NULL || spec2 == NULL) { 1675*0Sstevel@tonic-gate return (-1); 1676*0Sstevel@tonic-gate } 1677*0Sstevel@tonic-gate 1678*0Sstevel@tonic-gate if ((((device_spec_t *)spec1)->data.ctd->slice != ID_UNSPECIFIED) && 1679*0Sstevel@tonic-gate (((device_spec_t *)spec2)->data.ctd->slice == ID_UNSPECIFIED)) { 1680*0Sstevel@tonic-gate /* spec1 has slice, spec2 does not, spec1 more specific */ 1681*0Sstevel@tonic-gate return (1); 1682*0Sstevel@tonic-gate } 1683*0Sstevel@tonic-gate 1684*0Sstevel@tonic-gate if ((((device_spec_t *)spec2)->data.ctd->slice != ID_UNSPECIFIED) && 1685*0Sstevel@tonic-gate (((device_spec_t *)spec1)->data.ctd->slice == ID_UNSPECIFIED)) { 1686*0Sstevel@tonic-gate /* spec2 has slice, spec1 does not, spec2 more specific */ 1687*0Sstevel@tonic-gate return (-1); 1688*0Sstevel@tonic-gate } 1689*0Sstevel@tonic-gate 1690*0Sstevel@tonic-gate if ((((device_spec_t *)spec2)->data.ctd->slice != ID_UNSPECIFIED) && 1691*0Sstevel@tonic-gate (((device_spec_t *)spec1)->data.ctd->slice != ID_UNSPECIFIED)) { 1692*0Sstevel@tonic-gate /* both spec1 and spec2 have slice */ 1693*0Sstevel@tonic-gate return (0); 1694*0Sstevel@tonic-gate } 1695*0Sstevel@tonic-gate 1696*0Sstevel@tonic-gate if ((((device_spec_t *)spec1)->data.ctd->lun != ID_UNSPECIFIED) && 1697*0Sstevel@tonic-gate (((device_spec_t *)spec2)->data.ctd->lun == ID_UNSPECIFIED)) { 1698*0Sstevel@tonic-gate /* spec1 has lun, spec2 does not, spec1 more specific */ 1699*0Sstevel@tonic-gate return (1); 1700*0Sstevel@tonic-gate } 1701*0Sstevel@tonic-gate 1702*0Sstevel@tonic-gate if ((((device_spec_t *)spec2)->data.ctd->lun != ID_UNSPECIFIED) && 1703*0Sstevel@tonic-gate (((device_spec_t *)spec1)->data.ctd->lun == ID_UNSPECIFIED)) { 1704*0Sstevel@tonic-gate /* spec2 has lun, spec1 does not, spec2 more specific */ 1705*0Sstevel@tonic-gate return (-1); 1706*0Sstevel@tonic-gate } 1707*0Sstevel@tonic-gate 1708*0Sstevel@tonic-gate if ((((device_spec_t *)spec2)->data.ctd->lun != ID_UNSPECIFIED) && 1709*0Sstevel@tonic-gate (((device_spec_t *)spec1)->data.ctd->lun != ID_UNSPECIFIED)) { 1710*0Sstevel@tonic-gate /* both spec1 and spec2 have lun */ 1711*0Sstevel@tonic-gate return (0); 1712*0Sstevel@tonic-gate } 1713*0Sstevel@tonic-gate 1714*0Sstevel@tonic-gate if ((((device_spec_t *)spec1)->data.ctd->target != ID_UNSPECIFIED) && 1715*0Sstevel@tonic-gate (((device_spec_t *)spec2)->data.ctd->target == ID_UNSPECIFIED)) { 1716*0Sstevel@tonic-gate /* spec1 has target, spec2 does not, spec1 more specific */ 1717*0Sstevel@tonic-gate return (1); 1718*0Sstevel@tonic-gate } 1719*0Sstevel@tonic-gate 1720*0Sstevel@tonic-gate if ((((device_spec_t *)spec2)->data.ctd->target != ID_UNSPECIFIED) && 1721*0Sstevel@tonic-gate (((device_spec_t *)spec1)->data.ctd->target == ID_UNSPECIFIED)) { 1722*0Sstevel@tonic-gate /* spec2 has target, spec1 does not, spec2 more specific */ 1723*0Sstevel@tonic-gate return (-1); 1724*0Sstevel@tonic-gate } 1725*0Sstevel@tonic-gate 1726*0Sstevel@tonic-gate if ((((device_spec_t *)spec2)->data.ctd->target != ID_UNSPECIFIED) && 1727*0Sstevel@tonic-gate (((device_spec_t *)spec1)->data.ctd->target != ID_UNSPECIFIED)) { 1728*0Sstevel@tonic-gate /* both spec1 and spec2 have target */ 1729*0Sstevel@tonic-gate return (0); 1730*0Sstevel@tonic-gate } 1731*0Sstevel@tonic-gate 1732*0Sstevel@tonic-gate /* both specify just ctrl */ 1733*0Sstevel@tonic-gate return (0); 1734*0Sstevel@tonic-gate } 1735*0Sstevel@tonic-gate 1736*0Sstevel@tonic-gate /* 1737*0Sstevel@tonic-gate * FUNCTION: find_request_spec_list_entry(devconfig_t *request) 1738*0Sstevel@tonic-gate * 1739*0Sstevel@tonic-gate * INPUT: request - pointer to a devconfig_t struct 1740*0Sstevel@tonic-gate * 1741*0Sstevel@tonic-gate * RETURNS: request_spec_list_entry - pointer to a 1742*0Sstevel@tonic-gate * request_spec_list_entry struct 1743*0Sstevel@tonic-gate * 1744*0Sstevel@tonic-gate * PURPOSE: Lookup function which encapsulates the details of locating 1745*0Sstevel@tonic-gate * the device_spec_list_t cache entry for the input request. 1746*0Sstevel@tonic-gate */ 1747*0Sstevel@tonic-gate static request_spec_list_t * 1748*0Sstevel@tonic-gate find_request_spec_list_entry( 1749*0Sstevel@tonic-gate devconfig_t *request) 1750*0Sstevel@tonic-gate { 1751*0Sstevel@tonic-gate dlist_t *list_item = NULL; 1752*0Sstevel@tonic-gate request_spec_list_t *entry = NULL; 1753*0Sstevel@tonic-gate 1754*0Sstevel@tonic-gate list_item = dlist_find( 1755*0Sstevel@tonic-gate _request_spec_list_cache, 1756*0Sstevel@tonic-gate (void *)request, 1757*0Sstevel@tonic-gate compare_request_to_request_spec_list_request); 1758*0Sstevel@tonic-gate 1759*0Sstevel@tonic-gate if (list_item != NULL) { 1760*0Sstevel@tonic-gate entry = (request_spec_list_t *)list_item->obj; 1761*0Sstevel@tonic-gate } 1762*0Sstevel@tonic-gate 1763*0Sstevel@tonic-gate return (entry); 1764*0Sstevel@tonic-gate } 1765*0Sstevel@tonic-gate 1766*0Sstevel@tonic-gate /* 1767*0Sstevel@tonic-gate * FUNCTION: add_request_spec_list_entry(devconfig_t *request, 1768*0Sstevel@tonic-gate * char **avail_device_specs, char **unavail_device_specs, 1769*0Sstevel@tonic-gate * request_spec_list_entry_t **entry) 1770*0Sstevel@tonic-gate * 1771*0Sstevel@tonic-gate * INPUT: entry - pointer to the request_spec_list_entry struct to be 1772*0Sstevel@tonic-gate * added to the cache. 1773*0Sstevel@tonic-gate * 1774*0Sstevel@tonic-gate * RETURNS: int - 0 on success 1775*0Sstevel@tonic-gate * !0 otherwise. 1776*0Sstevel@tonic-gate * 1777*0Sstevel@tonic-gate * PURPOSE: Function which encapsulates the details of adding a 1778*0Sstevel@tonic-gate * device_spec_list_t cache entry. 1779*0Sstevel@tonic-gate */ 1780*0Sstevel@tonic-gate static int 1781*0Sstevel@tonic-gate add_request_spec_list_entry( 1782*0Sstevel@tonic-gate request_spec_list_t *entry) 1783*0Sstevel@tonic-gate { 1784*0Sstevel@tonic-gate dlist_t *list_item = dlist_new_item((void *)entry); 1785*0Sstevel@tonic-gate 1786*0Sstevel@tonic-gate if (list_item == NULL) { 1787*0Sstevel@tonic-gate return (ENOMEM); 1788*0Sstevel@tonic-gate } 1789*0Sstevel@tonic-gate 1790*0Sstevel@tonic-gate _request_spec_list_cache = dlist_append(list_item, 1791*0Sstevel@tonic-gate _request_spec_list_cache, AT_HEAD); 1792*0Sstevel@tonic-gate 1793*0Sstevel@tonic-gate return (0); 1794*0Sstevel@tonic-gate } 1795*0Sstevel@tonic-gate 1796*0Sstevel@tonic-gate /* 1797*0Sstevel@tonic-gate * FUNCTION: make_request_spec_list_entry(devconfig_t *request, 1798*0Sstevel@tonic-gate * char **avail_device_specs, char **unavail_device_specs, 1799*0Sstevel@tonic-gate * request_spec_list_entry_t **entry) 1800*0Sstevel@tonic-gate * 1801*0Sstevel@tonic-gate * INPUT: request - pointer to a devconfig_t struct 1802*0Sstevel@tonic-gate * avail_device_specs - char * array of user specified available 1803*0Sstevel@tonic-gate * devices associated with the input request 1804*0Sstevel@tonic-gate * unavail_device_specs - char * array of user specified 1805*0Sstevel@tonic-gate * unavailable devices associated with the input 1806*0Sstevel@tonic-gate * request 1807*0Sstevel@tonic-gate * 1808*0Sstevel@tonic-gate * RETURNS: int - 0 on success 1809*0Sstevel@tonic-gate * !0 otherwise. 1810*0Sstevel@tonic-gate * 1811*0Sstevel@tonic-gate * PURPOSE: Function which encapsulates the details of generating a new 1812*0Sstevel@tonic-gate * the device_spec_list_t cache entry for the input request 1813*0Sstevel@tonic-gate * and its lists of avail/unavail devices. 1814*0Sstevel@tonic-gate * 1815*0Sstevel@tonic-gate * Converts the input arrays of (un)available device names into 1816*0Sstevel@tonic-gate * equivalent lists of device_spec_t structs. 1817*0Sstevel@tonic-gate * 1818*0Sstevel@tonic-gate * Creates a new cache entry, populates it and adds it to the 1819*0Sstevel@tonic-gate * cache. 1820*0Sstevel@tonic-gate */ 1821*0Sstevel@tonic-gate static int 1822*0Sstevel@tonic-gate make_request_spec_list_entry( 1823*0Sstevel@tonic-gate devconfig_t *request, 1824*0Sstevel@tonic-gate char **avail_device_specs, 1825*0Sstevel@tonic-gate char **unavail_device_specs, 1826*0Sstevel@tonic-gate request_spec_list_t **entry) 1827*0Sstevel@tonic-gate { 1828*0Sstevel@tonic-gate int error = 0; 1829*0Sstevel@tonic-gate dlist_t *list = NULL; 1830*0Sstevel@tonic-gate 1831*0Sstevel@tonic-gate *entry = calloc(1, sizeof (request_spec_list_t)); 1832*0Sstevel@tonic-gate if (*entry == NULL) { 1833*0Sstevel@tonic-gate return (ENOMEM); 1834*0Sstevel@tonic-gate } 1835*0Sstevel@tonic-gate 1836*0Sstevel@tonic-gate (*entry)->request = request; 1837*0Sstevel@tonic-gate 1838*0Sstevel@tonic-gate /* 1839*0Sstevel@tonic-gate * map the avail_device_name array into a list of device_spec_t 1840*0Sstevel@tonic-gate * and save the list as the entry's available list 1841*0Sstevel@tonic-gate */ 1842*0Sstevel@tonic-gate error = convert_usernames_to_specs( 1843*0Sstevel@tonic-gate avail_device_specs, &list); 1844*0Sstevel@tonic-gate 1845*0Sstevel@tonic-gate if (error == 0) { 1846*0Sstevel@tonic-gate (*entry)->avail_specs_list = list; 1847*0Sstevel@tonic-gate } 1848*0Sstevel@tonic-gate 1849*0Sstevel@tonic-gate /* 1850*0Sstevel@tonic-gate * map the unavail_device_name array into a list of device_spec_t 1851*0Sstevel@tonic-gate * and save the list as the entry's unavailable list 1852*0Sstevel@tonic-gate */ 1853*0Sstevel@tonic-gate list = NULL; 1854*0Sstevel@tonic-gate error = convert_usernames_to_specs( 1855*0Sstevel@tonic-gate unavail_device_specs, &list); 1856*0Sstevel@tonic-gate 1857*0Sstevel@tonic-gate if (error == 0) { 1858*0Sstevel@tonic-gate (*entry)->unavail_specs_list = list; 1859*0Sstevel@tonic-gate } 1860*0Sstevel@tonic-gate 1861*0Sstevel@tonic-gate if (error != 0) { 1862*0Sstevel@tonic-gate /* delete the partial entry */ 1863*0Sstevel@tonic-gate destroy_request_spec_list_entry((void *)*entry); 1864*0Sstevel@tonic-gate *entry = NULL; 1865*0Sstevel@tonic-gate } 1866*0Sstevel@tonic-gate 1867*0Sstevel@tonic-gate return (error); 1868*0Sstevel@tonic-gate } 1869*0Sstevel@tonic-gate 1870*0Sstevel@tonic-gate /* 1871*0Sstevel@tonic-gate * FUNCTION: convert_usernames_to_specs(char **specs, dlist_t **list) 1872*0Sstevel@tonic-gate * 1873*0Sstevel@tonic-gate * INPUT: specs - char * array of device CTD names 1874*0Sstevel@tonic-gate * 1875*0Sstevel@tonic-gate * OUTPUT: list - pointer to a list of device_spec_t corresponding 1876*0Sstevel@tonic-gate * to each name in the input array 1877*0Sstevel@tonic-gate * 1878*0Sstevel@tonic-gate * RETURNS: int - 0 on success 1879*0Sstevel@tonic-gate * !0 otherwise. 1880*0Sstevel@tonic-gate * 1881*0Sstevel@tonic-gate * PURPOSE: Function which converts the input CTD device names to the 1882*0Sstevel@tonic-gate * equivalent device_spec_t structs. 1883*0Sstevel@tonic-gate * 1884*0Sstevel@tonic-gate * Iterates the input array and converts each CTD name to a 1885*0Sstevel@tonic-gate * device_spec_t using get_spec_for_name(). 1886*0Sstevel@tonic-gate */ 1887*0Sstevel@tonic-gate static int 1888*0Sstevel@tonic-gate convert_usernames_to_specs( 1889*0Sstevel@tonic-gate char **specs, 1890*0Sstevel@tonic-gate dlist_t **list) 1891*0Sstevel@tonic-gate { 1892*0Sstevel@tonic-gate int i = 0; 1893*0Sstevel@tonic-gate int error = 0; 1894*0Sstevel@tonic-gate 1895*0Sstevel@tonic-gate /* 1896*0Sstevel@tonic-gate * For each spec in the array, get the corresponding 1897*0Sstevel@tonic-gate * device_spec_t and add it to the list. 1898*0Sstevel@tonic-gate * 1899*0Sstevel@tonic-gate * Any spec in the array that looks to be a DID name 1900*0Sstevel@tonic-gate * is first converted to its equivalent CTD name. 1901*0Sstevel@tonic-gate */ 1902*0Sstevel@tonic-gate for (i = 0; 1903*0Sstevel@tonic-gate (specs != NULL) && (specs[i] != NULL) && (error == 0); 1904*0Sstevel@tonic-gate i++) { 1905*0Sstevel@tonic-gate 1906*0Sstevel@tonic-gate device_spec_t *spec = NULL; 1907*0Sstevel@tonic-gate char *userspec = specs[i]; 1908*0Sstevel@tonic-gate 1909*0Sstevel@tonic-gate error = get_spec_for_name(userspec, &spec); 1910*0Sstevel@tonic-gate if ((error == 0) && (spec != NULL)) { 1911*0Sstevel@tonic-gate dlist_t *list_item = dlist_new_item((void *)spec); 1912*0Sstevel@tonic-gate if (spec == NULL) { 1913*0Sstevel@tonic-gate error = ENOMEM; 1914*0Sstevel@tonic-gate } else { 1915*0Sstevel@tonic-gate *list = dlist_insert_ordered 1916*0Sstevel@tonic-gate (list_item, *list, DESCENDING, 1917*0Sstevel@tonic-gate compare_device_spec_specificity); 1918*0Sstevel@tonic-gate } 1919*0Sstevel@tonic-gate } 1920*0Sstevel@tonic-gate } 1921*0Sstevel@tonic-gate 1922*0Sstevel@tonic-gate if (error != 0) { 1923*0Sstevel@tonic-gate /* the device_spec_t in the list items are maintained */ 1924*0Sstevel@tonic-gate /* in a cache elsewhere, so don't free them here. */ 1925*0Sstevel@tonic-gate dlist_free_items(*list, NULL); 1926*0Sstevel@tonic-gate *list = NULL; 1927*0Sstevel@tonic-gate } 1928*0Sstevel@tonic-gate 1929*0Sstevel@tonic-gate return (error); 1930*0Sstevel@tonic-gate } 1931*0Sstevel@tonic-gate 1932*0Sstevel@tonic-gate /* 1933*0Sstevel@tonic-gate * FUNCTION: destroy_request_spec_list_entry(void *entry) 1934*0Sstevel@tonic-gate * 1935*0Sstevel@tonic-gate * INPUT: entry - opaque pointer to a request_spec_list_t 1936*0Sstevel@tonic-gate * 1937*0Sstevel@tonic-gate * RETURNS: nothing 1938*0Sstevel@tonic-gate * 1939*0Sstevel@tonic-gate * PURPOSE: Function which reclaims memory allocated to a 1940*0Sstevel@tonic-gate * request_spec_list_t. 1941*0Sstevel@tonic-gate * 1942*0Sstevel@tonic-gate * Frees memory allocated to the avail_spec_list and 1943*0Sstevel@tonic-gate * unavail_spec_list. Entries in the list are not freed, 1944*0Sstevel@tonic-gate * since they are owned by the device_spec cache. 1945*0Sstevel@tonic-gate */ 1946*0Sstevel@tonic-gate static void 1947*0Sstevel@tonic-gate destroy_request_spec_list_entry( 1948*0Sstevel@tonic-gate void *obj) 1949*0Sstevel@tonic-gate { 1950*0Sstevel@tonic-gate request_spec_list_t *entry = (request_spec_list_t *)obj; 1951*0Sstevel@tonic-gate 1952*0Sstevel@tonic-gate if (entry != NULL) { 1953*0Sstevel@tonic-gate /* items in the list are in the spec_cache and will */ 1954*0Sstevel@tonic-gate /* be cleaned up when it is destroyed. */ 1955*0Sstevel@tonic-gate dlist_free_items(entry->avail_specs_list, NULL); 1956*0Sstevel@tonic-gate dlist_free_items(entry->unavail_specs_list, NULL); 1957*0Sstevel@tonic-gate free(entry); 1958*0Sstevel@tonic-gate } 1959*0Sstevel@tonic-gate } 1960*0Sstevel@tonic-gate 1961*0Sstevel@tonic-gate /* 1962*0Sstevel@tonic-gate * FUNCTION: destroy_request_spec_list_cache() 1963*0Sstevel@tonic-gate * 1964*0Sstevel@tonic-gate * RETURNS: int - 0 on success 1965*0Sstevel@tonic-gate * !0 otherwise. 1966*0Sstevel@tonic-gate * 1967*0Sstevel@tonic-gate * PURPOSE: Function which destroys all entries in the request_spec_list 1968*0Sstevel@tonic-gate * cache. 1969*0Sstevel@tonic-gate */ 1970*0Sstevel@tonic-gate static int 1971*0Sstevel@tonic-gate destroy_request_spec_list_cache() 1972*0Sstevel@tonic-gate { 1973*0Sstevel@tonic-gate dlist_free_items(_request_spec_list_cache, 1974*0Sstevel@tonic-gate destroy_request_spec_list_entry); 1975*0Sstevel@tonic-gate _request_spec_list_cache = NULL; 1976*0Sstevel@tonic-gate 1977*0Sstevel@tonic-gate return (0); 1978*0Sstevel@tonic-gate } 1979*0Sstevel@tonic-gate 1980*0Sstevel@tonic-gate /* 1981*0Sstevel@tonic-gate * FUNCTION: get_request_avail_spec_list(devconfig_t *request, 1982*0Sstevel@tonic-gate * dlist_t **list) 1983*0Sstevel@tonic-gate * 1984*0Sstevel@tonic-gate * INPUT: request - a pointer to a devconfig_t 1985*0Sstevel@tonic-gate * 1986*0Sstevel@tonic-gate * OUTPUT: list - pointer to a list of device_spec_t corresponding 1987*0Sstevel@tonic-gate * to the devices specified as available by the 1988*0Sstevel@tonic-gate * input request. 1989*0Sstevel@tonic-gate * 1990*0Sstevel@tonic-gate * RETURNS: int - 0 on success 1991*0Sstevel@tonic-gate * !0 otherwise. 1992*0Sstevel@tonic-gate * 1993*0Sstevel@tonic-gate * PURPOSE: Function which locates or builds the list of device_spec_t 1994*0Sstevel@tonic-gate * for the available devices specified in the input request. 1995*0Sstevel@tonic-gate * 1996*0Sstevel@tonic-gate * Looks up the input request in the request_spec_list cache. 1997*0Sstevel@tonic-gate * If there is currently no entry in the cache for the request, 1998*0Sstevel@tonic-gate * an entry is built and added. 1999*0Sstevel@tonic-gate * 2000*0Sstevel@tonic-gate * The entry's list of available device_spec_t is returned. 2001*0Sstevel@tonic-gate */ 2002*0Sstevel@tonic-gate static int 2003*0Sstevel@tonic-gate get_request_avail_spec_list( 2004*0Sstevel@tonic-gate devconfig_t *request, 2005*0Sstevel@tonic-gate dlist_t **list) 2006*0Sstevel@tonic-gate { 2007*0Sstevel@tonic-gate request_spec_list_t *entry = NULL; 2008*0Sstevel@tonic-gate int error = 0; 2009*0Sstevel@tonic-gate 2010*0Sstevel@tonic-gate if ((entry = find_request_spec_list_entry(request)) == NULL) { 2011*0Sstevel@tonic-gate 2012*0Sstevel@tonic-gate /* create cache entry for this request */ 2013*0Sstevel@tonic-gate error = make_request_spec_list_entry( 2014*0Sstevel@tonic-gate request, 2015*0Sstevel@tonic-gate devconfig_get_available(request), 2016*0Sstevel@tonic-gate devconfig_get_unavailable(request), 2017*0Sstevel@tonic-gate &entry); 2018*0Sstevel@tonic-gate 2019*0Sstevel@tonic-gate if ((error == 0) && (entry != NULL)) { 2020*0Sstevel@tonic-gate if ((error = add_request_spec_list_entry(entry)) != 0) { 2021*0Sstevel@tonic-gate destroy_request_spec_list_entry(entry); 2022*0Sstevel@tonic-gate entry = NULL; 2023*0Sstevel@tonic-gate } 2024*0Sstevel@tonic-gate } 2025*0Sstevel@tonic-gate } 2026*0Sstevel@tonic-gate 2027*0Sstevel@tonic-gate if ((error == 0) && (entry != NULL)) { 2028*0Sstevel@tonic-gate *list = entry->avail_specs_list; 2029*0Sstevel@tonic-gate } 2030*0Sstevel@tonic-gate 2031*0Sstevel@tonic-gate return (error); 2032*0Sstevel@tonic-gate } 2033*0Sstevel@tonic-gate 2034*0Sstevel@tonic-gate /* 2035*0Sstevel@tonic-gate * FUNCTION: get_request_unavail_spec_list(devconfig_t *request, 2036*0Sstevel@tonic-gate * dlist_t **list) 2037*0Sstevel@tonic-gate * 2038*0Sstevel@tonic-gate * INPUT: request - a pointer to a devconfig_t 2039*0Sstevel@tonic-gate * 2040*0Sstevel@tonic-gate * OUTPUT: list - pointer to a list of device_spec_t corresponding 2041*0Sstevel@tonic-gate * to the devices specified as unavailable by the 2042*0Sstevel@tonic-gate * input request. 2043*0Sstevel@tonic-gate * 2044*0Sstevel@tonic-gate * RETURNS: int - 0 on success 2045*0Sstevel@tonic-gate * !0 otherwise. 2046*0Sstevel@tonic-gate * 2047*0Sstevel@tonic-gate * PURPOSE: Function which locates or builds the list of device_spec_t 2048*0Sstevel@tonic-gate * for the unavailable devices specified in the input request. 2049*0Sstevel@tonic-gate * 2050*0Sstevel@tonic-gate * Looks up the input request in the request_spec_list cache. 2051*0Sstevel@tonic-gate * If there is currently no entry in the cache for the request, 2052*0Sstevel@tonic-gate * an entry is built and added. 2053*0Sstevel@tonic-gate * 2054*0Sstevel@tonic-gate * The entry's list of unavailable device_spec_t is returned. 2055*0Sstevel@tonic-gate */ 2056*0Sstevel@tonic-gate static int 2057*0Sstevel@tonic-gate get_request_unavail_spec_list( 2058*0Sstevel@tonic-gate devconfig_t *request, 2059*0Sstevel@tonic-gate dlist_t **list) 2060*0Sstevel@tonic-gate { 2061*0Sstevel@tonic-gate request_spec_list_t *entry = NULL; 2062*0Sstevel@tonic-gate int error = 0; 2063*0Sstevel@tonic-gate 2064*0Sstevel@tonic-gate if ((entry = find_request_spec_list_entry(request)) == NULL) { 2065*0Sstevel@tonic-gate 2066*0Sstevel@tonic-gate /* create new entry for this request */ 2067*0Sstevel@tonic-gate error = make_request_spec_list_entry( 2068*0Sstevel@tonic-gate request, 2069*0Sstevel@tonic-gate devconfig_get_available(request), 2070*0Sstevel@tonic-gate devconfig_get_unavailable(request), 2071*0Sstevel@tonic-gate &entry); 2072*0Sstevel@tonic-gate 2073*0Sstevel@tonic-gate if ((error == 0) && (entry != NULL)) { 2074*0Sstevel@tonic-gate if ((error = add_request_spec_list_entry(entry)) != 0) { 2075*0Sstevel@tonic-gate destroy_request_spec_list_entry(entry); 2076*0Sstevel@tonic-gate entry = NULL; 2077*0Sstevel@tonic-gate } 2078*0Sstevel@tonic-gate } 2079*0Sstevel@tonic-gate } 2080*0Sstevel@tonic-gate 2081*0Sstevel@tonic-gate if ((error == 0) && (entry != NULL)) { 2082*0Sstevel@tonic-gate *list = entry->unavail_specs_list; 2083*0Sstevel@tonic-gate } 2084*0Sstevel@tonic-gate 2085*0Sstevel@tonic-gate return (error); 2086*0Sstevel@tonic-gate } 2087*0Sstevel@tonic-gate 2088*0Sstevel@tonic-gate /* 2089*0Sstevel@tonic-gate * FUNCTION: get_default_avail_spec_list(defaults_t *defaults, 2090*0Sstevel@tonic-gate * char *dsname, dlist_t **list) 2091*0Sstevel@tonic-gate * 2092*0Sstevel@tonic-gate * INPUT: defaults - a pointer to a defaults_t struct 2093*0Sstevel@tonic-gate * dsname - the name of the diskset whose defaults should be used 2094*0Sstevel@tonic-gate * 2095*0Sstevel@tonic-gate * OUTPUT: list - pointer to a list of device_spec_t corresponding 2096*0Sstevel@tonic-gate * to the devices specified as available by the 2097*0Sstevel@tonic-gate * defaults for the named diskset, or the global 2098*0Sstevel@tonic-gate * defaults for all disksets. 2099*0Sstevel@tonic-gate * 2100*0Sstevel@tonic-gate * RETURNS: int - 0 on success 2101*0Sstevel@tonic-gate * !0 otherwise. 2102*0Sstevel@tonic-gate * 2103*0Sstevel@tonic-gate * PURPOSE: Function which locates or builds the list of device_spec_t 2104*0Sstevel@tonic-gate * for the available devices for the named diskset. 2105*0Sstevel@tonic-gate * 2106*0Sstevel@tonic-gate * Locates the defaults for the named diskset, if there are none, 2107*0Sstevel@tonic-gate * locates the global defaults for all disksets. 2108*0Sstevel@tonic-gate * 2109*0Sstevel@tonic-gate * The defaults devconfig_t struct is then used to look up the 2110*0Sstevel@tonic-gate * the corresponding entry in the request_spec_list cache. 2111*0Sstevel@tonic-gate * 2112*0Sstevel@tonic-gate * If there is currently no entry in the cache for the defaults, 2113*0Sstevel@tonic-gate * an entry is built and added. 2114*0Sstevel@tonic-gate * 2115*0Sstevel@tonic-gate * The entry's list of available device_spec_t is returned. 2116*0Sstevel@tonic-gate */ 2117*0Sstevel@tonic-gate static int 2118*0Sstevel@tonic-gate get_default_avail_spec_list( 2119*0Sstevel@tonic-gate defaults_t *alldefaults, 2120*0Sstevel@tonic-gate char *dsname, 2121*0Sstevel@tonic-gate dlist_t **list) 2122*0Sstevel@tonic-gate { 2123*0Sstevel@tonic-gate request_spec_list_t *entry = NULL; 2124*0Sstevel@tonic-gate devconfig_t *defaults = NULL; 2125*0Sstevel@tonic-gate int error = 0; 2126*0Sstevel@tonic-gate 2127*0Sstevel@tonic-gate /* Get diskset defaults, or global if none for diskset */ 2128*0Sstevel@tonic-gate error = defaults_get_diskset_by_name( 2129*0Sstevel@tonic-gate alldefaults, dsname, &defaults); 2130*0Sstevel@tonic-gate 2131*0Sstevel@tonic-gate if (error != 0) { 2132*0Sstevel@tonic-gate if (error == ENOENT) { 2133*0Sstevel@tonic-gate /* to get global defaults, pass a NULL diskset name */ 2134*0Sstevel@tonic-gate error = defaults_get_diskset_by_name( 2135*0Sstevel@tonic-gate alldefaults, NULL, &defaults); 2136*0Sstevel@tonic-gate } 2137*0Sstevel@tonic-gate 2138*0Sstevel@tonic-gate if (error != 0) { 2139*0Sstevel@tonic-gate if (error != ENOENT) { 2140*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 2141*0Sstevel@tonic-gate gettext("get defaults for %s returned %d\n"), 2142*0Sstevel@tonic-gate dsname, error); 2143*0Sstevel@tonic-gate } else { 2144*0Sstevel@tonic-gate error = 0; 2145*0Sstevel@tonic-gate } 2146*0Sstevel@tonic-gate } 2147*0Sstevel@tonic-gate } 2148*0Sstevel@tonic-gate 2149*0Sstevel@tonic-gate if ((entry = find_request_spec_list_entry(defaults)) == NULL) { 2150*0Sstevel@tonic-gate 2151*0Sstevel@tonic-gate /* create new entry for these defaults */ 2152*0Sstevel@tonic-gate error = make_request_spec_list_entry( 2153*0Sstevel@tonic-gate defaults, 2154*0Sstevel@tonic-gate devconfig_get_available(defaults), 2155*0Sstevel@tonic-gate devconfig_get_unavailable(defaults), 2156*0Sstevel@tonic-gate &entry); 2157*0Sstevel@tonic-gate 2158*0Sstevel@tonic-gate if ((error == 0) && (entry != NULL)) { 2159*0Sstevel@tonic-gate if ((error = add_request_spec_list_entry(entry)) != 0) { 2160*0Sstevel@tonic-gate destroy_request_spec_list_entry(entry); 2161*0Sstevel@tonic-gate entry = NULL; 2162*0Sstevel@tonic-gate } 2163*0Sstevel@tonic-gate } 2164*0Sstevel@tonic-gate } 2165*0Sstevel@tonic-gate 2166*0Sstevel@tonic-gate if ((error == 0) && (entry != NULL)) { 2167*0Sstevel@tonic-gate *list = entry->avail_specs_list; 2168*0Sstevel@tonic-gate } 2169*0Sstevel@tonic-gate 2170*0Sstevel@tonic-gate return (error); 2171*0Sstevel@tonic-gate } 2172*0Sstevel@tonic-gate 2173*0Sstevel@tonic-gate /* 2174*0Sstevel@tonic-gate * FUNCTION: get_default_unavail_spec_list(defaults_t *defaults, 2175*0Sstevel@tonic-gate * char *dsname, dlist_t **list) 2176*0Sstevel@tonic-gate * 2177*0Sstevel@tonic-gate * INPUT: defaults - a pointer to a defaults_t struct 2178*0Sstevel@tonic-gate * dsname - the name of the diskset whose defaults should be used 2179*0Sstevel@tonic-gate * 2180*0Sstevel@tonic-gate * OUTPUT: list - pointer to a list of device_spec_t corresponding 2181*0Sstevel@tonic-gate * to the devices specified as unavailable by the 2182*0Sstevel@tonic-gate * defaults for the named diskset, or the global 2183*0Sstevel@tonic-gate * defaults for all disksets. 2184*0Sstevel@tonic-gate * 2185*0Sstevel@tonic-gate * RETURNS: int - 0 on success 2186*0Sstevel@tonic-gate * !0 otherwise. 2187*0Sstevel@tonic-gate * 2188*0Sstevel@tonic-gate * PURPOSE: Function which locates or builds the list of device_spec_t 2189*0Sstevel@tonic-gate * for the unavailable devices for the named diskset. 2190*0Sstevel@tonic-gate * 2191*0Sstevel@tonic-gate * Locates the defaults for the named diskset, if there are none, 2192*0Sstevel@tonic-gate * locates the global defaults for all disksets. 2193*0Sstevel@tonic-gate * 2194*0Sstevel@tonic-gate * The defaults devconfig_t struct is then used to look up the 2195*0Sstevel@tonic-gate * the corresponding entry in the request_spec_list cache. 2196*0Sstevel@tonic-gate * 2197*0Sstevel@tonic-gate * If there is currently no entry in the cache for the defaults, 2198*0Sstevel@tonic-gate * an entry is built and added. 2199*0Sstevel@tonic-gate * 2200*0Sstevel@tonic-gate * The entry's list of unavailable device_spec_t is returned. 2201*0Sstevel@tonic-gate */ 2202*0Sstevel@tonic-gate static int 2203*0Sstevel@tonic-gate get_default_unavail_spec_list( 2204*0Sstevel@tonic-gate defaults_t *alldefaults, 2205*0Sstevel@tonic-gate char *dsname, 2206*0Sstevel@tonic-gate dlist_t **list) 2207*0Sstevel@tonic-gate { 2208*0Sstevel@tonic-gate request_spec_list_t *entry = NULL; 2209*0Sstevel@tonic-gate devconfig_t *defaults = NULL; 2210*0Sstevel@tonic-gate int error = 0; 2211*0Sstevel@tonic-gate 2212*0Sstevel@tonic-gate /* Get diskset defaults, or global if none for diskset */ 2213*0Sstevel@tonic-gate error = defaults_get_diskset_by_name( 2214*0Sstevel@tonic-gate alldefaults, dsname, &defaults); 2215*0Sstevel@tonic-gate 2216*0Sstevel@tonic-gate if (error != 0) { 2217*0Sstevel@tonic-gate 2218*0Sstevel@tonic-gate if (error == ENOENT) { 2219*0Sstevel@tonic-gate /* to get global defaults, pass a NULL diskset name */ 2220*0Sstevel@tonic-gate error = defaults_get_diskset_by_name( 2221*0Sstevel@tonic-gate alldefaults, NULL, &defaults); 2222*0Sstevel@tonic-gate } 2223*0Sstevel@tonic-gate 2224*0Sstevel@tonic-gate if (error != 0) { 2225*0Sstevel@tonic-gate if (error != ENOENT) { 2226*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 2227*0Sstevel@tonic-gate gettext("get defaults for %s returned %d\n"), 2228*0Sstevel@tonic-gate dsname, error); 2229*0Sstevel@tonic-gate } else { 2230*0Sstevel@tonic-gate error = 0; 2231*0Sstevel@tonic-gate } 2232*0Sstevel@tonic-gate } 2233*0Sstevel@tonic-gate } 2234*0Sstevel@tonic-gate 2235*0Sstevel@tonic-gate if ((entry = find_request_spec_list_entry(defaults)) == NULL) { 2236*0Sstevel@tonic-gate 2237*0Sstevel@tonic-gate /* create new entry for these defaults */ 2238*0Sstevel@tonic-gate error = make_request_spec_list_entry( 2239*0Sstevel@tonic-gate defaults, 2240*0Sstevel@tonic-gate devconfig_get_available(defaults), 2241*0Sstevel@tonic-gate devconfig_get_unavailable(defaults), 2242*0Sstevel@tonic-gate &entry); 2243*0Sstevel@tonic-gate 2244*0Sstevel@tonic-gate if ((error == 0) && (entry != NULL)) { 2245*0Sstevel@tonic-gate if ((error = add_request_spec_list_entry(entry)) != 0) { 2246*0Sstevel@tonic-gate destroy_request_spec_list_entry(entry); 2247*0Sstevel@tonic-gate entry = NULL; 2248*0Sstevel@tonic-gate } 2249*0Sstevel@tonic-gate } 2250*0Sstevel@tonic-gate } 2251*0Sstevel@tonic-gate 2252*0Sstevel@tonic-gate if ((error == 0) && (entry != NULL)) { 2253*0Sstevel@tonic-gate *list = entry->unavail_specs_list; 2254*0Sstevel@tonic-gate } 2255*0Sstevel@tonic-gate 2256*0Sstevel@tonic-gate return (error); 2257*0Sstevel@tonic-gate } 2258*0Sstevel@tonic-gate 2259*0Sstevel@tonic-gate /* 2260*0Sstevel@tonic-gate * FUNCTION: is_named_device_avail(devconfig_t *request, char *device_name, 2261*0Sstevel@tonic-gate * boolean_t check_aliases, boolean_t *avail) 2262*0Sstevel@tonic-gate * 2263*0Sstevel@tonic-gate * INPUT: request - the current request devconfig_t 2264*0Sstevel@tonic-gate * device_name - char * device name 2265*0Sstevel@tonic-gate * check_aliases - boolean_t which indicates whether the device's 2266*0Sstevel@tonic-gate * aliases should be considered by the availability checks. 2267*0Sstevel@tonic-gate * 2268*0Sstevel@tonic-gate * OUTPUT: avail - a boolean_t * to hold the result 2269*0Sstevel@tonic-gate * 2270*0Sstevel@tonic-gate * RETURNS: int - !0 on error 2271*0Sstevel@tonic-gate * 2272*0Sstevel@tonic-gate * avail is set to B_TRUE if the named device is available for 2273*0Sstevel@tonic-gate * the input request, B_FALSE otherwise. 2274*0Sstevel@tonic-gate * 2275*0Sstevel@tonic-gate * PURPOSE: Determine if the named device can be used to satisfy the 2276*0Sstevel@tonic-gate * input request. 2277*0Sstevel@tonic-gate * 2278*0Sstevel@tonic-gate * There are several levels at which device availabiity or 2279*0Sstevel@tonic-gate * unavailability may be specifed: 2280*0Sstevel@tonic-gate * 2281*0Sstevel@tonic-gate * 1. the volume subrequest, 2282*0Sstevel@tonic-gate * 2. the toplevel (diskset) request, 2283*0Sstevel@tonic-gate * 3. the diskset-specific defaults 2284*0Sstevel@tonic-gate * 4. the global defaults 2285*0Sstevel@tonic-gate * 2286*0Sstevel@tonic-gate * If the diskset-specific defaults exist, only they are checked. 2287*0Sstevel@tonic-gate * 2288*0Sstevel@tonic-gate * The precedence ordering that is enforced: 2289*0Sstevel@tonic-gate * 2290*0Sstevel@tonic-gate * 1. if request has an avail list, the name must be in it 2291*0Sstevel@tonic-gate * and not in the request's unavail list. 2292*0Sstevel@tonic-gate * 2. if request has an unavail list, the name must not be in it. 2293*0Sstevel@tonic-gate * 3. if toplevel request has an avail list, the name must be 2294*0Sstevel@tonic-gate * in it and not in the toplevel request's unavailable 2295*0Sstevel@tonic-gate * list. 2296*0Sstevel@tonic-gate * 4. if toplevel request has an unavail list, the name must 2297*0Sstevel@tonic-gate * not be in it. 2298*0Sstevel@tonic-gate * 5. if defaults have an avail list, the name must be in it 2299*0Sstevel@tonic-gate * and not in the defaults unavailable list. 2300*0Sstevel@tonic-gate * 6. if defaults have an unavail list, the name must not be 2301*0Sstevel@tonic-gate * in it. 2302*0Sstevel@tonic-gate */ 2303*0Sstevel@tonic-gate static int 2304*0Sstevel@tonic-gate is_named_device_avail( 2305*0Sstevel@tonic-gate devconfig_t *request, 2306*0Sstevel@tonic-gate char *device_name, 2307*0Sstevel@tonic-gate boolean_t check_aliases, 2308*0Sstevel@tonic-gate boolean_t *avail) 2309*0Sstevel@tonic-gate { 2310*0Sstevel@tonic-gate typedef enum check_types { 2311*0Sstevel@tonic-gate DEVICE_REQUEST = 0, 2312*0Sstevel@tonic-gate DISKSET_REQUEST, 2313*0Sstevel@tonic-gate DEFAULTS, 2314*0Sstevel@tonic-gate N_CHECKS 2315*0Sstevel@tonic-gate } check_type_t; 2316*0Sstevel@tonic-gate 2317*0Sstevel@tonic-gate check_type_t check_type; 2318*0Sstevel@tonic-gate 2319*0Sstevel@tonic-gate typedef enum list_types { 2320*0Sstevel@tonic-gate AVAIL = 0, 2321*0Sstevel@tonic-gate UNAVAIL, 2322*0Sstevel@tonic-gate N_LISTS 2323*0Sstevel@tonic-gate } list_type_t; 2324*0Sstevel@tonic-gate 2325*0Sstevel@tonic-gate dlist_t *lists[N_CHECKS][N_LISTS]; 2326*0Sstevel@tonic-gate boolean_t includes; 2327*0Sstevel@tonic-gate int error = 0; 2328*0Sstevel@tonic-gate 2329*0Sstevel@tonic-gate memset(lists, 0, (N_CHECKS * N_LISTS) * sizeof (dlist_t *)); 2330*0Sstevel@tonic-gate 2331*0Sstevel@tonic-gate if (request != NULL) { 2332*0Sstevel@tonic-gate /* get avail/unavail specs for request */ 2333*0Sstevel@tonic-gate ((error = get_request_avail_spec_list( 2334*0Sstevel@tonic-gate request, &lists[DEVICE_REQUEST][AVAIL])) != 0) || 2335*0Sstevel@tonic-gate (error = get_request_unavail_spec_list( 2336*0Sstevel@tonic-gate request, &lists[DEVICE_REQUEST][UNAVAIL])); 2337*0Sstevel@tonic-gate } 2338*0Sstevel@tonic-gate 2339*0Sstevel@tonic-gate if ((error == 0) && (_toplevel_request != NULL)) { 2340*0Sstevel@tonic-gate /* diskset request */ 2341*0Sstevel@tonic-gate ((error = get_request_avail_spec_list( 2342*0Sstevel@tonic-gate _toplevel_request, &lists[DISKSET_REQUEST][AVAIL])) != 0) || 2343*0Sstevel@tonic-gate (error = get_request_unavail_spec_list( 2344*0Sstevel@tonic-gate _toplevel_request, &lists[DISKSET_REQUEST][UNAVAIL])); 2345*0Sstevel@tonic-gate } 2346*0Sstevel@tonic-gate 2347*0Sstevel@tonic-gate if ((error == 0) && (_defaults != NULL)) { 2348*0Sstevel@tonic-gate /* and diskset/global defaults */ 2349*0Sstevel@tonic-gate ((error = get_default_avail_spec_list(_defaults, 2350*0Sstevel@tonic-gate get_request_diskset(), &lists[DEFAULTS][AVAIL])) != 0) || 2351*0Sstevel@tonic-gate (error = get_default_unavail_spec_list(_defaults, 2352*0Sstevel@tonic-gate get_request_diskset(), &lists[DEFAULTS][UNAVAIL])); 2353*0Sstevel@tonic-gate } 2354*0Sstevel@tonic-gate 2355*0Sstevel@tonic-gate if (error != 0) { 2356*0Sstevel@tonic-gate return (error); 2357*0Sstevel@tonic-gate } 2358*0Sstevel@tonic-gate 2359*0Sstevel@tonic-gate *avail = B_TRUE; 2360*0Sstevel@tonic-gate 2361*0Sstevel@tonic-gate for (check_type = DEVICE_REQUEST; 2362*0Sstevel@tonic-gate (check_type < N_CHECKS) && (error == 0); 2363*0Sstevel@tonic-gate check_type++) { 2364*0Sstevel@tonic-gate 2365*0Sstevel@tonic-gate if (lists[check_type][AVAIL] != NULL) { 2366*0Sstevel@tonic-gate 2367*0Sstevel@tonic-gate /* does avail spec list include named device? */ 2368*0Sstevel@tonic-gate if ((error = avail_list_includes_device_name( 2369*0Sstevel@tonic-gate lists[check_type][AVAIL], device_name, check_aliases, 2370*0Sstevel@tonic-gate &includes)) == 0) { 2371*0Sstevel@tonic-gate 2372*0Sstevel@tonic-gate if (includes != B_TRUE) { 2373*0Sstevel@tonic-gate *avail = B_FALSE; 2374*0Sstevel@tonic-gate } 2375*0Sstevel@tonic-gate 2376*0Sstevel@tonic-gate if ((includes == B_TRUE) && 2377*0Sstevel@tonic-gate (lists[check_type][UNAVAIL] != NULL)) { 2378*0Sstevel@tonic-gate 2379*0Sstevel@tonic-gate /* device is available, is it in the unavail list? */ 2380*0Sstevel@tonic-gate if ((error = unavail_list_includes_device_name( 2381*0Sstevel@tonic-gate lists[check_type][UNAVAIL], device_name, 2382*0Sstevel@tonic-gate check_aliases, &includes)) == 0) { 2383*0Sstevel@tonic-gate 2384*0Sstevel@tonic-gate if (includes == B_TRUE) { 2385*0Sstevel@tonic-gate *avail = B_FALSE; 2386*0Sstevel@tonic-gate } 2387*0Sstevel@tonic-gate } 2388*0Sstevel@tonic-gate } 2389*0Sstevel@tonic-gate } 2390*0Sstevel@tonic-gate 2391*0Sstevel@tonic-gate /* lists at this level checked, skip remainder */ 2392*0Sstevel@tonic-gate break; 2393*0Sstevel@tonic-gate 2394*0Sstevel@tonic-gate } else if (lists[check_type][UNAVAIL] != NULL) { 2395*0Sstevel@tonic-gate 2396*0Sstevel@tonic-gate /* does unavail spec list include named device? */ 2397*0Sstevel@tonic-gate if ((error = unavail_list_includes_device_name( 2398*0Sstevel@tonic-gate lists[check_type][UNAVAIL], device_name, 2399*0Sstevel@tonic-gate check_aliases, &includes)) == 0) { 2400*0Sstevel@tonic-gate 2401*0Sstevel@tonic-gate if (includes == B_TRUE) { 2402*0Sstevel@tonic-gate *avail = B_FALSE; 2403*0Sstevel@tonic-gate } 2404*0Sstevel@tonic-gate } 2405*0Sstevel@tonic-gate 2406*0Sstevel@tonic-gate /* list at this level checked, skip remainder */ 2407*0Sstevel@tonic-gate break; 2408*0Sstevel@tonic-gate } 2409*0Sstevel@tonic-gate } 2410*0Sstevel@tonic-gate 2411*0Sstevel@tonic-gate return (error); 2412*0Sstevel@tonic-gate } 2413*0Sstevel@tonic-gate 2414*0Sstevel@tonic-gate /* 2415*0Sstevel@tonic-gate * FUNCTION: avail_list_includes_device_name(dlist_t *list, 2416*0Sstevel@tonic-gate * char *device_name, boolean_t check_aliases, 2417*0Sstevel@tonic-gate * boolean_t *includes) 2418*0Sstevel@tonic-gate * 2419*0Sstevel@tonic-gate * INPUT: list - a dlist_t list of available device_spec_t 2420*0Sstevel@tonic-gate * device_name - a char * device CTD name 2421*0Sstevel@tonic-gate * check_aliases - boolean_t which indicates if the device's 2422*0Sstevel@tonic-gate * aliases should be considered in the availability 2423*0Sstevel@tonic-gate * checking. 2424*0Sstevel@tonic-gate * 2425*0Sstevel@tonic-gate * OUTPUT: includes - B_TRUE - if named device is "included" by any 2426*0Sstevel@tonic-gate * specification in the input list 2427*0Sstevel@tonic-gate * B_FALSE - otherwise 2428*0Sstevel@tonic-gate * 2429*0Sstevel@tonic-gate * RETURNS: int - 0 on success 2430*0Sstevel@tonic-gate * - !0 otherwise 2431*0Sstevel@tonic-gate * 2432*0Sstevel@tonic-gate * PURPOSE: Helper used by is_named_device_avail that determines 2433*0Sstevel@tonic-gate * if the input list of device specifications "includes" 2434*0Sstevel@tonic-gate * a specific device. 2435*0Sstevel@tonic-gate * 2436*0Sstevel@tonic-gate * Iterates the elements of the input array and searches 2437*0Sstevel@tonic-gate * for a match using spec_includes_device_name(). 2438*0Sstevel@tonic-gate */ 2439*0Sstevel@tonic-gate static int 2440*0Sstevel@tonic-gate avail_list_includes_device_name( 2441*0Sstevel@tonic-gate dlist_t *list, 2442*0Sstevel@tonic-gate char *device_name, 2443*0Sstevel@tonic-gate boolean_t check_aliases, 2444*0Sstevel@tonic-gate boolean_t *includes) 2445*0Sstevel@tonic-gate { 2446*0Sstevel@tonic-gate dlist_t *iter = NULL; 2447*0Sstevel@tonic-gate int error = 0; 2448*0Sstevel@tonic-gate 2449*0Sstevel@tonic-gate *includes = B_FALSE; 2450*0Sstevel@tonic-gate 2451*0Sstevel@tonic-gate for (iter = list; 2452*0Sstevel@tonic-gate (*includes == B_FALSE) && (iter != NULL) && (error == 0); 2453*0Sstevel@tonic-gate iter = iter->next) { 2454*0Sstevel@tonic-gate 2455*0Sstevel@tonic-gate device_spec_t *spec = (device_spec_t *)iter->obj; 2456*0Sstevel@tonic-gate error = spec_includes_device_name(spec, device_name, 2457*0Sstevel@tonic-gate check_aliases, includes); 2458*0Sstevel@tonic-gate } 2459*0Sstevel@tonic-gate 2460*0Sstevel@tonic-gate return (0); 2461*0Sstevel@tonic-gate } 2462*0Sstevel@tonic-gate 2463*0Sstevel@tonic-gate /* 2464*0Sstevel@tonic-gate * FUNCTION: unavail_list_includes_device_name(dlist_t *list, 2465*0Sstevel@tonic-gate * char *device_name, boolean_t check_aliases, 2466*0Sstevel@tonic-gate * boolean_t *includes) 2467*0Sstevel@tonic-gate * 2468*0Sstevel@tonic-gate * INPUT: list - a dlist_t list of unavailable device_spec_t 2469*0Sstevel@tonic-gate * device_name - a char * device CTD name 2470*0Sstevel@tonic-gate * check_aliases - boolean_t which indicates if the device's 2471*0Sstevel@tonic-gate * aliases should be considered in the availability 2472*0Sstevel@tonic-gate * checking. 2473*0Sstevel@tonic-gate * 2474*0Sstevel@tonic-gate * OUTPUT: includes - B_TRUE - if named device is "included" by any 2475*0Sstevel@tonic-gate * specification in the input list 2476*0Sstevel@tonic-gate * B_FALSE - otherwise 2477*0Sstevel@tonic-gate * 2478*0Sstevel@tonic-gate * RETURNS: int - 0 on success 2479*0Sstevel@tonic-gate * - !0 otherwise 2480*0Sstevel@tonic-gate * 2481*0Sstevel@tonic-gate * PURPOSE: Helper used by is_named_device_avail that determines 2482*0Sstevel@tonic-gate * if the input list of device specifications "includes" 2483*0Sstevel@tonic-gate * a specific device. 2484*0Sstevel@tonic-gate * 2485*0Sstevel@tonic-gate * Iterates the elements of the input array and searches 2486*0Sstevel@tonic-gate * for a match using spec_includes_device_name_or_alias(). 2487*0Sstevel@tonic-gate */ 2488*0Sstevel@tonic-gate static int 2489*0Sstevel@tonic-gate unavail_list_includes_device_name( 2490*0Sstevel@tonic-gate dlist_t *list, 2491*0Sstevel@tonic-gate char *device_name, 2492*0Sstevel@tonic-gate boolean_t check_aliases, 2493*0Sstevel@tonic-gate boolean_t *includes) 2494*0Sstevel@tonic-gate { 2495*0Sstevel@tonic-gate dlist_t *iter = NULL; 2496*0Sstevel@tonic-gate int error = 0; 2497*0Sstevel@tonic-gate device_spec_t *unavail_spec; 2498*0Sstevel@tonic-gate boolean_t check_for_alternate_hba = B_FALSE; 2499*0Sstevel@tonic-gate 2500*0Sstevel@tonic-gate *includes = B_FALSE; 2501*0Sstevel@tonic-gate 2502*0Sstevel@tonic-gate /* 2503*0Sstevel@tonic-gate * the specs in the list are in descending order of specificity. 2504*0Sstevel@tonic-gate * so a more exact spec will rule the device out before a less 2505*0Sstevel@tonic-gate * exact spec. 2506*0Sstevel@tonic-gate * 2507*0Sstevel@tonic-gate * Meaning: if the list has { "c3t0d0", ..., "c3", ... } and the 2508*0Sstevel@tonic-gate * input device name is "c3t0d0s0", it will match "c3t0d0" 2509*0Sstevel@tonic-gate * before "c3". 2510*0Sstevel@tonic-gate * 2511*0Sstevel@tonic-gate * This is important for the multi-path alias checking below. 2512*0Sstevel@tonic-gate * If the input device name is ruled out by a non-controller 2513*0Sstevel@tonic-gate * specification, it is really unavailable. 2514*0Sstevel@tonic-gate */ 2515*0Sstevel@tonic-gate for (iter = list; 2516*0Sstevel@tonic-gate (*includes == B_FALSE) && (iter != NULL); 2517*0Sstevel@tonic-gate iter = iter->next) { 2518*0Sstevel@tonic-gate 2519*0Sstevel@tonic-gate unavail_spec = (device_spec_t *)iter->obj; 2520*0Sstevel@tonic-gate error = spec_includes_device_name( 2521*0Sstevel@tonic-gate unavail_spec, device_name, check_aliases, includes); 2522*0Sstevel@tonic-gate 2523*0Sstevel@tonic-gate } 2524*0Sstevel@tonic-gate 2525*0Sstevel@tonic-gate if ((error == 0) && (*includes == B_TRUE)) { 2526*0Sstevel@tonic-gate 2527*0Sstevel@tonic-gate /* matched an unavailable spec, was it a controller/HBA? */ 2528*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 2529*0Sstevel@tonic-gate "device \"%s\" is unavailable, " 2530*0Sstevel@tonic-gate "it matched \"c(%d)t(%d)d(%d)s(%d)\"\n", 2531*0Sstevel@tonic-gate device_name, 2532*0Sstevel@tonic-gate unavail_spec->data.ctd->ctrl, 2533*0Sstevel@tonic-gate unavail_spec->data.ctd->target, 2534*0Sstevel@tonic-gate unavail_spec->data.ctd->lun, 2535*0Sstevel@tonic-gate unavail_spec->data.ctd->slice); 2536*0Sstevel@tonic-gate 2537*0Sstevel@tonic-gate if ((unavail_spec->data.ctd->ctrl != ID_UNSPECIFIED) && 2538*0Sstevel@tonic-gate (unavail_spec->data.ctd->target == ID_UNSPECIFIED) && 2539*0Sstevel@tonic-gate (unavail_spec->data.ctd->lun == ID_UNSPECIFIED) && 2540*0Sstevel@tonic-gate (unavail_spec->data.ctd->slice == ID_UNSPECIFIED)) { 2541*0Sstevel@tonic-gate 2542*0Sstevel@tonic-gate /* 2543*0Sstevel@tonic-gate * Need to see if the named device is a disk or slice, 2544*0Sstevel@tonic-gate * and if so check to see if the it is multipathed 2545*0Sstevel@tonic-gate * and possibly accessible thru another controller/HBA. 2546*0Sstevel@tonic-gate */ 2547*0Sstevel@tonic-gate check_for_alternate_hba = B_TRUE; 2548*0Sstevel@tonic-gate } 2549*0Sstevel@tonic-gate } 2550*0Sstevel@tonic-gate 2551*0Sstevel@tonic-gate if ((error == 0) && (check_for_alternate_hba == B_TRUE)) { 2552*0Sstevel@tonic-gate 2553*0Sstevel@tonic-gate dm_descriptor_t slice = (dm_descriptor_t)0; 2554*0Sstevel@tonic-gate dm_descriptor_t disk = (dm_descriptor_t)0; 2555*0Sstevel@tonic-gate 2556*0Sstevel@tonic-gate ((error = slice_get_by_name(device_name, &slice)) != 0) || 2557*0Sstevel@tonic-gate (error = disk_get_by_name(device_name, &disk)); 2558*0Sstevel@tonic-gate if (error != 0) { 2559*0Sstevel@tonic-gate return (error); 2560*0Sstevel@tonic-gate } 2561*0Sstevel@tonic-gate 2562*0Sstevel@tonic-gate /* if it is a slice, get its disk */ 2563*0Sstevel@tonic-gate if ((error == 0) && (slice != (dm_descriptor_t)0)) { 2564*0Sstevel@tonic-gate error = slice_get_disk(slice, &disk); 2565*0Sstevel@tonic-gate } 2566*0Sstevel@tonic-gate 2567*0Sstevel@tonic-gate if ((error == 0) && (disk != (dm_descriptor_t)0)) { 2568*0Sstevel@tonic-gate 2569*0Sstevel@tonic-gate /* see if all the disk's HBAs are unavailable */ 2570*0Sstevel@tonic-gate dlist_t *hbas = NULL; 2571*0Sstevel@tonic-gate dlist_t *iter = NULL; 2572*0Sstevel@tonic-gate 2573*0Sstevel@tonic-gate error = disk_get_hbas(disk, &hbas); 2574*0Sstevel@tonic-gate 2575*0Sstevel@tonic-gate if (hbas != NULL) { 2576*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 2577*0Sstevel@tonic-gate gettext(" checking alternate paths for %s\n"), 2578*0Sstevel@tonic-gate device_name); 2579*0Sstevel@tonic-gate } else { 2580*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 2581*0Sstevel@tonic-gate gettext(" no alternate paths for %s\n"), 2582*0Sstevel@tonic-gate device_name); 2583*0Sstevel@tonic-gate } 2584*0Sstevel@tonic-gate 2585*0Sstevel@tonic-gate /* for each of the disk's HBAs */ 2586*0Sstevel@tonic-gate for (iter = hbas; 2587*0Sstevel@tonic-gate (iter != NULL) && (*includes == B_TRUE) && (error == 0); 2588*0Sstevel@tonic-gate iter = iter->next) { 2589*0Sstevel@tonic-gate 2590*0Sstevel@tonic-gate dm_descriptor_t hba = (uintptr_t)iter->obj; 2591*0Sstevel@tonic-gate device_spec_t *hbaspec; 2592*0Sstevel@tonic-gate char *hbaname = NULL; 2593*0Sstevel@tonic-gate dlist_t *iter2 = NULL; 2594*0Sstevel@tonic-gate 2595*0Sstevel@tonic-gate *includes = B_FALSE; 2596*0Sstevel@tonic-gate 2597*0Sstevel@tonic-gate ((error = get_display_name(hba, &hbaname)) != 0) || 2598*0Sstevel@tonic-gate (error = get_spec_for_name(hbaname, &hbaspec)); 2599*0Sstevel@tonic-gate 2600*0Sstevel@tonic-gate /* is HBA unavailable? */ 2601*0Sstevel@tonic-gate for (iter2 = list; 2602*0Sstevel@tonic-gate (iter2 != NULL) && (error == 0) && 2603*0Sstevel@tonic-gate (*includes == B_FALSE); 2604*0Sstevel@tonic-gate iter2 = iter2->next) { 2605*0Sstevel@tonic-gate 2606*0Sstevel@tonic-gate device_spec_t *spec = 2607*0Sstevel@tonic-gate (device_spec_t *)iter2->obj; 2608*0Sstevel@tonic-gate 2609*0Sstevel@tonic-gate *includes = spec_includes_device(spec, hbaspec); 2610*0Sstevel@tonic-gate } 2611*0Sstevel@tonic-gate } 2612*0Sstevel@tonic-gate dlist_free_items(hbas, NULL); 2613*0Sstevel@tonic-gate 2614*0Sstevel@tonic-gate /* if *includes==B_TRUE here, all HBAs are unavailable */ 2615*0Sstevel@tonic-gate } 2616*0Sstevel@tonic-gate } 2617*0Sstevel@tonic-gate 2618*0Sstevel@tonic-gate return (error); 2619*0Sstevel@tonic-gate } 2620*0Sstevel@tonic-gate 2621*0Sstevel@tonic-gate /* 2622*0Sstevel@tonic-gate * FUNCTION: spec_includes_device_name(device_spec_t *spec, 2623*0Sstevel@tonic-gate * char *device_name, boolean_t check_aliases, 2624*0Sstevel@tonic-gate * boolean_t *includes) 2625*0Sstevel@tonic-gate * 2626*0Sstevel@tonic-gate * INPUT: spec - a device_spec_t CTD specification. 2627*0Sstevel@tonic-gate * device_name - a char * device CTD name 2628*0Sstevel@tonic-gate * check_aliases - boolean_t which indicates if the device's 2629*0Sstevel@tonic-gate * aliases should be considered in the checking. 2630*0Sstevel@tonic-gate * 2631*0Sstevel@tonic-gate * OUTPUT: includes - B_TRUE - if device is "included" by the input 2632*0Sstevel@tonic-gate * specification 2633*0Sstevel@tonic-gate * B_FALSE - otherwise 2634*0Sstevel@tonic-gate * 2635*0Sstevel@tonic-gate * RETURNS: int - 0 on success 2636*0Sstevel@tonic-gate * - !0 otherwise 2637*0Sstevel@tonic-gate * 2638*0Sstevel@tonic-gate * PURPOSE: Helper used by (un)avail_specs_includes_device_name() that 2639*0Sstevel@tonic-gate * determines if the input device specification "includes" 2640*0Sstevel@tonic-gate * the named device. 2641*0Sstevel@tonic-gate * 2642*0Sstevel@tonic-gate * If check_aliases is true and the named device is a slice or 2643*0Sstevel@tonic-gate * a disk drive, its multi-pathed aliases are also checked 2644*0Sstevel@tonic-gate * against the spec. 2645*0Sstevel@tonic-gate */ 2646*0Sstevel@tonic-gate static int 2647*0Sstevel@tonic-gate spec_includes_device_name( 2648*0Sstevel@tonic-gate device_spec_t *spec, 2649*0Sstevel@tonic-gate char *device_name, 2650*0Sstevel@tonic-gate boolean_t check_aliases, 2651*0Sstevel@tonic-gate boolean_t *includes) 2652*0Sstevel@tonic-gate { 2653*0Sstevel@tonic-gate device_spec_t *device_spec; 2654*0Sstevel@tonic-gate int error = 0; 2655*0Sstevel@tonic-gate 2656*0Sstevel@tonic-gate error = get_spec_for_name(device_name, &device_spec); 2657*0Sstevel@tonic-gate if (error == 0) { 2658*0Sstevel@tonic-gate 2659*0Sstevel@tonic-gate *includes = spec_includes_device(spec, device_spec); 2660*0Sstevel@tonic-gate 2661*0Sstevel@tonic-gate if ((*includes == B_FALSE) && (check_aliases == B_TRUE)) { 2662*0Sstevel@tonic-gate 2663*0Sstevel@tonic-gate /* spec doesn't include name, check aliases */ 2664*0Sstevel@tonic-gate 2665*0Sstevel@tonic-gate dm_descriptor_t device = (dm_descriptor_t)0; 2666*0Sstevel@tonic-gate dlist_t *aliases = NULL; 2667*0Sstevel@tonic-gate 2668*0Sstevel@tonic-gate /* only slices and disks have aliases */ 2669*0Sstevel@tonic-gate error = slice_get_by_name(device_name, &device); 2670*0Sstevel@tonic-gate if (device != (dm_descriptor_t)0) { 2671*0Sstevel@tonic-gate error = get_aliases(device, &aliases); 2672*0Sstevel@tonic-gate } else if (error == 0) { 2673*0Sstevel@tonic-gate error = disk_get_by_name(device_name, &device); 2674*0Sstevel@tonic-gate if (device != (dm_descriptor_t)0) { 2675*0Sstevel@tonic-gate error = get_aliases(device, &aliases); 2676*0Sstevel@tonic-gate } 2677*0Sstevel@tonic-gate } 2678*0Sstevel@tonic-gate 2679*0Sstevel@tonic-gate if ((error == 0) && (aliases != NULL)) { 2680*0Sstevel@tonic-gate 2681*0Sstevel@tonic-gate dlist_t *iter; 2682*0Sstevel@tonic-gate for (iter = aliases; 2683*0Sstevel@tonic-gate (iter != NULL) && (*includes == B_FALSE) && 2684*0Sstevel@tonic-gate (error == 0); 2685*0Sstevel@tonic-gate iter = iter->next) { 2686*0Sstevel@tonic-gate 2687*0Sstevel@tonic-gate char *alias = (char *)iter->obj; 2688*0Sstevel@tonic-gate device_spec_t *alias_spec; 2689*0Sstevel@tonic-gate 2690*0Sstevel@tonic-gate error = get_spec_for_name(alias, &alias_spec); 2691*0Sstevel@tonic-gate if (error == 0) { 2692*0Sstevel@tonic-gate /* does spec include alias? */ 2693*0Sstevel@tonic-gate *includes = spec_includes_device(spec, alias_spec); 2694*0Sstevel@tonic-gate } 2695*0Sstevel@tonic-gate } 2696*0Sstevel@tonic-gate } 2697*0Sstevel@tonic-gate dlist_free_items(aliases, free); 2698*0Sstevel@tonic-gate } 2699*0Sstevel@tonic-gate } 2700*0Sstevel@tonic-gate 2701*0Sstevel@tonic-gate return (error); 2702*0Sstevel@tonic-gate } 2703*0Sstevel@tonic-gate 2704*0Sstevel@tonic-gate /* 2705*0Sstevel@tonic-gate * FUNCTION: destroy_device_spec(device_spec_t *spec) 2706*0Sstevel@tonic-gate * 2707*0Sstevel@tonic-gate * INPUT: spec - pointer to a device_spec_t 2708*0Sstevel@tonic-gate * 2709*0Sstevel@tonic-gate * RETURNS: nothing 2710*0Sstevel@tonic-gate * 2711*0Sstevel@tonic-gate * PURPOSE: Function which reclaims memory allocated to a device_spec_t. 2712*0Sstevel@tonic-gate * 2713*0Sstevel@tonic-gate * Frees memory allocated to hold the specific data in the spec. 2714*0Sstevel@tonic-gate */ 2715*0Sstevel@tonic-gate static void 2716*0Sstevel@tonic-gate destroy_device_spec( 2717*0Sstevel@tonic-gate device_spec_t *spec) 2718*0Sstevel@tonic-gate { 2719*0Sstevel@tonic-gate if (spec != NULL) { 2720*0Sstevel@tonic-gate if (spec->type == SPEC_TYPE_CTD) { 2721*0Sstevel@tonic-gate free(spec->data.ctd); 2722*0Sstevel@tonic-gate } else if (spec->type == SPEC_TYPE_RAW) { 2723*0Sstevel@tonic-gate free(spec->data.raw); 2724*0Sstevel@tonic-gate } 2725*0Sstevel@tonic-gate free(spec); 2726*0Sstevel@tonic-gate } 2727*0Sstevel@tonic-gate } 2728*0Sstevel@tonic-gate 2729*0Sstevel@tonic-gate /* 2730*0Sstevel@tonic-gate * FUNCTION: create_device_spec(char *name, device_spec_t **spec); 2731*0Sstevel@tonic-gate * 2732*0Sstevel@tonic-gate * INPUT: name - pointer to a char* device name 2733*0Sstevel@tonic-gate * 2734*0Sstevel@tonic-gate * OUTPUT: spec - pointer to a device_spec_t to hold the result 2735*0Sstevel@tonic-gate * 2736*0Sstevel@tonic-gate * RETURNS: int - 0 on success 2737*0Sstevel@tonic-gate * !0 otherwise 2738*0Sstevel@tonic-gate * 2739*0Sstevel@tonic-gate * PURPOSE: Function which creates a device_spec_t for the input 2740*0Sstevel@tonic-gate * device name. 2741*0Sstevel@tonic-gate * 2742*0Sstevel@tonic-gate */ 2743*0Sstevel@tonic-gate static int 2744*0Sstevel@tonic-gate create_device_spec( 2745*0Sstevel@tonic-gate char *name, 2746*0Sstevel@tonic-gate device_spec_t **spec) 2747*0Sstevel@tonic-gate { 2748*0Sstevel@tonic-gate int error = 0; 2749*0Sstevel@tonic-gate 2750*0Sstevel@tonic-gate /* allocate the device spec and try various parsing schemes */ 2751*0Sstevel@tonic-gate *spec = (device_spec_t *)calloc(1, sizeof (device_spec_t)); 2752*0Sstevel@tonic-gate if (*spec == NULL) { 2753*0Sstevel@tonic-gate error = ENOMEM; 2754*0Sstevel@tonic-gate } else { 2755*0Sstevel@tonic-gate if (((error = create_device_ctd_spec(name, spec)) != 0) && 2756*0Sstevel@tonic-gate (error != ENOMEM)) { 2757*0Sstevel@tonic-gate /* CTD failed, try other parsing schemes */ 2758*0Sstevel@tonic-gate error = create_device_raw_spec(name, spec); 2759*0Sstevel@tonic-gate } 2760*0Sstevel@tonic-gate } 2761*0Sstevel@tonic-gate 2762*0Sstevel@tonic-gate return (error); 2763*0Sstevel@tonic-gate } 2764*0Sstevel@tonic-gate 2765*0Sstevel@tonic-gate /* 2766*0Sstevel@tonic-gate * FUNCTION: create_device_ctd_spec(char *name, device_spec_t **spec); 2767*0Sstevel@tonic-gate * 2768*0Sstevel@tonic-gate * INPUT: name - pointer to a char* device name 2769*0Sstevel@tonic-gate * 2770*0Sstevel@tonic-gate * OUTPUT: spec - pointer to a device_spec_t updated with the parsed 2771*0Sstevel@tonic-gate * CTD spec, if successful 2772*0Sstevel@tonic-gate * 2773*0Sstevel@tonic-gate * RETURNS: int - 0 on success 2774*0Sstevel@tonic-gate * !0 otherwise 2775*0Sstevel@tonic-gate * 2776*0Sstevel@tonic-gate * PURPOSE: Function which atttempts to parse the input device name into 2777*0Sstevel@tonic-gate * cXtXdXsX component ids. The ids are the integer values of each 2778*0Sstevel@tonic-gate * specified segment of the input name. 2779*0Sstevel@tonic-gate * 2780*0Sstevel@tonic-gate * If the name doesn't contain a segment, the id is set to 2781*0Sstevel@tonic-gate * ID_UNSPECIFIED. 2782*0Sstevel@tonic-gate * 2783*0Sstevel@tonic-gate * The input name must be well-formed. 2784*0Sstevel@tonic-gate * 2785*0Sstevel@tonic-gate * These are the acceptable forms: 2786*0Sstevel@tonic-gate * 2787*0Sstevel@tonic-gate * cXtXdXsX 2788*0Sstevel@tonic-gate * cXtXdX 2789*0Sstevel@tonic-gate * cXtX 2790*0Sstevel@tonic-gate * cXdXsX 2791*0Sstevel@tonic-gate * cXdX 2792*0Sstevel@tonic-gate * cX 2793*0Sstevel@tonic-gate */ 2794*0Sstevel@tonic-gate static int 2795*0Sstevel@tonic-gate create_device_ctd_spec( 2796*0Sstevel@tonic-gate char *name, 2797*0Sstevel@tonic-gate device_spec_t **spec) 2798*0Sstevel@tonic-gate { 2799*0Sstevel@tonic-gate uint_t ctrl; 2800*0Sstevel@tonic-gate uint_t target; 2801*0Sstevel@tonic-gate uint_t lun; 2802*0Sstevel@tonic-gate uint_t slice; 2803*0Sstevel@tonic-gate 2804*0Sstevel@tonic-gate uint_t nscan; 2805*0Sstevel@tonic-gate uint_t nchars; 2806*0Sstevel@tonic-gate 2807*0Sstevel@tonic-gate char *device_str; 2808*0Sstevel@tonic-gate char *target_str; 2809*0Sstevel@tonic-gate char *ctd_str; 2810*0Sstevel@tonic-gate char *t_ptr; 2811*0Sstevel@tonic-gate char *d_ptr; 2812*0Sstevel@tonic-gate char *s_ptr; 2813*0Sstevel@tonic-gate 2814*0Sstevel@tonic-gate boolean_t is_ide = B_FALSE; 2815*0Sstevel@tonic-gate boolean_t got_slice = B_FALSE; 2816*0Sstevel@tonic-gate boolean_t got_lun = B_FALSE; 2817*0Sstevel@tonic-gate boolean_t got_target = B_FALSE; 2818*0Sstevel@tonic-gate boolean_t got_ctrl = B_FALSE; 2819*0Sstevel@tonic-gate 2820*0Sstevel@tonic-gate int error = 0; 2821*0Sstevel@tonic-gate 2822*0Sstevel@tonic-gate ctd_str = strdup(name); 2823*0Sstevel@tonic-gate if (ctd_str == NULL) { 2824*0Sstevel@tonic-gate return (ENOMEM); 2825*0Sstevel@tonic-gate } 2826*0Sstevel@tonic-gate 2827*0Sstevel@tonic-gate /* trim any leading path (/dev/dsk/cXtXdXsX) */ 2828*0Sstevel@tonic-gate if ((device_str = strrchr(ctd_str, '/')) != NULL) { 2829*0Sstevel@tonic-gate ++device_str; 2830*0Sstevel@tonic-gate } else { 2831*0Sstevel@tonic-gate device_str = ctd_str; 2832*0Sstevel@tonic-gate } 2833*0Sstevel@tonic-gate 2834*0Sstevel@tonic-gate /* find each segment start position */ 2835*0Sstevel@tonic-gate t_ptr = strrchr(device_str, 't'); 2836*0Sstevel@tonic-gate d_ptr = strrchr(device_str, 'd'); 2837*0Sstevel@tonic-gate s_ptr = strrchr(device_str, 's'); 2838*0Sstevel@tonic-gate 2839*0Sstevel@tonic-gate /* 2840*0Sstevel@tonic-gate * scan ids from each existing segment working backwards 2841*0Sstevel@tonic-gate * so as to leave the device_str in the correct state 2842*0Sstevel@tonic-gate * for the next expected segment 2843*0Sstevel@tonic-gate */ 2844*0Sstevel@tonic-gate if (s_ptr != NULL) { 2845*0Sstevel@tonic-gate 2846*0Sstevel@tonic-gate /* found 's', try to get slice */ 2847*0Sstevel@tonic-gate nchars = strlen(s_ptr); 2848*0Sstevel@tonic-gate if ((sscanf(s_ptr, "s%u%n", &slice, &nscan) != 1) || 2849*0Sstevel@tonic-gate (nscan != nchars)) { 2850*0Sstevel@tonic-gate 2851*0Sstevel@tonic-gate error = -1; 2852*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 2853*0Sstevel@tonic-gate gettext("no slice component in device " 2854*0Sstevel@tonic-gate "name \"%s\".\n"), 2855*0Sstevel@tonic-gate name); 2856*0Sstevel@tonic-gate 2857*0Sstevel@tonic-gate } else { 2858*0Sstevel@tonic-gate got_slice = B_TRUE; 2859*0Sstevel@tonic-gate *s_ptr = '\0'; 2860*0Sstevel@tonic-gate } 2861*0Sstevel@tonic-gate } 2862*0Sstevel@tonic-gate 2863*0Sstevel@tonic-gate if ((error == 0) && (d_ptr != NULL)) { 2864*0Sstevel@tonic-gate 2865*0Sstevel@tonic-gate /* found 'd', try to get disk/lun */ 2866*0Sstevel@tonic-gate nchars = strlen(d_ptr); 2867*0Sstevel@tonic-gate if ((sscanf(d_ptr, "d%u%n", &lun, &nscan) != 1) || 2868*0Sstevel@tonic-gate (nscan != nchars)) { 2869*0Sstevel@tonic-gate 2870*0Sstevel@tonic-gate error = -1; 2871*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 2872*0Sstevel@tonic-gate gettext("no disk/lun component " 2873*0Sstevel@tonic-gate "in device name \"%s\".\n"), 2874*0Sstevel@tonic-gate name); 2875*0Sstevel@tonic-gate 2876*0Sstevel@tonic-gate } else { 2877*0Sstevel@tonic-gate got_lun = B_TRUE; 2878*0Sstevel@tonic-gate *d_ptr = '\0'; 2879*0Sstevel@tonic-gate } 2880*0Sstevel@tonic-gate } 2881*0Sstevel@tonic-gate 2882*0Sstevel@tonic-gate if ((error == 0) && (t_ptr != NULL)) { 2883*0Sstevel@tonic-gate 2884*0Sstevel@tonic-gate /* found 't', try to get target, it may be a hex WWN id */ 2885*0Sstevel@tonic-gate 2886*0Sstevel@tonic-gate /* skip leading 't' and add two for the 'OX' */ 2887*0Sstevel@tonic-gate nchars = strlen(t_ptr + 1) + 2; 2888*0Sstevel@tonic-gate if ((target_str = (char *)malloc(nchars+1)) == NULL) { 2889*0Sstevel@tonic-gate 2890*0Sstevel@tonic-gate error = ENOMEM; 2891*0Sstevel@tonic-gate 2892*0Sstevel@tonic-gate } else { 2893*0Sstevel@tonic-gate 2894*0Sstevel@tonic-gate strcpy(target_str, "0X"); 2895*0Sstevel@tonic-gate strcpy(target_str+2, t_ptr + 1); 2896*0Sstevel@tonic-gate target_str[nchars] = '\0'; 2897*0Sstevel@tonic-gate 2898*0Sstevel@tonic-gate if ((sscanf(target_str, "%x%n", &target, &nscan) != 1) || 2899*0Sstevel@tonic-gate (nscan != nchars)) { 2900*0Sstevel@tonic-gate 2901*0Sstevel@tonic-gate error = -1; 2902*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 2903*0Sstevel@tonic-gate gettext("no target/WWN component " 2904*0Sstevel@tonic-gate "in device name \"%s\".\n"), 2905*0Sstevel@tonic-gate name); 2906*0Sstevel@tonic-gate 2907*0Sstevel@tonic-gate } else { 2908*0Sstevel@tonic-gate got_target = B_TRUE; 2909*0Sstevel@tonic-gate *t_ptr = '\0'; 2910*0Sstevel@tonic-gate } 2911*0Sstevel@tonic-gate 2912*0Sstevel@tonic-gate free(target_str); 2913*0Sstevel@tonic-gate } 2914*0Sstevel@tonic-gate 2915*0Sstevel@tonic-gate } else { 2916*0Sstevel@tonic-gate is_ide = B_TRUE; 2917*0Sstevel@tonic-gate } 2918*0Sstevel@tonic-gate 2919*0Sstevel@tonic-gate if ((error == 0) && (device_str != NULL)) { 2920*0Sstevel@tonic-gate 2921*0Sstevel@tonic-gate /* get controller/hba/channel */ 2922*0Sstevel@tonic-gate nchars = strlen(device_str); 2923*0Sstevel@tonic-gate if ((sscanf(device_str, "c%u%n", &ctrl, &nscan) != 1) || 2924*0Sstevel@tonic-gate (nscan != nchars)) { 2925*0Sstevel@tonic-gate 2926*0Sstevel@tonic-gate error = -1; 2927*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 2928*0Sstevel@tonic-gate gettext("no channel/HBA component " 2929*0Sstevel@tonic-gate "in device name \"%s\".\n"), 2930*0Sstevel@tonic-gate name); 2931*0Sstevel@tonic-gate 2932*0Sstevel@tonic-gate } else { 2933*0Sstevel@tonic-gate got_ctrl = B_TRUE; 2934*0Sstevel@tonic-gate } 2935*0Sstevel@tonic-gate } 2936*0Sstevel@tonic-gate 2937*0Sstevel@tonic-gate free(ctd_str); 2938*0Sstevel@tonic-gate 2939*0Sstevel@tonic-gate if (error == 0) { 2940*0Sstevel@tonic-gate 2941*0Sstevel@tonic-gate /* allocate the ctd_spec_t struct and store the ids */ 2942*0Sstevel@tonic-gate (*spec)->type = SPEC_TYPE_CTD; 2943*0Sstevel@tonic-gate (*spec)->data.ctd = (ctd_spec_t *)calloc(1, sizeof (ctd_spec_t)); 2944*0Sstevel@tonic-gate 2945*0Sstevel@tonic-gate if ((*spec)->data.ctd == NULL) { 2946*0Sstevel@tonic-gate error = ENOMEM; 2947*0Sstevel@tonic-gate } 2948*0Sstevel@tonic-gate 2949*0Sstevel@tonic-gate (*spec)->data.ctd->slice = ID_UNSPECIFIED; 2950*0Sstevel@tonic-gate (*spec)->data.ctd->lun = ID_UNSPECIFIED; 2951*0Sstevel@tonic-gate (*spec)->data.ctd->target = ID_UNSPECIFIED; 2952*0Sstevel@tonic-gate (*spec)->data.ctd->ctrl = ID_UNSPECIFIED; 2953*0Sstevel@tonic-gate 2954*0Sstevel@tonic-gate if (got_slice == B_TRUE) { 2955*0Sstevel@tonic-gate (*spec)->data.ctd->slice = slice; 2956*0Sstevel@tonic-gate } 2957*0Sstevel@tonic-gate 2958*0Sstevel@tonic-gate if (got_lun == B_TRUE) { 2959*0Sstevel@tonic-gate (*spec)->data.ctd->lun = lun; 2960*0Sstevel@tonic-gate } 2961*0Sstevel@tonic-gate 2962*0Sstevel@tonic-gate if (got_target == B_TRUE) { 2963*0Sstevel@tonic-gate (*spec)->data.ctd->target = target; 2964*0Sstevel@tonic-gate } 2965*0Sstevel@tonic-gate 2966*0Sstevel@tonic-gate if (got_ctrl == B_TRUE) { 2967*0Sstevel@tonic-gate (*spec)->data.ctd->ctrl = ctrl; 2968*0Sstevel@tonic-gate } 2969*0Sstevel@tonic-gate 2970*0Sstevel@tonic-gate (*spec)->data.ctd->is_ide = is_ide; 2971*0Sstevel@tonic-gate } 2972*0Sstevel@tonic-gate 2973*0Sstevel@tonic-gate return (error); 2974*0Sstevel@tonic-gate } 2975*0Sstevel@tonic-gate 2976*0Sstevel@tonic-gate /* 2977*0Sstevel@tonic-gate * FUNCTION: create_device_raw_spec(char *name, device_spec_t **spec); 2978*0Sstevel@tonic-gate * 2979*0Sstevel@tonic-gate * INPUT: name - pointer to a char* device name 2980*0Sstevel@tonic-gate * 2981*0Sstevel@tonic-gate * OUTPUT: spec - pointer to a device_spec_t updated with the raw spec 2982*0Sstevel@tonic-gate * 2983*0Sstevel@tonic-gate * RETURNS: int - 0 on success 2984*0Sstevel@tonic-gate * !0 otherwise 2985*0Sstevel@tonic-gate * 2986*0Sstevel@tonic-gate * PURPOSE: Function which creates a "raw" spec for the input name. 2987*0Sstevel@tonic-gate * 2988*0Sstevel@tonic-gate * This is a last resort if all other spec parsing schemes failed, 2989*0Sstevel@tonic-gate * the "raw" spec is just the input device name. 2990*0Sstevel@tonic-gate */ 2991*0Sstevel@tonic-gate static int 2992*0Sstevel@tonic-gate create_device_raw_spec( 2993*0Sstevel@tonic-gate char *name, 2994*0Sstevel@tonic-gate device_spec_t **spec) 2995*0Sstevel@tonic-gate { 2996*0Sstevel@tonic-gate int error = 0; 2997*0Sstevel@tonic-gate char *ctd_str = strdup(name); 2998*0Sstevel@tonic-gate 2999*0Sstevel@tonic-gate if (ctd_str == NULL) { 3000*0Sstevel@tonic-gate return (ENOMEM); 3001*0Sstevel@tonic-gate } 3002*0Sstevel@tonic-gate 3003*0Sstevel@tonic-gate (*spec)->type = SPEC_TYPE_RAW; 3004*0Sstevel@tonic-gate (*spec)->data.raw = ctd_str; 3005*0Sstevel@tonic-gate 3006*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 3007*0Sstevel@tonic-gate gettext("made raw device spec for \"%s\"\n"), ctd_str); 3008*0Sstevel@tonic-gate 3009*0Sstevel@tonic-gate return (error); 3010*0Sstevel@tonic-gate } 3011*0Sstevel@tonic-gate 3012*0Sstevel@tonic-gate /* 3013*0Sstevel@tonic-gate * FUNCTION: get_spec_for_name(char *name, device_spec_t **id); 3014*0Sstevel@tonic-gate * 3015*0Sstevel@tonic-gate * INPUT: name - pointer to a char* device name 3016*0Sstevel@tonic-gate * 3017*0Sstevel@tonic-gate * OUTPUT: id - pointer to a device_spec_t to hold the result 3018*0Sstevel@tonic-gate * 3019*0Sstevel@tonic-gate * RETURNS: int - 0 on success 3020*0Sstevel@tonic-gate * !0 otherwise 3021*0Sstevel@tonic-gate * 3022*0Sstevel@tonic-gate * PURPOSE: Function which finds the device_spec_t that already 3023*0Sstevel@tonic-gate * exists for the input name or creates it. 3024*0Sstevel@tonic-gate * 3025*0Sstevel@tonic-gate * The returned struct should not be freed, it is maintained 3026*0Sstevel@tonic-gate * in a cache that will be purged when the layout process 3027*0Sstevel@tonic-gate * is complete. 3028*0Sstevel@tonic-gate */ 3029*0Sstevel@tonic-gate int 3030*0Sstevel@tonic-gate get_spec_for_name( 3031*0Sstevel@tonic-gate char *name, 3032*0Sstevel@tonic-gate device_spec_t **id) 3033*0Sstevel@tonic-gate { 3034*0Sstevel@tonic-gate dlist_t *item; 3035*0Sstevel@tonic-gate int error = 0; 3036*0Sstevel@tonic-gate 3037*0Sstevel@tonic-gate item = dlist_find(_spec_cache, (void *)name, 3038*0Sstevel@tonic-gate compare_name_to_spec_cache_name); 3039*0Sstevel@tonic-gate 3040*0Sstevel@tonic-gate if (item == NULL) { 3041*0Sstevel@tonic-gate if ((error = create_device_spec(name, id)) == 0) { 3042*0Sstevel@tonic-gate 3043*0Sstevel@tonic-gate spec_cache_t *entry = (spec_cache_t *) 3044*0Sstevel@tonic-gate calloc(1, sizeof (spec_cache_t)); 3045*0Sstevel@tonic-gate 3046*0Sstevel@tonic-gate if (entry == NULL) { 3047*0Sstevel@tonic-gate destroy_device_spec(*id); 3048*0Sstevel@tonic-gate error = ENOMEM; 3049*0Sstevel@tonic-gate } else { 3050*0Sstevel@tonic-gate char *dup = strdup(name); 3051*0Sstevel@tonic-gate if (dup == NULL) { 3052*0Sstevel@tonic-gate free(entry); 3053*0Sstevel@tonic-gate destroy_device_spec(*id); 3054*0Sstevel@tonic-gate *id = NULL; 3055*0Sstevel@tonic-gate error = ENOMEM; 3056*0Sstevel@tonic-gate } else { 3057*0Sstevel@tonic-gate entry->name = dup; 3058*0Sstevel@tonic-gate entry->device_spec = *id; 3059*0Sstevel@tonic-gate } 3060*0Sstevel@tonic-gate 3061*0Sstevel@tonic-gate if (error == 0) { 3062*0Sstevel@tonic-gate dlist_t *item = dlist_new_item((void *)entry); 3063*0Sstevel@tonic-gate if (item == NULL) { 3064*0Sstevel@tonic-gate free(entry); 3065*0Sstevel@tonic-gate destroy_device_spec(*id); 3066*0Sstevel@tonic-gate *id = NULL; 3067*0Sstevel@tonic-gate error = ENOMEM; 3068*0Sstevel@tonic-gate } else { 3069*0Sstevel@tonic-gate _spec_cache = 3070*0Sstevel@tonic-gate dlist_append(item, _spec_cache, AT_HEAD); 3071*0Sstevel@tonic-gate } 3072*0Sstevel@tonic-gate } 3073*0Sstevel@tonic-gate } 3074*0Sstevel@tonic-gate } 3075*0Sstevel@tonic-gate } else { 3076*0Sstevel@tonic-gate *id = ((spec_cache_t *)item->obj)->device_spec; 3077*0Sstevel@tonic-gate } 3078*0Sstevel@tonic-gate 3079*0Sstevel@tonic-gate return (error); 3080*0Sstevel@tonic-gate } 3081*0Sstevel@tonic-gate 3082*0Sstevel@tonic-gate /* 3083*0Sstevel@tonic-gate * FUNCTION: spec_includes_device(device_spec_t *spec, 3084*0Sstevel@tonic-gate * device_spec_t *device) 3085*0Sstevel@tonic-gate * 3086*0Sstevel@tonic-gate * INPUT: spec - pointer to a device_spec struct 3087*0Sstevel@tonic-gate * device - pointer to a device_spec struct 3088*0Sstevel@tonic-gate * 3089*0Sstevel@tonic-gate * RETURNS: boolean_t - B_TRUE if the device is included in the spec 3090*0Sstevel@tonic-gate * B_FALSE otherwise 3091*0Sstevel@tonic-gate * 3092*0Sstevel@tonic-gate * PURPOSE: Function which determines if the input device matches the 3093*0Sstevel@tonic-gate * input spec. 3094*0Sstevel@tonic-gate * 3095*0Sstevel@tonic-gate * If both specs are of the same type, the appropriate 3096*0Sstevel@tonic-gate * comparison function is called. 3097*0Sstevel@tonic-gate * 3098*0Sstevel@tonic-gate * If the two specs are of different types, no comparison 3099*0Sstevel@tonic-gate * is done and B_FALSE is returned. 3100*0Sstevel@tonic-gate */ 3101*0Sstevel@tonic-gate boolean_t 3102*0Sstevel@tonic-gate spec_includes_device( 3103*0Sstevel@tonic-gate device_spec_t *spec, 3104*0Sstevel@tonic-gate device_spec_t *device) 3105*0Sstevel@tonic-gate { 3106*0Sstevel@tonic-gate if ((spec->type == SPEC_TYPE_CTD) && (device->type == SPEC_TYPE_CTD)) { 3107*0Sstevel@tonic-gate return (ctd_spec_includes_device(spec, device)); 3108*0Sstevel@tonic-gate } else if ((spec->type == SPEC_TYPE_RAW) && 3109*0Sstevel@tonic-gate (device->type == SPEC_TYPE_RAW)) { 3110*0Sstevel@tonic-gate return (raw_spec_includes_device(spec, device)); 3111*0Sstevel@tonic-gate } 3112*0Sstevel@tonic-gate 3113*0Sstevel@tonic-gate return (B_FALSE); 3114*0Sstevel@tonic-gate } 3115*0Sstevel@tonic-gate 3116*0Sstevel@tonic-gate /* 3117*0Sstevel@tonic-gate * FUNCTION: ctd_spec_includes_device(device_spec_t *spec, 3118*0Sstevel@tonic-gate * device_spec_t *device) 3119*0Sstevel@tonic-gate * 3120*0Sstevel@tonic-gate * INPUT: spec - pointer to a device_spec struct 3121*0Sstevel@tonic-gate * device - pointer to a device_spec struct 3122*0Sstevel@tonic-gate * 3123*0Sstevel@tonic-gate * RETURNS: boolean_t - B_TRUE if the device is included in the spec 3124*0Sstevel@tonic-gate * B_FALSE otherwise 3125*0Sstevel@tonic-gate * 3126*0Sstevel@tonic-gate * PURPOSE: Function which determines if the input CTD device spec 3127*0Sstevel@tonic-gate * matches the input CTD spec. 3128*0Sstevel@tonic-gate * 3129*0Sstevel@tonic-gate * The device_spec_t structs contain component "ids" for 3130*0Sstevel@tonic-gate * both the specification and the device. 3131*0Sstevel@tonic-gate * 3132*0Sstevel@tonic-gate * The device must match each of the ids in the spec that 3133*0Sstevel@tonic-gate * are specified. 3134*0Sstevel@tonic-gate * 3135*0Sstevel@tonic-gate * spec devices matched 3136*0Sstevel@tonic-gate * -------------------------------------------------------- 3137*0Sstevel@tonic-gate * cX cX, cXtX, cXtXdX, cXtXdXsX, cXdX, cXdXsX 3138*0Sstevel@tonic-gate * cXtX cXtX, cXtXdX, cXtXdXsX 3139*0Sstevel@tonic-gate * cXtXdX cXtXdX, cXtXdXsX 3140*0Sstevel@tonic-gate * cXtXdXsX cXtXdXsX 3141*0Sstevel@tonic-gate * cXdX cXdX, cXdXsX 3142*0Sstevel@tonic-gate * cXdXsX cXdXsX 3143*0Sstevel@tonic-gate */ 3144*0Sstevel@tonic-gate static boolean_t 3145*0Sstevel@tonic-gate ctd_spec_includes_device( 3146*0Sstevel@tonic-gate device_spec_t *spec, 3147*0Sstevel@tonic-gate device_spec_t *device) 3148*0Sstevel@tonic-gate { 3149*0Sstevel@tonic-gate boolean_t match = B_FALSE; 3150*0Sstevel@tonic-gate 3151*0Sstevel@tonic-gate if (spec->data.ctd->is_ide) { 3152*0Sstevel@tonic-gate 3153*0Sstevel@tonic-gate /* valid IDE names are cX, cXdX, cXdXsX, no target */ 3154*0Sstevel@tonic-gate 3155*0Sstevel@tonic-gate if ((spec->data.ctd->ctrl != ID_UNSPECIFIED) && 3156*0Sstevel@tonic-gate (spec->data.ctd->lun != ID_UNSPECIFIED) && 3157*0Sstevel@tonic-gate (spec->data.ctd->slice != ID_UNSPECIFIED)) { 3158*0Sstevel@tonic-gate 3159*0Sstevel@tonic-gate match = (spec->data.ctd->ctrl == device->data.ctd->ctrl) && 3160*0Sstevel@tonic-gate (spec->data.ctd->lun == device->data.ctd->lun) && 3161*0Sstevel@tonic-gate (spec->data.ctd->slice == device->data.ctd->slice); 3162*0Sstevel@tonic-gate 3163*0Sstevel@tonic-gate } else if ((spec->data.ctd->ctrl != ID_UNSPECIFIED) && 3164*0Sstevel@tonic-gate (spec->data.ctd->lun != ID_UNSPECIFIED)) { 3165*0Sstevel@tonic-gate 3166*0Sstevel@tonic-gate match = (spec->data.ctd->ctrl == device->data.ctd->ctrl) && 3167*0Sstevel@tonic-gate (spec->data.ctd->lun == device->data.ctd->lun); 3168*0Sstevel@tonic-gate 3169*0Sstevel@tonic-gate } else if (spec->data.ctd->ctrl != ID_UNSPECIFIED) { 3170*0Sstevel@tonic-gate 3171*0Sstevel@tonic-gate match = (spec->data.ctd->ctrl == device->data.ctd->ctrl); 3172*0Sstevel@tonic-gate 3173*0Sstevel@tonic-gate } 3174*0Sstevel@tonic-gate 3175*0Sstevel@tonic-gate } else { 3176*0Sstevel@tonic-gate 3177*0Sstevel@tonic-gate /* valid names are cX, cXtX, cXtXdX, cXtXdXsX */ 3178*0Sstevel@tonic-gate 3179*0Sstevel@tonic-gate if ((spec->data.ctd->ctrl != ID_UNSPECIFIED) && 3180*0Sstevel@tonic-gate (spec->data.ctd->target != ID_UNSPECIFIED) && 3181*0Sstevel@tonic-gate (spec->data.ctd->lun != ID_UNSPECIFIED) && 3182*0Sstevel@tonic-gate (spec->data.ctd->slice != ID_UNSPECIFIED)) { 3183*0Sstevel@tonic-gate 3184*0Sstevel@tonic-gate match = (spec->data.ctd->ctrl == device->data.ctd->ctrl) && 3185*0Sstevel@tonic-gate (spec->data.ctd->target == device->data.ctd->target) && 3186*0Sstevel@tonic-gate (spec->data.ctd->lun == device->data.ctd->lun) && 3187*0Sstevel@tonic-gate (spec->data.ctd->slice == device->data.ctd->slice); 3188*0Sstevel@tonic-gate 3189*0Sstevel@tonic-gate } else if ((spec->data.ctd->ctrl != ID_UNSPECIFIED) && 3190*0Sstevel@tonic-gate (spec->data.ctd->target != ID_UNSPECIFIED) && 3191*0Sstevel@tonic-gate (spec->data.ctd->lun != ID_UNSPECIFIED)) { 3192*0Sstevel@tonic-gate 3193*0Sstevel@tonic-gate match = (spec->data.ctd->ctrl == device->data.ctd->ctrl) && 3194*0Sstevel@tonic-gate (spec->data.ctd->target == device->data.ctd->target) && 3195*0Sstevel@tonic-gate (spec->data.ctd->lun == device->data.ctd->lun); 3196*0Sstevel@tonic-gate 3197*0Sstevel@tonic-gate } else if ((spec->data.ctd->ctrl != ID_UNSPECIFIED) && 3198*0Sstevel@tonic-gate (spec->data.ctd->target != ID_UNSPECIFIED)) { 3199*0Sstevel@tonic-gate 3200*0Sstevel@tonic-gate match = (spec->data.ctd->ctrl == device->data.ctd->ctrl) && 3201*0Sstevel@tonic-gate (spec->data.ctd->target == device->data.ctd->target); 3202*0Sstevel@tonic-gate 3203*0Sstevel@tonic-gate } else if (spec->data.ctd->ctrl != ID_UNSPECIFIED) { 3204*0Sstevel@tonic-gate 3205*0Sstevel@tonic-gate match = (spec->data.ctd->ctrl == device->data.ctd->ctrl); 3206*0Sstevel@tonic-gate 3207*0Sstevel@tonic-gate } 3208*0Sstevel@tonic-gate } 3209*0Sstevel@tonic-gate 3210*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 3211*0Sstevel@tonic-gate gettext("spec: c(%d) t(%d) d(%d) s(%d) " 3212*0Sstevel@tonic-gate "%s: c(%d) t(%d) d(%d) s(%d)\n"), 3213*0Sstevel@tonic-gate spec->data.ctd->ctrl, spec->data.ctd->target, 3214*0Sstevel@tonic-gate spec->data.ctd->lun, spec->data.ctd->slice, 3215*0Sstevel@tonic-gate (match ? gettext("includes") : gettext("does not include")), 3216*0Sstevel@tonic-gate device->data.ctd->ctrl, device->data.ctd->target, 3217*0Sstevel@tonic-gate device->data.ctd->lun, device->data.ctd->slice); 3218*0Sstevel@tonic-gate 3219*0Sstevel@tonic-gate return (match); 3220*0Sstevel@tonic-gate } 3221*0Sstevel@tonic-gate 3222*0Sstevel@tonic-gate /* 3223*0Sstevel@tonic-gate * FUNCTION: raw_spec_includes_device(device_spec_t *spec, 3224*0Sstevel@tonic-gate * device_spec_t *device) 3225*0Sstevel@tonic-gate * 3226*0Sstevel@tonic-gate * INPUT: spec - pointer to a device_spec struct 3227*0Sstevel@tonic-gate * device - pointer to a device_spec struct 3228*0Sstevel@tonic-gate * 3229*0Sstevel@tonic-gate * RETURNS: boolean_t - B_TRUE if the device is included in the spec 3230*0Sstevel@tonic-gate * B_FALSE otherwise 3231*0Sstevel@tonic-gate * 3232*0Sstevel@tonic-gate * PURPOSE: Function which determines if the input raw device spec 3233*0Sstevel@tonic-gate * matches the input spec. 3234*0Sstevel@tonic-gate * 3235*0Sstevel@tonic-gate * The device_spec_t raw elements are checked. 3236*0Sstevel@tonic-gate * 3237*0Sstevel@tonic-gate * If the spec's raw device name is exactly contained at the 3238*0Sstevel@tonic-gate * beginning of the device spec's raw name, then the function 3239*0Sstevel@tonic-gate * evaluates to true. 3240*0Sstevel@tonic-gate */ 3241*0Sstevel@tonic-gate static boolean_t 3242*0Sstevel@tonic-gate raw_spec_includes_device( 3243*0Sstevel@tonic-gate device_spec_t *spec, 3244*0Sstevel@tonic-gate device_spec_t *device) 3245*0Sstevel@tonic-gate { 3246*0Sstevel@tonic-gate return (strncasecmp(spec->data.raw, 3247*0Sstevel@tonic-gate device->data.raw, strlen(spec->data.raw)) == 0); 3248*0Sstevel@tonic-gate } 3249*0Sstevel@tonic-gate 3250*0Sstevel@tonic-gate /* 3251*0Sstevel@tonic-gate * FUNCTION: compare_name_to_spec_cache_name(void *name, void *list_item) 3252*0Sstevel@tonic-gate * 3253*0Sstevel@tonic-gate * INPUT: name - opaque pointer to a char * device name 3254*0Sstevel@tonic-gate * list_item - opaque pointer to a spec_cache_t entry 3255*0Sstevel@tonic-gate * 3256*0Sstevel@tonic-gate * RETURNS: int - 0 - if request is the same as list_item->request 3257*0Sstevel@tonic-gate * !0 - otherwise 3258*0Sstevel@tonic-gate * 3259*0Sstevel@tonic-gate * PURPOSE: dlist_t helper which compares the input device name 3260*0Sstevel@tonic-gate * to the list_item's device name for equality. 3261*0Sstevel@tonic-gate * 3262*0Sstevel@tonic-gate * This function is the lookup mechanism for the device_spec 3263*0Sstevel@tonic-gate * associated with the name. 3264*0Sstevel@tonic-gate */ 3265*0Sstevel@tonic-gate static int 3266*0Sstevel@tonic-gate compare_name_to_spec_cache_name( 3267*0Sstevel@tonic-gate void *name, 3268*0Sstevel@tonic-gate void *list_item) 3269*0Sstevel@tonic-gate { 3270*0Sstevel@tonic-gate spec_cache_t *entry = (spec_cache_t *)list_item; 3271*0Sstevel@tonic-gate 3272*0Sstevel@tonic-gate assert(name != NULL); 3273*0Sstevel@tonic-gate assert(entry != NULL); 3274*0Sstevel@tonic-gate 3275*0Sstevel@tonic-gate return (string_case_compare((char *)name, entry->name)); 3276*0Sstevel@tonic-gate } 3277*0Sstevel@tonic-gate 3278*0Sstevel@tonic-gate /* 3279*0Sstevel@tonic-gate * FUNCTION: destroy_spec_cache_entry(void *entry) 3280*0Sstevel@tonic-gate * 3281*0Sstevel@tonic-gate * INPUT: entry - opaque pointer to a spec_cache_t 3282*0Sstevel@tonic-gate * 3283*0Sstevel@tonic-gate * RETURNS: nothing 3284*0Sstevel@tonic-gate * 3285*0Sstevel@tonic-gate * PURPOSE: Function which reclaims memory allocated to a 3286*0Sstevel@tonic-gate * spec_cache_t entry. 3287*0Sstevel@tonic-gate * 3288*0Sstevel@tonic-gate * Frees memory allocated to hold the CTD name and the 3289*0Sstevel@tonic-gate * corresponding device_spec_t. 3290*0Sstevel@tonic-gate */ 3291*0Sstevel@tonic-gate static void 3292*0Sstevel@tonic-gate destroy_spec_cache_entry( 3293*0Sstevel@tonic-gate void *obj) 3294*0Sstevel@tonic-gate { 3295*0Sstevel@tonic-gate spec_cache_t *entry = (spec_cache_t *)obj; 3296*0Sstevel@tonic-gate 3297*0Sstevel@tonic-gate if (entry != NULL) { 3298*0Sstevel@tonic-gate free(entry->name); 3299*0Sstevel@tonic-gate destroy_device_spec(entry->device_spec); 3300*0Sstevel@tonic-gate free(entry); 3301*0Sstevel@tonic-gate } 3302*0Sstevel@tonic-gate } 3303*0Sstevel@tonic-gate 3304*0Sstevel@tonic-gate /* 3305*0Sstevel@tonic-gate * FUNCTION: destroy_spec_cache() 3306*0Sstevel@tonic-gate * 3307*0Sstevel@tonic-gate * RETURNS: int - 0 on success 3308*0Sstevel@tonic-gate * !0 otherwise. 3309*0Sstevel@tonic-gate * 3310*0Sstevel@tonic-gate * PURPOSE: Function which destroys all entries in the device_spec 3311*0Sstevel@tonic-gate * cache. 3312*0Sstevel@tonic-gate */ 3313*0Sstevel@tonic-gate static int 3314*0Sstevel@tonic-gate destroy_spec_cache() 3315*0Sstevel@tonic-gate { 3316*0Sstevel@tonic-gate dlist_free_items(_spec_cache, destroy_spec_cache_entry); 3317*0Sstevel@tonic-gate _spec_cache = NULL; 3318*0Sstevel@tonic-gate 3319*0Sstevel@tonic-gate return (0); 3320*0Sstevel@tonic-gate } 3321*0Sstevel@tonic-gate 3322*0Sstevel@tonic-gate /* 3323*0Sstevel@tonic-gate * FUNCTION: get_device_access_name(devconfig_t *request, 3324*0Sstevel@tonic-gate * dm_descriptor_t desc, char **name) 3325*0Sstevel@tonic-gate * 3326*0Sstevel@tonic-gate * INPUT: request - a devconfig_t request 3327*0Sstevel@tonic-gate * desc - a dm_descriptor_t device handle 3328*0Sstevel@tonic-gate * 3329*0Sstevel@tonic-gate * OUTPUT: name - a char * pointer to hold the preferred name 3330*0Sstevel@tonic-gate * 3331*0Sstevel@tonic-gate * RETURNS: int - 0 - if request is the same as list_item->request 3332*0Sstevel@tonic-gate * !0 - otherwise 3333*0Sstevel@tonic-gate * 3334*0Sstevel@tonic-gate * PURPOSE: Utility function to determine which of the possible device 3335*0Sstevel@tonic-gate * names should be used to access a known available device. 3336*0Sstevel@tonic-gate * 3337*0Sstevel@tonic-gate * Devices handled are slices and disks. 3338*0Sstevel@tonic-gate * 3339*0Sstevel@tonic-gate * If the input device is a multipathed disk or slice, it 3340*0Sstevel@tonic-gate * can have several possible names. Determine which of the 3341*0Sstevel@tonic-gate * names should be used based on the input request's available 3342*0Sstevel@tonic-gate * or unavailable device specifications. 3343*0Sstevel@tonic-gate * 3344*0Sstevel@tonic-gate */ 3345*0Sstevel@tonic-gate int 3346*0Sstevel@tonic-gate get_device_access_name( 3347*0Sstevel@tonic-gate devconfig_t *request, 3348*0Sstevel@tonic-gate dm_descriptor_t desc, 3349*0Sstevel@tonic-gate char **name) 3350*0Sstevel@tonic-gate { 3351*0Sstevel@tonic-gate int error = 0; 3352*0Sstevel@tonic-gate boolean_t avail = B_FALSE; 3353*0Sstevel@tonic-gate dlist_t *aliases = NULL; 3354*0Sstevel@tonic-gate 3355*0Sstevel@tonic-gate assert(desc != (dm_descriptor_t)0); 3356*0Sstevel@tonic-gate 3357*0Sstevel@tonic-gate *name = NULL; 3358*0Sstevel@tonic-gate 3359*0Sstevel@tonic-gate if ((error = get_display_name(desc, name)) != 0) { 3360*0Sstevel@tonic-gate return (error); 3361*0Sstevel@tonic-gate } 3362*0Sstevel@tonic-gate 3363*0Sstevel@tonic-gate if (is_did_name(*name) == B_TRUE) { 3364*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 3365*0Sstevel@tonic-gate gettext("device DID name %s is preferred\n"), 3366*0Sstevel@tonic-gate *name); 3367*0Sstevel@tonic-gate return (0); 3368*0Sstevel@tonic-gate } 3369*0Sstevel@tonic-gate 3370*0Sstevel@tonic-gate error = is_named_device_avail(request, *name, B_FALSE, &avail); 3371*0Sstevel@tonic-gate if (error != 0) { 3372*0Sstevel@tonic-gate return (error); 3373*0Sstevel@tonic-gate } 3374*0Sstevel@tonic-gate 3375*0Sstevel@tonic-gate if (avail == B_TRUE) { 3376*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 3377*0Sstevel@tonic-gate gettext("device name %s is accessible\n"), 3378*0Sstevel@tonic-gate *name); 3379*0Sstevel@tonic-gate return (0); 3380*0Sstevel@tonic-gate } 3381*0Sstevel@tonic-gate 3382*0Sstevel@tonic-gate /* search aliases for an 'available' name, prefer DID names */ 3383*0Sstevel@tonic-gate if ((error = get_aliases(desc, &aliases)) == 0) { 3384*0Sstevel@tonic-gate 3385*0Sstevel@tonic-gate dlist_t *iter = aliases; 3386*0Sstevel@tonic-gate char *availname = NULL; 3387*0Sstevel@tonic-gate char *didname = NULL; 3388*0Sstevel@tonic-gate 3389*0Sstevel@tonic-gate for (; (iter != NULL) && (error == 0); iter = iter->next) { 3390*0Sstevel@tonic-gate 3391*0Sstevel@tonic-gate char *alias = (char *)iter->obj; 3392*0Sstevel@tonic-gate error = is_named_device_avail(request, alias, B_FALSE, &avail); 3393*0Sstevel@tonic-gate 3394*0Sstevel@tonic-gate if ((error == 0) && (avail == B_TRUE)) { 3395*0Sstevel@tonic-gate oprintf(OUTPUT_DEBUG, 3396*0Sstevel@tonic-gate gettext("device alias %s is accessible for %s\n"), 3397*0Sstevel@tonic-gate alias, *name); 3398*0Sstevel@tonic-gate 3399*0Sstevel@tonic-gate availname = alias; 3400*0Sstevel@tonic-gate 3401*0Sstevel@tonic-gate if (is_did_name(availname) == B_TRUE) { 3402*0Sstevel@tonic-gate didname = alias; 3403*0Sstevel@tonic-gate break; 3404*0Sstevel@tonic-gate } 3405*0Sstevel@tonic-gate } 3406*0Sstevel@tonic-gate } 3407*0Sstevel@tonic-gate 3408*0Sstevel@tonic-gate if (error == 0) { 3409*0Sstevel@tonic-gate if (didname != NULL) { 3410*0Sstevel@tonic-gate *name = didname; 3411*0Sstevel@tonic-gate } else if (availname != NULL) { 3412*0Sstevel@tonic-gate *name = availname; 3413*0Sstevel@tonic-gate } 3414*0Sstevel@tonic-gate } 3415*0Sstevel@tonic-gate } 3416*0Sstevel@tonic-gate 3417*0Sstevel@tonic-gate return (error); 3418*0Sstevel@tonic-gate } 3419