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 md_mkdev_params_t params; 223 mdkey_t rval = 0; 224 char *p; 225 int len = strlen(uname); 226 227 (void) memset(¶ms, 0, sizeof (params)); 228 MD_SETDRIVERNAME(¶ms, "md", (*spp)->setno); 229 230 /* 231 * This ioctl call causes kernel to allocate a unit number 232 * and populate /devices for the named metadevice 233 */ 234 if (metaioctl(MD_IOCMAKE_DEV, ¶ms, ¶ms.mde, NULL) != 0) { 235 return (mdstealerror(ep, ¶ms.mde)); 236 } 237 238 /* 239 * Now we have minor number so add it to the namespace 240 * and return the key 241 */ 242 if ((rval = add_self_name(*spp, uname, ¶ms, ep)) <= 0) { 243 if (mdisok(ep)) 244 (void) mderror(ep, MDE_UNIT_NOT_FOUND, NULL); 245 246 return (-1); 247 } 248 249 /* Make sure the /dev link is created */ 250 if (meta_update_devtree(MD_MKMIN((*spp)->setno, params.un)) != 0) { 251 /* 252 * Delete name entry we just created 253 */ 254 (void) del_self_name(*spp, rval, ep); 255 p = Malloc(len + 3); 256 (void) snprintf(p, len + 3, "\"%s\"", uname); 257 rval = mderror(ep, MDE_UNIT_NOT_FOUND, p); 258 Free(p); 259 } 260 return (rval); 261 } 262 263 /* 264 * FUNCTION: is_metadb_cmd() 265 * INPUT: argc - number of command line arguments 266 * argv - pointer to array of command line arguments 267 * OUTPUT: none 268 * RETURNS: TRUE if a metadb is to be created, FALSE otherwise 269 * PURPOSE: parses enough of the command line to determine if a metadb 270 * create is being attempted 271 */ 272 static boolean_t 273 is_metadb_cmd( 274 int argc, 275 char *argv[] 276 ) 277 { 278 ulong_t num; 279 int len; 280 281 /* look for match */ 282 if (argc > 0 && (sscanf(argv[0], "mddb%lu%n", &num, &len) == 1) && 283 (strlen(argv[0]) == len) && ((long)num >= 0)) { 284 return (B_TRUE); 285 } 286 287 return (B_FALSE); 288 } 289 290 /* 291 * FUNCTION: is_stripe_cmd() 292 * INPUT: argc - number of command line arguments 293 * argv - pointer to array of command line arguments 294 * OUTPUT: none 295 * RETURNS: TRUE if a stripe is to be created, FALSE otherwise 296 * PURPOSE: parses enough of the command line to determine if a stripe 297 * create is being attempted 298 */ 299 static boolean_t 300 is_stripe_cmd( 301 int argc, 302 char *argv[] 303 ) 304 { 305 uint_t nrow; 306 307 if (argc > 1 && (sscanf(argv[1], "%u", &nrow) != 1) || ((int)nrow < 0)) 308 return (B_FALSE); 309 310 return (B_TRUE); 311 } 312 313 /* 314 * FUNCTION: meta_get_init_type() 315 * INPUT: argc - number of command line arguments 316 * argv - pointer to array of command line arguments 317 * OUTPUT: none 318 * RETURNS: type of metadevice or hot spare pools being initialized 319 * PURPOSE: parses enough of the command line to determine what type 320 * of metainit is being attempted 321 */ 322 mdinittypes_t 323 meta_get_init_type( 324 int argc, 325 char *argv[] 326 ) 327 { 328 char *arg = argv[1]; 329 mdinittypes_t init_type; 330 331 if (argc == 1) /* must be a hot spare pool w/o devices */ 332 return (TAB_HSP); 333 334 init_type = TAB_UNKNOWN; 335 if (arg != NULL) { 336 if (strcmp(arg, "-m") == 0) { 337 init_type = TAB_MIRROR; 338 } else if (strcmp(arg, "-r") == 0) { 339 init_type = TAB_RAID; 340 } else if (strcmp(arg, "-p") == 0) { 341 init_type = TAB_SP; 342 } else if (strcmp(arg, "-t") == 0) { 343 init_type = TAB_TRANS; 344 } else if (is_metadb_cmd(argc, argv)) { 345 init_type = TAB_MDDB; 346 } else if (is_stripe_cmd(argc, argv)) { 347 init_type = TAB_STRIPE; 348 } else { /* assume that it is a hsp */ 349 init_type = TAB_HSP; 350 } 351 } 352 return (init_type); 353 } 354 355 /* 356 * initialize named device or hotspare pool 357 */ 358 int 359 meta_init_name( 360 mdsetname_t **spp, 361 int argc, 362 char *argv[], 363 char *cname, /* canonical name */ 364 mdcmdopts_t options, 365 md_error_t *ep 366 ) 367 { 368 mdinittypes_t init_type; 369 char *p; 370 int rval; 371 char *uname = argv[0]; 372 mdkey_t key = MD_KEYWILD; 373 minor_t mnum; 374 md_error_t t_e = mdnullerror; 375 376 assert(argc > 0); 377 assert(*spp != NULL); 378 379 /* determine type of metadevice or hot spare pool being created */ 380 init_type = meta_get_init_type(argc, argv); 381 382 /* 383 * Metatrans is eof 384 */ 385 if (init_type == TAB_TRANS) 386 return (mderror(ep, MDE_EOF_TRANS, NULL)); 387 388 /* hotspare pool */ 389 if (init_type == TAB_HSP) 390 return (meta_init_hsp(spp, argc, argv, options, ep)); 391 392 /* 393 * We are creating metadevice so make sure the name 394 * has not been used 395 */ 396 if (is_existing_meta_hsp(*spp, cname)) { 397 /* 398 * The name has been used by hsp 399 */ 400 if (is_existing_hsp(*spp, cname)) { 401 return (mderror(ep, MDE_NAME_IN_USE, cname)); 402 } 403 404 /* 405 * If path exists but unit is not created 406 * then meta_init_make_device will correct 407 * that. If unit also exists then it 408 * will return a conflict error 409 */ 410 if (init_type != TAB_UNKNOWN) { 411 /* Create device node */ 412 if ((key = meta_init_make_device(spp, uname, 413 &t_e)) <= 0) { 414 return (mdstealerror(ep, &t_e)); 415 } 416 } 417 } 418 419 /* metadevice */ 420 if (argc >= 2 && init_type != TAB_UNKNOWN) { 421 /* 422 * We need to create the device node if the specified metadevice 423 * does not already exist in the database. The actual creation 424 * is undertaken by the md driver and the links propagated by 425 * devfsadm. 426 */ 427 if (key == MD_KEYWILD) { 428 if ((key = meta_init_make_device(spp, uname, 429 &t_e)) <= 0) 430 return (mdstealerror(ep, &t_e)); 431 } 432 433 switch (init_type) { 434 case TAB_MIRROR: 435 rval = meta_init_mirror(spp, argc, argv, options, ep); 436 break; 437 case TAB_RAID: 438 rval = meta_init_raid(spp, argc, argv, options, ep); 439 break; 440 case TAB_SP: 441 rval = meta_init_sp(spp, argc, argv, options, ep); 442 break; 443 case TAB_STRIPE: 444 rval = meta_init_stripe(spp, argc, argv, options, ep); 445 break; 446 } 447 448 if (rval == -1 || !(options & MDCMD_DOIT)) { 449 /* 450 * Remove the device node created before 451 */ 452 if ((meta_getnmentbykey((*spp)->setno, MD_SIDEWILD, 453 key, NULL, &mnum, NULL, ep) != NULL) && 454 MD_MIN2UNIT(mnum) < MD_MAXUNITS) { 455 (void) metaioctl(MD_IOCREM_DEV, &mnum, &t_e, NULL); 456 } 457 458 /* 459 * Del what we added before 460 */ 461 (void) del_self_name(*spp, key, &t_e); 462 } 463 return (rval); 464 } 465 466 /* unknown type */ 467 p = Malloc(1 + strlen(uname) + 1 + 1); 468 (void) strcpy(p, "\""); 469 (void) strcat(p, uname); 470 (void) strcat(p, "\""); 471 rval = mderror(ep, MDE_SYNTAX, p); 472 Free(p); 473 return (rval); 474 } 475