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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 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 41 #define CFG_DIRNAME "cfg" 42 43 static int scsi_cfg_creat_cb(di_minor_t minor, di_node_t node); 44 static int sbd_cfg_creat_cb(di_minor_t minor, di_node_t node); 45 static int usb_cfg_creat_cb(di_minor_t minor, di_node_t node); 46 static char *get_roothub(const char *path, void *cb_arg); 47 static int pci_cfg_creat_cb(di_minor_t minor, di_node_t node); 48 static int ib_cfg_creat_cb(di_minor_t minor, di_node_t node); 49 50 /* 51 * NOTE: The CREATE_DEFER flag is private to this module. 52 * NOT to be used by other modules 53 */ 54 static devfsadm_create_t cfg_create_cbt[] = { 55 { "attachment-point", "ddi_ctl:attachment_point:scsi", NULL, 56 TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb 57 }, 58 { "attachment-point", "ddi_ctl:attachment_point:sbd", NULL, 59 TYPE_EXACT, ILEVEL_0, sbd_cfg_creat_cb 60 }, 61 { "fc-attachment-point", "ddi_ctl:attachment_point:fc", NULL, 62 TYPE_EXACT | CREATE_DEFER, ILEVEL_0, scsi_cfg_creat_cb 63 }, 64 { "attachment-point", "ddi_ctl:attachment_point:usb", NULL, 65 TYPE_EXACT, ILEVEL_0, usb_cfg_creat_cb 66 }, 67 { "attachment-point", "ddi_ctl:attachment_point:pci", NULL, 68 TYPE_EXACT, ILEVEL_0, pci_cfg_creat_cb 69 }, 70 { "attachment-point", "ddi_ctl:attachment_point:ib", NULL, 71 TYPE_EXACT, ILEVEL_0, ib_cfg_creat_cb 72 } 73 }; 74 75 DEVFSADM_CREATE_INIT_V0(cfg_create_cbt); 76 77 static devfsadm_remove_t cfg_remove_cbt[] = { 78 { "attachment-point", SCSI_CFG_LINK_RE, RM_POST, 79 ILEVEL_0, devfsadm_rm_all 80 }, 81 { "attachment-point", SBD_CFG_LINK_RE, RM_POST, 82 ILEVEL_0, devfsadm_rm_all 83 }, 84 { "fc-attachment-point", SCSI_CFG_LINK_RE, RM_POST, 85 ILEVEL_0, devfsadm_rm_all 86 }, 87 { "attachment-point", USB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS, 88 ILEVEL_0, devfsadm_rm_all 89 }, 90 { "attachment-point", PCI_CFG_LINK_RE, RM_POST, 91 ILEVEL_0, devfsadm_rm_all 92 }, 93 { "attachment-point", IB_CFG_LINK_RE, RM_POST|RM_HOT|RM_ALWAYS, 94 ILEVEL_0, devfsadm_rm_all 95 } 96 }; 97 98 DEVFSADM_REMOVE_INIT_V0(cfg_remove_cbt); 99 100 static int 101 scsi_cfg_creat_cb(di_minor_t minor, di_node_t node) 102 { 103 char path[PATH_MAX + 1]; 104 char *c_num = NULL, *devfs_path, *mn; 105 devfsadm_enumerate_t rules[3] = { 106 {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT}, 107 {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR}, 108 {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT} 109 }; 110 111 mn = di_minor_name(minor); 112 113 if ((devfs_path = di_devfs_path(node)) == NULL) { 114 return (DEVFSADM_CONTINUE); 115 } 116 (void) strcpy(path, devfs_path); 117 (void) strcat(path, ":"); 118 (void) strcat(path, mn); 119 di_devfs_path_free(devfs_path); 120 121 if (devfsadm_enumerate_int(path, 1, &c_num, rules, 3) 122 == DEVFSADM_FAILURE) { 123 /* 124 * Unlike the disks module we don't retry on failure. 125 * If we have multiple "c" numbers for a single physical 126 * controller due to bug 4045879, we will not assign a 127 * c-number/symlink for the controller. 128 */ 129 return (DEVFSADM_CONTINUE); 130 } 131 132 (void) strcpy(path, CFG_DIRNAME); 133 (void) strcat(path, "/c"); 134 (void) strcat(path, c_num); 135 136 free(c_num); 137 138 (void) devfsadm_mklink(path, node, minor, 0); 139 140 return (DEVFSADM_CONTINUE); 141 } 142 143 static int 144 sbd_cfg_creat_cb(di_minor_t minor, di_node_t node) 145 { 146 char path[PATH_MAX + 1]; 147 148 (void) strcpy(path, CFG_DIRNAME); 149 (void) strcat(path, "/"); 150 (void) strcat(path, di_minor_name(minor)); 151 (void) devfsadm_mklink(path, node, minor, 0); 152 return (DEVFSADM_CONTINUE); 153 } 154 155 156 static int 157 usb_cfg_creat_cb(di_minor_t minor, di_node_t node) 158 { 159 char *cp, path[PATH_MAX + 1]; 160 devfsadm_enumerate_t rules[1] = 161 {"^cfg$/^usb([0-9]+)$", 1, MATCH_CALLBACK, NULL, get_roothub}; 162 163 if ((cp = di_devfs_path(node)) == NULL) { 164 return (DEVFSADM_CONTINUE); 165 } 166 167 (void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor)); 168 di_devfs_path_free(cp); 169 170 if (devfsadm_enumerate_int(path, 0, &cp, rules, 1)) { 171 return (DEVFSADM_CONTINUE); 172 } 173 174 /* create usbN and the symlink */ 175 (void) snprintf(path, sizeof (path), "%s/usb%s/%s", CFG_DIRNAME, cp, 176 di_minor_name(minor)); 177 free(cp); 178 179 (void) devfsadm_mklink(path, node, minor, 0); 180 181 return (DEVFSADM_CONTINUE); 182 } 183 184 185 /* 186 * get_roothub: 187 * figure out the root hub path to calculate /dev/cfg/usbN 188 */ 189 /* ARGSUSED */ 190 static char * 191 get_roothub(const char *path, void *cb_arg) 192 { 193 int i, count = 0; 194 char *physpath, *cp; 195 196 /* make a copy */ 197 if ((physpath = strdup(path)) == NULL) { 198 return (NULL); 199 } 200 201 /* 202 * physpath must always have a minor name component 203 */ 204 if ((cp = strrchr(physpath, ':')) == NULL) { 205 free(physpath); 206 return (NULL); 207 } 208 *cp++ = '\0'; 209 210 /* 211 * No '.' in the minor name indicates a roothub port. 212 */ 213 if (strchr(cp, '.') == NULL) { 214 /* roothub device */ 215 return (physpath); 216 } 217 218 while (*cp) { 219 if (*cp == '.') 220 count++; 221 cp++; 222 } 223 224 /* Remove as many trailing path components as there are '.'s */ 225 for (i = 0; i < count; i++) { 226 if ((cp = strrchr(physpath, '/')) == NULL || (cp == physpath)) { 227 free(physpath); 228 return (NULL); 229 } 230 *cp = '\0'; 231 } 232 233 return (physpath); 234 } 235 236 237 /* 238 * pci_cfg_creat_cb() search the <device mask> data from 239 * "slot-names" PROM property for the match device number, 240 * then create device link with the right slot label. 241 */ 242 static int 243 pci_cfg_creat_cb(di_minor_t minor, di_node_t node) 244 { 245 char *minor_name, *dev_path; 246 char path[PATH_MAX + 1]; 247 int *devlink_flags; 248 minor_t pci_dev; 249 di_node_t dev_node; 250 251 minor_name = di_minor_name(minor); 252 pci_dev = (minor->dev_minor) & 0xFF; 253 254 dev_path = di_devfs_path(node); 255 dev_node = di_init(dev_path, DINFOCPYALL); 256 if ((di_prop_lookup_ints(DDI_DEV_T_ANY, dev_node, 257 "ap-names", &devlink_flags)) > 0) { 258 if ((*devlink_flags) & (1 << pci_dev)) { 259 (void) snprintf(path, sizeof (path), "%s/%s", 260 CFG_DIRNAME, minor_name); 261 (void) devfsadm_mklink(path, node, minor, 0); 262 } 263 } 264 di_fini(dev_node); 265 (void) di_devfs_path_free(dev_path); 266 267 return (DEVFSADM_CONTINUE); 268 } 269 270 271 /* 272 * ib_cfg_creat_cb() creates two types of links 273 * One for the fabric as /dev/cfg/ib 274 * Another for each HCA seen in the fabric as /dev/cfg/hca:<HCA-GUID> 275 */ 276 static int 277 ib_cfg_creat_cb(di_minor_t minor, di_node_t node) 278 { 279 char *cp; 280 char path[PATH_MAX + 1]; 281 282 if ((cp = di_devfs_path(node)) == NULL) { 283 return (DEVFSADM_CONTINUE); 284 } 285 286 (void) snprintf(path, sizeof (path), "%s:%s", cp, di_minor_name(minor)); 287 di_devfs_path_free(cp); 288 289 /* create fabric or hca:GUID and the symlink */ 290 if (strstr(path, "ib:fabric") != NULL) { 291 (void) snprintf(path, sizeof (path), "%s/ib", CFG_DIRNAME); 292 } else { 293 (void) snprintf(path, sizeof (path), "%s/hca:%s", CFG_DIRNAME, 294 di_minor_name(minor)); 295 } 296 297 (void) devfsadm_mklink(path, node, minor, 0); 298 return (DEVFSADM_CONTINUE); 299 } 300