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