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 #include <devfsadm.h> 27 #include <stdio.h> 28 #include <strings.h> 29 #include <stdlib.h> 30 #include <limits.h> 31 #include <ctype.h> 32 #include <sys/stat.h> 33 #include <bsm/devalloc.h> 34 35 #define DISK_SUBPATH_MAX 100 36 #define RM_STALE 0x01 37 #define DISK_LINK_RE "^r?dsk/c[0-9]+(t[0-9A-F]+)?d[0-9]+(((s|p))[0-9]+)?$" 38 #define DISK_LINK_TO_UPPER(ch)\ 39 (((ch) >= 'a' && (ch) <= 'z') ? (ch - 'a' + 'A') : ch) 40 41 #define SLICE_SMI "s7" 42 #define SLICE_EFI "" 43 44 #define MN_SMI "h" 45 #define MN_EFI "wd" 46 #define ASCIIWWNSIZE 255 47 #if defined(__i386) || defined(__amd64) 48 /* 49 * The number of minor nodes per LUN is defined by the disk drivers. 50 * Currently it is set to 64. Refer CMLBUNIT_SHIFT (cmlb_impl.h) 51 */ 52 #define NUM_MINORS_PER_INSTANCE 64 53 #endif 54 55 56 extern int system_labeled; 57 58 static int disk_callback_chan(di_minor_t minor, di_node_t node); 59 static int disk_callback_nchan(di_minor_t minor, di_node_t node); 60 static int disk_callback_wwn(di_minor_t minor, di_node_t node); 61 static int disk_callback_xvmd(di_minor_t minor, di_node_t node); 62 static int disk_callback_fabric(di_minor_t minor, di_node_t node); 63 static int disk_callback_sas(di_minor_t minor, di_node_t node); 64 static void disk_common(di_minor_t minor, di_node_t node, char *disk, 65 int flags); 66 static char *diskctrl(di_node_t node, di_minor_t minor); 67 static int reserved_links_exist(di_node_t node, di_minor_t minor, int nflags); 68 69 70 static devfsadm_create_t disk_cbt[] = { 71 { "disk", "ddi_block", NULL, 72 TYPE_EXACT, ILEVEL_0, disk_callback_nchan 73 }, 74 { "disk", "ddi_block:channel", NULL, 75 TYPE_EXACT, ILEVEL_0, disk_callback_chan 76 }, 77 { "disk", "ddi_block:fabric", NULL, 78 TYPE_EXACT, ILEVEL_0, disk_callback_fabric 79 }, 80 { "disk", "ddi_block:wwn", NULL, 81 TYPE_EXACT, ILEVEL_0, disk_callback_wwn 82 }, 83 { "disk", "ddi_block:sas", NULL, 84 TYPE_EXACT, ILEVEL_0, disk_callback_sas 85 }, 86 { "disk", "ddi_block:cdrom", NULL, 87 TYPE_EXACT, ILEVEL_0, disk_callback_nchan 88 }, 89 { "disk", "ddi_block:cdrom:channel", NULL, 90 TYPE_EXACT, ILEVEL_0, disk_callback_chan 91 }, 92 { "disk", "ddi_block:xvmd", NULL, 93 TYPE_EXACT, ILEVEL_0, disk_callback_xvmd 94 }, 95 { "disk", "ddi_block:cdrom:xvmd", NULL, 96 TYPE_EXACT, ILEVEL_0, disk_callback_xvmd 97 }, 98 }; 99 100 DEVFSADM_CREATE_INIT_V0(disk_cbt); 101 102 /* 103 * HOT auto cleanup of disks not desired. 104 */ 105 static devfsadm_remove_t disk_remove_cbt[] = { 106 { "disk", DISK_LINK_RE, RM_POST, 107 ILEVEL_0, devfsadm_rm_all 108 } 109 }; 110 111 DEVFSADM_REMOVE_INIT_V0(disk_remove_cbt); 112 113 static devlink_re_t disks_re_array[] = { 114 {"^r?dsk/c([0-9]+)", 1}, 115 {"^cfg/c([0-9]+)$", 1}, 116 {"^scsi/.+/c([0-9]+)", 1}, 117 {NULL} 118 }; 119 120 static char *disk_mid = "disk_mid"; 121 static char *modname = "disk_link"; 122 123 int 124 minor_init() 125 { 126 devfsadm_print(disk_mid, 127 "%s: minor_init(): Creating disks reserved ID cache\n", 128 modname); 129 return (devfsadm_reserve_id_cache(disks_re_array, NULL)); 130 } 131 132 static int 133 disk_callback_chan(di_minor_t minor, di_node_t node) 134 { 135 char *addr; 136 char disk[20]; 137 uint_t targ; 138 uint_t lun; 139 140 addr = di_bus_addr(node); 141 (void) sscanf(addr, "%X,%X", &targ, &lun); 142 (void) sprintf(disk, "t%dd%d", targ, lun); 143 disk_common(minor, node, disk, 0); 144 return (DEVFSADM_CONTINUE); 145 146 } 147 148 static int 149 disk_callback_nchan(di_minor_t minor, di_node_t node) 150 { 151 char *addr; 152 char disk[10]; 153 uint_t lun; 154 155 addr = di_bus_addr(node); 156 (void) sscanf(addr, "%X", &lun); 157 (void) sprintf(disk, "d%d", lun); 158 disk_common(minor, node, disk, 0); 159 return (DEVFSADM_CONTINUE); 160 161 } 162 163 static int 164 disk_callback_wwn(di_minor_t minor, di_node_t node) 165 { 166 char disk[10]; 167 int lun; 168 int targ; 169 int *intp; 170 171 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "target", &intp) <= 0) { 172 return (DEVFSADM_CONTINUE); 173 } 174 targ = *intp; 175 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "lun", &intp) <= 0) { 176 lun = 0; 177 } else { 178 lun = *intp; 179 } 180 (void) sprintf(disk, "t%dd%d", targ, lun); 181 182 disk_common(minor, node, disk, RM_STALE); 183 184 return (DEVFSADM_CONTINUE); 185 } 186 187 static int 188 disk_callback_fabric(di_minor_t minor, di_node_t node) 189 { 190 char disk[DISK_SUBPATH_MAX]; 191 int lun; 192 int count; 193 int *intp; 194 uchar_t *str; 195 uchar_t *wwn; 196 uchar_t ascii_wwn[ASCIIWWNSIZE]; 197 198 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 199 "client-guid", (char **)&wwn) > 0) { 200 if (strlcpy((char *)ascii_wwn, (char *)wwn, 201 sizeof (ascii_wwn)) >= sizeof (ascii_wwn)) { 202 devfsadm_errprint("SUNW_disk_link: GUID too long:%d", 203 strlen((char *)wwn)); 204 return (DEVFSADM_CONTINUE); 205 } 206 lun = 0; 207 } else if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, 208 "port-wwn", &wwn) > 0) { 209 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 210 "lun", &intp) > 0) { 211 lun = *intp; 212 } else { 213 lun = 0; 214 } 215 216 for (count = 0, str = ascii_wwn; count < 8; count++, str += 2) { 217 (void) sprintf((caddr_t)str, "%02x", wwn[count]); 218 } 219 *str = '\0'; 220 } else { 221 return (DEVFSADM_CONTINUE); 222 } 223 224 for (str = ascii_wwn; *str != '\0'; str++) { 225 *str = DISK_LINK_TO_UPPER(*str); 226 } 227 228 (void) snprintf(disk, DISK_SUBPATH_MAX, "t%sd%d", ascii_wwn, lun); 229 230 disk_common(minor, node, disk, RM_STALE); 231 232 return (DEVFSADM_CONTINUE); 233 } 234 235 static int 236 disk_callback_sas(di_minor_t minor, di_node_t node) 237 { 238 char disk[DISK_SUBPATH_MAX]; 239 int lun; 240 int *intp; 241 char *str; 242 char *wwn; 243 244 /* 245 * get LUN property 246 */ 247 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 248 "lun", &intp) > 0) { 249 lun = *intp; 250 } else { 251 lun = 0; 252 } 253 if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 254 "target-port", &wwn) > 0) { 255 /* 256 * If the target-port property exist 257 * we use wwn format naming 258 */ 259 for (str = wwn; *str != '\0'; str++) { 260 *str = DISK_LINK_TO_UPPER(*str); 261 } 262 (void) snprintf(disk, DISK_SUBPATH_MAX, "t%sd%d", wwn, lun); 263 264 } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 265 "sata-phy", &intp) > 0) { 266 /* 267 * For direct attached SATA device without Device Name, 268 * no wwn exist, we use phy format naming 269 */ 270 (void) snprintf(disk, DISK_SUBPATH_MAX, "t%dd%d", *intp, lun); 271 } else { 272 return (DEVFSADM_CONTINUE); 273 } 274 275 disk_common(minor, node, disk, RM_STALE); 276 277 return (DEVFSADM_CONTINUE); 278 } 279 280 /* 281 * xVM virtual block device 282 * 283 * VBDs are enumerated into xenstore by xend and named using 284 * the linux dev_t values for 'hd' and 'xvd' devices. Linux 285 * dev_t's are 16-bit values. The upper 8 bits identify the major # 286 * of the device (hd, xvd) and the lower 8 bits the instance and partition 287 * 288 * For PV guests, VBDs are named by the virt-tools using 289 * the form xvd[a-p][1-15]. The corresponding Solaris /dev/dsk name 290 * created by this generator will be c0t[0-15]d[0-15]sN, 291 * were the target (t) value represents [a-p] and the 292 * disk (d) value is either 0 (e.g. xvda) or contains the partition 293 * information if it has been specified [1-15] (e.g. xvda1) 294 * 295 * For PV guests using the legacy naming (0, 1, 2, ...) 296 * the Solaris disk names created will be c0d[0..767]sN 297 * The Solaris version of virt-install based on virtinst.101 298 * named PV disks as sequential integers. With virtinst.300_1 and 299 * beyond, the virt-* tools will no longer create legacy disk 300 * names. 301 */ 302 static int 303 disk_callback_xvmd(di_minor_t minor, di_node_t node) 304 { 305 #define HD_BASE (3 << 8) 306 #define XVBDMAJ 202 307 308 char *addr; 309 char disk[16]; 310 uint_t targ; 311 uint_t lun = 0; 312 uint_t fmaj; 313 314 addr = di_bus_addr(node); 315 targ = strtol(addr, (char **)NULL, 10); 316 fmaj = targ >> 8; 317 318 /* legacy device address */ 319 if (targ < HD_BASE) 320 (void) snprintf(disk, sizeof (disk), "d%d", targ); 321 /* PV VBD */ 322 else if (fmaj == XVBDMAJ) { 323 lun = targ & 0xf; 324 targ = (targ & 0xff) >> 4; 325 (void) snprintf(disk, sizeof (disk), "t%dd%d", targ, lun); 326 /* HVM device names are generated using the standard generator */ 327 } else { 328 devfsadm_errprint("%s: invalid disk device number (%s)\n", 329 modname, addr); 330 return (DEVFSADM_CONTINUE); 331 } 332 disk_common(minor, node, disk, 0); 333 return (DEVFSADM_CONTINUE); 334 335 } 336 337 /* 338 * This function is called for every disk minor node. 339 * Calls enumerate to assign a logical controller number, and 340 * then devfsadm_mklink to make the link. 341 */ 342 static void 343 disk_common(di_minor_t minor, di_node_t node, char *disk, int flags) 344 { 345 char l_path[PATH_MAX + 1]; 346 char sec_path[PATH_MAX + 1]; 347 char stale_re[DISK_SUBPATH_MAX]; 348 char *dir; 349 char slice[4]; 350 char *mn; 351 char *ctrl; 352 char *nt = NULL; 353 int *int_prop; 354 int nflags = 0; 355 #if defined(__i386) || defined(__amd64) 356 char mn_copy[4]; 357 char *part; 358 int part_num; 359 #endif 360 361 mn = di_minor_name(minor); 362 if (strstr(mn, ",raw")) { 363 dir = "rdsk"; 364 #if defined(__i386) || defined(__amd64) 365 (void) strncpy(mn_copy, mn, 4); 366 part = strtok(mn_copy, ","); 367 #endif 368 } else { 369 dir = "dsk"; 370 #if defined(__i386) || defined(__amd64) 371 part = mn; 372 #endif 373 } 374 375 #if defined(__i386) || defined(__amd64) 376 /* 377 * The following is a table describing the allocation of 378 * minor numbers, minor names and /dev/dsk names for partitions 379 * and slices on x86 systems. 380 * 381 * Minor Number Minor Name /dev/dsk name 382 * --------------------------------------------- 383 * 0 to 15 "a" to "p" s0 to s15 384 * 16 "q" p0 385 * 17 to 20 "r" to "u" p1 to p4 386 * 21 to 52 "p5" to "p36" p5 to p36 387 * 388 */ 389 part_num = atoi(part + 1); 390 391 if ((mn[0] == 'p') && (part_num >= 5)) { 392 /* logical drive */ 393 (void) snprintf(slice, 4, "%s", part); 394 } else { 395 #endif 396 if (mn[0] < 'q') { 397 (void) sprintf(slice, "s%d", mn[0] - 'a'); 398 } else if (strncmp(mn, MN_EFI, 2) != 0) { 399 (void) sprintf(slice, "p%d", mn[0] - 'q'); 400 } else { 401 /* For EFI label */ 402 (void) sprintf(slice, SLICE_EFI); 403 } 404 #if defined(__i386) || defined(__amd64) 405 } 406 #endif 407 408 nflags = 0; 409 if (system_labeled) { 410 nt = di_minor_nodetype(minor); 411 if ((nt != NULL) && 412 ((strcmp(nt, DDI_NT_CD) == 0) || 413 (strcmp(nt, DDI_NT_CD_CHAN) == 0) || 414 (strcmp(nt, DDI_NT_BLOCK_CHAN) == 0))) { 415 nflags = DA_ADD|DA_CD; 416 } 417 } 418 419 if (reserved_links_exist(node, minor, nflags) == DEVFSADM_SUCCESS) { 420 devfsadm_print(disk_mid, "Reserved link exists. Not " 421 "creating links for slice %s\n", slice); 422 return; 423 } 424 425 if (NULL == (ctrl = diskctrl(node, minor))) 426 return; 427 428 (void) strcpy(l_path, dir); 429 (void) strcat(l_path, "/c"); 430 (void) strcat(l_path, ctrl); 431 (void) strcat(l_path, disk); 432 433 /* 434 * If switching between SMI and EFI label or vice versa 435 * cleanup the previous label's devlinks. 436 */ 437 if (*mn == *(MN_SMI) || (strncmp(mn, MN_EFI, 2) == 0)) { 438 char *s, tpath[PATH_MAX + 1]; 439 struct stat sb; 440 441 s = l_path + strlen(l_path); 442 (void) strcat(l_path, (*mn == *(MN_SMI)) 443 ? SLICE_EFI : SLICE_SMI); 444 /* 445 * Attempt the remove only if the stale link exists 446 */ 447 (void) snprintf(tpath, sizeof (tpath), "%s/dev/%s", 448 devfsadm_root_path(), l_path); 449 if (lstat(tpath, &sb) != -1) 450 devfsadm_rm_all(l_path); 451 *s = '\0'; 452 } 453 (void) strcat(l_path, slice); 454 455 (void) devfsadm_mklink(l_path, node, minor, nflags); 456 457 /* secondary links for removable and hotpluggable devices */ 458 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "removable-media", 459 &int_prop) >= 0) { 460 (void) strcpy(sec_path, "removable-media/"); 461 (void) strcat(sec_path, l_path); 462 (void) devfsadm_secondary_link(sec_path, l_path, 0); 463 } 464 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "hotpluggable", 465 &int_prop) >= 0) { 466 (void) strcpy(sec_path, "hotpluggable/"); 467 (void) strcat(sec_path, l_path); 468 (void) devfsadm_secondary_link(sec_path, l_path, 0); 469 } 470 471 if ((flags & RM_STALE) == RM_STALE) { 472 (void) strcpy(stale_re, "^"); 473 (void) strcat(stale_re, dir); 474 (void) strcat(stale_re, "/c"); 475 (void) strcat(stale_re, ctrl); 476 (void) strcat(stale_re, "t[0-9A-F]+d[0-9]+(s[0-9]+)?$"); 477 /* 478 * optimizations are made inside of devfsadm_rm_stale_links 479 * instead of before calling the function, as it always 480 * needs to add the valid link to the cache. 481 */ 482 devfsadm_rm_stale_links(stale_re, l_path, node, minor); 483 } 484 485 free(ctrl); 486 } 487 488 489 /* index of enumeration rule applicable to this module */ 490 #define RULE_INDEX 0 491 492 static char * 493 diskctrl(di_node_t node, di_minor_t minor) 494 { 495 char path[PATH_MAX + 1]; 496 char *devfspath; 497 char *buf, *mn; 498 499 devfsadm_enumerate_t rules[3] = { 500 {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT}, 501 {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR}, 502 {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT} 503 }; 504 505 mn = di_minor_name(minor); 506 507 if ((devfspath = di_devfs_path(node)) == NULL) { 508 return (NULL); 509 } 510 (void) strcpy(path, devfspath); 511 (void) strcat(path, ":"); 512 (void) strcat(path, mn); 513 di_devfs_path_free(devfspath); 514 515 /* 516 * Use controller component of disk path 517 */ 518 if (disk_enumerate_int(path, RULE_INDEX, &buf, rules, 3) == 519 DEVFSADM_MULTIPLE) { 520 521 /* 522 * We failed because there are multiple logical controller 523 * numbers for a single physical controller. If we use node 524 * name also in the match it should fix this and only find one 525 * logical controller. (See 4045879). 526 * NOTE: Rules for controllers are not changed, as there is 527 * no unique controller number for them in this case. 528 * 529 * MATCH_UNCACHED flag is private to the "disks" and "sgen" 530 * modules. NOT to be used by other modules. 531 */ 532 533 rules[0].flags = MATCH_NODE | MATCH_UNCACHED; /* disks */ 534 rules[2].flags = MATCH_NODE | MATCH_UNCACHED; /* generic scsi */ 535 if (devfsadm_enumerate_int(path, RULE_INDEX, &buf, rules, 3)) { 536 return (NULL); 537 } 538 } 539 540 return (buf); 541 } 542 543 typedef struct dvlist { 544 char *dv_link; 545 struct dvlist *dv_next; 546 } dvlist_t; 547 548 static void 549 free_dvlist(dvlist_t **pp) 550 { 551 dvlist_t *entry; 552 553 while (*pp) { 554 entry = *pp; 555 *pp = entry->dv_next; 556 assert(entry->dv_link); 557 free(entry->dv_link); 558 free(entry); 559 } 560 } 561 static int 562 dvlink_cb(di_devlink_t devlink, void *arg) 563 { 564 char *path; 565 char *can_path; 566 dvlist_t **pp = (dvlist_t **)arg; 567 dvlist_t *entry = NULL; 568 569 entry = calloc(1, sizeof (dvlist_t)); 570 if (entry == NULL) { 571 devfsadm_errprint("%s: calloc failed\n", modname); 572 goto error; 573 } 574 575 path = (char *)di_devlink_path(devlink); 576 assert(path); 577 if (path == NULL) { 578 devfsadm_errprint("%s: di_devlink_path() returned NULL\n", 579 modname); 580 goto error; 581 } 582 583 devfsadm_print(disk_mid, "%s: found link %s in reverse link cache\n", 584 modname, path); 585 586 /* 587 * Return linkname in canonical form i.e. without the 588 * "/dev/" prefix 589 */ 590 can_path = strstr(path, "/dev/"); 591 if (can_path == NULL) { 592 devfsadm_errprint("%s: devlink path %s has no /dev/\n", 593 modname, path); 594 goto error; 595 } 596 597 entry->dv_link = s_strdup(can_path + strlen("/dev/")); 598 entry->dv_next = *pp; 599 *pp = entry; 600 601 return (DI_WALK_CONTINUE); 602 603 error: 604 free(entry); 605 free_dvlist(pp); 606 *pp = NULL; 607 return (DI_WALK_TERMINATE); 608 } 609 610 /* 611 * Returns success only if all goes well. If there is no matching reserved link 612 * or if there is an error, we assume no match. It is better to err on the side 613 * of caution by creating extra links than to miss out creating a required link. 614 */ 615 static int 616 reserved_links_exist(di_node_t node, di_minor_t minor, int nflags) 617 { 618 di_devlink_handle_t dvlink_cache = devfsadm_devlink_cache(); 619 char phys_path[PATH_MAX]; 620 char *minor_path; 621 dvlist_t *head; 622 dvlist_t *entry; 623 char *s; 624 char l[PATH_MAX]; 625 int switch_link = 0; 626 char *mn = di_minor_name(minor); 627 628 if (dvlink_cache == NULL || mn == NULL) { 629 devfsadm_errprint("%s: No minor or devlink cache\n", modname); 630 return (DEVFSADM_FAILURE); 631 } 632 633 if (!devfsadm_have_reserved()) { 634 devfsadm_print(disk_mid, "%s: No reserved links\n", modname); 635 return (DEVFSADM_FAILURE); 636 } 637 638 minor_path = di_devfs_minor_path(minor); 639 if (minor_path == NULL) { 640 devfsadm_errprint("%s: di_devfs_minor_path failed\n", modname); 641 return (DEVFSADM_FAILURE); 642 } 643 644 (void) strlcpy(phys_path, minor_path, sizeof (phys_path)); 645 646 di_devfs_path_free(minor_path); 647 648 head = NULL; 649 (void) di_devlink_cache_walk(dvlink_cache, DISK_LINK_RE, phys_path, 650 DI_PRIMARY_LINK, &head, dvlink_cb); 651 652 /* 653 * We may be switching between EFI label and SMI label in which case 654 * we only have minors of the other type. 655 */ 656 if (head == NULL && (*mn == *(MN_SMI) || 657 (strncmp(mn, MN_EFI, 2) == 0))) { 658 devfsadm_print(disk_mid, "%s: No links for minor %s in /dev. " 659 "Trying another label\n", modname, mn); 660 s = strrchr(phys_path, ':'); 661 if (s == NULL) { 662 devfsadm_errprint("%s: invalid minor path: %s\n", 663 modname, phys_path); 664 return (DEVFSADM_FAILURE); 665 } 666 (void) snprintf(s+1, sizeof (phys_path) - (s + 1 - phys_path), 667 "%s%s", *mn == *(MN_SMI) ? MN_EFI : MN_SMI, 668 strstr(s, ",raw") ? ",raw" : ""); 669 (void) di_devlink_cache_walk(dvlink_cache, DISK_LINK_RE, 670 phys_path, DI_PRIMARY_LINK, &head, dvlink_cb); 671 } 672 673 if (head == NULL) { 674 devfsadm_print(disk_mid, "%s: minor %s has no links in /dev\n", 675 modname, phys_path); 676 /* no links on disk */ 677 return (DEVFSADM_FAILURE); 678 } 679 680 /* 681 * It suffices to use 1 link to this minor, since 682 * we are matching with reserved IDs on the basis of 683 * the controller number which will be the same for 684 * all links to this minor. 685 */ 686 if (!devfsadm_is_reserved(disks_re_array, head->dv_link)) { 687 /* not reserved links */ 688 devfsadm_print(disk_mid, "%s: devlink %s and its minor " 689 "are NOT reserved\n", modname, head->dv_link); 690 free_dvlist(&head); 691 return (DEVFSADM_FAILURE); 692 } 693 694 devfsadm_print(disk_mid, "%s: devlink %s and its minor are on " 695 "reserved list\n", modname, head->dv_link); 696 697 /* 698 * Switch between SMI and EFI labels if required 699 */ 700 switch_link = 0; 701 if (*mn == *(MN_SMI) || (strncmp(mn, MN_EFI, 2) == 0)) { 702 for (entry = head; entry; entry = entry->dv_next) { 703 s = strrchr(entry->dv_link, '/'); 704 assert(s); 705 if (s == NULL) { 706 devfsadm_errprint("%s: disk link %s has no " 707 "directory\n", modname, entry->dv_link); 708 continue; 709 } 710 if (*mn == *(MN_SMI) && strchr(s, 's') == NULL) { 711 (void) snprintf(l, sizeof (l), "%s%s", 712 entry->dv_link, SLICE_SMI); 713 switch_link = 1; 714 devfsadm_print(disk_mid, "%s: switching " 715 "reserved link from EFI to SMI label. " 716 "New link is %s\n", modname, l); 717 } else if (strncmp(mn, MN_EFI, 2) == 0 && 718 (s = strchr(s, 's'))) { 719 *s = '\0'; 720 (void) snprintf(l, sizeof (l), "%s", 721 entry->dv_link); 722 *s = 's'; 723 switch_link = 1; 724 devfsadm_print(disk_mid, "%s: switching " 725 "reserved link from SMI to EFI label. " 726 "New link is %s\n", modname, l); 727 } 728 if (switch_link) { 729 devfsadm_print(disk_mid, "%s: switching " 730 "link: deleting %s and creating %s\n", 731 modname, entry->dv_link, l); 732 devfsadm_rm_link(entry->dv_link); 733 (void) devfsadm_mklink(l, node, minor, nflags); 734 } 735 } 736 } 737 free_dvlist(&head); 738 739 /* 740 * return SUCCESS to indicate that new links to this minor should not 741 * be created so that only compatibility links to this minor remain. 742 */ 743 return (DEVFSADM_SUCCESS); 744 } 745