xref: /onnv-gate/usr/src/lib/storage/libg_fc/common/genf.c (revision 10264:1196af6129ec)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM /*
22*10264SZhong.Wang@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237836SJohn.Forte@Sun.COM  * Use is subject to license terms.
247836SJohn.Forte@Sun.COM  */
257836SJohn.Forte@Sun.COM 
267836SJohn.Forte@Sun.COM 
277836SJohn.Forte@Sun.COM 
287836SJohn.Forte@Sun.COM 
297836SJohn.Forte@Sun.COM /*LINTLIBRARY*/
307836SJohn.Forte@Sun.COM 
317836SJohn.Forte@Sun.COM /*
327836SJohn.Forte@Sun.COM  *	This module is part of the Fibre Channel Interface library.
337836SJohn.Forte@Sun.COM  *
347836SJohn.Forte@Sun.COM  */
357836SJohn.Forte@Sun.COM 
367836SJohn.Forte@Sun.COM /*
377836SJohn.Forte@Sun.COM  * I18N message number ranges
387836SJohn.Forte@Sun.COM  *  This file: 10500 - 10999
397836SJohn.Forte@Sun.COM  *  Shared common messages: 1 - 1999
407836SJohn.Forte@Sun.COM  */
417836SJohn.Forte@Sun.COM 
427836SJohn.Forte@Sun.COM /*	Includes	*/
437836SJohn.Forte@Sun.COM #include	<stdlib.h>
447836SJohn.Forte@Sun.COM #include 	<stdio.h>
457836SJohn.Forte@Sun.COM #include	<sys/file.h>
467836SJohn.Forte@Sun.COM #include	<sys/types.h>
477836SJohn.Forte@Sun.COM #include	<sys/stat.h>
487836SJohn.Forte@Sun.COM #include	<sys/param.h>
497836SJohn.Forte@Sun.COM #include	<fcntl.h>
507836SJohn.Forte@Sun.COM #include	<string.h>
517836SJohn.Forte@Sun.COM #include	<errno.h>
527836SJohn.Forte@Sun.COM #include	<assert.h>
537836SJohn.Forte@Sun.COM #include	<unistd.h>
547836SJohn.Forte@Sun.COM #include	<sys/types.h>
557836SJohn.Forte@Sun.COM #include	<sys/param.h>
567836SJohn.Forte@Sun.COM #include	<sys/dklabel.h>
577836SJohn.Forte@Sun.COM #include	<sys/autoconf.h>
587836SJohn.Forte@Sun.COM #include	<sys/utsname.h>
597836SJohn.Forte@Sun.COM #include 	<sys/ddi.h>		/* for min */
607836SJohn.Forte@Sun.COM #include	<ctype.h>		/* for isprint */
617836SJohn.Forte@Sun.COM #include	<sys/scsi/scsi.h>
627836SJohn.Forte@Sun.COM #include	<dirent.h>		/* for DIR */
637836SJohn.Forte@Sun.COM #include	<nl_types.h>
647836SJohn.Forte@Sun.COM #include	<locale.h>
657836SJohn.Forte@Sun.COM #include	<thread.h>
667836SJohn.Forte@Sun.COM #include	<synch.h>
677836SJohn.Forte@Sun.COM #include	<l_common.h>
687836SJohn.Forte@Sun.COM #include	<stgcom.h>
697836SJohn.Forte@Sun.COM #include	<l_error.h>
707836SJohn.Forte@Sun.COM #include	<g_state.h>
717836SJohn.Forte@Sun.COM #include	<libdevinfo.h>
727836SJohn.Forte@Sun.COM 
737836SJohn.Forte@Sun.COM 
747836SJohn.Forte@Sun.COM /*	Defines		*/
757836SJohn.Forte@Sun.COM #define	BYTES_PER_LINE		16	/* # of bytes to dump per line */
767836SJohn.Forte@Sun.COM #define	SCMD_UNKNOWN		0xff
777836SJohn.Forte@Sun.COM 
787836SJohn.Forte@Sun.COM /* Bus strings - for internal use by g_get_path_type() only */
797836SJohn.Forte@Sun.COM #define	PCI_BUS			1
807836SJohn.Forte@Sun.COM #define	SBUS			2
81*10264SZhong.Wang@Sun.COM #define	FCOE			3
827836SJohn.Forte@Sun.COM 
837836SJohn.Forte@Sun.COM struct str_type {
847836SJohn.Forte@Sun.COM 	char *string;
857836SJohn.Forte@Sun.COM 	uint_t type;
867836SJohn.Forte@Sun.COM };
877836SJohn.Forte@Sun.COM 
887836SJohn.Forte@Sun.COM static struct str_type ValidBusStrings[] = {
897836SJohn.Forte@Sun.COM 	{"pci@", PCI_BUS},
907836SJohn.Forte@Sun.COM 	{"sbus@", SBUS},
91*10264SZhong.Wang@Sun.COM 	{"fcoe", FCOE},
927836SJohn.Forte@Sun.COM 	{NULL, 0}
937836SJohn.Forte@Sun.COM };
947836SJohn.Forte@Sun.COM 
957836SJohn.Forte@Sun.COM 
967836SJohn.Forte@Sun.COM /*
977836SJohn.Forte@Sun.COM  *	Strings below were used before cougar driver(qlc) was proposed.
987836SJohn.Forte@Sun.COM  *	{"scsi/", FC_PCI_FCA},
997836SJohn.Forte@Sun.COM  *	{"fibre-channel/", FC_PCI_FCA},
1007836SJohn.Forte@Sun.COM  */
1017836SJohn.Forte@Sun.COM static struct str_type ValidFCAstrings[] = {
1027836SJohn.Forte@Sun.COM 	{"SUNW,ifp@", FC4_PCI_FCA | FC4_IFP_XPORT},
1037836SJohn.Forte@Sun.COM 	{"SUNW,socal@", FC4_SOCAL_FCA},
1047836SJohn.Forte@Sun.COM 	{NULL, 0}
1057836SJohn.Forte@Sun.COM };
1067836SJohn.Forte@Sun.COM 
1077836SJohn.Forte@Sun.COM static struct str_type ValidXportStrings[] = {
1087836SJohn.Forte@Sun.COM 	{"/sf@", FC4_SF_XPORT},
1097836SJohn.Forte@Sun.COM 	{"/fp@", FC_GEN_XPORT},
1107836SJohn.Forte@Sun.COM 	{NULL, 0}
1117836SJohn.Forte@Sun.COM };
1127836SJohn.Forte@Sun.COM 
1137836SJohn.Forte@Sun.COM struct _enclDisk {
1147836SJohn.Forte@Sun.COM 	char *vid;
1157836SJohn.Forte@Sun.COM 	char *pid;
1167836SJohn.Forte@Sun.COM };
1177836SJohn.Forte@Sun.COM 
1187836SJohn.Forte@Sun.COM /*
1197836SJohn.Forte@Sun.COM  * SENA/SUNWGS type enclosure disk table. This table contains vendor IDs and
1207836SJohn.Forte@Sun.COM  * the non-unique portion of the product identifier sufficient for
1217836SJohn.Forte@Sun.COM  * comparison. This table needs to be updated as new drives are supported
1227836SJohn.Forte@Sun.COM  * in the SENA/SUNWGS type enclosures that do not have a corresponding match
1237836SJohn.Forte@Sun.COM  * in this table. Currently, the v880 and v890 are the only shipping products
1247836SJohn.Forte@Sun.COM  * that utilize the SUNWGS type enclosure. SENA is EOL'd. The risk of new
1257836SJohn.Forte@Sun.COM  * devices being added that do not match an entry in this table is small but it
1267836SJohn.Forte@Sun.COM  * does exist.
1277836SJohn.Forte@Sun.COM  */
1287836SJohn.Forte@Sun.COM static struct _enclDisk enclDiskTbl[] = {
1297836SJohn.Forte@Sun.COM 	{"SUN", "SENA"},
1307836SJohn.Forte@Sun.COM 	{"SUN", "SUNWGS"},
1317836SJohn.Forte@Sun.COM 	{"FUJITSU", "MA"},
1327836SJohn.Forte@Sun.COM 	{"HITACHI", "DK"},
1337836SJohn.Forte@Sun.COM 	{"HITACHI", "HU"},
1347836SJohn.Forte@Sun.COM 	{"SEAGATE", "ST"},
1357836SJohn.Forte@Sun.COM 	{NULL, NULL}
1367836SJohn.Forte@Sun.COM };
1377836SJohn.Forte@Sun.COM 
1387836SJohn.Forte@Sun.COM 
1397836SJohn.Forte@Sun.COM /* i18n */
1407836SJohn.Forte@Sun.COM nl_catd		l_catd;
1417836SJohn.Forte@Sun.COM 
1427836SJohn.Forte@Sun.COM 
1437836SJohn.Forte@Sun.COM /*	Internal Functions	*/
1447836SJohn.Forte@Sun.COM static	void	string_dump(char *, uchar_t *, int, int, char msg_string[]);
1457836SJohn.Forte@Sun.COM 
1467836SJohn.Forte@Sun.COM /*
1477836SJohn.Forte@Sun.COM  * Allocate space for and return a pointer to a string
1487836SJohn.Forte@Sun.COM  * on the stack.  If the string is null, create
1497836SJohn.Forte@Sun.COM  * an empty string.
1507836SJohn.Forte@Sun.COM  * Use g_destroy_data() to free when no longer used.
1517836SJohn.Forte@Sun.COM  */
1527836SJohn.Forte@Sun.COM char *
g_alloc_string(char * s)1537836SJohn.Forte@Sun.COM g_alloc_string(char *s)
1547836SJohn.Forte@Sun.COM {
1557836SJohn.Forte@Sun.COM 	char	*ns;
1567836SJohn.Forte@Sun.COM 
1577836SJohn.Forte@Sun.COM 	if (s == (char *)NULL) {
1587836SJohn.Forte@Sun.COM 		ns = (char *)g_zalloc(1);
1597836SJohn.Forte@Sun.COM 	} else {
1607836SJohn.Forte@Sun.COM 		ns = (char *)g_zalloc(strlen(s) + 1);
1617836SJohn.Forte@Sun.COM 		if (ns != NULL) {
1627836SJohn.Forte@Sun.COM 			(void) strncpy(ns, s, (strlen(s) + 1));
1637836SJohn.Forte@Sun.COM 		}
1647836SJohn.Forte@Sun.COM 	}
1657836SJohn.Forte@Sun.COM 	return (ns);
1667836SJohn.Forte@Sun.COM }
1677836SJohn.Forte@Sun.COM 
1687836SJohn.Forte@Sun.COM 
1697836SJohn.Forte@Sun.COM /*
1707836SJohn.Forte@Sun.COM  * This routine is a wrapper for free.
1717836SJohn.Forte@Sun.COM  */
1727836SJohn.Forte@Sun.COM void
g_destroy_data(void * data)1737836SJohn.Forte@Sun.COM g_destroy_data(void *data)
1747836SJohn.Forte@Sun.COM {
1757836SJohn.Forte@Sun.COM 	A_DPRINTF("  g_destroy_data: Free\'ed buffer at 0x%x\n",
1767836SJohn.Forte@Sun.COM 		data);
1777836SJohn.Forte@Sun.COM 	free((void *)data);
1787836SJohn.Forte@Sun.COM }
1797836SJohn.Forte@Sun.COM 
1807836SJohn.Forte@Sun.COM 
1817836SJohn.Forte@Sun.COM /*
1827836SJohn.Forte@Sun.COM  * Dump a structure in hexadecimal.
1837836SJohn.Forte@Sun.COM  */
1847836SJohn.Forte@Sun.COM void
g_dump(char * hdr,uchar_t * src,int nbytes,int format)1857836SJohn.Forte@Sun.COM g_dump(char *hdr, uchar_t *src, int nbytes, int format)
1867836SJohn.Forte@Sun.COM {
1877836SJohn.Forte@Sun.COM 	int i;
1887836SJohn.Forte@Sun.COM 	int n;
1897836SJohn.Forte@Sun.COM 	char	*p;
1907836SJohn.Forte@Sun.COM 	char	s[256];
1917836SJohn.Forte@Sun.COM 
1927836SJohn.Forte@Sun.COM 	assert(format == HEX_ONLY || format == HEX_ASCII);
1937836SJohn.Forte@Sun.COM 
1947836SJohn.Forte@Sun.COM 	(void) strcpy(s, hdr);
1957836SJohn.Forte@Sun.COM 	for (p = s; *p; p++) {
1967836SJohn.Forte@Sun.COM 		*p = ' ';
1977836SJohn.Forte@Sun.COM 	}
1987836SJohn.Forte@Sun.COM 
1997836SJohn.Forte@Sun.COM 	p = hdr;
2007836SJohn.Forte@Sun.COM 	while (nbytes > 0) {
2017836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", p);
2027836SJohn.Forte@Sun.COM 		p = s;
2037836SJohn.Forte@Sun.COM 		n = min(nbytes, BYTES_PER_LINE);
2047836SJohn.Forte@Sun.COM 		for (i = 0; i < n; i++) {
2057836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%02x ", src[i] & 0xff);
2067836SJohn.Forte@Sun.COM 		}
2077836SJohn.Forte@Sun.COM 		if (format == HEX_ASCII) {
2087836SJohn.Forte@Sun.COM 			for (i = BYTES_PER_LINE-n; i > 0; i--) {
2097836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, "   ");
2107836SJohn.Forte@Sun.COM 			}
2117836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "    ");
2127836SJohn.Forte@Sun.COM 			for (i = 0; i < n; i++) {
2137836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, "%c",
2147836SJohn.Forte@Sun.COM 					isprint(src[i]) ? src[i] : '.');
2157836SJohn.Forte@Sun.COM 			}
2167836SJohn.Forte@Sun.COM 		}
2177836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
2187836SJohn.Forte@Sun.COM 		nbytes -= n;
2197836SJohn.Forte@Sun.COM 		src += n;
2207836SJohn.Forte@Sun.COM 	}
2217836SJohn.Forte@Sun.COM }
2227836SJohn.Forte@Sun.COM 
2237836SJohn.Forte@Sun.COM /*
2247836SJohn.Forte@Sun.COM  * Internal routine to clean up ../'s in paths.
2257836SJohn.Forte@Sun.COM  * returns 0 if no "../" are left.
2267836SJohn.Forte@Sun.COM  *
2277836SJohn.Forte@Sun.COM  * Wouldn't it be nice if there was a standard system library
2287836SJohn.Forte@Sun.COM  * routine to do this...?
2297836SJohn.Forte@Sun.COM  */
2307836SJohn.Forte@Sun.COM static int
cleanup_dotdot_path(char * path)2317836SJohn.Forte@Sun.COM cleanup_dotdot_path(char *path)
2327836SJohn.Forte@Sun.COM {
2337836SJohn.Forte@Sun.COM 	char holder[MAXPATHLEN];
2347836SJohn.Forte@Sun.COM 	char *dotdot;
2357836SJohn.Forte@Sun.COM 	char *previous_slash;
2367836SJohn.Forte@Sun.COM 
2377836SJohn.Forte@Sun.COM 	/* Find the first "/../" in the string */
2387836SJohn.Forte@Sun.COM 	dotdot = strstr(path, "/../");
2397836SJohn.Forte@Sun.COM 	if (dotdot == NULL) {
2407836SJohn.Forte@Sun.COM 		return (0);
2417836SJohn.Forte@Sun.COM 	}
2427836SJohn.Forte@Sun.COM 
2437836SJohn.Forte@Sun.COM 
2447836SJohn.Forte@Sun.COM 	/*
2457836SJohn.Forte@Sun.COM 	 * If the [0] character is '/' and "../" immediatly
2467836SJohn.Forte@Sun.COM 	 * follows it, then we can strip the ../
2477836SJohn.Forte@Sun.COM 	 *
2487836SJohn.Forte@Sun.COM 	 *	/../../foo/bar == /foo/bar
2497836SJohn.Forte@Sun.COM 	 *
2507836SJohn.Forte@Sun.COM 	 */
2517836SJohn.Forte@Sun.COM 	if (dotdot == path) {
2527836SJohn.Forte@Sun.COM 		strcpy(holder, &path[3]); /* strip "/.." */
2537836SJohn.Forte@Sun.COM 		strcpy(path, holder);
2547836SJohn.Forte@Sun.COM 		return (1);
2557836SJohn.Forte@Sun.COM 	}
2567836SJohn.Forte@Sun.COM 
2577836SJohn.Forte@Sun.COM 	/*
2587836SJohn.Forte@Sun.COM 	 * Now look for the LAST "/" before the "/../"
2597836SJohn.Forte@Sun.COM 	 * as this is the parent dir we can get rid of.
2607836SJohn.Forte@Sun.COM 	 * We do this by temporarily truncating the string
2617836SJohn.Forte@Sun.COM 	 * at the '/' just before "../" using the dotdot pointer.
2627836SJohn.Forte@Sun.COM 	 */
2637836SJohn.Forte@Sun.COM 	*dotdot = '\0';
2647836SJohn.Forte@Sun.COM 	previous_slash = strrchr(path, '/');
2657836SJohn.Forte@Sun.COM 	if (previous_slash == NULL) {
2667836SJohn.Forte@Sun.COM 		/*
2677836SJohn.Forte@Sun.COM 		 * hmm, somethings wrong.  path looks something
2687836SJohn.Forte@Sun.COM 		 * like "foo/../bar/" so we can't really deal with it.
2697836SJohn.Forte@Sun.COM 		 */
2707836SJohn.Forte@Sun.COM 		return (0);
2717836SJohn.Forte@Sun.COM 	}
2727836SJohn.Forte@Sun.COM 	/*
2737836SJohn.Forte@Sun.COM 	 * Now truncate the path just after the previous '/'
2747836SJohn.Forte@Sun.COM 	 * and slam everything after the "../" back on
2757836SJohn.Forte@Sun.COM 	 */
2767836SJohn.Forte@Sun.COM 	*(previous_slash+1) = '\0';
2777836SJohn.Forte@Sun.COM 	strcat(path, dotdot+4);
2787836SJohn.Forte@Sun.COM 	return (1); /* We may have more "../"s */
2797836SJohn.Forte@Sun.COM }
2807836SJohn.Forte@Sun.COM 
2817836SJohn.Forte@Sun.COM 
2827836SJohn.Forte@Sun.COM /*
2837836SJohn.Forte@Sun.COM  * Follow symbolic links from the logical device name to
2847836SJohn.Forte@Sun.COM  * the /devfs physical device name.  To be complete, we
2857836SJohn.Forte@Sun.COM  * handle the case of multiple links.  This function
2867836SJohn.Forte@Sun.COM  * either returns NULL (no links, or some other error),
2877836SJohn.Forte@Sun.COM  * or the physical device name, alloc'ed on the heap.
2887836SJohn.Forte@Sun.COM  *
2897836SJohn.Forte@Sun.COM  * NOTE: If the path is relative, it will be forced into
2907836SJohn.Forte@Sun.COM  * an absolute path by pre-pending the pwd to it.
2917836SJohn.Forte@Sun.COM  */
2927836SJohn.Forte@Sun.COM char *
g_get_physical_name_from_link(char * path)2937836SJohn.Forte@Sun.COM g_get_physical_name_from_link(char *path)
2947836SJohn.Forte@Sun.COM {
2957836SJohn.Forte@Sun.COM 	struct stat	stbuf;
2967836SJohn.Forte@Sun.COM 	char		source[MAXPATHLEN];
2977836SJohn.Forte@Sun.COM 	char		scratch[MAXPATHLEN];
2987836SJohn.Forte@Sun.COM 	char		pwd[MAXPATHLEN];
2997836SJohn.Forte@Sun.COM 	char		*tmp;
3007836SJohn.Forte@Sun.COM 	int			cnt;
3017836SJohn.Forte@Sun.COM 
3027836SJohn.Forte@Sun.COM 	/* return NULL if path is NULL */
3037836SJohn.Forte@Sun.COM 	if (path == NULL) {
3047836SJohn.Forte@Sun.COM 		return (NULL);
3057836SJohn.Forte@Sun.COM 	}
3067836SJohn.Forte@Sun.COM 
3077836SJohn.Forte@Sun.COM 	strcpy(source, path);
3087836SJohn.Forte@Sun.COM 	for (;;) {
3097836SJohn.Forte@Sun.COM 
3107836SJohn.Forte@Sun.COM 		/*
3117836SJohn.Forte@Sun.COM 		 * First make sure the path is absolute.  If not, make it.
3127836SJohn.Forte@Sun.COM 		 * If it's already an absolute path, we have no need
3137836SJohn.Forte@Sun.COM 		 * to determine the cwd, so the program should still
3147836SJohn.Forte@Sun.COM 		 * function within security-by-obscurity directories.
3157836SJohn.Forte@Sun.COM 		 */
3167836SJohn.Forte@Sun.COM 		if (source[0] != '/') {
3177836SJohn.Forte@Sun.COM 			tmp = getcwd(pwd, MAXPATHLEN);
3187836SJohn.Forte@Sun.COM 			if (tmp == NULL) {
3197836SJohn.Forte@Sun.COM 				O_DPRINTF("getcwd() failed - %s\n",
3207836SJohn.Forte@Sun.COM 					strerror(errno));
3217836SJohn.Forte@Sun.COM 				return (NULL);
3227836SJohn.Forte@Sun.COM 			}
3237836SJohn.Forte@Sun.COM 			/*
3247836SJohn.Forte@Sun.COM 			 * Handle special case of "./foo/bar"
3257836SJohn.Forte@Sun.COM 			 */
3267836SJohn.Forte@Sun.COM 			if (source[0] == '.' && source[1] == '/') {
3277836SJohn.Forte@Sun.COM 				strcpy(scratch, source+2);
3287836SJohn.Forte@Sun.COM 			} else { /* no "./" so just take everything */
3297836SJohn.Forte@Sun.COM 				strcpy(scratch, source);
3307836SJohn.Forte@Sun.COM 			}
3317836SJohn.Forte@Sun.COM 			strcpy(source, pwd);
3327836SJohn.Forte@Sun.COM 			strcat(source, "/");
3337836SJohn.Forte@Sun.COM 			strcat(source, scratch);
3347836SJohn.Forte@Sun.COM 		}
3357836SJohn.Forte@Sun.COM 
3367836SJohn.Forte@Sun.COM 		/*
3377836SJohn.Forte@Sun.COM 		 * Clean up any "../"s that are in the path
3387836SJohn.Forte@Sun.COM 		 */
3397836SJohn.Forte@Sun.COM 		while (cleanup_dotdot_path(source));
3407836SJohn.Forte@Sun.COM 
3417836SJohn.Forte@Sun.COM 		/*
3427836SJohn.Forte@Sun.COM 		 * source is now an absolute path to the link we're
3437836SJohn.Forte@Sun.COM 		 * concerned with
3447836SJohn.Forte@Sun.COM 		 *
3457836SJohn.Forte@Sun.COM 		 * See if there's a real file out there.  If not,
3467836SJohn.Forte@Sun.COM 		 * we have a dangling link and we ignore it.
3477836SJohn.Forte@Sun.COM 		 */
3487836SJohn.Forte@Sun.COM 
3497836SJohn.Forte@Sun.COM 		if (stat(source, &stbuf) == -1) {
3507836SJohn.Forte@Sun.COM 			O_DPRINTF("stat() failed for %s- %s\n",
3517836SJohn.Forte@Sun.COM 				source, strerror(errno));
3527836SJohn.Forte@Sun.COM 			return (NULL);
3537836SJohn.Forte@Sun.COM 		}
3547836SJohn.Forte@Sun.COM 		if (lstat(source, &stbuf) == -1) {
3557836SJohn.Forte@Sun.COM 			O_DPRINTF("lstat() failed for - %s\n",
3567836SJohn.Forte@Sun.COM 				source, strerror(errno));
3577836SJohn.Forte@Sun.COM 			return (NULL);
3587836SJohn.Forte@Sun.COM 		}
3597836SJohn.Forte@Sun.COM 		/*
3607836SJohn.Forte@Sun.COM 		 * If the file is not a link, we're done one
3617836SJohn.Forte@Sun.COM 		 * way or the other.  If there were links,
3627836SJohn.Forte@Sun.COM 		 * return the full pathname of the resulting
3637836SJohn.Forte@Sun.COM 		 * file.
3647836SJohn.Forte@Sun.COM 		 *
3657836SJohn.Forte@Sun.COM 		 * Note:  All of our temp's are on the stack,
3667836SJohn.Forte@Sun.COM 		 * so we have to copy the final result to the heap.
3677836SJohn.Forte@Sun.COM 		 */
3687836SJohn.Forte@Sun.COM 		if (!S_ISLNK(stbuf.st_mode)) {
3697836SJohn.Forte@Sun.COM 			return (g_alloc_string(source));
3707836SJohn.Forte@Sun.COM 		}
3717836SJohn.Forte@Sun.COM 		cnt = readlink(source, scratch, sizeof (scratch));
3727836SJohn.Forte@Sun.COM 		if (cnt < 0) {
3737836SJohn.Forte@Sun.COM 			O_DPRINTF("readlink() failed - %s\n",
3747836SJohn.Forte@Sun.COM 				strerror(errno));
3757836SJohn.Forte@Sun.COM 			return (NULL);
3767836SJohn.Forte@Sun.COM 		}
3777836SJohn.Forte@Sun.COM 		/*
3787836SJohn.Forte@Sun.COM 		 * scratch is on the heap, and for some reason readlink
3797836SJohn.Forte@Sun.COM 		 * doesn't always terminate things properly so we have
3807836SJohn.Forte@Sun.COM 		 * to make certain we're properly terminated
3817836SJohn.Forte@Sun.COM 		 */
3827836SJohn.Forte@Sun.COM 		scratch[cnt] = '\0';
3837836SJohn.Forte@Sun.COM 
3847836SJohn.Forte@Sun.COM 		/*
3857836SJohn.Forte@Sun.COM 		 * Now check to see if the link is relative.  If so,
3867836SJohn.Forte@Sun.COM 		 * then we have to append it to the directory
3877836SJohn.Forte@Sun.COM 		 * which the source was in. (This is non trivial)
3887836SJohn.Forte@Sun.COM 		 */
3897836SJohn.Forte@Sun.COM 		if (scratch[0] != '/') {
3907836SJohn.Forte@Sun.COM 			tmp = strrchr(source, '/');
3917836SJohn.Forte@Sun.COM 			if (tmp == NULL) { /* Whoa!  Something's hosed! */
3927836SJohn.Forte@Sun.COM 				O_DPRINTF("Internal error... corrupt path.\n");
3937836SJohn.Forte@Sun.COM 				return (NULL);
3947836SJohn.Forte@Sun.COM 			}
3957836SJohn.Forte@Sun.COM 			/* Now strip off just the directory path */
3967836SJohn.Forte@Sun.COM 			*(tmp+1) = '\0'; /* Keeping the last '/' */
3977836SJohn.Forte@Sun.COM 			/* and append the new link */
3987836SJohn.Forte@Sun.COM 			strcat(source, scratch);
3997836SJohn.Forte@Sun.COM 			/*
4007836SJohn.Forte@Sun.COM 			 * Note:  At this point, source should have "../"s
4017836SJohn.Forte@Sun.COM 			 * but we'll clean it up in the next pass through
4027836SJohn.Forte@Sun.COM 			 * the loop.
4037836SJohn.Forte@Sun.COM 			 */
4047836SJohn.Forte@Sun.COM 		} else {
4057836SJohn.Forte@Sun.COM 			/* It's an absolute link so no worries */
4067836SJohn.Forte@Sun.COM 			strcpy(source, scratch);
4077836SJohn.Forte@Sun.COM 		}
4087836SJohn.Forte@Sun.COM 	}
4097836SJohn.Forte@Sun.COM 	/* Never reach here */
4107836SJohn.Forte@Sun.COM }
4117836SJohn.Forte@Sun.COM 
4127836SJohn.Forte@Sun.COM /*
4137836SJohn.Forte@Sun.COM  * Function for getting physical pathnames
4147836SJohn.Forte@Sun.COM  *
4157836SJohn.Forte@Sun.COM  * This function can handle 3 different inputs.
4167836SJohn.Forte@Sun.COM  *
4177836SJohn.Forte@Sun.COM  * 1) Inputs of the form cN
4187836SJohn.Forte@Sun.COM  *	This requires the program  to search the /dev/rdsk
4197836SJohn.Forte@Sun.COM  *	directory for a device that is conected to the
4207836SJohn.Forte@Sun.COM  *	controller with number 'N' and then getting
4217836SJohn.Forte@Sun.COM  *	the physical pathname of the controller.
4227836SJohn.Forte@Sun.COM  *	The format of the controller pathname is
4237836SJohn.Forte@Sun.COM  *	/devices/.../.../SUNW,soc@x,x/SUNW,pln@xxxx,xxxxxxxx:ctlr
4247836SJohn.Forte@Sun.COM  *	The physical pathname is returned.
4257836SJohn.Forte@Sun.COM  *
4267836SJohn.Forte@Sun.COM  * 2) Inputs of the form /dev/rdsk/cNtNdNsN
4277836SJohn.Forte@Sun.COM  *	These are identified by being a link
4287836SJohn.Forte@Sun.COM  *	The physical path they are linked to is returned.
4297836SJohn.Forte@Sun.COM  *
4307836SJohn.Forte@Sun.COM  * 3) Inputs of the form /devices/...
4317836SJohn.Forte@Sun.COM  *	These are actual physical names.
4327836SJohn.Forte@Sun.COM  *	They are not converted.
4337836SJohn.Forte@Sun.COM  */
4347836SJohn.Forte@Sun.COM char *
g_get_physical_name(char * path)4357836SJohn.Forte@Sun.COM g_get_physical_name(char *path)
4367836SJohn.Forte@Sun.COM {
4377836SJohn.Forte@Sun.COM 	struct stat	stbuf;
4387836SJohn.Forte@Sun.COM 	char		s[MAXPATHLEN];
4397836SJohn.Forte@Sun.COM 	char		namebuf[MAXPATHLEN];
4407836SJohn.Forte@Sun.COM 	char		savedir[MAXPATHLEN];
4417836SJohn.Forte@Sun.COM 	char		*result = NULL;
4427836SJohn.Forte@Sun.COM 	DIR		*dirp;
4437836SJohn.Forte@Sun.COM 	struct dirent	*entp;
4447836SJohn.Forte@Sun.COM 	char		*dev_name, *char_ptr;
4457836SJohn.Forte@Sun.COM 	struct stat	sb;
4467836SJohn.Forte@Sun.COM 	int		found_flag = 0;
4477836SJohn.Forte@Sun.COM 	int		status = 0;
4487836SJohn.Forte@Sun.COM 	int		i;
4497836SJohn.Forte@Sun.COM 
4507836SJohn.Forte@Sun.COM 	/* return invalid path if path NULL */
4517836SJohn.Forte@Sun.COM 	if (path == NULL) {
4527836SJohn.Forte@Sun.COM 		return (NULL);
4537836SJohn.Forte@Sun.COM 	}
4547836SJohn.Forte@Sun.COM 
4557836SJohn.Forte@Sun.COM 	(void) strcpy(s, path);
4567836SJohn.Forte@Sun.COM 	/*
4577836SJohn.Forte@Sun.COM 	 * See if the form is cN
4587836SJohn.Forte@Sun.COM 	 * Must handle scenaro where there is a file cN in this directory
4597836SJohn.Forte@Sun.COM 	 * Bug ID: 1184633
4607836SJohn.Forte@Sun.COM 	 *
4617836SJohn.Forte@Sun.COM 	 * We could be in the /dev/rdsk directory and the file could be of
4627836SJohn.Forte@Sun.COM 	 * the form cNdNsN (See man disks).
4637836SJohn.Forte@Sun.COM 	 */
4647836SJohn.Forte@Sun.COM 	status = stat(s, &stbuf);
4657836SJohn.Forte@Sun.COM 	if (((status == -1) && (errno == ENOENT)) ||
4667836SJohn.Forte@Sun.COM 	    ((s[0] == 'c') && ((int)strlen(s) > 1) && ((int)strlen(s) < 5))) {
4677836SJohn.Forte@Sun.COM 		/*
4687836SJohn.Forte@Sun.COM 		 * Further qualify cN entry
4697836SJohn.Forte@Sun.COM 		 */
4707836SJohn.Forte@Sun.COM 		if ((s[0] != 'c') || ((int)strlen(s) <= 1) ||
4717836SJohn.Forte@Sun.COM 		((int)strlen(s) >= 5)) {
4727836SJohn.Forte@Sun.COM 			goto exit;
4737836SJohn.Forte@Sun.COM 		}
4747836SJohn.Forte@Sun.COM 		for (i = 1; i < (int)strlen(s); i++) {
4757836SJohn.Forte@Sun.COM 			if ((s[i] < '0') || (s[i] > '9')) {
4767836SJohn.Forte@Sun.COM 				goto exit;
4777836SJohn.Forte@Sun.COM 			}
4787836SJohn.Forte@Sun.COM 		}
4797836SJohn.Forte@Sun.COM 		/*
4807836SJohn.Forte@Sun.COM 		 * path does not point to a file or file is of form cN
4817836SJohn.Forte@Sun.COM 		 */
4827836SJohn.Forte@Sun.COM 		P_DPRINTF("  g_get_physical_name: "
4837836SJohn.Forte@Sun.COM 			"Found entry of the form cN n=%s len=%d\n",
4847836SJohn.Forte@Sun.COM 			&s[1], strlen(s));
4857836SJohn.Forte@Sun.COM 
4867836SJohn.Forte@Sun.COM 		dev_name = g_zalloc(sizeof ("/dev/rdsk"));
4877836SJohn.Forte@Sun.COM 		sprintf((char *)dev_name, "/dev/rdsk");
4887836SJohn.Forte@Sun.COM 
4897836SJohn.Forte@Sun.COM 		if ((dirp = opendir(dev_name)) == NULL) {
4907836SJohn.Forte@Sun.COM 			g_destroy_data(dev_name);
4917836SJohn.Forte@Sun.COM 			goto exit;
4927836SJohn.Forte@Sun.COM 		}
4937836SJohn.Forte@Sun.COM 
4947836SJohn.Forte@Sun.COM 		while ((entp = readdir(dirp)) != NULL) {
4957836SJohn.Forte@Sun.COM 		    if (strcmp(entp->d_name, ".") == 0 ||
4967836SJohn.Forte@Sun.COM 			strcmp(entp->d_name, "..") == 0)
4977836SJohn.Forte@Sun.COM 			continue;
4987836SJohn.Forte@Sun.COM 
4997836SJohn.Forte@Sun.COM 		    if (entp->d_name[0] != 'c')
5007836SJohn.Forte@Sun.COM 			/*
5017836SJohn.Forte@Sun.COM 			 * Silently Ignore for now any names
5027836SJohn.Forte@Sun.COM 			 * not stating with c
5037836SJohn.Forte@Sun.COM 			 */
5047836SJohn.Forte@Sun.COM 			continue;
5057836SJohn.Forte@Sun.COM 
5067836SJohn.Forte@Sun.COM 		    sprintf(namebuf, "%s/%s", dev_name, entp->d_name);
5077836SJohn.Forte@Sun.COM 
5087836SJohn.Forte@Sun.COM 		    if ((lstat(namebuf, &sb)) < 0) {
5097836SJohn.Forte@Sun.COM 				L_WARNINGS(MSGSTR(55,
5107836SJohn.Forte@Sun.COM 					"Warning: Cannot stat %s\n"),
5117836SJohn.Forte@Sun.COM 					namebuf);
5127836SJohn.Forte@Sun.COM 			continue;
5137836SJohn.Forte@Sun.COM 		    }
5147836SJohn.Forte@Sun.COM 
5157836SJohn.Forte@Sun.COM 		    if (!S_ISLNK(sb.st_mode)) {
5167836SJohn.Forte@Sun.COM 				L_WARNINGS(MSGSTR(56,
5177836SJohn.Forte@Sun.COM 					"Warning: %s is not a symbolic link\n"),
5187836SJohn.Forte@Sun.COM 					namebuf);
5197836SJohn.Forte@Sun.COM 			continue;
5207836SJohn.Forte@Sun.COM 		    }
5217836SJohn.Forte@Sun.COM 
5227836SJohn.Forte@Sun.COM 		    if (strstr(entp->d_name, s) != NULL) {
5237836SJohn.Forte@Sun.COM 			/*
5247836SJohn.Forte@Sun.COM 			 * found link to device in /devices
5257836SJohn.Forte@Sun.COM 			 *
5267836SJohn.Forte@Sun.COM 			 * Further qualify to be sure I have
5277836SJohn.Forte@Sun.COM 			 * not found entry of the form c10
5287836SJohn.Forte@Sun.COM 			 * when I am searching for c1
5297836SJohn.Forte@Sun.COM 			 */
5307836SJohn.Forte@Sun.COM 			if (atoi(&s[1]) == atoi(&entp->d_name[1])) {
5317836SJohn.Forte@Sun.COM 			    P_DPRINTF("  g_get_physical_name: "
5327836SJohn.Forte@Sun.COM 			    "Found entry in /dev/rdsk matching %s: %s\n",
5337836SJohn.Forte@Sun.COM 				s, entp->d_name);
5347836SJohn.Forte@Sun.COM 				found_flag = 1;
5357836SJohn.Forte@Sun.COM 				break;
5367836SJohn.Forte@Sun.COM 			}
5377836SJohn.Forte@Sun.COM 		    }
5387836SJohn.Forte@Sun.COM 		}
5397836SJohn.Forte@Sun.COM 		closedir(dirp);
5407836SJohn.Forte@Sun.COM 		g_destroy_data(dev_name);
5417836SJohn.Forte@Sun.COM 
5427836SJohn.Forte@Sun.COM 		if (found_flag) {
5437836SJohn.Forte@Sun.COM 		    result = g_get_physical_name_from_link(namebuf);
5447836SJohn.Forte@Sun.COM 		    if (result == NULL) {
5457836SJohn.Forte@Sun.COM 			goto exit;
5467836SJohn.Forte@Sun.COM 		    }
5477836SJohn.Forte@Sun.COM 			/*
5487836SJohn.Forte@Sun.COM 			 * Convert from device name to controller name
5497836SJohn.Forte@Sun.COM 			 */
5507836SJohn.Forte@Sun.COM 		    char_ptr = strrchr(result, '/');
5517836SJohn.Forte@Sun.COM 		    *char_ptr = '\0';   /* Terminate sting  */
5527836SJohn.Forte@Sun.COM 		    (void) strcat(result, CTLR_POSTFIX);
5537836SJohn.Forte@Sun.COM 		}
5547836SJohn.Forte@Sun.COM 		goto exit;
5557836SJohn.Forte@Sun.COM 	}
5567836SJohn.Forte@Sun.COM 	if (status == -1)
5577836SJohn.Forte@Sun.COM 		goto exit;
5587836SJohn.Forte@Sun.COM 
5597836SJohn.Forte@Sun.COM 	if (lstat(s, &stbuf) == -1) {
5607836SJohn.Forte@Sun.COM 			L_WARNINGS(MSGSTR(134,
5617836SJohn.Forte@Sun.COM 				"%s: lstat() failed - %s\n"),
5627836SJohn.Forte@Sun.COM 				s, strerror(errno));
5637836SJohn.Forte@Sun.COM 		goto exit;
5647836SJohn.Forte@Sun.COM 	}
5657836SJohn.Forte@Sun.COM 	/*
5667836SJohn.Forte@Sun.COM 	 */
5677836SJohn.Forte@Sun.COM 	if (!S_ISLNK(stbuf.st_mode)) {
5687836SJohn.Forte@Sun.COM 		/*
5697836SJohn.Forte@Sun.COM 		 * Path is not a linked file so must be
5707836SJohn.Forte@Sun.COM 		 * a physical path
5717836SJohn.Forte@Sun.COM 		 */
5727836SJohn.Forte@Sun.COM 		if (S_ISCHR(stbuf.st_mode) || S_ISDIR(stbuf.st_mode)) {
5737836SJohn.Forte@Sun.COM 			/* Make sure a full path as that is required. */
5747836SJohn.Forte@Sun.COM 			if (strstr(s, "/devices")) {
5757836SJohn.Forte@Sun.COM 				result = g_alloc_string(s);
5767836SJohn.Forte@Sun.COM 			} else {
5777836SJohn.Forte@Sun.COM 				if (getcwd(savedir,
5787836SJohn.Forte@Sun.COM 					sizeof (savedir)) == NULL) {
5797836SJohn.Forte@Sun.COM 					return (NULL);
5807836SJohn.Forte@Sun.COM 				}
5817836SJohn.Forte@Sun.COM 				/*
5827836SJohn.Forte@Sun.COM 				 * Check for this format:
5837836SJohn.Forte@Sun.COM 				 * ./ssd@0,1:g,raw
5847836SJohn.Forte@Sun.COM 				 */
5857836SJohn.Forte@Sun.COM 				if (s[0] == '.') {
5867836SJohn.Forte@Sun.COM 					strcat(savedir, &s[1]);
5877836SJohn.Forte@Sun.COM 				} else {
5887836SJohn.Forte@Sun.COM 					strcat(savedir, "/");
5897836SJohn.Forte@Sun.COM 					strcat(savedir, s);
5907836SJohn.Forte@Sun.COM 				}
5917836SJohn.Forte@Sun.COM 				result = g_alloc_string(savedir);
5927836SJohn.Forte@Sun.COM 			}
5937836SJohn.Forte@Sun.COM 		}
5947836SJohn.Forte@Sun.COM 	} else {
5957836SJohn.Forte@Sun.COM 		/*
5967836SJohn.Forte@Sun.COM 		 * Entry is linked file
5977836SJohn.Forte@Sun.COM 		 * so follow link to physical name
5987836SJohn.Forte@Sun.COM 		 */
5997836SJohn.Forte@Sun.COM 		result = g_get_physical_name_from_link(path);
6007836SJohn.Forte@Sun.COM 	}
6017836SJohn.Forte@Sun.COM 
6027836SJohn.Forte@Sun.COM exit:
6037836SJohn.Forte@Sun.COM 	return (result);
6047836SJohn.Forte@Sun.COM }
6057836SJohn.Forte@Sun.COM 
6067836SJohn.Forte@Sun.COM /*
6077836SJohn.Forte@Sun.COM  *	Function to open a device
6087836SJohn.Forte@Sun.COM  */
6097836SJohn.Forte@Sun.COM int
g_object_open(char * path,int flag)6107836SJohn.Forte@Sun.COM g_object_open(char *path, int flag)
6117836SJohn.Forte@Sun.COM {
6127836SJohn.Forte@Sun.COM int fd = -1, retry = 0;
6137836SJohn.Forte@Sun.COM 	if (getenv("_LUX_O_DEBUG") != NULL) {
6147836SJohn.Forte@Sun.COM 		(void) printf("  Object_open:%s ", path);
6157836SJohn.Forte@Sun.COM 		if (flag & O_WRONLY) {
6167836SJohn.Forte@Sun.COM 			(void) printf("O_WRONLY,");
6177836SJohn.Forte@Sun.COM 		} else if (flag & O_RDWR) {
6187836SJohn.Forte@Sun.COM 			(void) printf("O_RDWR,");
6197836SJohn.Forte@Sun.COM 		} else {
6207836SJohn.Forte@Sun.COM 			(void) printf("O_RDONLY,");
6217836SJohn.Forte@Sun.COM 		}
6227836SJohn.Forte@Sun.COM 		if (flag & O_NDELAY) {
6237836SJohn.Forte@Sun.COM 			(void) printf("O_NDELAY,");
6247836SJohn.Forte@Sun.COM 		}
6257836SJohn.Forte@Sun.COM 		if (flag & O_APPEND) {
6267836SJohn.Forte@Sun.COM 			(void) printf("O_APPEND,");
6277836SJohn.Forte@Sun.COM 		}
6287836SJohn.Forte@Sun.COM 		if (flag & O_DSYNC) {
6297836SJohn.Forte@Sun.COM 			(void) printf("O_DSYNC,");
6307836SJohn.Forte@Sun.COM 		}
6317836SJohn.Forte@Sun.COM 		if (flag & O_RSYNC) {
6327836SJohn.Forte@Sun.COM 			(void) printf("O_RSYNC,");
6337836SJohn.Forte@Sun.COM 		}
6347836SJohn.Forte@Sun.COM 		if (flag & O_SYNC) {
6357836SJohn.Forte@Sun.COM 			(void) printf("O_SYNC,");
6367836SJohn.Forte@Sun.COM 		}
6377836SJohn.Forte@Sun.COM 		if (flag & O_NOCTTY) {
6387836SJohn.Forte@Sun.COM 			(void) printf("O_NOCTTY,");
6397836SJohn.Forte@Sun.COM 		}
6407836SJohn.Forte@Sun.COM 		if (flag & O_CREAT) {
6417836SJohn.Forte@Sun.COM 			(void) printf("O_CREAT,");
6427836SJohn.Forte@Sun.COM 		}
6437836SJohn.Forte@Sun.COM 		if (flag & O_EXCL) {
6447836SJohn.Forte@Sun.COM 			(void) printf("O_EXCL,");
6457836SJohn.Forte@Sun.COM 		}
6467836SJohn.Forte@Sun.COM 		if (flag & O_TRUNC) {
6477836SJohn.Forte@Sun.COM 			(void) printf("O_TRUNC,");
6487836SJohn.Forte@Sun.COM 		}
6497836SJohn.Forte@Sun.COM 		(void) printf("\n");
6507836SJohn.Forte@Sun.COM 	}
6517836SJohn.Forte@Sun.COM 
6527836SJohn.Forte@Sun.COM 	/* Open retries introduced due to bugid 4473337	*/
6537836SJohn.Forte@Sun.COM 	errno	= 0;
6547836SJohn.Forte@Sun.COM 	fd	= open(path, flag);
6557836SJohn.Forte@Sun.COM 	while (fd < 0 && retry++ < RETRY_OBJECT_OPEN && (
6567836SJohn.Forte@Sun.COM 			errno == EBUSY || errno == EAGAIN)) {
6577836SJohn.Forte@Sun.COM 		O_DPRINTF("  Object_open: Retried:%d %d %s\n",
6587836SJohn.Forte@Sun.COM 			retry, errno, path);
6597836SJohn.Forte@Sun.COM 		(void) usleep(WAIT_OBJECT_OPEN);
6607836SJohn.Forte@Sun.COM 		fd = open(path, flag);
6617836SJohn.Forte@Sun.COM 	}
6627836SJohn.Forte@Sun.COM 	if (fd < 0) {
6637836SJohn.Forte@Sun.COM 		O_DPRINTF("  Object_open: Open failed:%s\n", path);
6647836SJohn.Forte@Sun.COM 	}
6657836SJohn.Forte@Sun.COM 	return (fd);
6667836SJohn.Forte@Sun.COM }
6677836SJohn.Forte@Sun.COM 
6687836SJohn.Forte@Sun.COM 
6697836SJohn.Forte@Sun.COM /*
6707836SJohn.Forte@Sun.COM  * Return a pointer to a string telling us the name of the command.
6717836SJohn.Forte@Sun.COM  */
6727836SJohn.Forte@Sun.COM char *
g_scsi_find_command_name(int cmd)6737836SJohn.Forte@Sun.COM g_scsi_find_command_name(int cmd)
6747836SJohn.Forte@Sun.COM {
6757836SJohn.Forte@Sun.COM /*
6767836SJohn.Forte@Sun.COM  * Names of commands.  Must have SCMD_UNKNOWN at end of list.
6777836SJohn.Forte@Sun.COM  */
6787836SJohn.Forte@Sun.COM struct scsi_command_name {
6797836SJohn.Forte@Sun.COM 	int command;
6807836SJohn.Forte@Sun.COM 	char	*name;
6817836SJohn.Forte@Sun.COM } scsi_command_names[29];
6827836SJohn.Forte@Sun.COM 
6837836SJohn.Forte@Sun.COM register struct scsi_command_name *c;
6847836SJohn.Forte@Sun.COM 
6857836SJohn.Forte@Sun.COM 	scsi_command_names[0].command = SCMD_TEST_UNIT_READY;
6867836SJohn.Forte@Sun.COM 	scsi_command_names[0].name = MSGSTR(61, "Test Unit Ready");
6877836SJohn.Forte@Sun.COM 
6887836SJohn.Forte@Sun.COM 	scsi_command_names[1].command = SCMD_FORMAT;
6897836SJohn.Forte@Sun.COM 	scsi_command_names[1].name = MSGSTR(110, "Format");
6907836SJohn.Forte@Sun.COM 
6917836SJohn.Forte@Sun.COM 	scsi_command_names[2].command = SCMD_REASSIGN_BLOCK;
6927836SJohn.Forte@Sun.COM 	scsi_command_names[2].name = MSGSTR(77, "Reassign Block");
6937836SJohn.Forte@Sun.COM 
6947836SJohn.Forte@Sun.COM 	scsi_command_names[3].command = SCMD_READ;
6957836SJohn.Forte@Sun.COM 	scsi_command_names[3].name = MSGSTR(27, "Read");
6967836SJohn.Forte@Sun.COM 
6977836SJohn.Forte@Sun.COM 	scsi_command_names[4].command = SCMD_WRITE;
6987836SJohn.Forte@Sun.COM 	scsi_command_names[4].name = MSGSTR(54, "Write");
6997836SJohn.Forte@Sun.COM 
7007836SJohn.Forte@Sun.COM 	scsi_command_names[5].command = SCMD_READ_G1;
7017836SJohn.Forte@Sun.COM 	scsi_command_names[5].name = MSGSTR(79, "Read(10 Byte)");
7027836SJohn.Forte@Sun.COM 
7037836SJohn.Forte@Sun.COM 	scsi_command_names[6].command = SCMD_WRITE_G1;
7047836SJohn.Forte@Sun.COM 	scsi_command_names[6].name = MSGSTR(51, "Write(10 Byte)");
7057836SJohn.Forte@Sun.COM 
7067836SJohn.Forte@Sun.COM 	scsi_command_names[7].command = SCMD_MODE_SELECT;
7077836SJohn.Forte@Sun.COM 	scsi_command_names[7].name = MSGSTR(97, "Mode Select");
7087836SJohn.Forte@Sun.COM 
7097836SJohn.Forte@Sun.COM 	scsi_command_names[8].command = SCMD_MODE_SENSE;
7107836SJohn.Forte@Sun.COM 	scsi_command_names[8].name = MSGSTR(95, "Mode Sense");
7117836SJohn.Forte@Sun.COM 
7127836SJohn.Forte@Sun.COM 	scsi_command_names[9].command = SCMD_REASSIGN_BLOCK;
7137836SJohn.Forte@Sun.COM 	scsi_command_names[9].name = MSGSTR(77, "Reassign Block");
7147836SJohn.Forte@Sun.COM 
7157836SJohn.Forte@Sun.COM 	scsi_command_names[10].command = SCMD_REQUEST_SENSE;
7167836SJohn.Forte@Sun.COM 	scsi_command_names[10].name = MSGSTR(74, "Request Sense");
7177836SJohn.Forte@Sun.COM 
7187836SJohn.Forte@Sun.COM 	scsi_command_names[11].command = SCMD_READ_DEFECT_LIST;
7197836SJohn.Forte@Sun.COM 	scsi_command_names[11].name = MSGSTR(80, "Read Defect List");
7207836SJohn.Forte@Sun.COM 
7217836SJohn.Forte@Sun.COM 	scsi_command_names[12].command = SCMD_INQUIRY;
7227836SJohn.Forte@Sun.COM 	scsi_command_names[12].name = MSGSTR(102, "Inquiry");
7237836SJohn.Forte@Sun.COM 
7247836SJohn.Forte@Sun.COM 	scsi_command_names[13].command = SCMD_WRITE_BUFFER;
7257836SJohn.Forte@Sun.COM 	scsi_command_names[13].name = MSGSTR(53, "Write Buffer");
7267836SJohn.Forte@Sun.COM 
7277836SJohn.Forte@Sun.COM 	scsi_command_names[14].command = SCMD_READ_BUFFER;
7287836SJohn.Forte@Sun.COM 	scsi_command_names[14].name = MSGSTR(82, "Read Buffer");
7297836SJohn.Forte@Sun.COM 
7307836SJohn.Forte@Sun.COM 	scsi_command_names[15].command = SCMD_START_STOP;
7317836SJohn.Forte@Sun.COM 	scsi_command_names[15].name = MSGSTR(67, "Start/Stop");
7327836SJohn.Forte@Sun.COM 
7337836SJohn.Forte@Sun.COM 	scsi_command_names[16].command = SCMD_RESERVE;
7347836SJohn.Forte@Sun.COM 	scsi_command_names[16].name = MSGSTR(72, "Reserve");
7357836SJohn.Forte@Sun.COM 
7367836SJohn.Forte@Sun.COM 	scsi_command_names[17].command = SCMD_RELEASE;
7377836SJohn.Forte@Sun.COM 	scsi_command_names[17].name = MSGSTR(75, "Release");
7387836SJohn.Forte@Sun.COM 
7397836SJohn.Forte@Sun.COM 	scsi_command_names[18].command = SCMD_MODE_SENSE_G1;
7407836SJohn.Forte@Sun.COM 	scsi_command_names[18].name = MSGSTR(94, "Mode Sense(10 Byte)");
7417836SJohn.Forte@Sun.COM 
7427836SJohn.Forte@Sun.COM 	scsi_command_names[19].command = SCMD_MODE_SELECT_G1;
7437836SJohn.Forte@Sun.COM 	scsi_command_names[19].name = MSGSTR(96, "Mode Select(10 Byte)");
7447836SJohn.Forte@Sun.COM 
7457836SJohn.Forte@Sun.COM 	scsi_command_names[20].command = SCMD_READ_CAPACITY;
7467836SJohn.Forte@Sun.COM 	scsi_command_names[20].name = MSGSTR(81, "Read Capacity");
7477836SJohn.Forte@Sun.COM 
7487836SJohn.Forte@Sun.COM 	scsi_command_names[21].command = SCMD_SYNC_CACHE;
7497836SJohn.Forte@Sun.COM 	scsi_command_names[21].name = MSGSTR(64, "Synchronize Cache");
7507836SJohn.Forte@Sun.COM 
7517836SJohn.Forte@Sun.COM 	scsi_command_names[22].command = SCMD_READ_DEFECT_LIST;
7527836SJohn.Forte@Sun.COM 	scsi_command_names[22].name = MSGSTR(80, "Read Defect List");
7537836SJohn.Forte@Sun.COM 
7547836SJohn.Forte@Sun.COM 	scsi_command_names[23].command = SCMD_GDIAG;
7557836SJohn.Forte@Sun.COM 	scsi_command_names[23].name = MSGSTR(108, "Get Diagnostic");
7567836SJohn.Forte@Sun.COM 
7577836SJohn.Forte@Sun.COM 	scsi_command_names[24].command = SCMD_SDIAG;
7587836SJohn.Forte@Sun.COM 	scsi_command_names[24].name = MSGSTR(69, "Set Diagnostic");
7597836SJohn.Forte@Sun.COM 
7607836SJohn.Forte@Sun.COM 	scsi_command_names[25].command = SCMD_PERS_RESERV_IN;
7617836SJohn.Forte@Sun.COM 	scsi_command_names[25].name = MSGSTR(10500, "Persistent Reserve In");
7627836SJohn.Forte@Sun.COM 
7637836SJohn.Forte@Sun.COM 	scsi_command_names[26].command = SCMD_PERS_RESERV_OUT;
7647836SJohn.Forte@Sun.COM 	scsi_command_names[26].name = MSGSTR(10501, "Persistent Reserve out");
7657836SJohn.Forte@Sun.COM 
7667836SJohn.Forte@Sun.COM 	scsi_command_names[27].command = SCMD_LOG_SENSE;
7677836SJohn.Forte@Sun.COM 	scsi_command_names[27].name = MSGSTR(10502, "Log Sense");
7687836SJohn.Forte@Sun.COM 
7697836SJohn.Forte@Sun.COM 	scsi_command_names[28].command = SCMD_UNKNOWN;
7707836SJohn.Forte@Sun.COM 	scsi_command_names[28].name = MSGSTR(25, "Unknown");
7717836SJohn.Forte@Sun.COM 
7727836SJohn.Forte@Sun.COM 
7737836SJohn.Forte@Sun.COM 	for (c = scsi_command_names; c->command != SCMD_UNKNOWN; c++)
7747836SJohn.Forte@Sun.COM 		if (c->command == cmd)
7757836SJohn.Forte@Sun.COM 			break;
7767836SJohn.Forte@Sun.COM 	return (c->name);
7777836SJohn.Forte@Sun.COM }
7787836SJohn.Forte@Sun.COM 
7797836SJohn.Forte@Sun.COM 
7807836SJohn.Forte@Sun.COM /*
7817836SJohn.Forte@Sun.COM  *	Function to create error message containing
7827836SJohn.Forte@Sun.COM  *	scsi request sense information
7837836SJohn.Forte@Sun.COM  */
7847836SJohn.Forte@Sun.COM 
7857836SJohn.Forte@Sun.COM void
g_scsi_printerr(struct uscsi_cmd * ucmd,struct scsi_extended_sense * rq,int rqlen,char msg_string[],char * err_string)7867836SJohn.Forte@Sun.COM g_scsi_printerr(struct uscsi_cmd *ucmd, struct scsi_extended_sense *rq,
7877836SJohn.Forte@Sun.COM 		int rqlen, char msg_string[], char *err_string)
7887836SJohn.Forte@Sun.COM {
7897836SJohn.Forte@Sun.COM 	int		blkno;
7907836SJohn.Forte@Sun.COM 
7917836SJohn.Forte@Sun.COM 	switch (rq->es_key) {
7927836SJohn.Forte@Sun.COM 	case KEY_NO_SENSE:
7937836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(91, "No sense error"));
7947836SJohn.Forte@Sun.COM 		break;
7957836SJohn.Forte@Sun.COM 	case KEY_RECOVERABLE_ERROR:
7967836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(76, "Recoverable error"));
7977836SJohn.Forte@Sun.COM 		break;
7987836SJohn.Forte@Sun.COM 	case KEY_NOT_READY:
7997836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string,
8007836SJohn.Forte@Sun.COM 			MSGSTR(10503,
8017836SJohn.Forte@Sun.COM 			"Device Not ready."
8027836SJohn.Forte@Sun.COM 			" Error: Random Retry Failed: %s\n."),
8037836SJohn.Forte@Sun.COM 			err_string);
8047836SJohn.Forte@Sun.COM 		break;
8057836SJohn.Forte@Sun.COM 	case KEY_MEDIUM_ERROR:
8067836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(99, "Medium error"));
8077836SJohn.Forte@Sun.COM 		break;
8087836SJohn.Forte@Sun.COM 	case KEY_HARDWARE_ERROR:
8097836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(106, "Hardware error"));
8107836SJohn.Forte@Sun.COM 		break;
8117836SJohn.Forte@Sun.COM 	case KEY_ILLEGAL_REQUEST:
8127836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(103, "Illegal request"));
8137836SJohn.Forte@Sun.COM 		break;
8147836SJohn.Forte@Sun.COM 	case KEY_UNIT_ATTENTION:
8157836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string,
8167836SJohn.Forte@Sun.COM 			MSGSTR(10504,
8177836SJohn.Forte@Sun.COM 			"Unit attention."
8187836SJohn.Forte@Sun.COM 			"Error: Random Retry Failed.\n"));
8197836SJohn.Forte@Sun.COM 		break;
8207836SJohn.Forte@Sun.COM 	case KEY_WRITE_PROTECT:
8217836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(52, "Write protect error"));
8227836SJohn.Forte@Sun.COM 		break;
8237836SJohn.Forte@Sun.COM 	case KEY_BLANK_CHECK:
8247836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(131, "Blank check error"));
8257836SJohn.Forte@Sun.COM 		break;
8267836SJohn.Forte@Sun.COM 	case KEY_VENDOR_UNIQUE:
8277836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(58, "Vendor unique error"));
8287836SJohn.Forte@Sun.COM 		break;
8297836SJohn.Forte@Sun.COM 	case KEY_COPY_ABORTED:
8307836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(123, "Copy aborted error"));
8317836SJohn.Forte@Sun.COM 		break;
8327836SJohn.Forte@Sun.COM 	case KEY_ABORTED_COMMAND:
8337836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string,
8347836SJohn.Forte@Sun.COM 			MSGSTR(10505,
8357836SJohn.Forte@Sun.COM 			"Aborted command."
8367836SJohn.Forte@Sun.COM 			" Error: Random Retry Failed.\n"));
8377836SJohn.Forte@Sun.COM 		break;
8387836SJohn.Forte@Sun.COM 	case KEY_EQUAL:
8397836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(117, "Equal error"));
8407836SJohn.Forte@Sun.COM 		break;
8417836SJohn.Forte@Sun.COM 	case KEY_VOLUME_OVERFLOW:
8427836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(57, "Volume overflow"));
8437836SJohn.Forte@Sun.COM 		break;
8447836SJohn.Forte@Sun.COM 	case KEY_MISCOMPARE:
8457836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(98, "Miscompare error"));
8467836SJohn.Forte@Sun.COM 		break;
8477836SJohn.Forte@Sun.COM 	case KEY_RESERVED:
8487836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(10506,
8497836SJohn.Forte@Sun.COM 			"Reserved value found"));
8507836SJohn.Forte@Sun.COM 		break;
8517836SJohn.Forte@Sun.COM 	default:
8527836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(59, "Unknown error"));
8537836SJohn.Forte@Sun.COM 		break;
8547836SJohn.Forte@Sun.COM 	}
8557836SJohn.Forte@Sun.COM 
8567836SJohn.Forte@Sun.COM 	(void) sprintf(&msg_string[strlen(msg_string)],
8577836SJohn.Forte@Sun.COM 		MSGSTR(10507, " during: %s"),
8587836SJohn.Forte@Sun.COM 		g_scsi_find_command_name(ucmd->uscsi_cdb[0]));
8597836SJohn.Forte@Sun.COM 
8607836SJohn.Forte@Sun.COM 	if (rq->es_valid) {
8617836SJohn.Forte@Sun.COM 		blkno = (rq->es_info_1 << 24) | (rq->es_info_2 << 16) |
8627836SJohn.Forte@Sun.COM 			(rq->es_info_3 << 8) | rq->es_info_4;
8637836SJohn.Forte@Sun.COM 		(void) sprintf(&msg_string[strlen(msg_string)],
8647836SJohn.Forte@Sun.COM 			MSGSTR(49, ": block %d (0x%x)"), blkno, blkno);
8657836SJohn.Forte@Sun.COM 	}
8667836SJohn.Forte@Sun.COM 
8677836SJohn.Forte@Sun.COM 	(void) sprintf(&msg_string[strlen(msg_string)], "\n");
8687836SJohn.Forte@Sun.COM 
8697836SJohn.Forte@Sun.COM 	if (rq->es_add_len >= 6) {
8707836SJohn.Forte@Sun.COM 		(void) sprintf(&msg_string[strlen(msg_string)],
8717836SJohn.Forte@Sun.COM 		MSGSTR(132, "  Additional sense: 0x%x   ASC Qualifier: 0x%x\n"),
8727836SJohn.Forte@Sun.COM 			rq->es_add_code, rq->es_qual_code);
8737836SJohn.Forte@Sun.COM 			/*
8747836SJohn.Forte@Sun.COM 			 * rq->es_add_info[ADD_SENSE_CODE],
8757836SJohn.Forte@Sun.COM 			 * rq->es_add_info[ADD_SENSE_QUAL_CODE]);
8767836SJohn.Forte@Sun.COM 			 */
8777836SJohn.Forte@Sun.COM 	}
8787836SJohn.Forte@Sun.COM 	if (rq->es_key == KEY_ILLEGAL_REQUEST) {
8797836SJohn.Forte@Sun.COM 		string_dump(MSGSTR(47, " cmd:   "), (uchar_t *)ucmd,
8807836SJohn.Forte@Sun.COM 			sizeof (struct uscsi_cmd), HEX_ONLY, msg_string);
8817836SJohn.Forte@Sun.COM 		string_dump(MSGSTR(48, " cdb:   "),
8827836SJohn.Forte@Sun.COM 			(uchar_t *)ucmd->uscsi_cdb,
8837836SJohn.Forte@Sun.COM 			ucmd->uscsi_cdblen, HEX_ONLY, msg_string);
8847836SJohn.Forte@Sun.COM 	}
8857836SJohn.Forte@Sun.COM 	string_dump(MSGSTR(43, " sense:  "),
8867836SJohn.Forte@Sun.COM 		(uchar_t *)rq, 8 + rq->es_add_len, HEX_ONLY,
8877836SJohn.Forte@Sun.COM 		msg_string);
8887836SJohn.Forte@Sun.COM 	rqlen = rqlen;	/* not used */
8897836SJohn.Forte@Sun.COM }
8907836SJohn.Forte@Sun.COM 
8917836SJohn.Forte@Sun.COM 
8927836SJohn.Forte@Sun.COM /*
8937836SJohn.Forte@Sun.COM  *		Special string dump for error message
8947836SJohn.Forte@Sun.COM  */
8957836SJohn.Forte@Sun.COM static	void
string_dump(char * hdr,uchar_t * src,int nbytes,int format,char msg_string[])8967836SJohn.Forte@Sun.COM string_dump(char *hdr, uchar_t *src, int nbytes, int format, char msg_string[])
8977836SJohn.Forte@Sun.COM {
8987836SJohn.Forte@Sun.COM 	int i;
8997836SJohn.Forte@Sun.COM 	int n;
9007836SJohn.Forte@Sun.COM 	char	*p;
9017836SJohn.Forte@Sun.COM 	char	s[256];
9027836SJohn.Forte@Sun.COM 
9037836SJohn.Forte@Sun.COM 	assert(format == HEX_ONLY || format == HEX_ASCII);
9047836SJohn.Forte@Sun.COM 
9057836SJohn.Forte@Sun.COM 	(void) strcpy(s, hdr);
9067836SJohn.Forte@Sun.COM 	for (p = s; *p; p++) {
9077836SJohn.Forte@Sun.COM 		*p = ' ';
9087836SJohn.Forte@Sun.COM 	}
9097836SJohn.Forte@Sun.COM 
9107836SJohn.Forte@Sun.COM 	p = hdr;
9117836SJohn.Forte@Sun.COM 	while (nbytes > 0) {
9127836SJohn.Forte@Sun.COM 		(void) sprintf(&msg_string[strlen(msg_string)],
9137836SJohn.Forte@Sun.COM 			"%s", p);
9147836SJohn.Forte@Sun.COM 		p = s;
9157836SJohn.Forte@Sun.COM 		n = min(nbytes, BYTES_PER_LINE);
9167836SJohn.Forte@Sun.COM 		for (i = 0; i < n; i++) {
9177836SJohn.Forte@Sun.COM 			(void) sprintf(&msg_string[strlen(msg_string)],
9187836SJohn.Forte@Sun.COM 				"%02x ",
9197836SJohn.Forte@Sun.COM 				src[i] & 0xff);
9207836SJohn.Forte@Sun.COM 		}
9217836SJohn.Forte@Sun.COM 		if (format == HEX_ASCII) {
9227836SJohn.Forte@Sun.COM 			for (i = BYTES_PER_LINE-n; i > 0; i--) {
9237836SJohn.Forte@Sun.COM 				(void) sprintf(&msg_string[strlen(msg_string)],
9247836SJohn.Forte@Sun.COM 					"   ");
9257836SJohn.Forte@Sun.COM 			}
9267836SJohn.Forte@Sun.COM 			(void) sprintf(&msg_string[strlen(msg_string)],
9277836SJohn.Forte@Sun.COM 				"    ");
9287836SJohn.Forte@Sun.COM 			for (i = 0; i < n; i++) {
9297836SJohn.Forte@Sun.COM 				(void) sprintf(&msg_string[strlen(msg_string)],
9307836SJohn.Forte@Sun.COM 					"%c",
9317836SJohn.Forte@Sun.COM 					isprint(src[i]) ? src[i] : '.');
9327836SJohn.Forte@Sun.COM 			}
9337836SJohn.Forte@Sun.COM 		}
9347836SJohn.Forte@Sun.COM 		(void) sprintf(&msg_string[strlen(msg_string)], "\n");
9357836SJohn.Forte@Sun.COM 		nbytes -= n;
9367836SJohn.Forte@Sun.COM 		src += n;
9377836SJohn.Forte@Sun.COM 	}
9387836SJohn.Forte@Sun.COM }
9397836SJohn.Forte@Sun.COM 
9407836SJohn.Forte@Sun.COM 
9417836SJohn.Forte@Sun.COM 
9427836SJohn.Forte@Sun.COM /*
9437836SJohn.Forte@Sun.COM  * This routine is a wrapper for malloc.  It allocates pre-zeroed space,
9447836SJohn.Forte@Sun.COM  * and checks the return value so the caller doesn't have to.
9457836SJohn.Forte@Sun.COM  */
9467836SJohn.Forte@Sun.COM void *
g_zalloc(int count)9477836SJohn.Forte@Sun.COM g_zalloc(int count)
9487836SJohn.Forte@Sun.COM {
9497836SJohn.Forte@Sun.COM 	void	*ptr;
9507836SJohn.Forte@Sun.COM 
9517836SJohn.Forte@Sun.COM 	ptr = (void *) calloc(1, (unsigned)count);
9527836SJohn.Forte@Sun.COM 	A_DPRINTF("  g_zalloc: Allocated 0x%x bytes "
9537836SJohn.Forte@Sun.COM 			"at 0x%x\n", count, ptr);
9547836SJohn.Forte@Sun.COM 
9557836SJohn.Forte@Sun.COM 	return (ptr);
9567836SJohn.Forte@Sun.COM }
9577836SJohn.Forte@Sun.COM 
9587836SJohn.Forte@Sun.COM /*
9597836SJohn.Forte@Sun.COM  * Open up the i18n catalog.
9607836SJohn.Forte@Sun.COM  * Returns:
9617836SJohn.Forte@Sun.COM  *  0 = O.K.
9627836SJohn.Forte@Sun.COM  * -1 = Failed (Will revert to default strings)
9637836SJohn.Forte@Sun.COM  */
9647836SJohn.Forte@Sun.COM int
g_i18n_catopen(void)9657836SJohn.Forte@Sun.COM g_i18n_catopen(void)
9667836SJohn.Forte@Sun.COM {
9677836SJohn.Forte@Sun.COM 	static int fileopen = 0;
9687836SJohn.Forte@Sun.COM 	static mutex_t mp;
9697836SJohn.Forte@Sun.COM 
9707836SJohn.Forte@Sun.COM 	if (setlocale(LC_ALL, "") == NULL) {
9717836SJohn.Forte@Sun.COM 	    (void) fprintf(stderr,
9727836SJohn.Forte@Sun.COM 		"Cannot operate in the locale requested. "
9737836SJohn.Forte@Sun.COM 		"Continuing in the default C locale\n");
9747836SJohn.Forte@Sun.COM 	}
9757836SJohn.Forte@Sun.COM 	if (mutex_lock(&mp) != 0) {
9767836SJohn.Forte@Sun.COM 		return (-1);
9777836SJohn.Forte@Sun.COM 	}
9787836SJohn.Forte@Sun.COM 	if (!fileopen) {
9797836SJohn.Forte@Sun.COM 		l_catd = catopen("a5k_g_fc_i18n_cat", NL_CAT_LOCALE);
9807836SJohn.Forte@Sun.COM 		if (l_catd == (nl_catd)-1) {
9817836SJohn.Forte@Sun.COM 			(void) mutex_unlock(&mp);
9827836SJohn.Forte@Sun.COM 			return (-1);
9837836SJohn.Forte@Sun.COM 		}
9847836SJohn.Forte@Sun.COM 		fileopen = 1;
9857836SJohn.Forte@Sun.COM 	}
9867836SJohn.Forte@Sun.COM 	(void) mutex_unlock(&mp);
9877836SJohn.Forte@Sun.COM 	return (0);
9887836SJohn.Forte@Sun.COM }
9897836SJohn.Forte@Sun.COM 
9907836SJohn.Forte@Sun.COM /* Macro used by g_get_path_type() */
9917836SJohn.Forte@Sun.COM #define	GetMatch(s_ptr)	\
9927836SJohn.Forte@Sun.COM 	for (found = 0, search_arr_ptr = s_ptr; \
9937836SJohn.Forte@Sun.COM 		search_arr_ptr->string != NULL; \
9947836SJohn.Forte@Sun.COM 			search_arr_ptr++) {\
9957836SJohn.Forte@Sun.COM 		if (strstr(path_ptr, search_arr_ptr->string) != NULL) {\
9967836SJohn.Forte@Sun.COM 			found = 1;\
9977836SJohn.Forte@Sun.COM 			break;\
9987836SJohn.Forte@Sun.COM 		}\
9997836SJohn.Forte@Sun.COM 	}
10007836SJohn.Forte@Sun.COM 
10017836SJohn.Forte@Sun.COM /*
10027836SJohn.Forte@Sun.COM  * Input  : A NULL terminated string
10037836SJohn.Forte@Sun.COM  *          This string is checked to be an absolute device path
10047836SJohn.Forte@Sun.COM  * Output :
10057836SJohn.Forte@Sun.COM  * 	The FCA type and Xport type if found in the path on success
10067836SJohn.Forte@Sun.COM  *	0 on Failure
10077836SJohn.Forte@Sun.COM  *
10087836SJohn.Forte@Sun.COM  * Examples of valid device strings :
10097836SJohn.Forte@Sun.COM  *
10107836SJohn.Forte@Sun.COM  * Non Fabric FC driver :
10117836SJohn.Forte@Sun.COM  * /devices/io-unit@f,e0200000/sbi@0,0/SUNW,socal@1,0/sf@1,0:ctlr
10127836SJohn.Forte@Sun.COM  * /devices/io-unit@f,e2200000/sbi@0,0/SUNW,socal@3,0/sf@0,0/ssd@20,0:c,raw
10137836SJohn.Forte@Sun.COM  * /devices/sbus@1f,0/SUNW,socal@0,0/sf@0,0:devctl
10147836SJohn.Forte@Sun.COM  * /devices/sbus@1f,0/SUNW,socal@2,0/sf@1,0/ssd@w2200002037110cbf,0:b,raw
10157836SJohn.Forte@Sun.COM  * /devices/pci@1f,4000/SUNW,ifp@4:devctl
10167836SJohn.Forte@Sun.COM  * /devices/pci@1f,4000/SUNW,ifp@2/ssd@w2100002037049ba0,0:c,raw
10177836SJohn.Forte@Sun.COM  * /devices/pci@6,4000/pci@2/SUNW,ifp@5/ssd@w210000203708b44f,0:c,raw
10187836SJohn.Forte@Sun.COM  *
10197836SJohn.Forte@Sun.COM  * Fabric FC driver (fp) :
10207836SJohn.Forte@Sun.COM  * 	- offical device path for Qlogic 2202 with proper FCODE
10217836SJohn.Forte@Sun.COM  *	  as of 12/99.
10227836SJohn.Forte@Sun.COM  * /devices/pci@1f,2000/pci@1/SUNW,qlc@5/fp@0,0:devctl
10237836SJohn.Forte@Sun.COM  * /devices/pci@e,2000/pci@2/SUNW,qlc@4/fp@0,0:devctl
10247836SJohn.Forte@Sun.COM  *
10257836SJohn.Forte@Sun.COM  */
10267836SJohn.Forte@Sun.COM uint_t
g_get_path_type(char * path)10277836SJohn.Forte@Sun.COM g_get_path_type(char *path)
10287836SJohn.Forte@Sun.COM {
10297836SJohn.Forte@Sun.COM 	uint_t path_type = 0;
10307836SJohn.Forte@Sun.COM 	int	i = 0, pathcnt = 1;
10317836SJohn.Forte@Sun.COM 	char *path_ptr = path;
10327836SJohn.Forte@Sun.COM 	struct str_type *search_arr_ptr; /* updated by GetMatch macro */
10337836SJohn.Forte@Sun.COM 	char found;			 /* Updated by GetMatch marco */
10347836SJohn.Forte@Sun.COM 	char		drvr_path1[MAXPATHLEN];
10357836SJohn.Forte@Sun.COM 	mp_pathlist_t	pathlist;
10367836SJohn.Forte@Sun.COM 	int		p_on = 0, p_st = 0;
10377836SJohn.Forte@Sun.COM 
10387836SJohn.Forte@Sun.COM 	/* Path passed must be an absolute device path */
10397836SJohn.Forte@Sun.COM 	if (strncmp(path_ptr, DEV_PREFIX, DEV_PREFIX_LEN) ||
10407836SJohn.Forte@Sun.COM 				(strlen(path_ptr) == DEV_PREFIX_LEN)) {
10417836SJohn.Forte@Sun.COM 		return (0);	/* Invalid path */
10427836SJohn.Forte@Sun.COM 	}
10437836SJohn.Forte@Sun.COM 
10447836SJohn.Forte@Sun.COM 	/* if mpxio device, need to convert from vhci to phci */
10457836SJohn.Forte@Sun.COM 	if (strstr(path, SCSI_VHCI)) {
10467836SJohn.Forte@Sun.COM 		(void) strcpy(drvr_path1, path);
10477836SJohn.Forte@Sun.COM 		if (g_get_pathlist(drvr_path1, &pathlist)) {
10487836SJohn.Forte@Sun.COM 			return (0);
10497836SJohn.Forte@Sun.COM 		}
10507836SJohn.Forte@Sun.COM 		pathcnt = pathlist.path_count;
10517836SJohn.Forte@Sun.COM 		p_on = p_st = 0;
10527836SJohn.Forte@Sun.COM 		for (i = 0; i < pathcnt; i++) {
10537836SJohn.Forte@Sun.COM 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
10547836SJohn.Forte@Sun.COM 				if (pathlist.path_info[i].path_state ==
10557836SJohn.Forte@Sun.COM 					MDI_PATHINFO_STATE_ONLINE) {
10567836SJohn.Forte@Sun.COM 					p_on = i;
10577836SJohn.Forte@Sun.COM 					break;
10587836SJohn.Forte@Sun.COM 				} else if (pathlist.path_info[i].path_state ==
10597836SJohn.Forte@Sun.COM 					MDI_PATHINFO_STATE_STANDBY) {
10607836SJohn.Forte@Sun.COM 					p_st = i;
10617836SJohn.Forte@Sun.COM 				}
10627836SJohn.Forte@Sun.COM 			}
10637836SJohn.Forte@Sun.COM 		}
10647836SJohn.Forte@Sun.COM 		if (pathlist.path_info[p_on].path_state ==
10657836SJohn.Forte@Sun.COM 		    MDI_PATHINFO_STATE_ONLINE) {
10667836SJohn.Forte@Sun.COM 			/* on_line path */
10677836SJohn.Forte@Sun.COM 			(void) strcpy(drvr_path1,
10687836SJohn.Forte@Sun.COM 				pathlist.path_info[p_on].path_hba);
10697836SJohn.Forte@Sun.COM 		} else {
10707836SJohn.Forte@Sun.COM 			/* standby or path0 */
10717836SJohn.Forte@Sun.COM 			(void) strcpy(drvr_path1,
10727836SJohn.Forte@Sun.COM 				pathlist.path_info[p_st].path_hba);
10737836SJohn.Forte@Sun.COM 		}
10747836SJohn.Forte@Sun.COM 		free(pathlist.path_info);
10757836SJohn.Forte@Sun.COM 		path_ptr = drvr_path1;
10767836SJohn.Forte@Sun.COM 	}
10777836SJohn.Forte@Sun.COM 
10787836SJohn.Forte@Sun.COM 	GetMatch(ValidBusStrings);
10797836SJohn.Forte@Sun.COM 	if (found == 0) {
10807836SJohn.Forte@Sun.COM 		/* No valid bus string - so not a valid path */
10817836SJohn.Forte@Sun.COM 		return (0);
10827836SJohn.Forte@Sun.COM 	}
10837836SJohn.Forte@Sun.COM 
10847836SJohn.Forte@Sun.COM 	GetMatch(ValidFCAstrings);	/* Check for a valid FCA string */
10857836SJohn.Forte@Sun.COM 	if (found != 0) {
10867836SJohn.Forte@Sun.COM 		path_type |= search_arr_ptr->type;
10877836SJohn.Forte@Sun.COM 	}
10887836SJohn.Forte@Sun.COM 
10897836SJohn.Forte@Sun.COM 	/*
10907836SJohn.Forte@Sun.COM 	 * continue to check xport even without valid FCA string.
10917836SJohn.Forte@Sun.COM 	 * This is to support 3rd party FCA vendor on Leadville stack.
10927836SJohn.Forte@Sun.COM 	 */
10937836SJohn.Forte@Sun.COM 	GetMatch(ValidXportStrings);	/* Check for a valid transport str */
10947836SJohn.Forte@Sun.COM 	if (found == 0) {
10957836SJohn.Forte@Sun.COM 		return (path_type);
10967836SJohn.Forte@Sun.COM 	} else {
10977836SJohn.Forte@Sun.COM 		/*
10987836SJohn.Forte@Sun.COM 		 * if leadville tranport is detected and fca is not set yet,
10997836SJohn.Forte@Sun.COM 		 * set fca flag to generic FC_FCA_MASK.
11007836SJohn.Forte@Sun.COM 		 */
11017836SJohn.Forte@Sun.COM 		if ((search_arr_ptr->type == FC_GEN_XPORT) &&
11027836SJohn.Forte@Sun.COM 			(!(path_type & FC_FCA_MASK))) {
11037836SJohn.Forte@Sun.COM 			path_type |= FC_FCA_MASK;
11047836SJohn.Forte@Sun.COM 		}
11057836SJohn.Forte@Sun.COM 	}
11067836SJohn.Forte@Sun.COM 	path_type |= search_arr_ptr->type;
11077836SJohn.Forte@Sun.COM 
11087836SJohn.Forte@Sun.COM 	/*
11097836SJohn.Forte@Sun.COM 	 * A quick sanity check to make sure that we dont have
11107836SJohn.Forte@Sun.COM 	 * a combination that is not possible
11117836SJohn.Forte@Sun.COM 	 */
11127836SJohn.Forte@Sun.COM 	if (((path_type & (FC4_FCA_MASK | FC_XPORT_MASK)) ==
11137836SJohn.Forte@Sun.COM 			path_type) ||
11147836SJohn.Forte@Sun.COM 		((path_type & (FC_FCA_MASK | FC4_XPORT_MASK)) ==
11157836SJohn.Forte@Sun.COM 			path_type)) {
11167836SJohn.Forte@Sun.COM 		path_type = 0;
11177836SJohn.Forte@Sun.COM 	}
11187836SJohn.Forte@Sun.COM 
11197836SJohn.Forte@Sun.COM 	return (path_type);
11207836SJohn.Forte@Sun.COM }
11217836SJohn.Forte@Sun.COM 
11227836SJohn.Forte@Sun.COM 
11237836SJohn.Forte@Sun.COM /*
11247836SJohn.Forte@Sun.COM  * g_get_port_path(char *, portlist_t *)
11257836SJohn.Forte@Sun.COM  * Purpose: Find all port nexus paths for a particular driver
11267836SJohn.Forte@Sun.COM  * Input:   portdrvr
11277836SJohn.Forte@Sun.COM  *		set to name of driver for which to find the paths
11287836SJohn.Forte@Sun.COM  * Output:  portlist
11297836SJohn.Forte@Sun.COM  *		allocated structure to hold paths found
11307836SJohn.Forte@Sun.COM  *		user must call g_free_portlist(portlist_t *) to
11317836SJohn.Forte@Sun.COM  *		free allocated memory
11327836SJohn.Forte@Sun.COM  */
11337836SJohn.Forte@Sun.COM int
g_get_port_path(char * portdrvr,portlist_t * portlist)11347836SJohn.Forte@Sun.COM g_get_port_path(char *portdrvr, portlist_t *portlist)
11357836SJohn.Forte@Sun.COM {
11367836SJohn.Forte@Sun.COM 	di_node_t root;
11377836SJohn.Forte@Sun.COM 	di_node_t node;
11387836SJohn.Forte@Sun.COM 	di_minor_t minor_node;
11397836SJohn.Forte@Sun.COM 	char hbapathfound[MAXPATHLEN];
11407836SJohn.Forte@Sun.COM 	char *tmppath;
11417836SJohn.Forte@Sun.COM 	struct stat buf;
11427836SJohn.Forte@Sun.COM 
11437836SJohn.Forte@Sun.COM 	/* return invalid argument if *portdrvr or *portlist is NULL */
11447836SJohn.Forte@Sun.COM 	if ((portdrvr == NULL) || (portlist == NULL)) {
11457836SJohn.Forte@Sun.COM 		return (L_INVALID_ARG);
11467836SJohn.Forte@Sun.COM 	}
11477836SJohn.Forte@Sun.COM 
11487836SJohn.Forte@Sun.COM 	/* Create a snapshot of the kernel device tree */
11497836SJohn.Forte@Sun.COM 	root = di_init("/", DINFOCPYALL);
11507836SJohn.Forte@Sun.COM 	if (root == DI_NODE_NIL) {
11517836SJohn.Forte@Sun.COM 		return (L_DEV_SNAPSHOT_FAILED);
11527836SJohn.Forte@Sun.COM 	}
11537836SJohn.Forte@Sun.COM 
11547836SJohn.Forte@Sun.COM 	/* point to first node which matches portdrvr */
11557836SJohn.Forte@Sun.COM 	node = di_drv_first_node(portdrvr, root);
11567836SJohn.Forte@Sun.COM 	if (node == DI_NODE_NIL) {
11577836SJohn.Forte@Sun.COM 		/*
11587836SJohn.Forte@Sun.COM 		 * Could not find driver node
11597836SJohn.Forte@Sun.COM 		 */
11607836SJohn.Forte@Sun.COM 		(void) di_fini(root);
11617836SJohn.Forte@Sun.COM 		if (errno == EINVAL)
11627836SJohn.Forte@Sun.COM 			return (L_PORT_DRIVER_NOT_FOUND);
11637836SJohn.Forte@Sun.COM 		else
11647836SJohn.Forte@Sun.COM 			return (L_PHYS_PATH_NOT_FOUND);
11657836SJohn.Forte@Sun.COM 	}
11667836SJohn.Forte@Sun.COM 
11677836SJohn.Forte@Sun.COM 	while (node) {
11687836SJohn.Forte@Sun.COM 		/* point to first minor node which matches node */
11697836SJohn.Forte@Sun.COM 		minor_node = di_minor_next(node, DI_MINOR_NIL);
11707836SJohn.Forte@Sun.COM 
11717836SJohn.Forte@Sun.COM 		/* if we have a minor node use it */
11727836SJohn.Forte@Sun.COM 		while (minor_node) {
11737836SJohn.Forte@Sun.COM 			/*
11747836SJohn.Forte@Sun.COM 			 * Is this a devctl or pseudo node?
11757836SJohn.Forte@Sun.COM 			 * If not, skip it.
11767836SJohn.Forte@Sun.COM 			 * Soc+ HBA port device paths such as:
11777836SJohn.Forte@Sun.COM 			 * 	/devices/sbus@2,0/SUNW,socal@d,10000:0
11787836SJohn.Forte@Sun.COM 			 * are pseudo nodes as of S9 so we need to
11797836SJohn.Forte@Sun.COM 			 * include those as well.
11807836SJohn.Forte@Sun.COM 			 */
11817836SJohn.Forte@Sun.COM 			if (di_minor_nodetype(minor_node) &&
11827836SJohn.Forte@Sun.COM 				(strcmp(di_minor_nodetype(minor_node),
11837836SJohn.Forte@Sun.COM 					DDI_NT_NEXUS) &&
11847836SJohn.Forte@Sun.COM 				strcmp(di_minor_nodetype(minor_node),
11857836SJohn.Forte@Sun.COM 					DDI_PSEUDO))) {
11867836SJohn.Forte@Sun.COM 				minor_node = di_minor_next(node, minor_node);
11877836SJohn.Forte@Sun.COM 				continue;
11887836SJohn.Forte@Sun.COM 			}
11897836SJohn.Forte@Sun.COM 			/*
11907836SJohn.Forte@Sun.COM 			 * Prepend '/devices' to path
11917836SJohn.Forte@Sun.COM 			 * Note: The path returned from di_devfs_path
11927836SJohn.Forte@Sun.COM 			 * does NOT begin with '/devices'.
11937836SJohn.Forte@Sun.COM 			 * '/devices' is considered a mount point
11947836SJohn.Forte@Sun.COM 			 */
11957836SJohn.Forte@Sun.COM 			strcpy(hbapathfound, "/devices");
11967836SJohn.Forte@Sun.COM 			tmppath = di_devfs_path(node);
11977836SJohn.Forte@Sun.COM 			strcat(hbapathfound, tmppath);
11987836SJohn.Forte@Sun.COM 			(void) free(tmppath);
11997836SJohn.Forte@Sun.COM 			strcat(hbapathfound, ":");
12007836SJohn.Forte@Sun.COM 			strcat(hbapathfound, di_minor_name(minor_node));
12017836SJohn.Forte@Sun.COM 			/*
12027836SJohn.Forte@Sun.COM 			 * Verify that the path is validly constructed
12037836SJohn.Forte@Sun.COM 			 */
12047836SJohn.Forte@Sun.COM 			if ((stat(hbapathfound, (struct stat *)&buf)) < 0) {
12057836SJohn.Forte@Sun.COM 				(void) di_fini(root);
12067836SJohn.Forte@Sun.COM 				return (L_STAT_ERROR);
12077836SJohn.Forte@Sun.COM 			}
12087836SJohn.Forte@Sun.COM 			/* allocate memory and copy constructed path */
12097836SJohn.Forte@Sun.COM 			if ((portlist->hbacnt > MAX_HBA_PORT - 1) ||
12107836SJohn.Forte@Sun.COM 			    ((portlist->physpath[portlist->hbacnt] =
12117836SJohn.Forte@Sun.COM 				(char *)malloc(MAXPATHLEN)) == NULL)) {
12127836SJohn.Forte@Sun.COM 				(void) di_fini(root);
12137836SJohn.Forte@Sun.COM 				return (L_MALLOC_FAILED);
12147836SJohn.Forte@Sun.COM 			}
12157836SJohn.Forte@Sun.COM 			strcpy(portlist->physpath[portlist->hbacnt],
12167836SJohn.Forte@Sun.COM 				hbapathfound);
12177836SJohn.Forte@Sun.COM 			portlist->hbacnt++;
12187836SJohn.Forte@Sun.COM 			minor_node = di_minor_next(node, minor_node);
12197836SJohn.Forte@Sun.COM 		}
12207836SJohn.Forte@Sun.COM 		node = di_drv_next_node(node);
12217836SJohn.Forte@Sun.COM 	}
12227836SJohn.Forte@Sun.COM 	/*
12237836SJohn.Forte@Sun.COM 	 * Destroy the snapshot and return
12247836SJohn.Forte@Sun.COM 	 */
12257836SJohn.Forte@Sun.COM 	(void) di_fini(root);
12267836SJohn.Forte@Sun.COM 	return (0);
12277836SJohn.Forte@Sun.COM }
12287836SJohn.Forte@Sun.COM 
12297836SJohn.Forte@Sun.COM /*
12307836SJohn.Forte@Sun.COM  * Free the allocated portlist structure
12317836SJohn.Forte@Sun.COM  */
12327836SJohn.Forte@Sun.COM void
g_free_portlist(portlist_t * portlist)12337836SJohn.Forte@Sun.COM g_free_portlist(portlist_t *portlist)
12347836SJohn.Forte@Sun.COM {
12357836SJohn.Forte@Sun.COM 	int x = 0;
12367836SJohn.Forte@Sun.COM 
12377836SJohn.Forte@Sun.COM 	/* return if portlist is NULL */
12387836SJohn.Forte@Sun.COM 	if (portlist == NULL) {
12397836SJohn.Forte@Sun.COM 		return;
12407836SJohn.Forte@Sun.COM 	}
12417836SJohn.Forte@Sun.COM 
12427836SJohn.Forte@Sun.COM 	for (x = 0; x < portlist->hbacnt; x++) {
12437836SJohn.Forte@Sun.COM 		if (portlist->physpath[x] != NULL) {
12447836SJohn.Forte@Sun.COM 			free(portlist->physpath[x]);
12457836SJohn.Forte@Sun.COM 		}
12467836SJohn.Forte@Sun.COM 	}
12477836SJohn.Forte@Sun.COM }
12487836SJohn.Forte@Sun.COM 
12497836SJohn.Forte@Sun.COM /*
12507836SJohn.Forte@Sun.COM  * Check VID/PID against enclosure disk table
12517836SJohn.Forte@Sun.COM  */
12527836SJohn.Forte@Sun.COM boolean_t
g_enclDiskChk(char * vid,char * pid)12537836SJohn.Forte@Sun.COM g_enclDiskChk(char *vid, char *pid)
12547836SJohn.Forte@Sun.COM {
12557836SJohn.Forte@Sun.COM 	int i;
12567836SJohn.Forte@Sun.COM 	for (i = 0; enclDiskTbl[i].vid; i++) {
12577836SJohn.Forte@Sun.COM 		if ((strncmp(vid, enclDiskTbl[i].vid,
12587836SJohn.Forte@Sun.COM 		    strlen(enclDiskTbl[i].vid)) == 0) &&
12597836SJohn.Forte@Sun.COM 		    (strncmp(pid, enclDiskTbl[i].pid,
12607836SJohn.Forte@Sun.COM 		    strlen(enclDiskTbl[i].pid)) == 0)) {
12617836SJohn.Forte@Sun.COM 			return (B_TRUE);
12627836SJohn.Forte@Sun.COM 		}
12637836SJohn.Forte@Sun.COM 	}
12647836SJohn.Forte@Sun.COM 	return (B_FALSE);
12657836SJohn.Forte@Sun.COM }
1266