1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <devfsadm.h> 30*0Sstevel@tonic-gate #include <stdio.h> 31*0Sstevel@tonic-gate #include <strings.h> 32*0Sstevel@tonic-gate #include <stdlib.h> 33*0Sstevel@tonic-gate #include <limits.h> 34*0Sstevel@tonic-gate #include <sys/stat.h> 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gate #define DISK_SUBPATH_MAX 100 37*0Sstevel@tonic-gate #define RM_STALE 0x01 38*0Sstevel@tonic-gate #define DISK_LINK_RE "^r?dsk/c[0-9]+(t[0-9A-F]+)?d[0-9]+(((s|p))[0-9]+)?$" 39*0Sstevel@tonic-gate #define DISK_LINK_TO_UPPER(ch)\ 40*0Sstevel@tonic-gate (((ch) >= 'a' && (ch) <= 'z') ? (ch - 'a' + 'A') : ch) 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate #define SLICE_SMI "s7" 43*0Sstevel@tonic-gate #define SLICE_EFI "" 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate #define MN_SMI "h" 46*0Sstevel@tonic-gate #define MN_EFI "wd" 47*0Sstevel@tonic-gate #define ASCIIWWNSIZE 255 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate static int disk_callback_chan(di_minor_t minor, di_node_t node); 50*0Sstevel@tonic-gate static int disk_callback_nchan(di_minor_t minor, di_node_t node); 51*0Sstevel@tonic-gate static int disk_callback_wwn(di_minor_t minor, di_node_t node); 52*0Sstevel@tonic-gate static int disk_callback_fabric(di_minor_t minor, di_node_t node); 53*0Sstevel@tonic-gate static void disk_common(di_minor_t minor, di_node_t node, char *disk, 54*0Sstevel@tonic-gate int flags); 55*0Sstevel@tonic-gate static char *diskctrl(di_node_t node, di_minor_t minor); 56*0Sstevel@tonic-gate extern void rm_link_from_cache(char *devlink, char *physpath); 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate static devfsadm_create_t disk_cbt[] = { 60*0Sstevel@tonic-gate { "disk", "ddi_block", NULL, 61*0Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, disk_callback_nchan 62*0Sstevel@tonic-gate }, 63*0Sstevel@tonic-gate { "disk", "ddi_block:channel", NULL, 64*0Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, disk_callback_chan 65*0Sstevel@tonic-gate }, 66*0Sstevel@tonic-gate { "disk", "ddi_block:fabric", NULL, 67*0Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, disk_callback_fabric 68*0Sstevel@tonic-gate }, 69*0Sstevel@tonic-gate { "disk", "ddi_block:wwn", NULL, 70*0Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, disk_callback_wwn 71*0Sstevel@tonic-gate }, 72*0Sstevel@tonic-gate { "disk", "ddi_block:cdrom", NULL, 73*0Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, disk_callback_nchan 74*0Sstevel@tonic-gate }, 75*0Sstevel@tonic-gate { "disk", "ddi_block:cdrom:channel", NULL, 76*0Sstevel@tonic-gate TYPE_EXACT, ILEVEL_0, disk_callback_chan 77*0Sstevel@tonic-gate }, 78*0Sstevel@tonic-gate }; 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate DEVFSADM_CREATE_INIT_V0(disk_cbt); 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate /* 83*0Sstevel@tonic-gate * HOT auto cleanup of disks not desired. 84*0Sstevel@tonic-gate */ 85*0Sstevel@tonic-gate static devfsadm_remove_t disk_remove_cbt[] = { 86*0Sstevel@tonic-gate { "disk", DISK_LINK_RE, RM_POST, 87*0Sstevel@tonic-gate ILEVEL_0, devfsadm_rm_all 88*0Sstevel@tonic-gate } 89*0Sstevel@tonic-gate }; 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate DEVFSADM_REMOVE_INIT_V0(disk_remove_cbt); 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate static int 94*0Sstevel@tonic-gate disk_callback_chan(di_minor_t minor, di_node_t node) 95*0Sstevel@tonic-gate { 96*0Sstevel@tonic-gate char *addr; 97*0Sstevel@tonic-gate char disk[20]; 98*0Sstevel@tonic-gate uint_t targ; 99*0Sstevel@tonic-gate uint_t lun; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate addr = di_bus_addr(node); 102*0Sstevel@tonic-gate (void) sscanf(addr, "%X,%X", &targ, &lun); 103*0Sstevel@tonic-gate (void) sprintf(disk, "t%dd%d", targ, lun); 104*0Sstevel@tonic-gate disk_common(minor, node, disk, 0); 105*0Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate } 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate static int 110*0Sstevel@tonic-gate disk_callback_nchan(di_minor_t minor, di_node_t node) 111*0Sstevel@tonic-gate { 112*0Sstevel@tonic-gate char *addr; 113*0Sstevel@tonic-gate char disk[10]; 114*0Sstevel@tonic-gate uint_t lun; 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate addr = di_bus_addr(node); 117*0Sstevel@tonic-gate (void) sscanf(addr, "%X", &lun); 118*0Sstevel@tonic-gate (void) sprintf(disk, "d%d", lun); 119*0Sstevel@tonic-gate disk_common(minor, node, disk, 0); 120*0Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate } 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate static int 125*0Sstevel@tonic-gate disk_callback_wwn(di_minor_t minor, di_node_t node) 126*0Sstevel@tonic-gate { 127*0Sstevel@tonic-gate char disk[10]; 128*0Sstevel@tonic-gate int lun; 129*0Sstevel@tonic-gate int targ; 130*0Sstevel@tonic-gate int *intp; 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gate if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 133*0Sstevel@tonic-gate "target", &intp) <= 0) { 134*0Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 135*0Sstevel@tonic-gate } 136*0Sstevel@tonic-gate targ = *intp; 137*0Sstevel@tonic-gate if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 138*0Sstevel@tonic-gate "lun", &intp) <= 0) { 139*0Sstevel@tonic-gate lun = 0; 140*0Sstevel@tonic-gate } else { 141*0Sstevel@tonic-gate lun = *intp; 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate (void) sprintf(disk, "t%dd%d", targ, lun); 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate disk_common(minor, node, disk, RM_STALE); 146*0Sstevel@tonic-gate 147*0Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 148*0Sstevel@tonic-gate } 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate static int 151*0Sstevel@tonic-gate disk_callback_fabric(di_minor_t minor, di_node_t node) 152*0Sstevel@tonic-gate { 153*0Sstevel@tonic-gate char disk[DISK_SUBPATH_MAX]; 154*0Sstevel@tonic-gate int lun; 155*0Sstevel@tonic-gate int count; 156*0Sstevel@tonic-gate int *intp; 157*0Sstevel@tonic-gate uchar_t *str; 158*0Sstevel@tonic-gate uchar_t *wwn; 159*0Sstevel@tonic-gate uchar_t ascii_wwn[ASCIIWWNSIZE]; 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, 162*0Sstevel@tonic-gate "client-guid", (char **)&wwn) > 0) { 163*0Sstevel@tonic-gate if (strlcpy((char *)ascii_wwn, (char *)wwn, sizeof (ascii_wwn)) 164*0Sstevel@tonic-gate >= sizeof (ascii_wwn)) { 165*0Sstevel@tonic-gate devfsadm_errprint("SUNW_disk_link: GUID too long:%d", 166*0Sstevel@tonic-gate strlen((char *)wwn)); 167*0Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate lun = 0; 170*0Sstevel@tonic-gate } else if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node, 171*0Sstevel@tonic-gate "port-wwn", &wwn) > 0) { 172*0Sstevel@tonic-gate if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, 173*0Sstevel@tonic-gate "lun", &intp) > 0) { 174*0Sstevel@tonic-gate lun = *intp; 175*0Sstevel@tonic-gate } else { 176*0Sstevel@tonic-gate lun = 0; 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate for (count = 0, str = ascii_wwn; count < 8; count++, str += 2) { 180*0Sstevel@tonic-gate (void) sprintf((caddr_t)str, "%02x", wwn[count]); 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate *str = '\0'; 183*0Sstevel@tonic-gate } else { 184*0Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate for (str = ascii_wwn; *str != '\0'; str++) { 188*0Sstevel@tonic-gate *str = DISK_LINK_TO_UPPER(*str); 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gate (void) snprintf(disk, DISK_SUBPATH_MAX, "t%sd%d", ascii_wwn, lun); 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate disk_common(minor, node, disk, RM_STALE); 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate return (DEVFSADM_CONTINUE); 196*0Sstevel@tonic-gate } 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate /* 199*0Sstevel@tonic-gate * This function is called for every disk minor node. 200*0Sstevel@tonic-gate * Calls enumerate to assign a logical controller number, and 201*0Sstevel@tonic-gate * then devfsadm_mklink to make the link. 202*0Sstevel@tonic-gate */ 203*0Sstevel@tonic-gate static void 204*0Sstevel@tonic-gate disk_common(di_minor_t minor, di_node_t node, char *disk, int flags) 205*0Sstevel@tonic-gate { 206*0Sstevel@tonic-gate char l_path[PATH_MAX + 1]; 207*0Sstevel@tonic-gate char stale_re[DISK_SUBPATH_MAX]; 208*0Sstevel@tonic-gate char *dir; 209*0Sstevel@tonic-gate char slice[4]; 210*0Sstevel@tonic-gate char *mn; 211*0Sstevel@tonic-gate char *ctrl; 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate if (strstr(mn = di_minor_name(minor), ",raw")) { 214*0Sstevel@tonic-gate dir = "rdsk"; 215*0Sstevel@tonic-gate } else { 216*0Sstevel@tonic-gate dir = "dsk"; 217*0Sstevel@tonic-gate } 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate if (mn[0] < 113) { 220*0Sstevel@tonic-gate (void) sprintf(slice, "s%d", mn[0] - 'a'); 221*0Sstevel@tonic-gate } else if (strncmp(mn, MN_EFI, 2) != 0) { 222*0Sstevel@tonic-gate (void) sprintf(slice, "p%d", mn[0] - 'q'); 223*0Sstevel@tonic-gate } else { 224*0Sstevel@tonic-gate /* For EFI label */ 225*0Sstevel@tonic-gate (void) sprintf(slice, SLICE_EFI); 226*0Sstevel@tonic-gate } 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate if (NULL == (ctrl = diskctrl(node, minor))) 229*0Sstevel@tonic-gate return; 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate (void) strcpy(l_path, dir); 232*0Sstevel@tonic-gate (void) strcat(l_path, "/c"); 233*0Sstevel@tonic-gate (void) strcat(l_path, ctrl); 234*0Sstevel@tonic-gate (void) strcat(l_path, disk); 235*0Sstevel@tonic-gate 236*0Sstevel@tonic-gate /* 237*0Sstevel@tonic-gate * If switching between SMI and EFI label or vice versa 238*0Sstevel@tonic-gate * cleanup the previous label's devlinks. 239*0Sstevel@tonic-gate */ 240*0Sstevel@tonic-gate if (*mn == *(MN_SMI) || (strncmp(mn, MN_EFI, 2) == 0)) { 241*0Sstevel@tonic-gate char *s, tpath[PATH_MAX + 1]; 242*0Sstevel@tonic-gate struct stat sb; 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate s = l_path + strlen(l_path); 245*0Sstevel@tonic-gate (void) strcat(l_path, (*mn == *(MN_SMI)) 246*0Sstevel@tonic-gate ? SLICE_EFI : SLICE_SMI); 247*0Sstevel@tonic-gate /* 248*0Sstevel@tonic-gate * Attempt the remove only if the stale link exists 249*0Sstevel@tonic-gate */ 250*0Sstevel@tonic-gate (void) snprintf(tpath, sizeof (tpath), "%s/dev/%s", 251*0Sstevel@tonic-gate devfsadm_root_path(), l_path); 252*0Sstevel@tonic-gate if (lstat(tpath, &sb) != -1) 253*0Sstevel@tonic-gate devfsadm_rm_all(l_path); 254*0Sstevel@tonic-gate *s = '\0'; 255*0Sstevel@tonic-gate } 256*0Sstevel@tonic-gate (void) strcat(l_path, slice); 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate (void) devfsadm_mklink(l_path, node, minor, 0); 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate if ((flags & RM_STALE) == RM_STALE) { 261*0Sstevel@tonic-gate (void) strcpy(stale_re, "^"); 262*0Sstevel@tonic-gate (void) strcat(stale_re, dir); 263*0Sstevel@tonic-gate (void) strcat(stale_re, "/c"); 264*0Sstevel@tonic-gate (void) strcat(stale_re, ctrl); 265*0Sstevel@tonic-gate (void) strcat(stale_re, "t[0-9A-F]+d[0-9]+(s[0-9]+)?$"); 266*0Sstevel@tonic-gate /* 267*0Sstevel@tonic-gate * optimizations are made inside of devfsadm_rm_stale_links 268*0Sstevel@tonic-gate * instead of before calling the function, as it always 269*0Sstevel@tonic-gate * needs to add the valid link to the cache. 270*0Sstevel@tonic-gate */ 271*0Sstevel@tonic-gate devfsadm_rm_stale_links(stale_re, l_path, node, minor); 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate 274*0Sstevel@tonic-gate free(ctrl); 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate /* index of enumeration rule applicable to this module */ 279*0Sstevel@tonic-gate #define RULE_INDEX 0 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate static char * 282*0Sstevel@tonic-gate diskctrl(di_node_t node, di_minor_t minor) 283*0Sstevel@tonic-gate { 284*0Sstevel@tonic-gate char path[PATH_MAX + 1]; 285*0Sstevel@tonic-gate char *devfspath; 286*0Sstevel@tonic-gate char *buf, *mn; 287*0Sstevel@tonic-gate 288*0Sstevel@tonic-gate devfsadm_enumerate_t rules[3] = { 289*0Sstevel@tonic-gate {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT}, 290*0Sstevel@tonic-gate {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR}, 291*0Sstevel@tonic-gate {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT} 292*0Sstevel@tonic-gate }; 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate mn = di_minor_name(minor); 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate if ((devfspath = di_devfs_path(node)) == NULL) { 297*0Sstevel@tonic-gate return (NULL); 298*0Sstevel@tonic-gate } 299*0Sstevel@tonic-gate (void) strcpy(path, devfspath); 300*0Sstevel@tonic-gate (void) strcat(path, ":"); 301*0Sstevel@tonic-gate (void) strcat(path, mn); 302*0Sstevel@tonic-gate di_devfs_path_free(devfspath); 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate /* 305*0Sstevel@tonic-gate * Use controller component of disk path 306*0Sstevel@tonic-gate */ 307*0Sstevel@tonic-gate if (disk_enumerate_int(path, RULE_INDEX, &buf, rules, 3) == 308*0Sstevel@tonic-gate DEVFSADM_MULTIPLE) { 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate /* 311*0Sstevel@tonic-gate * We failed because there are multiple logical controller 312*0Sstevel@tonic-gate * numbers for a single physical controller. If we use node 313*0Sstevel@tonic-gate * name also in the match it should fix this and only find one 314*0Sstevel@tonic-gate * logical controller. (See 4045879). 315*0Sstevel@tonic-gate * NOTE: Rules for controllers are not changed, as there is 316*0Sstevel@tonic-gate * no unique controller number for them in this case. 317*0Sstevel@tonic-gate * 318*0Sstevel@tonic-gate * MATCH_UNCACHED flag is private to the "disks" and "sgen" 319*0Sstevel@tonic-gate * modules. NOT to be used by other modules. 320*0Sstevel@tonic-gate */ 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate rules[0].flags = MATCH_NODE | MATCH_UNCACHED; /* disks */ 323*0Sstevel@tonic-gate rules[2].flags = MATCH_NODE | MATCH_UNCACHED; /* generic scsi */ 324*0Sstevel@tonic-gate if (devfsadm_enumerate_int(path, RULE_INDEX, &buf, rules, 3)) { 325*0Sstevel@tonic-gate return (NULL); 326*0Sstevel@tonic-gate } 327*0Sstevel@tonic-gate } 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate return (buf); 330*0Sstevel@tonic-gate } 331