1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * initialize metadevices 31 */ 32 33 #include <meta.h> 34 #include <sys/lvm/mdio.h> 35 #include <libdevinfo.h> 36 37 38 int 39 parse_interlace( 40 char *uname, /* Meta Device name (eg d0) */ 41 char *str, /* String to Parse */ 42 diskaddr_t *interlacep, 43 md_error_t *ep 44 ) 45 { 46 diskaddr_t num; 47 char c; 48 int cnt; 49 50 /* parse interlace */ 51 if ((cnt = sscanf(str, "%llu%c", &num, &c)) < 1) { 52 return (meta_cook_syntax(ep, MDE_BAD_INTERLACE, 53 uname, 1, &str)); 54 } else if (cnt == 1) { 55 if (num & (DEV_BSIZE - 1)) { 56 return (meta_cook_syntax(ep, MDE_BAD_INTERLACE, 57 uname, 1, &str)); 58 } 59 num = lbtodb(num); 60 } else switch (c) { 61 case 'b': 62 case 'B': 63 num *= DEV_BSIZE / DEV_BSIZE; 64 break; 65 case 'k': 66 case 'K': 67 num *= 1024 / DEV_BSIZE; 68 break; 69 case 'm': 70 case 'M': 71 num *= 1024 * 1024 / DEV_BSIZE; 72 break; 73 default: 74 return (meta_cook_syntax(ep, MDE_BAD_INTERLACE, 75 NULL, 1, &str)); 76 } 77 78 /* return success */ 79 *interlacep = num; 80 return (0); 81 } 82 83 /* 84 * cook up syntax error 85 */ 86 int 87 meta_cook_syntax( 88 md_error_t *ep, 89 md_void_errno_t errcode, 90 char *uname, 91 int argc, 92 char *argv[] 93 ) 94 { 95 int rval; 96 97 /* if we have a token, concat it to uname */ 98 if ((argc > 0) && (argv[0] != NULL) && (argv[0][0] != '\0')) { 99 char *p; 100 101 if ((uname != NULL) && (uname[0] != '\0')) { 102 p = Malloc(strlen(uname) + 2 103 + 1 + strlen(argv[0]) + 1 + 1); 104 (void) strcpy(p, uname); 105 (void) strcat(p, ": "); 106 } else { 107 p = Malloc(1 + strlen(argv[0]) + 1 + 1); 108 p[0] = '\0'; 109 } 110 (void) strcat(p, "\""); 111 (void) strcat(p, argv[0]); 112 (void) strcat(p, "\""); 113 rval = mderror(ep, errcode, p); 114 Free(p); 115 } else { 116 rval = mderror(ep, errcode, uname); 117 } 118 119 return (rval); 120 } 121 122 int 123 meta_check_devicesize( 124 diskaddr_t total_blocks 125 ) 126 { 127 int rval = MD_CRO_32BIT; 128 129 130 if (total_blocks > MD_MAX_BLKS_FOR_SMALL_DEVS) { 131 rval = MD_CRO_64BIT; 132 } 133 return (rval); 134 } 135 136 137 /* 138 * setup metadevice geometry 139 */ 140 /*ARGSUSED*/ 141 int 142 meta_setup_geom( 143 md_unit_t *md, 144 mdname_t *np, 145 mdgeom_t *geomp, 146 uint_t write_reinstruct, 147 uint_t read_reinstruct, 148 uint_t round_cyl, 149 md_error_t *ep 150 ) 151 { 152 diskaddr_t cylsize = geomp->nhead * geomp->nsect; 153 diskaddr_t total_blocks; 154 155 if (round_cyl) { 156 total_blocks = rounddown(md->c.un_actual_tb, cylsize); 157 } else { 158 total_blocks = md->c.un_actual_tb; 159 } 160 161 md->c.un_total_blocks = total_blocks; 162 md->c.un_nhead = geomp->nhead; 163 md->c.un_nsect = geomp->nsect; 164 md->c.un_rpm = geomp->rpm; 165 md->c.un_wr_reinstruct = write_reinstruct; 166 md->c.un_rd_reinstruct = read_reinstruct; 167 return (0); 168 } 169 170 /* 171 * adjust metadevice geometry 172 */ 173 /*ARGSUSED*/ 174 int 175 meta_adjust_geom( 176 md_unit_t *md, 177 mdname_t *np, 178 uint_t write_reinstruct, 179 uint_t read_reinstruct, 180 uint_t round_cyl, 181 md_error_t *ep 182 ) 183 { 184 diskaddr_t cylsize = md->c.un_nhead * md->c.un_nsect; 185 diskaddr_t total_blocks; 186 187 if (round_cyl) { 188 total_blocks = rounddown(md->c.un_actual_tb, cylsize); 189 } else { 190 total_blocks = md->c.un_actual_tb; 191 } 192 193 md->c.un_total_blocks = total_blocks; 194 if (write_reinstruct > md->c.un_wr_reinstruct) 195 md->c.un_wr_reinstruct = write_reinstruct; 196 if (read_reinstruct > md->c.un_rd_reinstruct) 197 md->c.un_rd_reinstruct = read_reinstruct; 198 return (0); 199 } 200 201 /* 202 * Function: meta_init_make_device 203 * Purpose: 204 * Create the device node <uname> by constructing the necessary 205 * md_mkdev_params_t structure. We have to handle relative names 206 * (e.g. "d80") and fully-qualified names (e.g. "/dev/md/red/dsk/d80"). 207 * The field that we need is the unit number of the metadevice (80 in 208 * the above examples). 209 * Input: spp set structure 210 * uname unit-name (fully qualified or relative) 211 * Output: ep error return structure 212 * Returns: > 0 success and return 'key' 213 * -1 Error. <ep> contains error reason 214 */ 215 mdkey_t 216 meta_init_make_device( 217 mdsetname_t **spp, 218 char *uname, 219 md_error_t *ep 220 ) 221 { 222 di_devlink_handle_t hdl; 223 md_mkdev_params_t params; 224 mdkey_t rval = 0; 225 char *p; 226 int len = strlen(uname); 227 228 (void) memset(¶ms, 0, sizeof (params)); 229 MD_SETDRIVERNAME(¶ms, "md", (*spp)->setno); 230 231 /* 232 * This ioctl call causes kernel to allocate a unit number 233 * and populate /devices for the named metadevice 234 */ 235 if (metaioctl(MD_IOCMAKE_DEV, ¶ms, ¶ms.mde, NULL) != 0) { 236 return (mdstealerror(ep, ¶ms.mde)); 237 } 238 239 /* 240 * Now we have minor number so add it to the namespace 241 * and return the key 242 */ 243 if ((rval = add_self_name(*spp, uname, ¶ms, ep)) <= 0) { 244 if (mdisok(ep)) 245 (void) mderror(ep, MDE_UNIT_NOT_FOUND, NULL); 246 247 return (-1); 248 } 249 250 /* 251 * Wait until device appears in namespace. di_devlink_init() returns 252 * once the /dev links have been created. If NULL is returned the 253 * link operation failed and we haven't got a device to use. 254 * NOTE: This will take a _long_ time for large numbers of metadevices. 255 * Change to use the enhanced di_devlink_init() interface when 256 * available. 257 */ 258 hdl = di_devlink_init("md", DI_MAKE_LINK); 259 if (hdl != NULL) { 260 (void) di_devlink_fini(&hdl); 261 } else { 262 /* 263 * Delete name entry we just created 264 */ 265 (void) del_self_name(*spp, rval, ep); 266 p = Malloc(len + 3); 267 (void) snprintf(p, len + 3, "\"%s\"", uname); 268 rval = mderror(ep, MDE_UNIT_NOT_FOUND, p); 269 Free(p); 270 } 271 return (rval); 272 } 273 274 /* 275 * FUNCTION: is_metadb_cmd() 276 * INPUT: argc - number of command line arguments 277 * argv - pointer to array of command line arguments 278 * OUTPUT: none 279 * RETURNS: TRUE if a metadb is to be created, FALSE otherwise 280 * PURPOSE: parses enough of the command line to determine if a metadb 281 * create is being attempted 282 */ 283 static boolean_t 284 is_metadb_cmd( 285 int argc, 286 char *argv[] 287 ) 288 { 289 ulong_t num; 290 int len; 291 292 /* look for match */ 293 if (argc > 0 && (sscanf(argv[0], "mddb%lu%n", &num, &len) == 1) && 294 (strlen(argv[0]) == len) && ((long)num >= 0)) { 295 return (B_TRUE); 296 } 297 298 return (B_FALSE); 299 } 300 301 /* 302 * FUNCTION: is_stripe_cmd() 303 * INPUT: argc - number of command line arguments 304 * argv - pointer to array of command line arguments 305 * OUTPUT: none 306 * RETURNS: TRUE if a stripe is to be created, FALSE otherwise 307 * PURPOSE: parses enough of the command line to determine if a stripe 308 * create is being attempted 309 */ 310 static boolean_t 311 is_stripe_cmd( 312 int argc, 313 char *argv[] 314 ) 315 { 316 uint_t nrow; 317 318 if (argc > 1 && (sscanf(argv[1], "%u", &nrow) != 1) || ((int)nrow < 0)) 319 return (B_FALSE); 320 321 return (B_TRUE); 322 } 323 324 /* 325 * FUNCTION: meta_get_init_type() 326 * INPUT: argc - number of command line arguments 327 * argv - pointer to array of command line arguments 328 * OUTPUT: none 329 * RETURNS: type of metadevice or hot spare pools being initialized 330 * PURPOSE: parses enough of the command line to determine what type 331 * of metainit is being attempted 332 */ 333 mdinittypes_t 334 meta_get_init_type( 335 int argc, 336 char *argv[] 337 ) 338 { 339 char *arg = argv[1]; 340 mdinittypes_t init_type; 341 342 if (argc == 1) /* must be a hot spare pool w/o devices */ 343 return (TAB_HSP); 344 345 init_type = TAB_UNKNOWN; 346 if (arg != NULL) { 347 if (strcmp(arg, "-m") == 0) { 348 init_type = TAB_MIRROR; 349 } else if (strcmp(arg, "-r") == 0) { 350 init_type = TAB_RAID; 351 } else if (strcmp(arg, "-p") == 0) { 352 init_type = TAB_SP; 353 } else if (strcmp(arg, "-t") == 0) { 354 init_type = TAB_TRANS; 355 } else if (is_metadb_cmd(argc, argv)) { 356 init_type = TAB_MDDB; 357 } else if (is_stripe_cmd(argc, argv)) { 358 init_type = TAB_STRIPE; 359 } else { /* assume that it is a hsp */ 360 init_type = TAB_HSP; 361 } 362 } 363 return (init_type); 364 } 365 366 /* 367 * initialize named device or hotspare pool 368 */ 369 int 370 meta_init_name( 371 mdsetname_t **spp, 372 int argc, 373 char *argv[], 374 char *cname, /* canonical name */ 375 mdcmdopts_t options, 376 md_error_t *ep 377 ) 378 { 379 mdinittypes_t init_type; 380 char *p; 381 int rval; 382 char *uname = argv[0]; 383 mdkey_t key = MD_KEYWILD; 384 minor_t mnum; 385 md_error_t t_e = mdnullerror; 386 387 assert(argc > 0); 388 assert(*spp != NULL); 389 390 /* determine type of metadevice or hot spare pool being created */ 391 init_type = meta_get_init_type(argc, argv); 392 393 /* 394 * Metatrans is eof 395 */ 396 if (init_type == TAB_TRANS) 397 return (mderror(ep, MDE_EOF_TRANS, NULL)); 398 399 /* hotspare pool */ 400 if (init_type == TAB_HSP) 401 return (meta_init_hsp(spp, argc, argv, options, ep)); 402 403 /* 404 * We are creating metadevice so make sure the name 405 * has not been used 406 */ 407 if (is_existing_meta_hsp(*spp, cname)) { 408 /* 409 * The name has been used by hsp 410 */ 411 if (is_existing_hsp(*spp, cname)) { 412 return (mderror(ep, MDE_NAME_IN_USE, cname)); 413 } 414 415 /* 416 * If path exists but unit is not created 417 * then meta_init_make_device will correct 418 * that. If unit also exists then it 419 * will return a conflict error 420 */ 421 if (init_type != TAB_UNKNOWN) { 422 /* Create device node */ 423 if ((key = meta_init_make_device(spp, uname, 424 &t_e)) <= 0) { 425 return (mdstealerror(ep, &t_e)); 426 } 427 } 428 } 429 430 /* metadevice */ 431 if (argc >= 2 && init_type != TAB_UNKNOWN) { 432 /* 433 * We need to create the device node if the specified metadevice 434 * does not already exist in the database. The actual creation 435 * is undertaken by the md driver and the links propagated by 436 * devfsadm. 437 */ 438 if (key == MD_KEYWILD) { 439 if ((key = meta_init_make_device(spp, uname, 440 &t_e)) <= 0) 441 return (mdstealerror(ep, &t_e)); 442 } 443 444 switch (init_type) { 445 case TAB_MIRROR: 446 rval = meta_init_mirror(spp, argc, argv, options, ep); 447 break; 448 case TAB_RAID: 449 rval = meta_init_raid(spp, argc, argv, options, ep); 450 break; 451 case TAB_SP: 452 rval = meta_init_sp(spp, argc, argv, options, ep); 453 break; 454 case TAB_STRIPE: 455 rval = meta_init_stripe(spp, argc, argv, options, ep); 456 break; 457 } 458 459 if (rval == -1 || !(options & MDCMD_DOIT)) { 460 /* 461 * Remove the device node created before 462 */ 463 if ((meta_getnmentbykey((*spp)->setno, MD_SIDEWILD, 464 key, NULL, &mnum, NULL, ep) != NULL) && 465 MD_MIN2UNIT(mnum) < MD_MAXUNITS) { 466 (void) metaioctl(MD_IOCREM_DEV, &mnum, &t_e, NULL); 467 } 468 469 /* 470 * Del what we added before 471 */ 472 (void) del_self_name(*spp, key, &t_e); 473 } 474 return (rval); 475 } 476 477 /* unknown type */ 478 p = Malloc(1 + strlen(uname) + 1 + 1); 479 (void) strcpy(p, "\""); 480 (void) strcat(p, uname); 481 (void) strcat(p, "\""); 482 rval = mderror(ep, MDE_SYNTAX, p); 483 Free(p); 484 return (rval); 485 } 486