1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 6630 sk102515 * Common Development and Distribution License (the "License"). 6 6630 sk102515 * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 0 stevel /* 22 9818 Andrew * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 0 stevel * Use is subject to license terms. 24 0 stevel */ 25 0 stevel 26 0 stevel 27 0 stevel #include "md_monitord.h" 28 0 stevel 29 0 stevel #define MD_PROBE_OPEN_T "probe open test" 30 0 stevel 31 0 stevel /* 32 0 stevel * Failure return's a 1 33 0 stevel */ 34 0 stevel int 35 0 stevel hotspare_ok(char *bname) 36 0 stevel { 37 0 stevel int fd; 38 0 stevel char buf[512]; 39 0 stevel 40 0 stevel if ((fd = open(bname, O_RDONLY)) < 0) 41 0 stevel return (0); 42 6630 sk102515 if (read(fd, buf, sizeof (buf)) < 0) { 43 6630 sk102515 (void) close(fd); 44 0 stevel return (0); 45 6630 sk102515 } 46 6630 sk102515 (void) close(fd); 47 0 stevel return (1); 48 0 stevel } 49 0 stevel 50 0 stevel void 51 0 stevel delete_hotspares_impl(mdhspname_t *hspnp, md_hsp_t *hspp, boolean_e verbose) 52 0 stevel { 53 0 stevel md_hs_t *hsp; 54 0 stevel uint_t hsi; 55 0 stevel char *cname, *bname, *hs_state; 56 0 stevel md_error_t e = mdnullerror; 57 0 stevel int deleted_hs = 0; 58 0 stevel 59 0 stevel for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 60 0 stevel mdnamelist_t *nlp; 61 0 stevel 62 0 stevel hsp = &hspp->hotspares.hotspares_val[hsi]; 63 0 stevel if (verbose == True) 64 0 stevel monitord_print(6, "hsi %d\n", hsi); 65 0 stevel cname = hsp->hsnamep->cname; 66 0 stevel bname = hsp->hsnamep->bname; 67 0 stevel nlp = NULL; 68 11053 Surya (void) metanamelist_append(&nlp, hsp->hsnamep); 69 0 stevel hs_state = hs_state_to_name(hsp, NULL); 70 0 stevel /* print hotspare */ 71 0 stevel if (verbose == True) 72 0 stevel monitord_print(6, "\t%-19s\t%-19s\t%-12s\n", 73 0 stevel cname, bname, hs_state); 74 0 stevel if (hsp->state == HSS_AVAILABLE) { 75 0 stevel if (hotspare_ok(bname)) 76 0 stevel continue; 77 0 stevel 78 0 stevel monitord_print(6, gettext( 79 6630 sk102515 "NOTICE: Hotspare %s in %s has failed.\n" 80 6630 sk102515 "\tDeleting %s since it is not in use\n\n"), 81 6630 sk102515 bname, hspnp->hspname, bname); 82 0 stevel 83 0 stevel if (meta_hs_delete(sp, hspnp, nlp, 0, &e) != NULL) { 84 0 stevel mde_perror(&e, ""); 85 9818 Andrew mdclrerror(&e); 86 0 stevel } else { 87 0 stevel deleted_hs++; 88 0 stevel } 89 0 stevel } else { 90 0 stevel if (verbose == True) 91 0 stevel monitord_print(6, gettext( 92 6630 sk102515 "%s in use - skipping\n"), cname); 93 0 stevel } 94 0 stevel } 95 0 stevel } 96 0 stevel 97 0 stevel 98 0 stevel 99 0 stevel /* 100 0 stevel * Generic routine to issue probe ioctls 101 0 stevel */ 102 0 stevel 103 0 stevel int 104 0 stevel md_probe_ioctl(mdnamelist_t *nlp, int ndevs, char *drvname, boolean_e verbose) 105 0 stevel { 106 0 stevel mdnamelist_t *p; 107 0 stevel mdname_t *np; 108 6630 sk102515 md_probedev_t probe_ioc, *iocp; 109 6630 sk102515 int i, retval = 0; 110 0 stevel /* 111 0 stevel * Allocate space for all the metadevices and fill in 112 0 stevel * the minor numbers. 113 0 stevel */ 114 0 stevel 115 11053 Surya (void) memset(&probe_ioc, 0, sizeof (probe_ioc)); 116 0 stevel iocp = &probe_ioc; 117 0 stevel 118 0 stevel if ((iocp->mnum_list = (uintptr_t)calloc(ndevs, sizeof (minor_t))) 119 0 stevel == 0) { 120 0 stevel monitord_print(0, "md_probe_ioctl: calloc"); 121 0 stevel return (-1); 122 0 stevel } 123 0 stevel 124 0 stevel (void) strcpy(iocp->test_name, MD_PROBE_OPEN_T); 125 0 stevel MD_SETDRIVERNAME(&probe_ioc, drvname, sp->setno); 126 0 stevel 127 0 stevel if (verbose == True) { 128 0 stevel monitord_print(6, "\n\nmd_probe_ioctl: %s: %s\n", 129 0 stevel (strcmp(sp->setname, MD_LOCAL_NAME) == 0) ? 130 0 stevel gettext("local_set") : 131 0 stevel sp->setname, iocp->md_driver.md_drivername); 132 0 stevel } 133 0 stevel 134 0 stevel iocp->nmdevs = ndevs; 135 0 stevel if (verbose == True) 136 0 stevel monitord_print(6, "...ndevs 0x%x\n", ndevs); 137 0 stevel 138 0 stevel for (p = nlp, i = 0; p; p = p->next, i++) { 139 0 stevel np = p->namep; 140 62 jeanm ((minor_t *)(uintptr_t)iocp->mnum_list)[i] = 141 62 jeanm meta_getminor(np->dev); 142 0 stevel if (verbose == True) 143 0 stevel monitord_print(6, "...%s 0x%lx\n", np->cname, 144 62 jeanm ((minor_t *)(uintptr_t)iocp->mnum_list)[i]); 145 0 stevel } 146 0 stevel 147 0 stevel 148 0 stevel if (issue_ioctl == True) { 149 0 stevel if (metaioctl(MD_IOCPROBE_DEV, iocp, &(iocp->mde), NULL) != 0) 150 0 stevel retval = -1; 151 0 stevel } 152 9818 Andrew 153 9818 Andrew Free((void *)(uintptr_t)iocp->mnum_list); 154 0 stevel return (retval); 155 0 stevel } 156 0 stevel /* 157 0 stevel * 158 0 stevel * - remove p from nlp list 159 0 stevel * - put it on the toplp list. 160 0 stevel * - update the p to the next element 161 0 stevel */ 162 0 stevel 163 0 stevel void 164 0 stevel add_to_list(mdnamelist_t **curpp, mdnamelist_t **prevpp, 165 0 stevel mdnamelist_t **newlpp) 166 0 stevel { 167 0 stevel mdnamelist_t *p, *prevp, *nlp; 168 0 stevel 169 0 stevel p = *curpp; 170 0 stevel prevp = *prevpp; 171 0 stevel nlp = *newlpp; 172 0 stevel 173 0 stevel if (prevp == p) { 174 0 stevel /* if first element reset prevp */ 175 0 stevel prevp = p->next; 176 0 stevel p->next = nlp; 177 0 stevel nlp = p; 178 0 stevel p = prevp; 179 0 stevel } else { 180 0 stevel prevp->next = p->next; 181 0 stevel p->next = nlp; 182 0 stevel nlp = p; 183 0 stevel p = prevp->next; 184 0 stevel } 185 0 stevel *curpp = p; 186 0 stevel *prevpp = prevp; 187 0 stevel *newlpp = nlp; 188 0 stevel } 189 0 stevel /* 190 0 stevel * Scans the given list of metadeivces and returns a list of top level 191 0 stevel * metadevices. 192 0 stevel * Note: The orignal list is not valid at the end and is set to NULL. 193 0 stevel */ 194 0 stevel 195 0 stevel int 196 0 stevel get_toplevel_mds(mdnamelist_t **lpp, mdnamelist_t **top_pp, boolean_e verbose) 197 0 stevel { 198 0 stevel mdnamelist_t *p, *prevp, *toplp; 199 0 stevel int ntopmd, i; 200 0 stevel md_common_t *mdp; 201 0 stevel md_error_t e = mdnullerror; 202 0 stevel 203 0 stevel i = ntopmd = 0; 204 0 stevel prevp = p = *lpp; 205 0 stevel toplp = NULL; 206 0 stevel 207 0 stevel while (p) { 208 0 stevel if ((mdp = meta_get_unit(sp, p->namep, &e)) == NULL) { 209 9818 Andrew mdclrerror(&e); 210 0 stevel if (verbose == True) 211 0 stevel monitord_print(6, gettext( 212 6630 sk102515 "......error on (%d)%s\n"), i, 213 6630 sk102515 p->namep->devicesname); 214 0 stevel prevp = p; 215 0 stevel p = p->next; 216 0 stevel continue; 217 0 stevel } 218 0 stevel 219 0 stevel if (mdp->parent == MD_NO_PARENT) { 220 0 stevel /* increment the top level md count. */ 221 0 stevel ntopmd++; 222 0 stevel add_to_list(&p, &prevp, &toplp); 223 0 stevel } else { 224 0 stevel prevp = p; 225 0 stevel p = p->next; 226 0 stevel } 227 0 stevel i++; 228 0 stevel } 229 0 stevel 230 0 stevel *lpp = NULL; 231 0 stevel *top_pp = toplp; 232 0 stevel 233 0 stevel return (ntopmd); 234 0 stevel } 235 0 stevel 236 0 stevel int 237 0 stevel get_namelist(mdnamelist_t **transdevlist, mdnamelist_t **devlist, 238 0 stevel char *dev_type) 239 0 stevel { 240 0 stevel mdnamelist_t *np, *prevp; 241 0 stevel md_error_t e = mdnullerror; 242 0 stevel char *type_name; 243 0 stevel int i = 0; 244 0 stevel 245 0 stevel prevp = np = *transdevlist; 246 0 stevel while (np) { 247 0 stevel if ((type_name = metagetmiscname(np->namep, &e)) == NULL) { 248 0 stevel *devlist = NULL; 249 9818 Andrew mdclrerror(&e); 250 0 stevel return (-1); 251 0 stevel } 252 0 stevel if (strcmp(type_name, dev_type) == 0) { 253 0 stevel /* move it to the devlist */ 254 0 stevel add_to_list(&np, &prevp, devlist); 255 0 stevel i++; 256 0 stevel } else { 257 0 stevel prevp = np; 258 0 stevel np = np->next; 259 0 stevel } 260 0 stevel } 261 0 stevel return (i); 262 0 stevel } 263 0 stevel 264 0 stevel 265 0 stevel mdnamelist_t * 266 0 stevel create_nlp() 267 0 stevel { 268 0 stevel mdnamelist_t *np; 269 0 stevel 270 0 stevel if (np = (mdnamelist_t *)malloc(sizeof (mdnamelist_t))) { 271 0 stevel np->next = NULL; 272 0 stevel return (np); 273 0 stevel } else { 274 0 stevel /* error condition below */ 275 0 stevel monitord_print(0, gettext( 276 0 stevel "create_nlp: malloc failed\n")); 277 0 stevel monitord_exit(errno); 278 0 stevel } 279 62 jeanm return (0); 280 0 stevel } 281 0 stevel 282 0 stevel /* 283 0 stevel * Create a list of metadevices associated with trans. top_pp points to 284 0 stevel * this list. The number of components in the list are also returned. 285 0 stevel */ 286 0 stevel int 287 0 stevel create_trans_compslist(mdnamelist_t **lpp, mdnamelist_t **top_pp, 288 0 stevel boolean_e verbose) 289 0 stevel { 290 0 stevel mdnamelist_t *p, *tailp, *toplp, *newlp; 291 0 stevel int ntoptrans; 292 0 stevel md_error_t e = mdnullerror; 293 0 stevel md_trans_t *tp; 294 0 stevel 295 0 stevel ntoptrans = 0; 296 0 stevel p = *lpp; 297 0 stevel tailp = toplp = NULL; 298 0 stevel /* 299 0 stevel * Scan the current list of trans devices. From that 300 0 stevel * extract all the lower level metadevices and put them on 301 0 stevel * toplp list. 302 0 stevel */ 303 0 stevel 304 0 stevel while (p) { 305 0 stevel if (tp = meta_get_trans(sp, p->namep, &e)) { 306 0 stevel /* 307 0 stevel * Check the master and log devices to see if they 308 0 stevel * are metadevices 309 0 stevel */ 310 0 stevel if (metaismeta(tp->masternamep)) { 311 0 stevel if (verbose == True) 312 0 stevel monitord_print(6, gettext( 313 0 stevel "master metadevice\n")); 314 0 stevel /* get a mdnamelist_t. */ 315 0 stevel newlp = create_nlp(); 316 0 stevel newlp->namep = tp->masternamep; 317 0 stevel if (toplp == NULL) { 318 0 stevel toplp = tailp = newlp; 319 0 stevel } else { 320 0 stevel tailp->next = newlp; 321 0 stevel tailp = newlp; 322 0 stevel } 323 0 stevel ntoptrans++; 324 0 stevel } 325 0 stevel 326 0 stevel if (tp->lognamep && metaismeta(tp->lognamep)) { 327 0 stevel if (verbose == True) 328 0 stevel monitord_print(6, gettext( 329 0 stevel "log metadevice\n")); 330 0 stevel newlp = create_nlp(); 331 0 stevel newlp->namep = tp->lognamep; 332 0 stevel if (toplp == NULL) { 333 0 stevel toplp = tailp = newlp; 334 0 stevel } else { 335 0 stevel tailp->next = newlp; 336 0 stevel tailp = newlp; 337 0 stevel } 338 0 stevel ntoptrans++; 339 0 stevel } 340 0 stevel p = p->next; 341 9818 Andrew } else { 342 9818 Andrew mdclrerror(&e); 343 0 stevel } 344 0 stevel } 345 0 stevel *top_pp = toplp; 346 0 stevel return (ntoptrans); 347 0 stevel } 348 0 stevel 349 0 stevel void 350 0 stevel probe_mirror_devs(boolean_e verbose) 351 0 stevel { 352 0 stevel mdnamelist_t *nlp, *toplp; 353 0 stevel int cnt; 354 0 stevel md_error_t e = mdnullerror; 355 0 stevel 356 0 stevel nlp = toplp = NULL; 357 0 stevel 358 0 stevel if (meta_get_mirror_names(sp, &nlp, 0, &e) > 0) { 359 0 stevel /* 360 0 stevel * We have some mirrors to probe 361 0 stevel * get a list of top-level mirrors 362 0 stevel */ 363 0 stevel 364 0 stevel cnt = get_toplevel_mds(&nlp, &toplp, verbose); 365 0 stevel if (cnt && (md_probe_ioctl(toplp, cnt, 366 6630 sk102515 MD_MIRROR, verbose) < 0)) 367 0 stevel monitord_print(0, gettext( 368 0 stevel "probe_mirror_devs: " 369 0 stevel "mirror components %d ioctl error\n"), 370 0 stevel cnt); 371 0 stevel 372 9818 Andrew } else { 373 9818 Andrew mdclrerror(&e); 374 0 stevel } 375 0 stevel 376 0 stevel metafreenamelist(nlp); 377 0 stevel metafreenamelist(toplp); 378 0 stevel } 379 0 stevel 380 0 stevel void 381 0 stevel probe_raid_devs(boolean_e verbose) 382 0 stevel { 383 0 stevel mdnamelist_t *nlp, *toplp; 384 0 stevel int cnt; 385 0 stevel md_error_t e = mdnullerror; 386 0 stevel 387 0 stevel nlp = toplp = NULL; 388 0 stevel 389 0 stevel if (meta_get_raid_names(sp, &nlp, 0, &e) > 0) { 390 0 stevel /* 391 0 stevel * We have some mirrors to probe 392 0 stevel * get a list of top-level mirrors 393 0 stevel */ 394 0 stevel 395 0 stevel cnt = get_toplevel_mds(&nlp, &toplp, verbose); 396 0 stevel 397 0 stevel if (cnt && (md_probe_ioctl(toplp, cnt, 398 6630 sk102515 MD_RAID, verbose) < 0)) 399 0 stevel monitord_print(0, gettext( 400 0 stevel "probe_raid_devs: " 401 0 stevel "RAID-5 components %d ioctl error\n"), 402 0 stevel cnt); 403 9818 Andrew } else { 404 9818 Andrew mdclrerror(&e); 405 0 stevel } 406 0 stevel 407 0 stevel metafreenamelist(nlp); 408 0 stevel metafreenamelist(toplp); 409 0 stevel } 410 0 stevel 411 0 stevel /* 412 0 stevel * Trans probes are different. -- so whats new. 413 0 stevel * we separate out the master and log device and then issue the 414 0 stevel * probe calls. 415 0 stevel * Since the underlying device could be disk, stripe, RAID or miror, 416 0 stevel * we have to sort them out and then call the ioctl for each. 417 0 stevel */ 418 0 stevel 419 0 stevel void 420 0 stevel probe_trans_devs(boolean_e verbose) 421 0 stevel { 422 0 stevel mdnamelist_t *nlp, *toplp; 423 0 stevel mdnamelist_t *trans_raidlp, *trans_mmlp, *trans_stripelp; 424 0 stevel int cnt; 425 0 stevel md_error_t e = mdnullerror; 426 0 stevel 427 0 stevel nlp = toplp = NULL; 428 0 stevel trans_raidlp = trans_mmlp = trans_stripelp = NULL; 429 0 stevel 430 0 stevel if (meta_get_trans_names(sp, &nlp, 0, &e) > 0) { 431 0 stevel /* 432 0 stevel * get a list of master and log metadevices. 433 0 stevel */ 434 0 stevel 435 0 stevel cnt = create_trans_compslist(&nlp, &toplp, verbose); 436 0 stevel if (verbose == True) { 437 0 stevel int i; 438 0 stevel 439 0 stevel for (i = 0, nlp = toplp; i < cnt; i++) { 440 0 stevel monitord_print(6, gettext( 441 0 stevel "tran: underlying drv %s\n"), 442 0 stevel (nlp->namep)->cname); 443 0 stevel nlp = nlp->next; 444 0 stevel } 445 0 stevel } 446 0 stevel 447 0 stevel /* underlying RAID-5 components */ 448 0 stevel 449 0 stevel cnt = get_namelist(&toplp, &trans_raidlp, MD_RAID); 450 0 stevel if ((cnt > 0) && (md_probe_ioctl(trans_raidlp, cnt, 451 0 stevel MD_RAID, verbose) < 0)) 452 0 stevel monitord_print(0, gettext( 453 0 stevel "probe_trans_devs: " 454 0 stevel "RAID-5 components %d ioctl error\n"), 455 0 stevel cnt); 456 0 stevel metafreenamelist(trans_raidlp); 457 0 stevel 458 0 stevel /* underlying mirror components */ 459 0 stevel 460 0 stevel cnt = get_namelist(&toplp, &trans_mmlp, MD_MIRROR); 461 0 stevel 462 0 stevel if ((cnt > 0) && (md_probe_ioctl(trans_mmlp, cnt, 463 0 stevel MD_MIRROR, verbose) < 0)) 464 0 stevel monitord_print(0, gettext( 465 0 stevel "probe_trans_devs: " 466 0 stevel "mirror components %d ioctl error\n"), 467 0 stevel cnt); 468 0 stevel metafreenamelist(trans_mmlp); 469 0 stevel 470 0 stevel /* underlying stripe components */ 471 0 stevel 472 0 stevel cnt = get_namelist(&toplp, &trans_stripelp, MD_STRIPE); 473 0 stevel if ((cnt > 0) && (md_probe_ioctl(trans_stripelp, cnt, 474 0 stevel MD_STRIPE, verbose) < 0)) 475 0 stevel monitord_print(0, gettext( 476 0 stevel "probe_trans_devs: " 477 0 stevel "stripe components %d ioctl error\n"), 478 0 stevel cnt); 479 0 stevel 480 0 stevel metafreenamelist(trans_stripelp); 481 0 stevel metafreenamelist(nlp); 482 9818 Andrew } else { 483 9818 Andrew mdclrerror(&e); 484 0 stevel } 485 0 stevel } 486 0 stevel 487 0 stevel /* 488 0 stevel * probe hot spares. This is differs from other approaches since 489 0 stevel * there are no read/write routines through md. We check at the physical 490 0 stevel * component level and then delete it if its bad. 491 0 stevel */ 492 0 stevel 493 0 stevel void 494 0 stevel probe_hotspare_devs(boolean_e verbose) 495 0 stevel { 496 0 stevel mdhspnamelist_t *hspnlp = NULL; 497 0 stevel mdhspnamelist_t *p; 498 0 stevel md_hsp_t *hspp; 499 0 stevel md_error_t e = mdnullerror; 500 0 stevel 501 9818 Andrew if (meta_get_hsp_names(sp, &hspnlp, 0, &e) <= 0) { 502 9818 Andrew mdclrerror(&e); 503 0 stevel return; 504 0 stevel } 505 9818 Andrew 506 0 stevel for (p = hspnlp; (p != NULL); p = p->next) { 507 0 stevel mdhspname_t *hspnp = p->hspnamep; 508 0 stevel 509 0 stevel if (verbose == True) 510 0 stevel monitord_print(6, "%s %s\n", gettext("name"), 511 0 stevel hspnp->hspname); 512 0 stevel 513 0 stevel if ((hspp = meta_get_hsp(sp, hspnp, &e)) == NULL) 514 0 stevel continue; 515 0 stevel 516 0 stevel if (hspp->hotspares.hotspares_len != 0) { 517 0 stevel if (verbose == True) 518 0 stevel monitord_print(6, " %u hotspares\n", 519 6630 sk102515 hspp->hotspares.hotspares_len); 520 0 stevel delete_hotspares_impl(hspnp, hspp, verbose); 521 0 stevel } 522 0 stevel } 523 9818 Andrew mdclrerror(&e); 524 0 stevel metafreehspnamelist(hspnlp); 525 0 stevel } 526