10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51676Sjpk * Common Development and Distribution License (the "License"). 61676Sjpk * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*9249SJaven.Wu@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #include <devfsadm.h> 270Sstevel@tonic-gate #include <stdio.h> 280Sstevel@tonic-gate #include <strings.h> 290Sstevel@tonic-gate #include <stdlib.h> 300Sstevel@tonic-gate #include <limits.h> 316500Sjhd #include <ctype.h> 320Sstevel@tonic-gate #include <sys/stat.h> 331676Sjpk #include <bsm/devalloc.h> 340Sstevel@tonic-gate 350Sstevel@tonic-gate #define DISK_SUBPATH_MAX 100 360Sstevel@tonic-gate #define RM_STALE 0x01 370Sstevel@tonic-gate #define DISK_LINK_RE "^r?dsk/c[0-9]+(t[0-9A-F]+)?d[0-9]+(((s|p))[0-9]+)?$" 380Sstevel@tonic-gate #define DISK_LINK_TO_UPPER(ch)\ 390Sstevel@tonic-gate (((ch) >= 'a' && (ch) <= 'z') ? (ch - 'a' + 'A') : ch) 400Sstevel@tonic-gate 410Sstevel@tonic-gate #define SLICE_SMI "s7" 420Sstevel@tonic-gate #define SLICE_EFI "" 430Sstevel@tonic-gate 440Sstevel@tonic-gate #define MN_SMI "h" 450Sstevel@tonic-gate #define MN_EFI "wd" 460Sstevel@tonic-gate #define ASCIIWWNSIZE 255 470Sstevel@tonic-gate 481676Sjpk extern int system_labeled; 491676Sjpk 500Sstevel@tonic-gate static int disk_callback_chan(di_minor_t minor, di_node_t node); 510Sstevel@tonic-gate static int disk_callback_nchan(di_minor_t minor, di_node_t node); 520Sstevel@tonic-gate static int disk_callback_wwn(di_minor_t minor, di_node_t node); 536500Sjhd static int disk_callback_xvmd(di_minor_t minor, di_node_t node); 540Sstevel@tonic-gate static int disk_callback_fabric(di_minor_t minor, di_node_t node); 55*9249SJaven.Wu@Sun.COM static int disk_callback_sas(di_minor_t minor, di_node_t node); 560Sstevel@tonic-gate static void disk_common(di_minor_t minor, di_node_t node, char *disk, 570Sstevel@tonic-gate int flags); 580Sstevel@tonic-gate static char *diskctrl(di_node_t node, di_minor_t minor); 594876Smlf static int reserved_links_exist(di_node_t node, di_minor_t minor, int nflags); 600Sstevel@tonic-gate 610Sstevel@tonic-gate 620Sstevel@tonic-gate static devfsadm_create_t disk_cbt[] = { 630Sstevel@tonic-gate { "disk", "ddi_block", NULL, 640Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, disk_callback_nchan 650Sstevel@tonic-gate }, 660Sstevel@tonic-gate { "disk", "ddi_block:channel", NULL, 670Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, disk_callback_chan 680Sstevel@tonic-gate }, 690Sstevel@tonic-gate { "disk", "ddi_block:fabric", NULL, 700Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, disk_callback_fabric 710Sstevel@tonic-gate }, 720Sstevel@tonic-gate { "disk", "ddi_block:wwn", NULL, 730Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, disk_callback_wwn 740Sstevel@tonic-gate }, 75*9249SJaven.Wu@Sun.COM { "disk", "ddi_block:sas", NULL, 76*9249SJaven.Wu@Sun.COM TYPE_EXACT, ILEVEL_0, disk_callback_sas 77*9249SJaven.Wu@Sun.COM }, 780Sstevel@tonic-gate { "disk", "ddi_block:cdrom", NULL, 790Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, disk_callback_nchan 800Sstevel@tonic-gate }, 810Sstevel@tonic-gate { "disk", "ddi_block:cdrom:channel", NULL, 820Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, disk_callback_chan 830Sstevel@tonic-gate }, 846500Sjhd { "disk", "ddi_block:xvmd", NULL, 856500Sjhd TYPE_EXACT, ILEVEL_0, disk_callback_xvmd 866500Sjhd }, 876500Sjhd { "disk", "ddi_block:cdrom:xvmd", NULL, 886500Sjhd TYPE_EXACT, ILEVEL_0, disk_callback_xvmd 896500Sjhd }, 900Sstevel@tonic-gate }; 910Sstevel@tonic-gate 920Sstevel@tonic-gate DEVFSADM_CREATE_INIT_V0(disk_cbt); 930Sstevel@tonic-gate 940Sstevel@tonic-gate /* 950Sstevel@tonic-gate * HOT auto cleanup of disks not desired. 960Sstevel@tonic-gate */ 970Sstevel@tonic-gate static devfsadm_remove_t disk_remove_cbt[] = { 980Sstevel@tonic-gate { "disk", DISK_LINK_RE, RM_POST, 990Sstevel@tonic-gate ILEVEL_0, devfsadm_rm_all 1000Sstevel@tonic-gate } 1010Sstevel@tonic-gate }; 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate DEVFSADM_REMOVE_INIT_V0(disk_remove_cbt); 1040Sstevel@tonic-gate 1054876Smlf static devlink_re_t disks_re_array[] = { 1064876Smlf {"^r?dsk/c([0-9]+)", 1}, 1074876Smlf {"^cfg/c([0-9]+)$", 1}, 1084876Smlf {"^scsi/.+/c([0-9]+)", 1}, 1094876Smlf {NULL} 1104876Smlf }; 1114876Smlf 1124876Smlf static char *disk_mid = "disk_mid"; 1134876Smlf static char *modname = "disk_link"; 1144876Smlf 1154876Smlf int 1164876Smlf minor_init() 1174876Smlf { 1184876Smlf devfsadm_print(disk_mid, 1194876Smlf "%s: minor_init(): Creating disks reserved ID cache\n", 1204876Smlf modname); 1214876Smlf return (devfsadm_reserve_id_cache(disks_re_array, NULL)); 1224876Smlf } 1234876Smlf 1240Sstevel@tonic-gate static int 1250Sstevel@tonic-gate disk_callback_chan(di_minor_t minor, di_node_t node) 1260Sstevel@tonic-gate { 1270Sstevel@tonic-gate char *addr; 1280Sstevel@tonic-gate char disk[20]; 1290Sstevel@tonic-gate uint_t targ; 1300Sstevel@tonic-gate uint_t lun; 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate addr = di_bus_addr(node); 1330Sstevel@tonic-gate (void) sscanf(addr, "%X,%X", &targ, &lun); 1340Sstevel@tonic-gate (void) sprintf(disk, "t%dd%d", targ, lun); 1350Sstevel@tonic-gate disk_common(minor, node, disk, 0); 1360Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate static int 1410Sstevel@tonic-gate disk_callback_nchan(di_minor_t minor, di_node_t node) 1420Sstevel@tonic-gate { 1430Sstevel@tonic-gate char *addr; 1440Sstevel@tonic-gate char disk[10]; 1450Sstevel@tonic-gate uint_t lun; 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate addr = di_bus_addr(node); 1480Sstevel@tonic-gate (void) sscanf(addr, "%X", &lun); 1490Sstevel@tonic-gate (void) sprintf(disk, "d%d", lun); 1500Sstevel@tonic-gate disk_common(minor, node, disk, 0); 1510Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate static int 1560Sstevel@tonic-gate disk_callback_wwn(di_minor_t minor, di_node_t node) 1570Sstevel@tonic-gate { 1580Sstevel@tonic-gate char disk[10]; 1590Sstevel@tonic-gate int lun; 1600Sstevel@tonic-gate int targ; 1610Sstevel@tonic-gate int *intp; 1620Sstevel@tonic-gate 1636065Scth if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "target", &intp) <= 0) { 1640Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 1650Sstevel@tonic-gate } 1660Sstevel@tonic-gate targ = *intp; 1676065Scth if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "lun", &intp) <= 0) { 1686065Scth lun = 0; 1690Sstevel@tonic-gate } else { 1706065Scth lun = *intp; 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate (void) sprintf(disk, "t%dd%d", targ, lun); 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate disk_common(minor, node, disk, RM_STALE); 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 1770Sstevel@tonic-gate } 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate static int 1800Sstevel@tonic-gate disk_callback_fabric(di_minor_t minor, di_node_t node) 1810Sstevel@tonic-gate { 1820Sstevel@tonic-gate char disk[DISK_SUBPATH_MAX]; 1830Sstevel@tonic-gate int lun; 1840Sstevel@tonic-gate int count; 1850Sstevel@tonic-gate int *intp; 1860Sstevel@tonic-gate uchar_t *str; 1870Sstevel@tonic-gate uchar_t *wwn; 1880Sstevel@tonic-gate uchar_t ascii_wwn[ASCIIWWNSIZE]; 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 1910Sstevel@tonic-gate "client-guid", (char **)&wwn) > 0) { 1926065Scth if (strlcpy((char *)ascii_wwn, (char *)wwn, 1936065Scth sizeof (ascii_wwn)) >= sizeof (ascii_wwn)) { 1940Sstevel@tonic-gate devfsadm_errprint("SUNW_disk_link: GUID too long:%d", 1956065Scth strlen((char *)wwn)); 1960Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 1970Sstevel@tonic-gate } 1980Sstevel@tonic-gate lun = 0; 1990Sstevel@tonic-gate } else if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, 2000Sstevel@tonic-gate "port-wwn", &wwn) > 0) { 2010Sstevel@tonic-gate if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 2020Sstevel@tonic-gate "lun", &intp) > 0) { 2030Sstevel@tonic-gate lun = *intp; 2040Sstevel@tonic-gate } else { 2050Sstevel@tonic-gate lun = 0; 2060Sstevel@tonic-gate } 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate for (count = 0, str = ascii_wwn; count < 8; count++, str += 2) { 2090Sstevel@tonic-gate (void) sprintf((caddr_t)str, "%02x", wwn[count]); 2100Sstevel@tonic-gate } 2110Sstevel@tonic-gate *str = '\0'; 2120Sstevel@tonic-gate } else { 2130Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate for (str = ascii_wwn; *str != '\0'; str++) { 2170Sstevel@tonic-gate *str = DISK_LINK_TO_UPPER(*str); 2180Sstevel@tonic-gate } 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate (void) snprintf(disk, DISK_SUBPATH_MAX, "t%sd%d", ascii_wwn, lun); 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate disk_common(minor, node, disk, RM_STALE); 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate 227*9249SJaven.Wu@Sun.COM static int 228*9249SJaven.Wu@Sun.COM disk_callback_sas(di_minor_t minor, di_node_t node) 229*9249SJaven.Wu@Sun.COM { 230*9249SJaven.Wu@Sun.COM char disk[DISK_SUBPATH_MAX]; 231*9249SJaven.Wu@Sun.COM int lun; 232*9249SJaven.Wu@Sun.COM int *intp; 233*9249SJaven.Wu@Sun.COM char *str; 234*9249SJaven.Wu@Sun.COM char *wwn; 235*9249SJaven.Wu@Sun.COM 236*9249SJaven.Wu@Sun.COM /* 237*9249SJaven.Wu@Sun.COM * get LUN property 238*9249SJaven.Wu@Sun.COM */ 239*9249SJaven.Wu@Sun.COM if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 240*9249SJaven.Wu@Sun.COM "lun", &intp) > 0) { 241*9249SJaven.Wu@Sun.COM lun = *intp; 242*9249SJaven.Wu@Sun.COM } else { 243*9249SJaven.Wu@Sun.COM lun = 0; 244*9249SJaven.Wu@Sun.COM } 245*9249SJaven.Wu@Sun.COM if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 246*9249SJaven.Wu@Sun.COM "target-port", &wwn) > 0) { 247*9249SJaven.Wu@Sun.COM /* 248*9249SJaven.Wu@Sun.COM * If the target-port property exist 249*9249SJaven.Wu@Sun.COM * we use wwn format naming 250*9249SJaven.Wu@Sun.COM */ 251*9249SJaven.Wu@Sun.COM for (str = wwn; *str != '\0'; str++) { 252*9249SJaven.Wu@Sun.COM *str = DISK_LINK_TO_UPPER(*str); 253*9249SJaven.Wu@Sun.COM } 254*9249SJaven.Wu@Sun.COM (void) snprintf(disk, DISK_SUBPATH_MAX, "t%sd%d", wwn, lun); 255*9249SJaven.Wu@Sun.COM 256*9249SJaven.Wu@Sun.COM } else if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 257*9249SJaven.Wu@Sun.COM "sata-phy", &intp) > 0) { 258*9249SJaven.Wu@Sun.COM /* 259*9249SJaven.Wu@Sun.COM * For direct attached SATA device without Device Name, 260*9249SJaven.Wu@Sun.COM * no wwn exist, we use phy format naming 261*9249SJaven.Wu@Sun.COM */ 262*9249SJaven.Wu@Sun.COM (void) snprintf(disk, DISK_SUBPATH_MAX, "t%dd%d", *intp, lun); 263*9249SJaven.Wu@Sun.COM } else { 264*9249SJaven.Wu@Sun.COM return (DEVFSADM_CONTINUE); 265*9249SJaven.Wu@Sun.COM } 266*9249SJaven.Wu@Sun.COM 267*9249SJaven.Wu@Sun.COM disk_common(minor, node, disk, RM_STALE); 268*9249SJaven.Wu@Sun.COM 269*9249SJaven.Wu@Sun.COM return (DEVFSADM_CONTINUE); 270*9249SJaven.Wu@Sun.COM } 271*9249SJaven.Wu@Sun.COM 2720Sstevel@tonic-gate /* 2736500Sjhd * xVM virtual block device 2746500Sjhd * 2756500Sjhd * VBDs are enumerated into xenstore by xend and named using 2766500Sjhd * the linux dev_t values for 'hd' and 'xvd' devices. Linux 2776500Sjhd * dev_t's are 16-bit values. The upper 8 bits identify the major # 2786500Sjhd * of the device (hd, xvd) and the lower 8 bits the instance and partition 2796500Sjhd * 2806500Sjhd * For PV guests, VBDs are named by the virt-tools using 2816500Sjhd * the form xvd[a-p][1-15]. The corresponding Solaris /dev/dsk name 2826500Sjhd * created by this generator will be c0t[0-15]d[0-15]sN, 2836500Sjhd * were the target (t) value represents [a-p] and the 2846500Sjhd * disk (d) value is either 0 (e.g. xvda) or contains the partition 2856500Sjhd * information if it has been specified [1-15] (e.g. xvda1) 2866500Sjhd * 2876500Sjhd * For PV guests using the legacy naming (0, 1, 2, ...) 2886500Sjhd * the Solaris disk names created will be c0d[0..767]sN 2896500Sjhd * The Solaris version of virt-install based on virtinst.101 2906500Sjhd * named PV disks as sequential integers. With virtinst.300_1 and 2916500Sjhd * beyond, the virt-* tools will no longer create legacy disk 2926500Sjhd * names. 2936500Sjhd */ 2946500Sjhd static int 2956500Sjhd disk_callback_xvmd(di_minor_t minor, di_node_t node) 2966500Sjhd { 2976500Sjhd #define HD_BASE (3 << 8) 2986500Sjhd #define XVBDMAJ 202 2996500Sjhd 3006500Sjhd char *addr; 3016500Sjhd char disk[16]; 3026500Sjhd uint_t targ; 3036500Sjhd uint_t lun = 0; 3046500Sjhd uint_t fmaj; 3056500Sjhd 3066500Sjhd addr = di_bus_addr(node); 3076500Sjhd targ = strtol(addr, (char **)NULL, 10); 3086500Sjhd fmaj = targ >> 8; 3096500Sjhd 3106500Sjhd /* legacy device address */ 3116500Sjhd if (targ < HD_BASE) 3126500Sjhd (void) snprintf(disk, sizeof (disk), "d%d", targ); 3136500Sjhd /* PV VBD */ 3146500Sjhd else if (fmaj == XVBDMAJ) { 3156500Sjhd lun = targ & 0xf; 3166500Sjhd targ = (targ & 0xff) >> 4; 3176500Sjhd (void) snprintf(disk, sizeof (disk), "t%dd%d", targ, lun); 3186500Sjhd /* HVM device names are generated using the standard generator */ 3196500Sjhd } else { 3206500Sjhd devfsadm_errprint("%s: invalid disk device number (%s)\n", 3216500Sjhd modname, addr); 3226500Sjhd return (DEVFSADM_CONTINUE); 3236500Sjhd } 3246500Sjhd disk_common(minor, node, disk, 0); 3256500Sjhd return (DEVFSADM_CONTINUE); 3266500Sjhd 3276500Sjhd } 3286500Sjhd 3296500Sjhd /* 3300Sstevel@tonic-gate * This function is called for every disk minor node. 3310Sstevel@tonic-gate * Calls enumerate to assign a logical controller number, and 3320Sstevel@tonic-gate * then devfsadm_mklink to make the link. 3330Sstevel@tonic-gate */ 3340Sstevel@tonic-gate static void 3350Sstevel@tonic-gate disk_common(di_minor_t minor, di_node_t node, char *disk, int flags) 3360Sstevel@tonic-gate { 3370Sstevel@tonic-gate char l_path[PATH_MAX + 1]; 3382912Sartem char sec_path[PATH_MAX + 1]; 3390Sstevel@tonic-gate char stale_re[DISK_SUBPATH_MAX]; 3400Sstevel@tonic-gate char *dir; 3410Sstevel@tonic-gate char slice[4]; 3420Sstevel@tonic-gate char *mn; 3430Sstevel@tonic-gate char *ctrl; 3441676Sjpk char *nt = NULL; 3452912Sartem int *int_prop; 3461676Sjpk int nflags = 0; 3470Sstevel@tonic-gate 3488333SSuhasini.Peddada@Sun.COM if (strstr(mn = di_minor_name(minor), ",raw")) { 3490Sstevel@tonic-gate dir = "rdsk"; 3500Sstevel@tonic-gate } else { 3510Sstevel@tonic-gate dir = "dsk"; 3520Sstevel@tonic-gate } 3530Sstevel@tonic-gate 3548333SSuhasini.Peddada@Sun.COM if (mn[0] < 113) { 3550Sstevel@tonic-gate (void) sprintf(slice, "s%d", mn[0] - 'a'); 3560Sstevel@tonic-gate } else if (strncmp(mn, MN_EFI, 2) != 0) { 3570Sstevel@tonic-gate (void) sprintf(slice, "p%d", mn[0] - 'q'); 3580Sstevel@tonic-gate } else { 3590Sstevel@tonic-gate /* For EFI label */ 3600Sstevel@tonic-gate (void) sprintf(slice, SLICE_EFI); 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate 3634876Smlf nflags = 0; 3644876Smlf if (system_labeled) { 3654876Smlf nt = di_minor_nodetype(minor); 3664876Smlf if ((nt != NULL) && 3674876Smlf ((strcmp(nt, DDI_NT_CD) == 0) || 3684876Smlf (strcmp(nt, DDI_NT_CD_CHAN) == 0) || 3694876Smlf (strcmp(nt, DDI_NT_BLOCK_CHAN) == 0))) { 3704876Smlf nflags = DA_ADD|DA_CD; 3714876Smlf } 3724876Smlf } 3734876Smlf 3744876Smlf if (reserved_links_exist(node, minor, nflags) == DEVFSADM_SUCCESS) { 3754876Smlf devfsadm_print(disk_mid, "Reserved link exists. Not " 3764876Smlf "creating links for slice %s\n", slice); 3774876Smlf return; 3784876Smlf } 3794876Smlf 3800Sstevel@tonic-gate if (NULL == (ctrl = diskctrl(node, minor))) 3810Sstevel@tonic-gate return; 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate (void) strcpy(l_path, dir); 3840Sstevel@tonic-gate (void) strcat(l_path, "/c"); 3850Sstevel@tonic-gate (void) strcat(l_path, ctrl); 3860Sstevel@tonic-gate (void) strcat(l_path, disk); 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate /* 3890Sstevel@tonic-gate * If switching between SMI and EFI label or vice versa 3900Sstevel@tonic-gate * cleanup the previous label's devlinks. 3910Sstevel@tonic-gate */ 3920Sstevel@tonic-gate if (*mn == *(MN_SMI) || (strncmp(mn, MN_EFI, 2) == 0)) { 3930Sstevel@tonic-gate char *s, tpath[PATH_MAX + 1]; 3940Sstevel@tonic-gate struct stat sb; 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate s = l_path + strlen(l_path); 3970Sstevel@tonic-gate (void) strcat(l_path, (*mn == *(MN_SMI)) 3980Sstevel@tonic-gate ? SLICE_EFI : SLICE_SMI); 3990Sstevel@tonic-gate /* 4000Sstevel@tonic-gate * Attempt the remove only if the stale link exists 4010Sstevel@tonic-gate */ 4020Sstevel@tonic-gate (void) snprintf(tpath, sizeof (tpath), "%s/dev/%s", 4030Sstevel@tonic-gate devfsadm_root_path(), l_path); 4040Sstevel@tonic-gate if (lstat(tpath, &sb) != -1) 4050Sstevel@tonic-gate devfsadm_rm_all(l_path); 4060Sstevel@tonic-gate *s = '\0'; 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate (void) strcat(l_path, slice); 4090Sstevel@tonic-gate 4101676Sjpk (void) devfsadm_mklink(l_path, node, minor, nflags); 4110Sstevel@tonic-gate 4122912Sartem /* secondary links for removable and hotpluggable devices */ 4132912Sartem if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "removable-media", 4142912Sartem &int_prop) >= 0) { 4152912Sartem (void) strcpy(sec_path, "removable-media/"); 4162912Sartem (void) strcat(sec_path, l_path); 4172912Sartem (void) devfsadm_secondary_link(sec_path, l_path, 0); 4183020Sartem } 4193020Sartem if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "hotpluggable", 4202912Sartem &int_prop) >= 0) { 4212912Sartem (void) strcpy(sec_path, "hotpluggable/"); 4222912Sartem (void) strcat(sec_path, l_path); 4232912Sartem (void) devfsadm_secondary_link(sec_path, l_path, 0); 4242912Sartem } 4252912Sartem 4260Sstevel@tonic-gate if ((flags & RM_STALE) == RM_STALE) { 4270Sstevel@tonic-gate (void) strcpy(stale_re, "^"); 4280Sstevel@tonic-gate (void) strcat(stale_re, dir); 4290Sstevel@tonic-gate (void) strcat(stale_re, "/c"); 4300Sstevel@tonic-gate (void) strcat(stale_re, ctrl); 4310Sstevel@tonic-gate (void) strcat(stale_re, "t[0-9A-F]+d[0-9]+(s[0-9]+)?$"); 4320Sstevel@tonic-gate /* 4330Sstevel@tonic-gate * optimizations are made inside of devfsadm_rm_stale_links 4340Sstevel@tonic-gate * instead of before calling the function, as it always 4350Sstevel@tonic-gate * needs to add the valid link to the cache. 4360Sstevel@tonic-gate */ 4370Sstevel@tonic-gate devfsadm_rm_stale_links(stale_re, l_path, node, minor); 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate free(ctrl); 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate /* index of enumeration rule applicable to this module */ 4450Sstevel@tonic-gate #define RULE_INDEX 0 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate static char * 4480Sstevel@tonic-gate diskctrl(di_node_t node, di_minor_t minor) 4490Sstevel@tonic-gate { 4500Sstevel@tonic-gate char path[PATH_MAX + 1]; 4510Sstevel@tonic-gate char *devfspath; 4520Sstevel@tonic-gate char *buf, *mn; 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate devfsadm_enumerate_t rules[3] = { 4550Sstevel@tonic-gate {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT}, 4560Sstevel@tonic-gate {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR}, 4570Sstevel@tonic-gate {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT} 4580Sstevel@tonic-gate }; 4590Sstevel@tonic-gate 4600Sstevel@tonic-gate mn = di_minor_name(minor); 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate if ((devfspath = di_devfs_path(node)) == NULL) { 4630Sstevel@tonic-gate return (NULL); 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate (void) strcpy(path, devfspath); 4660Sstevel@tonic-gate (void) strcat(path, ":"); 4670Sstevel@tonic-gate (void) strcat(path, mn); 4680Sstevel@tonic-gate di_devfs_path_free(devfspath); 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate /* 4710Sstevel@tonic-gate * Use controller component of disk path 4720Sstevel@tonic-gate */ 4730Sstevel@tonic-gate if (disk_enumerate_int(path, RULE_INDEX, &buf, rules, 3) == 4740Sstevel@tonic-gate DEVFSADM_MULTIPLE) { 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate /* 4770Sstevel@tonic-gate * We failed because there are multiple logical controller 4780Sstevel@tonic-gate * numbers for a single physical controller. If we use node 4790Sstevel@tonic-gate * name also in the match it should fix this and only find one 4800Sstevel@tonic-gate * logical controller. (See 4045879). 4810Sstevel@tonic-gate * NOTE: Rules for controllers are not changed, as there is 4820Sstevel@tonic-gate * no unique controller number for them in this case. 4830Sstevel@tonic-gate * 4840Sstevel@tonic-gate * MATCH_UNCACHED flag is private to the "disks" and "sgen" 4850Sstevel@tonic-gate * modules. NOT to be used by other modules. 4860Sstevel@tonic-gate */ 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate rules[0].flags = MATCH_NODE | MATCH_UNCACHED; /* disks */ 4890Sstevel@tonic-gate rules[2].flags = MATCH_NODE | MATCH_UNCACHED; /* generic scsi */ 4900Sstevel@tonic-gate if (devfsadm_enumerate_int(path, RULE_INDEX, &buf, rules, 3)) { 4910Sstevel@tonic-gate return (NULL); 4920Sstevel@tonic-gate } 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate return (buf); 4960Sstevel@tonic-gate } 4974876Smlf 4984876Smlf typedef struct dvlist { 4994876Smlf char *dv_link; 5004876Smlf struct dvlist *dv_next; 5014876Smlf } dvlist_t; 5024876Smlf 5034876Smlf static void 5044876Smlf free_dvlist(dvlist_t **pp) 5054876Smlf { 5064876Smlf dvlist_t *entry; 5074876Smlf 5084876Smlf while (*pp) { 5094876Smlf entry = *pp; 5104876Smlf *pp = entry->dv_next; 5114876Smlf assert(entry->dv_link); 5124876Smlf free(entry->dv_link); 5134876Smlf free(entry); 5144876Smlf } 5154876Smlf } 5164876Smlf static int 5174876Smlf dvlink_cb(di_devlink_t devlink, void *arg) 5184876Smlf { 5194876Smlf char *path; 5204876Smlf char *can_path; 5214876Smlf dvlist_t **pp = (dvlist_t **)arg; 5224876Smlf dvlist_t *entry = NULL; 5234876Smlf 5244876Smlf entry = calloc(1, sizeof (dvlist_t)); 5254876Smlf if (entry == NULL) { 5264876Smlf devfsadm_errprint("%s: calloc failed\n", modname); 5274876Smlf goto error; 5284876Smlf } 5294876Smlf 5304876Smlf path = (char *)di_devlink_path(devlink); 5314876Smlf assert(path); 5324876Smlf if (path == NULL) { 5334876Smlf devfsadm_errprint("%s: di_devlink_path() returned NULL\n", 5344876Smlf modname); 5354876Smlf goto error; 5364876Smlf } 5374876Smlf 5384876Smlf devfsadm_print(disk_mid, "%s: found link %s in reverse link cache\n", 5394876Smlf modname, path); 5404876Smlf 5414876Smlf /* 5424876Smlf * Return linkname in canonical form i.e. without the 5434876Smlf * "/dev/" prefix 5444876Smlf */ 5454876Smlf can_path = strstr(path, "/dev/"); 5464876Smlf if (can_path == NULL) { 5474876Smlf devfsadm_errprint("%s: devlink path %s has no /dev/\n", 5484876Smlf modname, path); 5494876Smlf goto error; 5504876Smlf } 5514876Smlf 5524876Smlf entry->dv_link = s_strdup(can_path + strlen("/dev/")); 5534876Smlf entry->dv_next = *pp; 5544876Smlf *pp = entry; 5554876Smlf 5564876Smlf return (DI_WALK_CONTINUE); 5574876Smlf 5584876Smlf error: 5594876Smlf free(entry); 5604876Smlf free_dvlist(pp); 5614876Smlf *pp = NULL; 5624876Smlf return (DI_WALK_TERMINATE); 5634876Smlf } 5644876Smlf 5654876Smlf /* 5664876Smlf * Returns success only if all goes well. If there is no matching reserved link 5674876Smlf * or if there is an error, we assume no match. It is better to err on the side 5684876Smlf * of caution by creating extra links than to miss out creating a required link. 5694876Smlf */ 5704876Smlf static int 5714876Smlf reserved_links_exist(di_node_t node, di_minor_t minor, int nflags) 5724876Smlf { 5734876Smlf di_devlink_handle_t dvlink_cache = devfsadm_devlink_cache(); 5744876Smlf char phys_path[PATH_MAX]; 5754876Smlf char *minor_path; 5764876Smlf dvlist_t *head; 5774876Smlf dvlist_t *entry; 5784876Smlf char *s; 5794876Smlf char l[PATH_MAX]; 5804876Smlf int switch_link = 0; 5814876Smlf char *mn = di_minor_name(minor); 5824876Smlf 5834876Smlf if (dvlink_cache == NULL || mn == NULL) { 5844876Smlf devfsadm_errprint("%s: No minor or devlink cache\n", modname); 5854876Smlf return (DEVFSADM_FAILURE); 5864876Smlf } 5874876Smlf 5886065Scth if (!devfsadm_have_reserved()) { 5896065Scth devfsadm_print(disk_mid, "%s: No reserved links\n", modname); 5904876Smlf return (DEVFSADM_FAILURE); 5914876Smlf } 5924876Smlf 5934876Smlf minor_path = di_devfs_minor_path(minor); 5944876Smlf if (minor_path == NULL) { 5954876Smlf devfsadm_errprint("%s: di_devfs_minor_path failed\n", modname); 5964876Smlf return (DEVFSADM_FAILURE); 5974876Smlf } 5984876Smlf 5994876Smlf (void) strlcpy(phys_path, minor_path, sizeof (phys_path)); 6004876Smlf 6014876Smlf di_devfs_path_free(minor_path); 6024876Smlf 6034876Smlf head = NULL; 6044876Smlf (void) di_devlink_cache_walk(dvlink_cache, DISK_LINK_RE, phys_path, 6054876Smlf DI_PRIMARY_LINK, &head, dvlink_cb); 6064876Smlf 6074876Smlf /* 6084876Smlf * We may be switching between EFI label and SMI label in which case 6094876Smlf * we only have minors of the other type. 6104876Smlf */ 6114876Smlf if (head == NULL && (*mn == *(MN_SMI) || 6124876Smlf (strncmp(mn, MN_EFI, 2) == 0))) { 6134876Smlf devfsadm_print(disk_mid, "%s: No links for minor %s in /dev. " 6144876Smlf "Trying another label\n", modname, mn); 6154876Smlf s = strrchr(phys_path, ':'); 6164876Smlf if (s == NULL) { 6174876Smlf devfsadm_errprint("%s: invalid minor path: %s\n", 6184876Smlf modname, phys_path); 6194876Smlf return (DEVFSADM_FAILURE); 6204876Smlf } 6214876Smlf (void) snprintf(s+1, sizeof (phys_path) - (s + 1 - phys_path), 6226065Scth "%s%s", *mn == *(MN_SMI) ? MN_EFI : MN_SMI, 6236065Scth strstr(s, ",raw") ? ",raw" : ""); 6244876Smlf (void) di_devlink_cache_walk(dvlink_cache, DISK_LINK_RE, 6254876Smlf phys_path, DI_PRIMARY_LINK, &head, dvlink_cb); 6264876Smlf } 6274876Smlf 6284876Smlf if (head == NULL) { 6294876Smlf devfsadm_print(disk_mid, "%s: minor %s has no links in /dev\n", 6304876Smlf modname, phys_path); 6314876Smlf /* no links on disk */ 6324876Smlf return (DEVFSADM_FAILURE); 6334876Smlf } 6344876Smlf 6354876Smlf /* 6364876Smlf * It suffices to use 1 link to this minor, since 6374876Smlf * we are matching with reserved IDs on the basis of 6384876Smlf * the controller number which will be the same for 6394876Smlf * all links to this minor. 6404876Smlf */ 6414876Smlf if (!devfsadm_is_reserved(disks_re_array, head->dv_link)) { 6424876Smlf /* not reserved links */ 6434876Smlf devfsadm_print(disk_mid, "%s: devlink %s and its minor " 6444876Smlf "are NOT reserved\n", modname, head->dv_link); 6454876Smlf free_dvlist(&head); 6464876Smlf return (DEVFSADM_FAILURE); 6474876Smlf } 6484876Smlf 6494876Smlf devfsadm_print(disk_mid, "%s: devlink %s and its minor are on " 6504876Smlf "reserved list\n", modname, head->dv_link); 6514876Smlf 6524876Smlf /* 6534876Smlf * Switch between SMI and EFI labels if required 6544876Smlf */ 6554876Smlf switch_link = 0; 6564876Smlf if (*mn == *(MN_SMI) || (strncmp(mn, MN_EFI, 2) == 0)) { 6574876Smlf for (entry = head; entry; entry = entry->dv_next) { 6584876Smlf s = strrchr(entry->dv_link, '/'); 6594876Smlf assert(s); 6604876Smlf if (s == NULL) { 6614876Smlf devfsadm_errprint("%s: disk link %s has no " 6624876Smlf "directory\n", modname, entry->dv_link); 6634876Smlf continue; 6644876Smlf } 6654876Smlf if (*mn == *(MN_SMI) && strchr(s, 's') == NULL) { 6664876Smlf (void) snprintf(l, sizeof (l), "%s%s", 6674876Smlf entry->dv_link, SLICE_SMI); 6684876Smlf switch_link = 1; 6694876Smlf devfsadm_print(disk_mid, "%s: switching " 6704876Smlf "reserved link from EFI to SMI label. " 6714876Smlf "New link is %s\n", modname, l); 6724876Smlf } else if (strncmp(mn, MN_EFI, 2) == 0 && 6734876Smlf (s = strchr(s, 's'))) { 6744876Smlf *s = '\0'; 6754876Smlf (void) snprintf(l, sizeof (l), "%s", 6764876Smlf entry->dv_link); 6774876Smlf *s = 's'; 6784876Smlf switch_link = 1; 6794876Smlf devfsadm_print(disk_mid, "%s: switching " 6804876Smlf "reserved link from SMI to EFI label. " 6814876Smlf "New link is %s\n", modname, l); 6824876Smlf } 6834876Smlf if (switch_link) { 6844876Smlf devfsadm_print(disk_mid, "%s: switching " 6854876Smlf "link: deleting %s and creating %s\n", 6864876Smlf modname, entry->dv_link, l); 6874876Smlf devfsadm_rm_link(entry->dv_link); 6884876Smlf (void) devfsadm_mklink(l, node, minor, nflags); 6894876Smlf } 6904876Smlf } 6914876Smlf } 6924876Smlf free_dvlist(&head); 6934876Smlf 6944876Smlf /* 6954876Smlf * return SUCCESS to indicate that new links to this minor should not 6964876Smlf * be created so that only compatibility links to this minor remain. 6974876Smlf */ 6984876Smlf return (DEVFSADM_SUCCESS); 6994876Smlf } 700