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 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <devfsadm.h> 30 #include <stdio.h> 31 #include <strings.h> 32 #include <stdlib.h> 33 #include <limits.h> 34 35 #define SCSI_CFG_LINK_RE "^cfg/c[0-9]+$" 36 #define SBD_CFG_LINK_RE "^cfg/((((N[0-9]+[.])?(SB|IB))?[0-9]+)|[abcd])$" 37 #define USB_CFG_LINK_RE "^cfg/((usb[0-9]+)/([0-9]+)([.]([0-9])+)*)$" 38 #define PCI_CFG_LINK_RE "^cfg/[:alnum:]$" 39 #define IB_CFG_LINK_RE "^cfg/(hca[0-9A-F]+)$" 40 #define SATA_CFG_LINK_RE "^cfg/((sata[0-9]+)/([0-9]+)([.]([0-9])+)*)$" 41 42 #define CFG_DIRNAME "cfg" 43 44 static int scsi_cfg_creat_cb(di_minor_t minor, di_node_t node); 45 static int sbd_cfg_creat_cb(di_minor_t minor, di_node_t node); 46 static int usb_cfg_creat_cb(di_minor_t minor, di_node_t node); 47 static char *get_roothub(const char *path, void *cb_arg); 48 static int pci_cfg_creat_cb(di_minor_t minor, di_node_t node); 49 static int ib_cfg_creat_cb(di_minor_t minor, di_node_t node); 50 static int sata_cfg_creat_cb(di_minor_t minor, di_node_t node); 51 52 /* 53 * NOTE: The CREATE_DEFER flag is private to this module. 54 * NOT to be used by other modules 55 */ 56 static devfsadm_create_t cfg_create_cbt[] = { 57 { "attachment-point", "ddi_ctl:attachment_point:scsi", NULL, 58 TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb 59 }, 60 { "attachment-point", "ddi_ctl:attachment_point:sbd", NULL, 61 TYPE_EXACT, ILEVEL_0, sbd_cfg_creat_cb 62 }, 63 { "fc-attachment-point", "ddi_ctl:attachment_point:fc", NULL, 64 TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb 65 }, 66 { "attachment-point", "ddi_ctl:attachment_point:usb", NULL, 67 TYPE_EXACT, ILEVEL_0, usb_cfg_creat_cb 68 }, 69 { "attachment-point", "ddi_ctl:attachment_point:pci", NULL, 70 TYPE_EXACT, ILEVEL_0, pci_cfg_creat_cb 71 }, 72 { "attachment-point", "ddi_ctl:attachment_point:ib", NULL, 73 TYPE_EXACT, ILEVEL_0, ib_cfg_creat_cb 74 }, 75 { "attachment-point", "ddi_ctl:attachment_point:sata", NULL, 76 TYPE_EXACT, ILEVEL_0, sata_cfg_creat_cb 77 } 78 }; 79 80 DEVFSADM_CREATE_INIT_V0(cfg_create_cbt); 81 82 static devfsadm_remove_t cfg_remove_cbt[] = { 83 { "attachment-point", SCSI_CFG_LINK_RE, RM_POST, 84 ILEVEL_0, devfsadm_rm_all 85 }, 86 { "attachment-point", SBD_CFG_LINK_RE, RM_POST, 87 ILEVEL_0, devfsadm_rm_all 88 }, 89 { "fc-attachment-point", SCSI_CFG_LINK_RE, RM_POST, 90 ILEVEL_0, devfsadm_rm_all 91 }, 92 { "attachment-point", USB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS, 93 ILEVEL_0, devfsadm_rm_all 94 }, 95 { "attachment-point", PCI_CFG_LINK_RE, RM_POST, 96 ILEVEL_0, devfsadm_rm_all 97 }, 98 { "attachment-point", IB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS, 99 ILEVEL_0, devfsadm_rm_all 100 }, 101 { "attachment-point", SATA_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS, 102 ILEVEL_0, devfsadm_rm_all 103 } 104 }; 105 106 DEVFSADM_REMOVE_INIT_V0(cfg_remove_cbt); 107 108 static int 109 scsi_cfg_creat_cb(di_minor_t minor, di_node_t node) 110 { 111 char path[PATH_MAX + 1]; 112 char *c_num = NULL, *devfs_path, *mn; 113 devfsadm_enumerate_t rules[3] = { 114 {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT}, 115 {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR}, 116 {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT} 117 }; 118 119 mn = di_minor_name(minor); 120 121 if ((devfs_path = di_devfs_path(node)) == NULL) { 122 return (DEVFSADM_CONTINUE); 123 } 124 (void) strcpy(path, devfs_path); 125 (void) strcat(path, ":"); 126 (void) strcat(path, mn); 127 di_devfs_path_free(devfs_path); 128 129 if (devfsadm_enumerate_int(path, 1, &c_num, rules, 3) 130 == DEVFSADM_FAILURE) { 131 /* 132 * Unlike the disks module we don't retry on failure. 133 * If we have multiple "c" numbers for a single physical 134 * controller due to bug 4045879, we will not assign a 135 * c-number/symlink for the controller. 136 */ 137 return (DEVFSADM_CONTINUE); 138 } 139 140 (void) strcpy(path, CFG_DIRNAME); 141 (void) strcat(path, "/c"); 142 (void) strcat(path, c_num); 143 144 free(c_num); 145 146 (void) devfsadm_mklink(path, node, minor, 0); 147 148 return (DEVFSADM_CONTINUE); 149 } 150 151 static int 152 sbd_cfg_creat_cb(di_minor_t minor, di_node_t node) 153 { 154 char path[PATH_MAX + 1]; 155 156 (void) strcpy(path, CFG_DIRNAME); 157 (void) strcat(path, "/"); 158 (void) strcat(path, di_minor_name(minor)); 159 (void) devfsadm_mklink(path, node, minor, 0); 160 return (DEVFSADM_CONTINUE); 161 } 162 163 164 static int 165 usb_cfg_creat_cb(di_minor_t minor, di_node_t node) 166 { 167 char *cp, path[PATH_MAX + 1]; 168 devfsadm_enumerate_t rules[1] = 169 {"^cfg$/^usb([0-9]+)$", 1, MATCH_CALLBACK, NULL, get_roothub}; 170 171 if ((cp = di_devfs_path(node)) == NULL) { 172 return (DEVFSADM_CONTINUE); 173 } 174 175 (void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor)); 176 di_devfs_path_free(cp); 177 178 if (devfsadm_enumerate_int(path, 0, &cp, rules, 1)) { 179 return (DEVFSADM_CONTINUE); 180 } 181 182 /* create usbN and the symlink */ 183 (void) snprintf(path, sizeof (path), "%s/usb%s/%s", CFG_DIRNAME, cp, 184 di_minor_name(minor)); 185 free(cp); 186 187 (void) devfsadm_mklink(path, node, minor, 0); 188 189 return (DEVFSADM_CONTINUE); 190 } 191 192 193 static int 194 sata_cfg_creat_cb(di_minor_t minor, di_node_t node) 195 { 196 char path[PATH_MAX + 1], l_path[PATH_MAX], *buf, *devfspath; 197 char *minor_nm; 198 devfsadm_enumerate_t rules[1] = 199 {"^cfg$/^sata([0-9]+)$", 1, MATCH_ADDR}; 200 201 minor_nm = di_minor_name(minor); 202 if (minor_nm == NULL) 203 return (DEVFSADM_CONTINUE); 204 205 devfspath = di_devfs_path(node); 206 if (devfspath == NULL) 207 return (DEVFSADM_CONTINUE); 208 209 (void) strlcpy(path, devfspath, sizeof (path)); 210 (void) strlcat(path, ":", sizeof (path)); 211 (void) strlcat(path, minor_nm, sizeof (path)); 212 di_devfs_path_free(devfspath); 213 214 /* build the physical path from the components */ 215 if (devfsadm_enumerate_int(path, 0, &buf, rules, 1) == 216 DEVFSADM_FAILURE) { 217 return (DEVFSADM_CONTINUE); 218 } 219 220 (void) snprintf(l_path, sizeof (l_path), "%s/sata%s/%s", CFG_DIRNAME, 221 buf, minor_nm); 222 free(buf); 223 224 (void) devfsadm_mklink(l_path, node, minor, 0); 225 226 return (DEVFSADM_CONTINUE); 227 } 228 229 230 /* 231 * get_roothub: 232 * figure out the root hub path to calculate /dev/cfg/usbN 233 */ 234 /* ARGSUSED */ 235 static char * 236 get_roothub(const char *path, void *cb_arg) 237 { 238 int i, count = 0; 239 char *physpath, *cp; 240 241 /* make a copy */ 242 if ((physpath = strdup(path)) == NULL) { 243 return (NULL); 244 } 245 246 /* 247 * physpath must always have a minor name component 248 */ 249 if ((cp = strrchr(physpath, ':')) == NULL) { 250 free(physpath); 251 return (NULL); 252 } 253 *cp++ = '\0'; 254 255 /* 256 * No '.' in the minor name indicates a roothub port. 257 */ 258 if (strchr(cp, '.') == NULL) { 259 /* roothub device */ 260 return (physpath); 261 } 262 263 while (*cp) { 264 if (*cp == '.') 265 count++; 266 cp++; 267 } 268 269 /* Remove as many trailing path components as there are '.'s */ 270 for (i = 0; i < count; i++) { 271 if ((cp = strrchr(physpath, '/')) == NULL || (cp == physpath)) { 272 free(physpath); 273 return (NULL); 274 } 275 *cp = '\0'; 276 } 277 278 return (physpath); 279 } 280 281 282 /* 283 * pci_cfg_creat_cb() search the <device mask> data from 284 * "slot-names" PROM property for the match device number, 285 * then create device link with the right slot label. 286 */ 287 static int 288 pci_cfg_creat_cb(di_minor_t minor, di_node_t node) 289 { 290 char *minor_name, *dev_path; 291 char path[PATH_MAX + 1]; 292 int *devlink_flags; 293 minor_t pci_dev; 294 di_node_t dev_node; 295 296 minor_name = di_minor_name(minor); 297 pci_dev = (minor->dev_minor) & 0xFF; 298 299 dev_path = di_devfs_path(node); 300 dev_node = di_init(dev_path, DINFOCPYALL); 301 if ((di_prop_lookup_ints(DDI_DEV_T_ANY, dev_node, 302 "ap-names", &devlink_flags)) > 0) { 303 if ((*devlink_flags) & (1 << pci_dev)) { 304 (void) snprintf(path, sizeof (path), "%s/%s", 305 CFG_DIRNAME, minor_name); 306 (void) devfsadm_mklink(path, node, minor, 0); 307 } 308 } 309 di_fini(dev_node); 310 (void) di_devfs_path_free(dev_path); 311 312 return (DEVFSADM_CONTINUE); 313 } 314 315 316 /* 317 * ib_cfg_creat_cb() creates two types of links 318 * One for the fabric as /dev/cfg/ib 319 * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID> 320 */ 321 static int 322 ib_cfg_creat_cb(di_minor_t minor, di_node_t node) 323 { 324 char *cp; 325 char path[PATH_MAX + 1]; 326 327 if ((cp = di_devfs_path(node)) == NULL) { 328 return (DEVFSADM_CONTINUE); 329 } 330 331 (void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor)); 332 di_devfs_path_free(cp); 333 334 /* create fabric or hca:GUID and the symlink */ 335 if (strstr(path, "ib:fabric") != NULL) { 336 (void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME); 337 } else { 338 (void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME, 339 di_minor_name(minor)); 340 } 341 342 (void) devfsadm_mklink(path, node, minor, 0); 343 return (DEVFSADM_CONTINUE); 344 } 345