Home | History | Annotate | Download | only in devfsadm
      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 #include <ctype.h>
     35 
     36 #define	SGEN_LINK_RE	"^scsi/.+/c[0-9]+t[0-9A-F]+d[0-9]+$"
     37 #define	SGEN_DIR	"scsi"
     38 #define	SGEN_CLASS	"generic-scsi"
     39 
     40 static int sgen_callback(di_minor_t minor, di_node_t node);
     41 static char *find_ctrlr(di_node_t node, di_minor_t minor);
     42 
     43 
     44 static devfsadm_create_t sgen_create_cbt[] = {
     45 	{ SGEN_CLASS, "ddi_generic:scsi", NULL,
     46 	    TYPE_EXACT | CREATE_DEFER, ILEVEL_0, sgen_callback
     47 	}
     48 };
     49 
     50 DEVFSADM_CREATE_INIT_V0(sgen_create_cbt);
     51 
     52 /*
     53  * HOT auto cleanup of sgen links not desired.
     54  */
     55 static devfsadm_remove_t sgen_remove_cbt[] = {
     56 	{ SGEN_CLASS, SGEN_LINK_RE, RM_POST,
     57 		ILEVEL_0, devfsadm_rm_all
     58 	}
     59 };
     60 
     61 DEVFSADM_REMOVE_INIT_V0(sgen_remove_cbt);
     62 
     63 static int
     64 sgen_callback(di_minor_t minor, di_node_t node)
     65 {
     66 	char *baddr, *cnum, *tstr;
     67 	char lpath[PATH_MAX], buf[PATH_MAX];
     68 	uchar_t *wwn;
     69 
     70 	if ((cnum = find_ctrlr(node, minor)) == NULL)
     71 		goto done;
     72 
     73 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
     74 	    "client-guid", (char **)&wwn) > 0) {
     75 		/*
     76 		 * MPXIO-enabled devices; lun is always 0.
     77 		 */
     78 		if (strlcpy((char *)buf, (char *)wwn, sizeof (buf)) >=
     79 		    sizeof (buf))
     80 			goto done;
     81 
     82 		for (tstr = buf; *tstr != '\0'; tstr++) {
     83 			*tstr = toupper(*tstr);
     84 		}
     85 		if (snprintf(lpath, sizeof (lpath), "%s/%s/c%st%sd0", SGEN_DIR,
     86 		    di_minor_name(minor), cnum, buf) >= sizeof (lpath))
     87 			goto done;
     88 
     89 	} else if (di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
     90 	    "port-wwn", &wwn) == 8) {
     91 		/*
     92 		 * "normal" fibre channel devices
     93 		 */
     94 		int lun, *lunp, count;
     95 		if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "lun", &lunp) > 0)
     96 			lun = *lunp;
     97 		else
     98 			lun = 0;
     99 
    100 		for (count = 0, tstr = buf; count < 8; count++, tstr += 2)
    101 			(void) sprintf(tstr, "%02X", wwn[count]);
    102 
    103 		*tstr = '\0';
    104 		if (snprintf(lpath, sizeof (lpath), "%s/%s/c%st%sd%d", SGEN_DIR,
    105 		    di_minor_name(minor), cnum, buf, lun) >= sizeof (lpath))
    106 			goto done;
    107 	} else {
    108 		/*
    109 		 * Parallel SCSI devices
    110 		 */
    111 		uint_t targ, lun;
    112 
    113 		if ((baddr = di_bus_addr(node)) == NULL)
    114 			goto done;
    115 
    116 		if (sscanf(baddr, "%X,%X", &targ, &lun) != 2)
    117 			goto done;
    118 
    119 		if (snprintf(lpath, sizeof (lpath), "%s/%s/c%st%dd%d", SGEN_DIR,
    120 		    di_minor_name(minor), cnum, targ, lun) >= sizeof (lpath))
    121 			goto done;
    122 	}
    123 
    124 	(void) devfsadm_mklink(lpath, node, minor, 0);
    125 done:
    126 	free(cnum);
    127 	return (DEVFSADM_CONTINUE);
    128 }
    129 
    130 /* index of enumeration rule applicable to this module */
    131 #define	RULE_INDEX	2
    132 
    133 static char *
    134 find_ctrlr(di_node_t node, di_minor_t minor)
    135 {
    136 	char path[PATH_MAX + 1];
    137 	char *devfspath;
    138 	char *buf, *mn;
    139 
    140 	devfsadm_enumerate_t rules[3] = {
    141 	    {"^r?dsk$/^c([0-9]+)", 1, MATCH_PARENT},
    142 	    {"^cfg$/^c([0-9]+)$", 1, MATCH_ADDR},
    143 	    {"^scsi$/^.+$/^c([0-9]+)", 1, MATCH_PARENT}
    144 	};
    145 
    146 	mn = di_minor_name(minor);
    147 
    148 	if ((devfspath = di_devfs_path(node)) == NULL) {
    149 		return (NULL);
    150 	}
    151 	(void) strcpy(path, devfspath);
    152 	(void) strcat(path, ":");
    153 	(void) strcat(path, mn);
    154 	di_devfs_path_free(devfspath);
    155 
    156 	/*
    157 	 * Use controller (parent) component of device path
    158 	 */
    159 	if (disk_enumerate_int(path, RULE_INDEX, &buf, rules, 3) ==
    160 	    DEVFSADM_MULTIPLE) {
    161 
    162 		/*
    163 		 * We failed because there are multiple logical controller
    164 		 * numbers for a single physical controller.  If we use node
    165 		 * name also for DEVICE paths in the match it should fix this
    166 		 * and only find one logical controller. (See 4045879).
    167 		 * NOTE: Rules for controllers are not changed, as there is
    168 		 * no unique controller number for them in this case.
    169 		 *
    170 		 * MATCH_UNCACHED flag is private to the "disks" and "sgen"
    171 		 * modules. NOT to be used by other modules.
    172 		 */
    173 		rules[0].flags = MATCH_NODE | MATCH_UNCACHED; /* disks */
    174 		rules[2].flags = MATCH_NODE | MATCH_UNCACHED; /* generic scsi */
    175 		if (devfsadm_enumerate_int(path, RULE_INDEX, &buf, rules, 3)) {
    176 			return (NULL);
    177 		}
    178 	}
    179 
    180 	return (buf);
    181 }
    182