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