xref: /onnv-gate/usr/src/cmd/luxadm/lux_util.c (revision 12909:0e5521492f8c)
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*12909SMilan.Jurik@Sun.COM  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
237836SJohn.Forte@Sun.COM  */
247836SJohn.Forte@Sun.COM 
257836SJohn.Forte@Sun.COM 
267836SJohn.Forte@Sun.COM 
277836SJohn.Forte@Sun.COM #include	<stdio.h>
287836SJohn.Forte@Sun.COM #include	<unistd.h>
297836SJohn.Forte@Sun.COM #include	<stdlib.h>
307836SJohn.Forte@Sun.COM #include	<sys/param.h>
317836SJohn.Forte@Sun.COM #include	<sys/types.h>
327836SJohn.Forte@Sun.COM #include	<fcntl.h>
337836SJohn.Forte@Sun.COM #include	<sys/stat.h>
347836SJohn.Forte@Sun.COM #include	<string.h>
357836SJohn.Forte@Sun.COM #include	<strings.h>
367836SJohn.Forte@Sun.COM #include	<ctype.h>
377836SJohn.Forte@Sun.COM #include	<errno.h>
387836SJohn.Forte@Sun.COM #include	<assert.h>
397836SJohn.Forte@Sun.COM #include	<sys/scsi/impl/uscsi.h>
407836SJohn.Forte@Sun.COM #include	<sys/scsi/generic/commands.h>
417836SJohn.Forte@Sun.COM #include	<sys/scsi/impl/commands.h>
427836SJohn.Forte@Sun.COM #include	<sys/scsi/generic/sense.h>
437836SJohn.Forte@Sun.COM #include	<sys/scsi/generic/mode.h>
447836SJohn.Forte@Sun.COM #include	<sys/scsi/generic/status.h>
457836SJohn.Forte@Sun.COM #include	<sys/scsi/generic/inquiry.h>
467836SJohn.Forte@Sun.COM #include	<sys/scsi/adapters/scsi_vhci.h>
477836SJohn.Forte@Sun.COM #include	<sys/byteorder.h>
487836SJohn.Forte@Sun.COM #include	"common.h"
497836SJohn.Forte@Sun.COM #include	"errorcodes.h"
507836SJohn.Forte@Sun.COM 
517836SJohn.Forte@Sun.COM #define	MAX_MODE_SENSE_LEN		0xffff
527836SJohn.Forte@Sun.COM #define	MAXLEN		1000
537836SJohn.Forte@Sun.COM 
547836SJohn.Forte@Sun.COM #define	RETRY_PATHLIST	1
557836SJohn.Forte@Sun.COM #define	BYTES_PER_LINE	16
567836SJohn.Forte@Sun.COM #define	SCMD_UNKNOWN	0xff
577836SJohn.Forte@Sun.COM 
587836SJohn.Forte@Sun.COM #define	SCSI_VHCI	"/devices/scsi_vhci/"
597836SJohn.Forte@Sun.COM #define	SLASH		"/"
607836SJohn.Forte@Sun.COM #define	DEV_PREFIX	"/devices/"
617836SJohn.Forte@Sun.COM #define	DEV_PREFIX_STRLEN	strlen(DEV_PREFIX)
627836SJohn.Forte@Sun.COM #define	DEVICES_DIR	"/devices"
637836SJohn.Forte@Sun.COM 
647836SJohn.Forte@Sun.COM extern	char	*dtype[]; /* from adm.c */
657836SJohn.Forte@Sun.COM extern	int	rand_r(unsigned int *);
667836SJohn.Forte@Sun.COM 
677836SJohn.Forte@Sun.COM static int cleanup_dotdot_path(char *path);
687836SJohn.Forte@Sun.COM static int wait_random_time(void);
697836SJohn.Forte@Sun.COM static char *scsi_find_command_name(int cmd);
707836SJohn.Forte@Sun.COM static void scsi_printerr(struct uscsi_cmd *ucmd,
717836SJohn.Forte@Sun.COM 	    struct scsi_extended_sense *rq, int rqlen,
727836SJohn.Forte@Sun.COM 	    char msg_string[], char *err_string);
737836SJohn.Forte@Sun.COM static void string_dump(char *hdr, uchar_t *src, int nbytes, int format,
747836SJohn.Forte@Sun.COM 	    char msg_string[]);
757836SJohn.Forte@Sun.COM static int issue_uscsi_cmd(int file, struct uscsi_cmd *command, int flag);
767836SJohn.Forte@Sun.COM 
777836SJohn.Forte@Sun.COM 
787836SJohn.Forte@Sun.COM static int
wait_random_time(void)797836SJohn.Forte@Sun.COM wait_random_time(void)
807836SJohn.Forte@Sun.COM {
8110387SMilan.Jurik@Sun.COM 	time_t		timeval;
8210387SMilan.Jurik@Sun.COM 	struct tm	*tmbuf = NULL;
8310387SMilan.Jurik@Sun.COM 	struct timeval	tval;
8410387SMilan.Jurik@Sun.COM 	unsigned int	seed;
8510387SMilan.Jurik@Sun.COM 	int		random;
8610387SMilan.Jurik@Sun.COM 	pid_t		pid;
877836SJohn.Forte@Sun.COM 
887836SJohn.Forte@Sun.COM 	/*
897836SJohn.Forte@Sun.COM 	 * Get the system time and use "system seconds"
907836SJohn.Forte@Sun.COM 	 * as 'seed' to generate a random number. Then,
917836SJohn.Forte@Sun.COM 	 * wait between 1/10 - 1/2 seconds before retry.
927836SJohn.Forte@Sun.COM 	 * Get the current process id and ex-or it with
937836SJohn.Forte@Sun.COM 	 * the seed so that the random number is always
947836SJohn.Forte@Sun.COM 	 * different even in case of multiple processes
957836SJohn.Forte@Sun.COM 	 * generate a random number at the same time.
967836SJohn.Forte@Sun.COM 	 */
977836SJohn.Forte@Sun.COM 	if ((timeval = time(NULL)) == -1) {
987836SJohn.Forte@Sun.COM 		return (errno);
997836SJohn.Forte@Sun.COM 	}
1007836SJohn.Forte@Sun.COM 	if ((tmbuf = localtime(&timeval)) == NULL) {
1017836SJohn.Forte@Sun.COM 		return (-1); /* L_LOCALTIME_ERROR */
1027836SJohn.Forte@Sun.COM 	}
1037836SJohn.Forte@Sun.COM 
1047836SJohn.Forte@Sun.COM 	pid = getpid();
1057836SJohn.Forte@Sun.COM 
1067836SJohn.Forte@Sun.COM 	/* get a random number. */
1077836SJohn.Forte@Sun.COM 	seed = (unsigned int) tmbuf->tm_sec;
1087836SJohn.Forte@Sun.COM 	seed ^= pid;
1097836SJohn.Forte@Sun.COM 	random = rand_r(&seed);
1107836SJohn.Forte@Sun.COM 
1117836SJohn.Forte@Sun.COM 
1127836SJohn.Forte@Sun.COM 	random = ((random % 500) + 100) * MILLISEC;
1137836SJohn.Forte@Sun.COM 	tval.tv_sec = random / MICROSEC;
1147836SJohn.Forte@Sun.COM 	tval.tv_usec = random % MICROSEC;
1157836SJohn.Forte@Sun.COM 
1167836SJohn.Forte@Sun.COM 	if (select(0, NULL, NULL, NULL, &tval) == -1) {
1177836SJohn.Forte@Sun.COM 		return (-1); /* L_SELECT_ERROR */
1187836SJohn.Forte@Sun.COM 	}
1197836SJohn.Forte@Sun.COM 	return (0);
1207836SJohn.Forte@Sun.COM }
1217836SJohn.Forte@Sun.COM 
1227836SJohn.Forte@Sun.COM /*
1237836SJohn.Forte@Sun.COM  *		Special string dump for error message
1247836SJohn.Forte@Sun.COM  */
1257836SJohn.Forte@Sun.COM static	void
string_dump(char * hdr,uchar_t * src,int nbytes,int format,char msg_string[])1267836SJohn.Forte@Sun.COM string_dump(char *hdr, uchar_t *src, int nbytes, int format, char msg_string[])
1277836SJohn.Forte@Sun.COM {
1287836SJohn.Forte@Sun.COM 	int i;
1297836SJohn.Forte@Sun.COM 	int n;
1307836SJohn.Forte@Sun.COM 	char	*p;
1317836SJohn.Forte@Sun.COM 	char	s[256];
1327836SJohn.Forte@Sun.COM 
1337836SJohn.Forte@Sun.COM 	assert(format == HEX_ONLY || format == HEX_ASCII);
1347836SJohn.Forte@Sun.COM 
1357836SJohn.Forte@Sun.COM 	(void) strcpy(s, hdr);
1367836SJohn.Forte@Sun.COM 	for (p = s; *p; p++) {
1377836SJohn.Forte@Sun.COM 		*p = ' ';
1387836SJohn.Forte@Sun.COM 	}
1397836SJohn.Forte@Sun.COM 
1407836SJohn.Forte@Sun.COM 	p = hdr;
1417836SJohn.Forte@Sun.COM 	while (nbytes > 0) {
14210387SMilan.Jurik@Sun.COM 		(void) sprintf(&msg_string[strlen(msg_string)], "%s", p);
1437836SJohn.Forte@Sun.COM 		p = s;
1447836SJohn.Forte@Sun.COM 		n = MIN(nbytes, BYTES_PER_LINE);
1457836SJohn.Forte@Sun.COM 		for (i = 0; i < n; i++) {
1467836SJohn.Forte@Sun.COM 			(void) sprintf(&msg_string[strlen(msg_string)],
14710387SMilan.Jurik@Sun.COM 			    "%02x ", src[i] & 0xff);
1487836SJohn.Forte@Sun.COM 		}
1497836SJohn.Forte@Sun.COM 		if (format == HEX_ASCII) {
1507836SJohn.Forte@Sun.COM 			for (i = BYTES_PER_LINE-n; i > 0; i--) {
1517836SJohn.Forte@Sun.COM 				(void) sprintf(&msg_string[strlen(msg_string)],
15210387SMilan.Jurik@Sun.COM 				    "   ");
1537836SJohn.Forte@Sun.COM 			}
1547836SJohn.Forte@Sun.COM 			(void) sprintf(&msg_string[strlen(msg_string)],
15510387SMilan.Jurik@Sun.COM 			    "    ");
1567836SJohn.Forte@Sun.COM 			for (i = 0; i < n; i++) {
1577836SJohn.Forte@Sun.COM 				(void) sprintf(&msg_string[strlen(msg_string)],
15810387SMilan.Jurik@Sun.COM 				    "%c", isprint(src[i]) ? src[i] : '.');
1597836SJohn.Forte@Sun.COM 			}
1607836SJohn.Forte@Sun.COM 		}
1617836SJohn.Forte@Sun.COM 		(void) sprintf(&msg_string[strlen(msg_string)], "\n");
1627836SJohn.Forte@Sun.COM 		nbytes -= n;
1637836SJohn.Forte@Sun.COM 		src += n;
1647836SJohn.Forte@Sun.COM 	}
1657836SJohn.Forte@Sun.COM }
1667836SJohn.Forte@Sun.COM /*
1677836SJohn.Forte@Sun.COM  * Return a pointer to a string telling us the name of the command.
1687836SJohn.Forte@Sun.COM  */
1697836SJohn.Forte@Sun.COM static char *
scsi_find_command_name(int cmd)1707836SJohn.Forte@Sun.COM scsi_find_command_name(int cmd)
1717836SJohn.Forte@Sun.COM {
17210387SMilan.Jurik@Sun.COM 	/*
17310387SMilan.Jurik@Sun.COM 	 * Names of commands.  Must have SCMD_UNKNOWN at end of list.
17410387SMilan.Jurik@Sun.COM 	 */
17510387SMilan.Jurik@Sun.COM 	struct scsi_command_name {
17610387SMilan.Jurik@Sun.COM 		int command;
17710387SMilan.Jurik@Sun.COM 		char	*name;
17810387SMilan.Jurik@Sun.COM 	} scsi_command_names[29];
1797836SJohn.Forte@Sun.COM 
18010387SMilan.Jurik@Sun.COM 	register struct scsi_command_name *c;
1817836SJohn.Forte@Sun.COM 
1827836SJohn.Forte@Sun.COM 	scsi_command_names[0].command = SCMD_TEST_UNIT_READY;
1837836SJohn.Forte@Sun.COM 	scsi_command_names[0].name = MSGSTR(61, "Test Unit Ready");
1847836SJohn.Forte@Sun.COM 
1857836SJohn.Forte@Sun.COM 	scsi_command_names[1].command = SCMD_FORMAT;
1867836SJohn.Forte@Sun.COM 	scsi_command_names[1].name = MSGSTR(110, "Format");
1877836SJohn.Forte@Sun.COM 
1887836SJohn.Forte@Sun.COM 	scsi_command_names[2].command = SCMD_REASSIGN_BLOCK;
1897836SJohn.Forte@Sun.COM 	scsi_command_names[2].name = MSGSTR(77, "Reassign Block");
1907836SJohn.Forte@Sun.COM 
1917836SJohn.Forte@Sun.COM 	scsi_command_names[3].command = SCMD_READ;
1927836SJohn.Forte@Sun.COM 	scsi_command_names[3].name = MSGSTR(27, "Read");
1937836SJohn.Forte@Sun.COM 
1947836SJohn.Forte@Sun.COM 	scsi_command_names[4].command = SCMD_WRITE;
1957836SJohn.Forte@Sun.COM 	scsi_command_names[4].name = MSGSTR(54, "Write");
1967836SJohn.Forte@Sun.COM 
1977836SJohn.Forte@Sun.COM 	scsi_command_names[5].command = SCMD_READ_G1;
1987836SJohn.Forte@Sun.COM 	scsi_command_names[5].name = MSGSTR(79, "Read(10 Byte)");
1997836SJohn.Forte@Sun.COM 
2007836SJohn.Forte@Sun.COM 	scsi_command_names[6].command = SCMD_WRITE_G1;
2017836SJohn.Forte@Sun.COM 	scsi_command_names[6].name = MSGSTR(51, "Write(10 Byte)");
2027836SJohn.Forte@Sun.COM 
2037836SJohn.Forte@Sun.COM 	scsi_command_names[7].command = SCMD_MODE_SELECT;
2047836SJohn.Forte@Sun.COM 	scsi_command_names[7].name = MSGSTR(97, "Mode Select");
2057836SJohn.Forte@Sun.COM 
2067836SJohn.Forte@Sun.COM 	scsi_command_names[8].command = SCMD_MODE_SENSE;
2077836SJohn.Forte@Sun.COM 	scsi_command_names[8].name = MSGSTR(95, "Mode Sense");
2087836SJohn.Forte@Sun.COM 
2097836SJohn.Forte@Sun.COM 	scsi_command_names[9].command = SCMD_REASSIGN_BLOCK;
2107836SJohn.Forte@Sun.COM 	scsi_command_names[9].name = MSGSTR(77, "Reassign Block");
2117836SJohn.Forte@Sun.COM 
2127836SJohn.Forte@Sun.COM 	scsi_command_names[10].command = SCMD_REQUEST_SENSE;
2137836SJohn.Forte@Sun.COM 	scsi_command_names[10].name = MSGSTR(74, "Request Sense");
2147836SJohn.Forte@Sun.COM 
2157836SJohn.Forte@Sun.COM 	scsi_command_names[11].command = SCMD_READ_DEFECT_LIST;
2167836SJohn.Forte@Sun.COM 	scsi_command_names[11].name = MSGSTR(80, "Read Defect List");
2177836SJohn.Forte@Sun.COM 
2187836SJohn.Forte@Sun.COM 	scsi_command_names[12].command = SCMD_INQUIRY;
2197836SJohn.Forte@Sun.COM 	scsi_command_names[12].name = MSGSTR(102, "Inquiry");
2207836SJohn.Forte@Sun.COM 
2217836SJohn.Forte@Sun.COM 	scsi_command_names[13].command = SCMD_WRITE_BUFFER;
2227836SJohn.Forte@Sun.COM 	scsi_command_names[13].name = MSGSTR(53, "Write Buffer");
2237836SJohn.Forte@Sun.COM 
2247836SJohn.Forte@Sun.COM 	scsi_command_names[14].command = SCMD_READ_BUFFER;
2257836SJohn.Forte@Sun.COM 	scsi_command_names[14].name = MSGSTR(82, "Read Buffer");
2267836SJohn.Forte@Sun.COM 
2277836SJohn.Forte@Sun.COM 	scsi_command_names[15].command = SCMD_START_STOP;
2287836SJohn.Forte@Sun.COM 	scsi_command_names[15].name = MSGSTR(67, "Start/Stop");
2297836SJohn.Forte@Sun.COM 
2307836SJohn.Forte@Sun.COM 	scsi_command_names[16].command = SCMD_RESERVE;
2317836SJohn.Forte@Sun.COM 	scsi_command_names[16].name = MSGSTR(72, "Reserve");
2327836SJohn.Forte@Sun.COM 
2337836SJohn.Forte@Sun.COM 	scsi_command_names[17].command = SCMD_RELEASE;
2347836SJohn.Forte@Sun.COM 	scsi_command_names[17].name = MSGSTR(75, "Release");
2357836SJohn.Forte@Sun.COM 
2367836SJohn.Forte@Sun.COM 	scsi_command_names[18].command = SCMD_MODE_SENSE_G1;
2377836SJohn.Forte@Sun.COM 	scsi_command_names[18].name = MSGSTR(94, "Mode Sense(10 Byte)");
2387836SJohn.Forte@Sun.COM 
2397836SJohn.Forte@Sun.COM 	scsi_command_names[19].command = SCMD_MODE_SELECT_G1;
2407836SJohn.Forte@Sun.COM 	scsi_command_names[19].name = MSGSTR(96, "Mode Select(10 Byte)");
2417836SJohn.Forte@Sun.COM 
2427836SJohn.Forte@Sun.COM 	scsi_command_names[20].command = SCMD_READ_CAPACITY;
2437836SJohn.Forte@Sun.COM 	scsi_command_names[20].name = MSGSTR(81, "Read Capacity");
2447836SJohn.Forte@Sun.COM 
2457836SJohn.Forte@Sun.COM 	scsi_command_names[21].command = SCMD_SYNC_CACHE;
2467836SJohn.Forte@Sun.COM 	scsi_command_names[21].name = MSGSTR(64, "Synchronize Cache");
2477836SJohn.Forte@Sun.COM 
2487836SJohn.Forte@Sun.COM 	scsi_command_names[22].command = SCMD_READ_DEFECT_LIST;
2497836SJohn.Forte@Sun.COM 	scsi_command_names[22].name = MSGSTR(80, "Read Defect List");
2507836SJohn.Forte@Sun.COM 
2517836SJohn.Forte@Sun.COM 	scsi_command_names[23].command = SCMD_GDIAG;
2527836SJohn.Forte@Sun.COM 	scsi_command_names[23].name = MSGSTR(108, "Get Diagnostic");
2537836SJohn.Forte@Sun.COM 
2547836SJohn.Forte@Sun.COM 	scsi_command_names[24].command = SCMD_SDIAG;
2557836SJohn.Forte@Sun.COM 	scsi_command_names[24].name = MSGSTR(69, "Set Diagnostic");
2567836SJohn.Forte@Sun.COM 
2577836SJohn.Forte@Sun.COM 	scsi_command_names[25].command = SCMD_PERS_RESERV_IN;
2587836SJohn.Forte@Sun.COM 	scsi_command_names[25].name = MSGSTR(10500, "Persistent Reserve In");
2597836SJohn.Forte@Sun.COM 
2607836SJohn.Forte@Sun.COM 	scsi_command_names[26].command = SCMD_PERS_RESERV_OUT;
2617836SJohn.Forte@Sun.COM 	scsi_command_names[26].name = MSGSTR(10501, "Persistent Reserve out");
2627836SJohn.Forte@Sun.COM 
2637836SJohn.Forte@Sun.COM 	scsi_command_names[27].command = SCMD_LOG_SENSE;
2647836SJohn.Forte@Sun.COM 	scsi_command_names[27].name = MSGSTR(10502, "Log Sense");
2657836SJohn.Forte@Sun.COM 
2667836SJohn.Forte@Sun.COM 	scsi_command_names[28].command = SCMD_UNKNOWN;
2677836SJohn.Forte@Sun.COM 	scsi_command_names[28].name = MSGSTR(25, "Unknown");
2687836SJohn.Forte@Sun.COM 
2697836SJohn.Forte@Sun.COM 
2707836SJohn.Forte@Sun.COM 	for (c = scsi_command_names; c->command != SCMD_UNKNOWN; c++)
2717836SJohn.Forte@Sun.COM 		if (c->command == cmd)
2727836SJohn.Forte@Sun.COM 			break;
2737836SJohn.Forte@Sun.COM 	return (c->name);
2747836SJohn.Forte@Sun.COM }
2757836SJohn.Forte@Sun.COM 
2767836SJohn.Forte@Sun.COM 
2777836SJohn.Forte@Sun.COM /*
2787836SJohn.Forte@Sun.COM  *	Function to create error message containing
2797836SJohn.Forte@Sun.COM  *	scsi request sense information
2807836SJohn.Forte@Sun.COM  */
2817836SJohn.Forte@Sun.COM 
2827836SJohn.Forte@Sun.COM static void
scsi_printerr(struct uscsi_cmd * ucmd,struct scsi_extended_sense * rq,int rqlen,char msg_string[],char * err_string)2837836SJohn.Forte@Sun.COM scsi_printerr(struct uscsi_cmd *ucmd, struct scsi_extended_sense *rq,
2847836SJohn.Forte@Sun.COM 		int rqlen, char msg_string[], char *err_string)
2857836SJohn.Forte@Sun.COM {
2867836SJohn.Forte@Sun.COM 	int		blkno;
2877836SJohn.Forte@Sun.COM 
2887836SJohn.Forte@Sun.COM 	switch (rq->es_key) {
2897836SJohn.Forte@Sun.COM 	case KEY_NO_SENSE:
2907836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(91, "No sense error"));
2917836SJohn.Forte@Sun.COM 		break;
2927836SJohn.Forte@Sun.COM 	case KEY_RECOVERABLE_ERROR:
2937836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(76, "Recoverable error"));
2947836SJohn.Forte@Sun.COM 		break;
2957836SJohn.Forte@Sun.COM 	case KEY_NOT_READY:
2967836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string,
29710387SMilan.Jurik@Sun.COM 		    MSGSTR(10503,
29810387SMilan.Jurik@Sun.COM 		    "Device Not ready. Error: Random Retry Failed: %s\n."),
29910387SMilan.Jurik@Sun.COM 		    err_string);
3007836SJohn.Forte@Sun.COM 		break;
3017836SJohn.Forte@Sun.COM 	case KEY_MEDIUM_ERROR:
3027836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(99, "Medium error"));
3037836SJohn.Forte@Sun.COM 		break;
3047836SJohn.Forte@Sun.COM 	case KEY_HARDWARE_ERROR:
3057836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(106, "Hardware error"));
3067836SJohn.Forte@Sun.COM 		break;
3077836SJohn.Forte@Sun.COM 	case KEY_ILLEGAL_REQUEST:
3087836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(103, "Illegal request"));
3097836SJohn.Forte@Sun.COM 		break;
3107836SJohn.Forte@Sun.COM 	case KEY_UNIT_ATTENTION:
3117836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string,
31210387SMilan.Jurik@Sun.COM 		    MSGSTR(10504,
31310387SMilan.Jurik@Sun.COM 		    "Unit attention."
31410387SMilan.Jurik@Sun.COM 		    "Error: Random Retry Failed.\n"));
3157836SJohn.Forte@Sun.COM 		break;
3167836SJohn.Forte@Sun.COM 	case KEY_WRITE_PROTECT:
3177836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(52, "Write protect error"));
3187836SJohn.Forte@Sun.COM 		break;
3197836SJohn.Forte@Sun.COM 	case KEY_BLANK_CHECK:
3207836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(131, "Blank check error"));
3217836SJohn.Forte@Sun.COM 		break;
3227836SJohn.Forte@Sun.COM 	case KEY_VENDOR_UNIQUE:
3237836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(58, "Vendor unique error"));
3247836SJohn.Forte@Sun.COM 		break;
3257836SJohn.Forte@Sun.COM 	case KEY_COPY_ABORTED:
3267836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(123, "Copy aborted error"));
3277836SJohn.Forte@Sun.COM 		break;
3287836SJohn.Forte@Sun.COM 	case KEY_ABORTED_COMMAND:
3297836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string,
33010387SMilan.Jurik@Sun.COM 		    MSGSTR(10505,
33110387SMilan.Jurik@Sun.COM 		    "Aborted command. Error: Random Retry Failed.\n"));
3327836SJohn.Forte@Sun.COM 		break;
3337836SJohn.Forte@Sun.COM 	case KEY_EQUAL:
3347836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(117, "Equal error"));
3357836SJohn.Forte@Sun.COM 		break;
3367836SJohn.Forte@Sun.COM 	case KEY_VOLUME_OVERFLOW:
3377836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(57, "Volume overflow"));
3387836SJohn.Forte@Sun.COM 		break;
3397836SJohn.Forte@Sun.COM 	case KEY_MISCOMPARE:
3407836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(98, "Miscompare error"));
3417836SJohn.Forte@Sun.COM 		break;
3427836SJohn.Forte@Sun.COM 	case KEY_RESERVED:
3437836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(10506,
34410387SMilan.Jurik@Sun.COM 		    "Reserved value found"));
3457836SJohn.Forte@Sun.COM 		break;
3467836SJohn.Forte@Sun.COM 	default:
3477836SJohn.Forte@Sun.COM 		(void) sprintf(msg_string, MSGSTR(59, "Unknown error"));
3487836SJohn.Forte@Sun.COM 		break;
3497836SJohn.Forte@Sun.COM 	}
3507836SJohn.Forte@Sun.COM 
3517836SJohn.Forte@Sun.COM 	(void) sprintf(&msg_string[strlen(msg_string)],
35210387SMilan.Jurik@Sun.COM 	    MSGSTR(10507, " during: %s"),
35310387SMilan.Jurik@Sun.COM 	    scsi_find_command_name(ucmd->uscsi_cdb[0]));
3547836SJohn.Forte@Sun.COM 
3557836SJohn.Forte@Sun.COM 	if (rq->es_valid) {
3567836SJohn.Forte@Sun.COM 		blkno = (rq->es_info_1 << 24) | (rq->es_info_2 << 16) |
35710387SMilan.Jurik@Sun.COM 		    (rq->es_info_3 << 8) | rq->es_info_4;
3587836SJohn.Forte@Sun.COM 		(void) sprintf(&msg_string[strlen(msg_string)],
35910387SMilan.Jurik@Sun.COM 		    MSGSTR(49, ": block %d (0x%x)"), blkno, blkno);
3607836SJohn.Forte@Sun.COM 	}
3617836SJohn.Forte@Sun.COM 
3627836SJohn.Forte@Sun.COM 	(void) sprintf(&msg_string[strlen(msg_string)], "\n");
3637836SJohn.Forte@Sun.COM 
3647836SJohn.Forte@Sun.COM 	if (rq->es_add_len >= 6) {
3657836SJohn.Forte@Sun.COM 		(void) sprintf(&msg_string[strlen(msg_string)],
36610387SMilan.Jurik@Sun.COM 		    MSGSTR(132, "  Additional sense: 0x%x   "
36710387SMilan.Jurik@Sun.COM 		    "ASC Qualifier: 0x%x\n"),
36810387SMilan.Jurik@Sun.COM 		    rq->es_add_code, rq->es_qual_code);
36910387SMilan.Jurik@Sun.COM 		/*
37010387SMilan.Jurik@Sun.COM 		 * rq->es_add_info[ADD_SENSE_CODE],
37110387SMilan.Jurik@Sun.COM 		 * rq->es_add_info[ADD_SENSE_QUAL_CODE]);
37210387SMilan.Jurik@Sun.COM 		 */
3737836SJohn.Forte@Sun.COM 	}
3747836SJohn.Forte@Sun.COM 	if (rq->es_key == KEY_ILLEGAL_REQUEST) {
3757836SJohn.Forte@Sun.COM 		string_dump(MSGSTR(47, " cmd:   "), (uchar_t *)ucmd,
37610387SMilan.Jurik@Sun.COM 		    sizeof (struct uscsi_cmd), HEX_ONLY, msg_string);
3777836SJohn.Forte@Sun.COM 		string_dump(MSGSTR(48, " cdb:   "),
37810387SMilan.Jurik@Sun.COM 		    (uchar_t *)ucmd->uscsi_cdb,
37910387SMilan.Jurik@Sun.COM 		    ucmd->uscsi_cdblen, HEX_ONLY, msg_string);
3807836SJohn.Forte@Sun.COM 	}
3817836SJohn.Forte@Sun.COM 	string_dump(MSGSTR(43, " sense:  "),
38210387SMilan.Jurik@Sun.COM 	    (uchar_t *)rq, 8 + rq->es_add_len, HEX_ONLY, msg_string);
3837836SJohn.Forte@Sun.COM 	rqlen = rqlen;	/* not used */
3847836SJohn.Forte@Sun.COM }
3857836SJohn.Forte@Sun.COM 
3867836SJohn.Forte@Sun.COM 
3877836SJohn.Forte@Sun.COM /*
3887836SJohn.Forte@Sun.COM  * Execute a command and determine the result.
3897836SJohn.Forte@Sun.COM  */
3907836SJohn.Forte@Sun.COM static int
issue_uscsi_cmd(int file,struct uscsi_cmd * command,int flag)3917836SJohn.Forte@Sun.COM issue_uscsi_cmd(int file, struct uscsi_cmd *command, int flag)
3927836SJohn.Forte@Sun.COM {
39310387SMilan.Jurik@Sun.COM 	struct scsi_extended_sense	*rqbuf;
39410387SMilan.Jurik@Sun.COM 	int				status, i, retry_cnt = 0, err;
39510387SMilan.Jurik@Sun.COM 	char				errorMsg[MAXLEN];
3967836SJohn.Forte@Sun.COM 
3977836SJohn.Forte@Sun.COM 	/*
3987836SJohn.Forte@Sun.COM 	 * Set function flags for driver.
3997836SJohn.Forte@Sun.COM 	 *
4007836SJohn.Forte@Sun.COM 	 * Set Automatic request sense enable
4017836SJohn.Forte@Sun.COM 	 *
4027836SJohn.Forte@Sun.COM 	 */
4037836SJohn.Forte@Sun.COM 	command->uscsi_flags = USCSI_RQENABLE;
4047836SJohn.Forte@Sun.COM 	command->uscsi_flags |= flag;
4057836SJohn.Forte@Sun.COM 
4067836SJohn.Forte@Sun.COM 	/* intialize error message array */
4077836SJohn.Forte@Sun.COM 	errorMsg[0] = '\0';
4087836SJohn.Forte@Sun.COM 
4097836SJohn.Forte@Sun.COM 	/* print command for debug */
4107836SJohn.Forte@Sun.COM 	if (getenv("_LUX_S_DEBUG") != NULL) {
4117836SJohn.Forte@Sun.COM 		if ((command->uscsi_cdb == NULL) ||
41210387SMilan.Jurik@Sun.COM 		    (flag & USCSI_RESET) ||
41310387SMilan.Jurik@Sun.COM 		    (flag & USCSI_RESET_ALL)) {
4147836SJohn.Forte@Sun.COM 			if (flag & USCSI_RESET) {
4157836SJohn.Forte@Sun.COM 				(void) printf("  Issuing a SCSI Reset.\n");
4167836SJohn.Forte@Sun.COM 			}
4177836SJohn.Forte@Sun.COM 			if (flag & USCSI_RESET_ALL) {
4187836SJohn.Forte@Sun.COM 				(void) printf("  Issuing a SCSI Reset All.\n");
4197836SJohn.Forte@Sun.COM 			}
4207836SJohn.Forte@Sun.COM 
4217836SJohn.Forte@Sun.COM 		} else {
4227836SJohn.Forte@Sun.COM 			(void) printf("  Issuing the following "
42310387SMilan.Jurik@Sun.COM 			    "SCSI command: %s\n",
42410387SMilan.Jurik@Sun.COM 			    scsi_find_command_name(command->uscsi_cdb[0]));
4257836SJohn.Forte@Sun.COM 			(void) printf("	fd=0x%x cdb=", file);
4267836SJohn.Forte@Sun.COM 			for (i = 0; i < (int)command->uscsi_cdblen; i++) {
4277836SJohn.Forte@Sun.COM 				(void) printf("%x ", *(command->uscsi_cdb + i));
4287836SJohn.Forte@Sun.COM 			}
4297836SJohn.Forte@Sun.COM 			(void) printf("\n\tlen=0x%x bufaddr=0x%x buflen=0x%x"
43010387SMilan.Jurik@Sun.COM 			    " flags=0x%x\n",
43110387SMilan.Jurik@Sun.COM 			    command->uscsi_cdblen,
43210387SMilan.Jurik@Sun.COM 			    command->uscsi_bufaddr,
43310387SMilan.Jurik@Sun.COM 			    command->uscsi_buflen, command->uscsi_flags);
4347836SJohn.Forte@Sun.COM 
4357836SJohn.Forte@Sun.COM 			if ((command->uscsi_buflen > 0) &&
43610387SMilan.Jurik@Sun.COM 			    ((flag & USCSI_READ) == 0)) {
4377836SJohn.Forte@Sun.COM 				(void) dump_hex_data("  Buffer data: ",
43810387SMilan.Jurik@Sun.COM 				    (uchar_t *)command->uscsi_bufaddr,
43910387SMilan.Jurik@Sun.COM 				    MIN(command->uscsi_buflen, 512), HEX_ASCII);
4407836SJohn.Forte@Sun.COM 			}
4417836SJohn.Forte@Sun.COM 		}
4427836SJohn.Forte@Sun.COM 		(void) fflush(stdout);
4437836SJohn.Forte@Sun.COM 	}
4447836SJohn.Forte@Sun.COM 
4457836SJohn.Forte@Sun.COM 
4467836SJohn.Forte@Sun.COM 	/*
4477836SJohn.Forte@Sun.COM 	 * Default command timeout in case command left it 0
4487836SJohn.Forte@Sun.COM 	 */
4497836SJohn.Forte@Sun.COM 	if (command->uscsi_timeout == 0) {
4507836SJohn.Forte@Sun.COM 		command->uscsi_timeout = 60;
4517836SJohn.Forte@Sun.COM 	}
4527836SJohn.Forte@Sun.COM 	/*	Issue command - finally */
4537836SJohn.Forte@Sun.COM 
4547836SJohn.Forte@Sun.COM retry:
4557836SJohn.Forte@Sun.COM 	status = ioctl(file, USCSICMD, command);
4567836SJohn.Forte@Sun.COM 	if (status == 0 && command->uscsi_status == 0) {
4577836SJohn.Forte@Sun.COM 		if (getenv("_LUX_S_DEBUG") != NULL) {
4587836SJohn.Forte@Sun.COM 			if ((command->uscsi_buflen > 0) &&
45910387SMilan.Jurik@Sun.COM 			    (flag & USCSI_READ)) {
4607836SJohn.Forte@Sun.COM 				(void) dump_hex_data("\tData read:",
46110387SMilan.Jurik@Sun.COM 				    (uchar_t *)command->uscsi_bufaddr,
46210387SMilan.Jurik@Sun.COM 				    MIN(command->uscsi_buflen, 512), HEX_ASCII);
4637836SJohn.Forte@Sun.COM 			}
4647836SJohn.Forte@Sun.COM 		}
4657836SJohn.Forte@Sun.COM 		return (status);
4667836SJohn.Forte@Sun.COM 	}
4677836SJohn.Forte@Sun.COM 	if ((status != 0) && (command->uscsi_status == 0)) {
4687836SJohn.Forte@Sun.COM 		if ((getenv("_LUX_S_DEBUG") != NULL) ||
46910387SMilan.Jurik@Sun.COM 		    (getenv("_LUX_ER_DEBUG") != NULL)) {
4707836SJohn.Forte@Sun.COM 			(void) printf("Unexpected USCSICMD ioctl error: %s\n",
47110387SMilan.Jurik@Sun.COM 			    strerror(errno));
4727836SJohn.Forte@Sun.COM 		}
4737836SJohn.Forte@Sun.COM 		return (status);
4747836SJohn.Forte@Sun.COM 	}
4757836SJohn.Forte@Sun.COM 
4767836SJohn.Forte@Sun.COM 	/*
4777836SJohn.Forte@Sun.COM 	 * Just a SCSI error, create error message
4787836SJohn.Forte@Sun.COM 	 * Retry once for Unit Attention,
4797836SJohn.Forte@Sun.COM 	 * Not Ready, and Aborted Command
4807836SJohn.Forte@Sun.COM 	 */
4817836SJohn.Forte@Sun.COM 	if ((command->uscsi_rqbuf != NULL) &&
4827836SJohn.Forte@Sun.COM 	    (((char)command->uscsi_rqlen - (char)command->uscsi_rqresid) > 0)) {
4837836SJohn.Forte@Sun.COM 
4847836SJohn.Forte@Sun.COM 		rqbuf = (struct scsi_extended_sense *)command->uscsi_rqbuf;
4857836SJohn.Forte@Sun.COM 
4867836SJohn.Forte@Sun.COM 		switch (rqbuf->es_key) {
4877836SJohn.Forte@Sun.COM 		case KEY_NOT_READY:
4887836SJohn.Forte@Sun.COM 			if (retry_cnt++ < 1) {
4897836SJohn.Forte@Sun.COM 				ER_DPRINTF("Note: Device Not Ready."
49010387SMilan.Jurik@Sun.COM 				    " Retrying...\n");
4917836SJohn.Forte@Sun.COM 
4927836SJohn.Forte@Sun.COM 				if ((err = wait_random_time()) == 0) {
4937836SJohn.Forte@Sun.COM 					goto retry;
4947836SJohn.Forte@Sun.COM 				} else {
4957836SJohn.Forte@Sun.COM 					return (err);
4967836SJohn.Forte@Sun.COM 				}
4977836SJohn.Forte@Sun.COM 			}
4987836SJohn.Forte@Sun.COM 			break;
4997836SJohn.Forte@Sun.COM 
5007836SJohn.Forte@Sun.COM 		case KEY_UNIT_ATTENTION:
5017836SJohn.Forte@Sun.COM 			if (retry_cnt++ < 1) {
5027836SJohn.Forte@Sun.COM 				ER_DPRINTF("  cmd():"
5037836SJohn.Forte@Sun.COM 				" UNIT_ATTENTION: Retrying...\n");
5047836SJohn.Forte@Sun.COM 
5057836SJohn.Forte@Sun.COM 				goto retry;
5067836SJohn.Forte@Sun.COM 			}
5077836SJohn.Forte@Sun.COM 			break;
5087836SJohn.Forte@Sun.COM 
5097836SJohn.Forte@Sun.COM 		case KEY_ABORTED_COMMAND:
5107836SJohn.Forte@Sun.COM 			if (retry_cnt++ < 1) {
5117836SJohn.Forte@Sun.COM 				ER_DPRINTF("Note: Command is aborted."
5127836SJohn.Forte@Sun.COM 				" Retrying...\n");
5137836SJohn.Forte@Sun.COM 
5147836SJohn.Forte@Sun.COM 				goto retry;
5157836SJohn.Forte@Sun.COM 			}
5167836SJohn.Forte@Sun.COM 			break;
5177836SJohn.Forte@Sun.COM 		}
5187836SJohn.Forte@Sun.COM 		if ((getenv("_LUX_S_DEBUG") != NULL) ||
51910387SMilan.Jurik@Sun.COM 		    (getenv("_LUX_ER_DEBUG") != NULL)) {
5207836SJohn.Forte@Sun.COM 			scsi_printerr(command,
52110387SMilan.Jurik@Sun.COM 			    (struct scsi_extended_sense *)command->uscsi_rqbuf,
52210387SMilan.Jurik@Sun.COM 			    (command->uscsi_rqlen - command->uscsi_rqresid),
52310387SMilan.Jurik@Sun.COM 			    errorMsg, strerror(errno));
5247836SJohn.Forte@Sun.COM 		}
5257836SJohn.Forte@Sun.COM 
5267836SJohn.Forte@Sun.COM 	} else {
5277836SJohn.Forte@Sun.COM 
5287836SJohn.Forte@Sun.COM 		/*
5297836SJohn.Forte@Sun.COM 		 * Retry 5 times in case of BUSY, and only
5307836SJohn.Forte@Sun.COM 		 * once for Reservation-conflict, Command
5317836SJohn.Forte@Sun.COM 		 * Termination and Queue Full. Wait for
5327836SJohn.Forte@Sun.COM 		 * random amount of time (between 1/10 - 1/2 secs.)
5337836SJohn.Forte@Sun.COM 		 * between each retry. This random wait is to avoid
5347836SJohn.Forte@Sun.COM 		 * the multiple threads being executed at the same time
5357836SJohn.Forte@Sun.COM 		 * and also the constraint in Photon IB, where the
5367836SJohn.Forte@Sun.COM 		 * command queue has a depth of one command.
5377836SJohn.Forte@Sun.COM 		 */
5387836SJohn.Forte@Sun.COM 		switch ((uchar_t)command->uscsi_status & STATUS_MASK) {
5397836SJohn.Forte@Sun.COM 		case STATUS_BUSY:
5407836SJohn.Forte@Sun.COM 			if (retry_cnt++ < 5) {
5417836SJohn.Forte@Sun.COM 				if ((err = wait_random_time()) == 0) {
5427836SJohn.Forte@Sun.COM 					R_DPRINTF("  cmd(): No. of retries %d."
54310387SMilan.Jurik@Sun.COM 					    " STATUS_BUSY: Retrying...\n",
54410387SMilan.Jurik@Sun.COM 					    retry_cnt);
5457836SJohn.Forte@Sun.COM 					goto retry;
5467836SJohn.Forte@Sun.COM 
5477836SJohn.Forte@Sun.COM 				} else {
5487836SJohn.Forte@Sun.COM 					return (err);
5497836SJohn.Forte@Sun.COM 				}
5507836SJohn.Forte@Sun.COM 			}
5517836SJohn.Forte@Sun.COM 			break;
5527836SJohn.Forte@Sun.COM 
5537836SJohn.Forte@Sun.COM 		case STATUS_RESERVATION_CONFLICT:
5547836SJohn.Forte@Sun.COM 			if (retry_cnt++ < 1) {
5557836SJohn.Forte@Sun.COM 				if ((err = wait_random_time()) == 0) {
5567836SJohn.Forte@Sun.COM 					R_DPRINTF("  cmd():"
5577836SJohn.Forte@Sun.COM 					" RESERVATION_CONFLICT:"
5587836SJohn.Forte@Sun.COM 					" Retrying...\n");
5597836SJohn.Forte@Sun.COM 					goto retry;
5607836SJohn.Forte@Sun.COM 
5617836SJohn.Forte@Sun.COM 				} else {
5627836SJohn.Forte@Sun.COM 					return (err);
5637836SJohn.Forte@Sun.COM 				}
5647836SJohn.Forte@Sun.COM 			}
5657836SJohn.Forte@Sun.COM 			break;
5667836SJohn.Forte@Sun.COM 
5677836SJohn.Forte@Sun.COM 		case STATUS_TERMINATED:
5687836SJohn.Forte@Sun.COM 			if (retry_cnt++ < 1) {
5697836SJohn.Forte@Sun.COM 				R_DPRINTF("Note: Command Terminated."
57010387SMilan.Jurik@Sun.COM 				    " Retrying...\n");
5717836SJohn.Forte@Sun.COM 
5727836SJohn.Forte@Sun.COM 				if ((err = wait_random_time()) == 0) {
5737836SJohn.Forte@Sun.COM 					goto retry;
5747836SJohn.Forte@Sun.COM 				} else {
5757836SJohn.Forte@Sun.COM 					return (err);
5767836SJohn.Forte@Sun.COM 				}
5777836SJohn.Forte@Sun.COM 			}
5787836SJohn.Forte@Sun.COM 			break;
5797836SJohn.Forte@Sun.COM 
5807836SJohn.Forte@Sun.COM 		case STATUS_QFULL:
5817836SJohn.Forte@Sun.COM 			if (retry_cnt++ < 1) {
5827836SJohn.Forte@Sun.COM 				R_DPRINTF("Note: Command Queue is full."
5837836SJohn.Forte@Sun.COM 				" Retrying...\n");
5847836SJohn.Forte@Sun.COM 
5857836SJohn.Forte@Sun.COM 				if ((err = wait_random_time()) == 0) {
5867836SJohn.Forte@Sun.COM 					goto retry;
5877836SJohn.Forte@Sun.COM 				} else {
5887836SJohn.Forte@Sun.COM 					return (err);
5897836SJohn.Forte@Sun.COM 				}
5907836SJohn.Forte@Sun.COM 			}
5917836SJohn.Forte@Sun.COM 			break;
5927836SJohn.Forte@Sun.COM 		}
5937836SJohn.Forte@Sun.COM 
5947836SJohn.Forte@Sun.COM 	}
5957836SJohn.Forte@Sun.COM 	if (((getenv("_LUX_S_DEBUG") != NULL) ||
59610387SMilan.Jurik@Sun.COM 	    (getenv("_LUX_ER_DEBUG") != NULL)) &&
59710387SMilan.Jurik@Sun.COM 	    (errorMsg[0] != '\0')) {
5987836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "  %s\n", errorMsg);
5997836SJohn.Forte@Sun.COM 	}
6007836SJohn.Forte@Sun.COM 	return (L_SCSI_ERROR | command->uscsi_status);
6017836SJohn.Forte@Sun.COM }
6027836SJohn.Forte@Sun.COM 
6037836SJohn.Forte@Sun.COM /*
6047836SJohn.Forte@Sun.COM  *		MODE SENSE USCSI command
6057836SJohn.Forte@Sun.COM  *
6067836SJohn.Forte@Sun.COM  *
6077836SJohn.Forte@Sun.COM  *		pc = page control field
6087836SJohn.Forte@Sun.COM  *		page_code = Pages to return
6097836SJohn.Forte@Sun.COM  */
6107836SJohn.Forte@Sun.COM int
scsi_mode_sense_cmd(int fd,uchar_t * buf_ptr,int buf_len,uchar_t pc,uchar_t page_code)6117836SJohn.Forte@Sun.COM scsi_mode_sense_cmd(int fd,
6127836SJohn.Forte@Sun.COM 	uchar_t *buf_ptr,
6137836SJohn.Forte@Sun.COM 	int buf_len,
6147836SJohn.Forte@Sun.COM 	uchar_t pc,
6157836SJohn.Forte@Sun.COM 	uchar_t page_code)
6167836SJohn.Forte@Sun.COM {
61710387SMilan.Jurik@Sun.COM 	struct uscsi_cmd	ucmd;
61810387SMilan.Jurik@Sun.COM 	/* 10 byte Mode Select cmd */
61910387SMilan.Jurik@Sun.COM 	union scsi_cdb	cdb =  {SCMD_MODE_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0};
62010387SMilan.Jurik@Sun.COM 	struct	scsi_extended_sense	sense;
62110387SMilan.Jurik@Sun.COM 	int		status;
62210387SMilan.Jurik@Sun.COM 	static	int	uscsi_count;
6237836SJohn.Forte@Sun.COM 
6247836SJohn.Forte@Sun.COM 	if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) {
6257836SJohn.Forte@Sun.COM 		return (-1); /* L_INVALID_ARG */
6267836SJohn.Forte@Sun.COM 	}
6277836SJohn.Forte@Sun.COM 
6287836SJohn.Forte@Sun.COM 	(void) memset(buf_ptr, 0, buf_len);
6297836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
6307836SJohn.Forte@Sun.COM 	/* Just for me  - a sanity check */
6317836SJohn.Forte@Sun.COM 	if ((page_code > MODEPAGE_ALLPAGES) || (pc > 3) ||
63210387SMilan.Jurik@Sun.COM 	    (buf_len > MAX_MODE_SENSE_LEN)) {
6337836SJohn.Forte@Sun.COM 		return (-1); /* L_ILLEGAL_MODE_SENSE_PAGE */
6347836SJohn.Forte@Sun.COM 	}
6357836SJohn.Forte@Sun.COM 	cdb.g1_addr3 = (pc << 6) + page_code;
6367836SJohn.Forte@Sun.COM 	cdb.g1_count1 = buf_len>>8;
6377836SJohn.Forte@Sun.COM 	cdb.g1_count0 = buf_len & 0xff;
6387836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
6397836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP1;
6407836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = (caddr_t)buf_ptr;
6417836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = buf_len;
6427836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
6437836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
6447836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 120;
6457836SJohn.Forte@Sun.COM 
6467836SJohn.Forte@Sun.COM 	status = issue_uscsi_cmd(fd, &ucmd, USCSI_READ);
6477836SJohn.Forte@Sun.COM 	/* Bytes actually transfered */
6487836SJohn.Forte@Sun.COM 	if (status == 0) {
6497836SJohn.Forte@Sun.COM 		uscsi_count = buf_len - ucmd.uscsi_resid;
6507836SJohn.Forte@Sun.COM 		S_DPRINTF("  Number of bytes read on "
6517836SJohn.Forte@Sun.COM 		"Mode Sense 0x%x\n", uscsi_count);
6527836SJohn.Forte@Sun.COM 		if (getenv("_LUX_D_DEBUG") != NULL) {
65310387SMilan.Jurik@Sun.COM 			(void) dump_hex_data("  Mode Sense data: ", buf_ptr,
65410387SMilan.Jurik@Sun.COM 			    uscsi_count, HEX_ASCII);
6557836SJohn.Forte@Sun.COM 		}
6567836SJohn.Forte@Sun.COM 	}
6577836SJohn.Forte@Sun.COM 	return (status);
6587836SJohn.Forte@Sun.COM }
6597836SJohn.Forte@Sun.COM 
6607836SJohn.Forte@Sun.COM int
scsi_release(char * path)6617836SJohn.Forte@Sun.COM scsi_release(char *path)
6627836SJohn.Forte@Sun.COM {
66310387SMilan.Jurik@Sun.COM 	struct uscsi_cmd	ucmd;
66410387SMilan.Jurik@Sun.COM 	union scsi_cdb		cdb = {SCMD_RELEASE, 0, 0, 0, 0, 0};
66510387SMilan.Jurik@Sun.COM 	struct	scsi_extended_sense	sense;
66610387SMilan.Jurik@Sun.COM 	int	fd, status;
6677836SJohn.Forte@Sun.COM 
6687836SJohn.Forte@Sun.COM 	P_DPRINTF("  scsi_release: Release: Path %s\n", path);
6697836SJohn.Forte@Sun.COM 	if ((fd = open(path, O_NDELAY | O_RDONLY)) == -1)
67010387SMilan.Jurik@Sun.COM 		return (1);
6717836SJohn.Forte@Sun.COM 
6727836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
6737836SJohn.Forte@Sun.COM 
6747836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
6757836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP0;
6767836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = NULL;
6777836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = 0;
6787836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
6797836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
6807836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
6817836SJohn.Forte@Sun.COM 	status = (issue_uscsi_cmd(fd, &ucmd, 0));
6827836SJohn.Forte@Sun.COM 
6837836SJohn.Forte@Sun.COM 	(void) close(fd);
6847836SJohn.Forte@Sun.COM 	return (status);
6857836SJohn.Forte@Sun.COM }
6867836SJohn.Forte@Sun.COM 
6877836SJohn.Forte@Sun.COM int
scsi_reserve(char * path)6887836SJohn.Forte@Sun.COM scsi_reserve(char *path)
6897836SJohn.Forte@Sun.COM {
69010387SMilan.Jurik@Sun.COM 	struct uscsi_cmd	ucmd;
69110387SMilan.Jurik@Sun.COM 	union scsi_cdb	cdb = {SCMD_RESERVE, 0, 0, 0, 0, 0};
69210387SMilan.Jurik@Sun.COM 	struct	scsi_extended_sense	sense;
69310387SMilan.Jurik@Sun.COM 	int	fd, status;
6947836SJohn.Forte@Sun.COM 
6957836SJohn.Forte@Sun.COM 	P_DPRINTF("  scsi_reserve: Reserve: Path %s\n", path);
6967836SJohn.Forte@Sun.COM 	if ((fd = open(path, O_NDELAY | O_RDONLY)) == -1)
69710387SMilan.Jurik@Sun.COM 		return (1);
6987836SJohn.Forte@Sun.COM 
6997836SJohn.Forte@Sun.COM 	(void) memset((char *)&ucmd, 0, sizeof (ucmd));
7007836SJohn.Forte@Sun.COM 
7017836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdb = (caddr_t)&cdb;
7027836SJohn.Forte@Sun.COM 	ucmd.uscsi_cdblen = CDB_GROUP0;
7037836SJohn.Forte@Sun.COM 	ucmd.uscsi_bufaddr = NULL;
7047836SJohn.Forte@Sun.COM 	ucmd.uscsi_buflen = 0;
7057836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqbuf = (caddr_t)&sense;
7067836SJohn.Forte@Sun.COM 	ucmd.uscsi_rqlen = sizeof (struct  scsi_extended_sense);
7077836SJohn.Forte@Sun.COM 	ucmd.uscsi_timeout = 60;
7087836SJohn.Forte@Sun.COM 	status = (issue_uscsi_cmd(fd, &ucmd, 0));
7097836SJohn.Forte@Sun.COM 
7107836SJohn.Forte@Sun.COM 	(void) close(fd);
7117836SJohn.Forte@Sun.COM 	return (status);
7127836SJohn.Forte@Sun.COM }
7137836SJohn.Forte@Sun.COM 
7147836SJohn.Forte@Sun.COM /*
7157836SJohn.Forte@Sun.COM  * Print out fabric dev dtype
7167836SJohn.Forte@Sun.COM  */
7177836SJohn.Forte@Sun.COM void
print_fabric_dtype_prop(uchar_t * hba_port_wwn,uchar_t * port_wwn,uchar_t dtype_prop)7187836SJohn.Forte@Sun.COM print_fabric_dtype_prop(uchar_t *hba_port_wwn, uchar_t *port_wwn,
7197836SJohn.Forte@Sun.COM 	uchar_t dtype_prop)
7207836SJohn.Forte@Sun.COM {
7217836SJohn.Forte@Sun.COM 	if ((dtype_prop & DTYPE_MASK) < 0x10) {
7227836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, " 0x%-2x (%s)\n",
72310387SMilan.Jurik@Sun.COM 		    (dtype_prop & DTYPE_MASK),
72410387SMilan.Jurik@Sun.COM 		    dtype[(dtype_prop & DTYPE_MASK)]);
7257836SJohn.Forte@Sun.COM 	} else if ((dtype_prop & DTYPE_MASK) < 0x1f) {
7267836SJohn.Forte@Sun.COM 		(void) fprintf(stdout,
72710387SMilan.Jurik@Sun.COM 		    MSGSTR(2096, " 0x%-2x (Reserved)\n"),
72810387SMilan.Jurik@Sun.COM 		    (dtype_prop & DTYPE_MASK));
7297836SJohn.Forte@Sun.COM 	} else {
7307836SJohn.Forte@Sun.COM 		/* Check to see if this is the HBA */
7317836SJohn.Forte@Sun.COM 		if (wwnConversion(hba_port_wwn) != wwnConversion(port_wwn)) {
7327836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, MSGSTR(2097,
73310387SMilan.Jurik@Sun.COM 			    " 0x%-2x (Unknown Type)\n"),
73410387SMilan.Jurik@Sun.COM 			    (dtype_prop & DTYPE_MASK));
7357836SJohn.Forte@Sun.COM 		} else {
7367836SJohn.Forte@Sun.COM 			/* MATCH */
7377836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, MSGSTR(2241,
73810387SMilan.Jurik@Sun.COM 			    " 0x%-2x (Unknown Type,Host Bus Adapter)\n"),
73910387SMilan.Jurik@Sun.COM 			    (dtype_prop & DTYPE_MASK));
7407836SJohn.Forte@Sun.COM 		}
7417836SJohn.Forte@Sun.COM 	}
7427836SJohn.Forte@Sun.COM }
7437836SJohn.Forte@Sun.COM 
7447836SJohn.Forte@Sun.COM 
7457836SJohn.Forte@Sun.COM void
print_inq_data(char * arg_path,char * path,L_inquiry inq,uchar_t * serial,size_t serial_len)7467836SJohn.Forte@Sun.COM print_inq_data(char *arg_path, char *path, L_inquiry inq, uchar_t *serial,
7477836SJohn.Forte@Sun.COM     size_t serial_len)
7487836SJohn.Forte@Sun.COM {
74910387SMilan.Jurik@Sun.COM 	char	**p;
75010387SMilan.Jurik@Sun.COM 	uchar_t	*v_parm;
75110387SMilan.Jurik@Sun.COM 	int	scsi_3, length;
75210387SMilan.Jurik@Sun.COM 	char	byte_number[MAXNAMELEN];
75310387SMilan.Jurik@Sun.COM 	static	char *scsi_inquiry_labels_2[21];
75410387SMilan.Jurik@Sun.COM 	static	char *scsi_inquiry_labels_3[22];
75510387SMilan.Jurik@Sun.COM #define	MAX_ANSI_VERSION	6
75610387SMilan.Jurik@Sun.COM 	static	char	*ansi_version[MAX_ANSI_VERSION];
7577836SJohn.Forte@Sun.COM 	/*
7587836SJohn.Forte@Sun.COM 	 * Intialize scsi_inquiry_labels_2 with i18n strings
7597836SJohn.Forte@Sun.COM 	 */
7607836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[0] = MSGSTR(138, "Vendor:                     ");
7617836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[1] = MSGSTR(149, "Product:                    ");
7627836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[2] = MSGSTR(139, "Revision:                   ");
7637836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[3] = MSGSTR(143, "Firmware Revision           ");
7647836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[4] = MSGSTR(144, "Serial Number               ");
7657836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[5] = MSGSTR(140, "Device type:                ");
7667836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[6] = MSGSTR(145, "Removable media:            ");
7677836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[7] = MSGSTR(146, "ISO version:                ");
7687836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[8] = MSGSTR(147, "ECMA version:               ");
7697836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[9] = MSGSTR(148, "ANSI version:               ");
7707836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[10] =
77110387SMilan.Jurik@Sun.COM 	    MSGSTR(2168, "Async event notification:   ");
7727836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[11] =
77310387SMilan.Jurik@Sun.COM 	    MSGSTR(2169, "Terminate i/o process msg:  ");
7747836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[12] = MSGSTR(150, "Response data format:       ");
7757836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[13] = MSGSTR(151, "Additional length:          ");
7767836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[14] = MSGSTR(152, "Relative addressing:        ");
7777836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[15] =
77810387SMilan.Jurik@Sun.COM 	    MSGSTR(2170, "32 bit transfers:           ");
7797836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[16] =
78010387SMilan.Jurik@Sun.COM 	    MSGSTR(2171, "16 bit transfers:           ");
7817836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[17] =
78210387SMilan.Jurik@Sun.COM 	    MSGSTR(2172, "Synchronous transfers:      ");
7837836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[18] = MSGSTR(153, "Linked commands:            ");
7847836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[19] = MSGSTR(154, "Command queueing:           ");
7857836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_2[20] =
78610387SMilan.Jurik@Sun.COM 	    MSGSTR(2173, "Soft reset option:          ");
7877836SJohn.Forte@Sun.COM 
7887836SJohn.Forte@Sun.COM 	/*
7897836SJohn.Forte@Sun.COM 	 * Intialize scsi_inquiry_labels_3 with i18n strings
7907836SJohn.Forte@Sun.COM 	 */
7917836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[0] = MSGSTR(138, "Vendor:                     ");
7927836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[1] = MSGSTR(149, "Product:                    ");
7937836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[2] = MSGSTR(139, "Revision:                   ");
7947836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[3] = MSGSTR(143, "Firmware Revision           ");
7957836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[4] = MSGSTR(144, "Serial Number               ");
7967836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[5] = MSGSTR(140, "Device type:                ");
7977836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[6] = MSGSTR(145, "Removable media:            ");
7987836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[7] = MSGSTR(2174, "Medium Changer Element:     ");
7997836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[8] = MSGSTR(146, "ISO version:                ");
8007836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[9] = MSGSTR(147, "ECMA version:               ");
8017836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[10] = MSGSTR(148, "ANSI version:               ");
8027836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[11] =
80310387SMilan.Jurik@Sun.COM 	    MSGSTR(2175, "Async event reporting:      ");
8047836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[12] =
80510387SMilan.Jurik@Sun.COM 	    MSGSTR(2176, "Terminate task:             ");
8067836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[13] =
80710387SMilan.Jurik@Sun.COM 	    MSGSTR(2177, "Normal ACA Supported:       ");
8087836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[14] = MSGSTR(150, "Response data format:       ");
8097836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[15] = MSGSTR(151, "Additional length:          ");
8107836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[16] =
81110387SMilan.Jurik@Sun.COM 	    MSGSTR(2178, "Cmd received on port:       ");
8127836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[17] =
81310387SMilan.Jurik@Sun.COM 	    MSGSTR(2179, "SIP Bits:                   ");
8147836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[18] = MSGSTR(152, "Relative addressing:        ");
8157836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[19] = MSGSTR(153, "Linked commands:            ");
8167836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[20] =
81710387SMilan.Jurik@Sun.COM 	    MSGSTR(2180, "Transfer Disable:           ");
8187836SJohn.Forte@Sun.COM 	scsi_inquiry_labels_3[21] = MSGSTR(154, "Command queueing:           ");
8197836SJohn.Forte@Sun.COM 
8207836SJohn.Forte@Sun.COM 	/*
8217836SJohn.Forte@Sun.COM 	 * Intialize scsi_inquiry_labels_3 with i18n strings
8227836SJohn.Forte@Sun.COM 	 */
8237836SJohn.Forte@Sun.COM 	ansi_version[0] = MSGSTR(2181,
82410387SMilan.Jurik@Sun.COM 	    " (Device might or might not comply to an ANSI version)");
8257836SJohn.Forte@Sun.COM 	ansi_version[1] = MSGSTR(2182,
82610387SMilan.Jurik@Sun.COM 	    " (This code is reserved for historical uses)");
8277836SJohn.Forte@Sun.COM 	ansi_version[2] = MSGSTR(2183,
82810387SMilan.Jurik@Sun.COM 	    " (Device complies to ANSI X3.131-1994 (SCSI-2))");
8297836SJohn.Forte@Sun.COM 	ansi_version[3] = MSGSTR(2184,
83010387SMilan.Jurik@Sun.COM 	    " (Device complies to ANSI INCITS 301-1997 (SPC))");
83110387SMilan.Jurik@Sun.COM 	ansi_version[4] = MSGSTR(2226,
83210387SMilan.Jurik@Sun.COM 	    " (Device complies to ANSI INCITS 351-2001 (SPC-2))");
83310387SMilan.Jurik@Sun.COM 	ansi_version[5] = MSGSTR(2227,
83410387SMilan.Jurik@Sun.COM 	    " (Device complies to ANSI INCITS 408-2005 (SPC-3))");
8357836SJohn.Forte@Sun.COM 
83610387SMilan.Jurik@Sun.COM 	/* print inquiry information */
8377836SJohn.Forte@Sun.COM 
83810387SMilan.Jurik@Sun.COM 	(void) fprintf(stdout, MSGSTR(2185, "\nINQUIRY:\n"));
8397836SJohn.Forte@Sun.COM 		/*
8407836SJohn.Forte@Sun.COM 		 * arg_path is the path sent to luxadm by the user.  if arg_path
8417836SJohn.Forte@Sun.COM 		 * is a /devices path, then we do not need to print out physical
8427836SJohn.Forte@Sun.COM 		 * path info
8437836SJohn.Forte@Sun.COM 		 */
84410387SMilan.Jurik@Sun.COM 	if (strcmp(arg_path, path) != 0 &&
84510387SMilan.Jurik@Sun.COM 	    strstr(arg_path, "/devices/") == NULL) {
8467836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "  ");
8477836SJohn.Forte@Sun.COM 		(void) fprintf(stdout,
84810387SMilan.Jurik@Sun.COM 		    MSGSTR(5, "Physical Path:"));
8497836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n  %s\n", path);
85010387SMilan.Jurik@Sun.COM 	}
85110387SMilan.Jurik@Sun.COM 	if (inq.inq_ansi < 3) {
8527836SJohn.Forte@Sun.COM 		p = scsi_inquiry_labels_2;
8537836SJohn.Forte@Sun.COM 		scsi_3 = 0;
85410387SMilan.Jurik@Sun.COM 	} else {
8557836SJohn.Forte@Sun.COM 		p = scsi_inquiry_labels_3;
8567836SJohn.Forte@Sun.COM 		scsi_3 = 1;
85710387SMilan.Jurik@Sun.COM 	}
85810387SMilan.Jurik@Sun.COM 	if (inq.inq_len < 11) {
8597836SJohn.Forte@Sun.COM 		p += 1;
86010387SMilan.Jurik@Sun.COM 	} else {
8617836SJohn.Forte@Sun.COM 		/* */
8627836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", *p++);
8637836SJohn.Forte@Sun.COM 		print_chars(inq.inq_vid, sizeof (inq.inq_vid), 0);
8647836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
86510387SMilan.Jurik@Sun.COM 	}
86610387SMilan.Jurik@Sun.COM 	if (inq.inq_len < 27) {
8677836SJohn.Forte@Sun.COM 		p += 1;
86810387SMilan.Jurik@Sun.COM 	} else {
8697836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", *p++);
8707836SJohn.Forte@Sun.COM 		print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0);
8717836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
87210387SMilan.Jurik@Sun.COM 	}
87310387SMilan.Jurik@Sun.COM 	if (inq.inq_len < 31) {
8747836SJohn.Forte@Sun.COM 		p += 1;
87510387SMilan.Jurik@Sun.COM 	} else {
8767836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", *p++);
8777836SJohn.Forte@Sun.COM 		print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0);
8787836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
87910387SMilan.Jurik@Sun.COM 	}
88010387SMilan.Jurik@Sun.COM 	if (inq.inq_len < 39) {
8817836SJohn.Forte@Sun.COM 		p += 2;
88210387SMilan.Jurik@Sun.COM 	} else {
8837836SJohn.Forte@Sun.COM 		/*
8847836SJohn.Forte@Sun.COM 		 * If Pluto then print
8857836SJohn.Forte@Sun.COM 		 * firmware rev & serial #.
8867836SJohn.Forte@Sun.COM 		 */
8877836SJohn.Forte@Sun.COM 		if (strstr((char *)inq.inq_pid, "SSA") != 0) {
8887836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%s", *p++);
8897836SJohn.Forte@Sun.COM 			print_chars(inq.inq_firmware_rev,
89010387SMilan.Jurik@Sun.COM 			    sizeof (inq.inq_firmware_rev), 0);
8917836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "\n");
8927836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%s", *p++);
8937836SJohn.Forte@Sun.COM 			print_chars(serial, serial_len, 0);
8947836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "\n");
8957836SJohn.Forte@Sun.COM 		} else if ((inq.inq_dtype & DTYPE_MASK) != DTYPE_ESI) {
8967836SJohn.Forte@Sun.COM 			p++;
8977836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%s", *p++);
8987836SJohn.Forte@Sun.COM 			print_chars(serial, serial_len, 0);
8997836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "\n");
9007836SJohn.Forte@Sun.COM 		} else {
9017836SJohn.Forte@Sun.COM 			/* if we miss both the above if's */
9027836SJohn.Forte@Sun.COM 			p += 2;
9037836SJohn.Forte@Sun.COM 		}
90410387SMilan.Jurik@Sun.COM 	}
9057836SJohn.Forte@Sun.COM 
90610387SMilan.Jurik@Sun.COM 	(void) fprintf(stdout, "%s0x%x (", *p++, (inq.inq_dtype & DTYPE_MASK));
90710387SMilan.Jurik@Sun.COM 	if ((inq.inq_dtype & DTYPE_MASK) < 0x10) {
9087836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", dtype[inq.inq_dtype & DTYPE_MASK]);
90910387SMilan.Jurik@Sun.COM 	} else if ((inq.inq_dtype & DTYPE_MASK) < 0x1f) {
9107836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, MSGSTR(71, "Reserved"));
91110387SMilan.Jurik@Sun.COM 	} else {
9127836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, MSGSTR(2186, "Unknown device"));
91310387SMilan.Jurik@Sun.COM 	}
91410387SMilan.Jurik@Sun.COM 	(void) fprintf(stdout, ")\n");
9157836SJohn.Forte@Sun.COM 
91610387SMilan.Jurik@Sun.COM 	(void) fprintf(stdout, "%s", *p++);
91710387SMilan.Jurik@Sun.COM 	if (inq.inq_rmb != NULL) {
9187836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, MSGSTR(40, "yes"));
91910387SMilan.Jurik@Sun.COM 	} else {
9207836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, MSGSTR(45, "no"));
92110387SMilan.Jurik@Sun.COM 	}
92210387SMilan.Jurik@Sun.COM 	(void) fprintf(stdout, "\n");
9237836SJohn.Forte@Sun.COM 
92410387SMilan.Jurik@Sun.COM 	if (scsi_3) {
9257836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", *p++);
9267836SJohn.Forte@Sun.COM 		if (inq.inq_mchngr != NULL) {
9277836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, MSGSTR(40, "yes"));
9287836SJohn.Forte@Sun.COM 		} else {
9297836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, MSGSTR(45, "no"));
9307836SJohn.Forte@Sun.COM 		}
9317836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
93210387SMilan.Jurik@Sun.COM 	}
93310387SMilan.Jurik@Sun.COM 	(void) fprintf(stdout, "%s%d\n", *p++, inq.inq_iso);
93410387SMilan.Jurik@Sun.COM 	(void) fprintf(stdout, "%s%d\n", *p++, inq.inq_ecma);
9357836SJohn.Forte@Sun.COM 
93610387SMilan.Jurik@Sun.COM 	(void) fprintf(stdout, "%s%d", *p++, inq.inq_ansi);
93710387SMilan.Jurik@Sun.COM 	if (inq.inq_ansi < MAX_ANSI_VERSION) {
9387836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", ansi_version[inq.inq_ansi]);
93910387SMilan.Jurik@Sun.COM 	} else
940*12909SMilan.Jurik@Sun.COM 		(void) fprintf(stdout, " (%s)", MSGSTR(71, "Reserved"));
9417836SJohn.Forte@Sun.COM 
94210387SMilan.Jurik@Sun.COM 	(void) fprintf(stdout, "\n");
94310387SMilan.Jurik@Sun.COM 
94410387SMilan.Jurik@Sun.COM 	if (inq.inq_aenc) {
9457836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", *p++);
9467836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, MSGSTR(40, "yes"));
9477836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
94810387SMilan.Jurik@Sun.COM 	} else {
9497836SJohn.Forte@Sun.COM 		p++;
95010387SMilan.Jurik@Sun.COM 	}
95110387SMilan.Jurik@Sun.COM 	if (scsi_3) {
9527836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", *p++);
9537836SJohn.Forte@Sun.COM 		if (inq.inq_normaca != NULL) {
9547836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, MSGSTR(40, "yes"));
9557836SJohn.Forte@Sun.COM 		} else {
9567836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, MSGSTR(45, "no"));
9577836SJohn.Forte@Sun.COM 		}
9587836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
95910387SMilan.Jurik@Sun.COM 	}
96010387SMilan.Jurik@Sun.COM 	if (inq.inq_trmiop) {
9617836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", *p++);
9627836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, MSGSTR(40, "yes"));
9637836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
96410387SMilan.Jurik@Sun.COM 	} else {
9657836SJohn.Forte@Sun.COM 		p++;
96610387SMilan.Jurik@Sun.COM 	}
96710387SMilan.Jurik@Sun.COM 	(void) fprintf(stdout, "%s%d\n", *p++, inq.inq_rdf);
96810387SMilan.Jurik@Sun.COM 	(void) fprintf(stdout, "%s0x%x\n", *p++, inq.inq_len);
96910387SMilan.Jurik@Sun.COM 	if (scsi_3) {
9707836SJohn.Forte@Sun.COM 		if (inq.inq_dual_p) {
9717836SJohn.Forte@Sun.COM 			if (inq.inq_port != NULL) {
9727836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, MSGSTR(2187,
97310387SMilan.Jurik@Sun.COM 				    "%sa\n"), *p++);
9747836SJohn.Forte@Sun.COM 			} else {
9757836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, MSGSTR(2188,
97610387SMilan.Jurik@Sun.COM 				    "%sb\n"), *p++);
9777836SJohn.Forte@Sun.COM 			}
9787836SJohn.Forte@Sun.COM 		} else {
97910387SMilan.Jurik@Sun.COM 			p++;
9807836SJohn.Forte@Sun.COM 		}
98110387SMilan.Jurik@Sun.COM 	}
98210387SMilan.Jurik@Sun.COM 	if (scsi_3) {
9837836SJohn.Forte@Sun.COM 		if (inq.inq_SIP_1 || inq.ui.inq_3.inq_SIP_2 ||
98410387SMilan.Jurik@Sun.COM 		    inq.ui.inq_3.inq_SIP_3) {
98510387SMilan.Jurik@Sun.COM 			(void) fprintf(stdout, "%s%d, %d, %d\n", *p,
98610387SMilan.Jurik@Sun.COM 			    inq.inq_SIP_1, inq.ui.inq_3.inq_SIP_2,
98710387SMilan.Jurik@Sun.COM 			    inq.ui.inq_3.inq_SIP_3);
9887836SJohn.Forte@Sun.COM 		}
9897836SJohn.Forte@Sun.COM 		p++;
9907836SJohn.Forte@Sun.COM 
99110387SMilan.Jurik@Sun.COM 	}
9927836SJohn.Forte@Sun.COM 
99310387SMilan.Jurik@Sun.COM 	if (inq.ui.inq_2.inq_2_reladdr) {
9947836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", *p);
9957836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, MSGSTR(40, "yes"));
9967836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
99710387SMilan.Jurik@Sun.COM 	}
99810387SMilan.Jurik@Sun.COM 	p++;
9997836SJohn.Forte@Sun.COM 
100010387SMilan.Jurik@Sun.COM 	if (!scsi_3) {
100110387SMilan.Jurik@Sun.COM 		if (inq.ui.inq_2.inq_wbus32) {
10027836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%s", *p);
10037836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, MSGSTR(40, "yes"));
10047836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "\n");
100510387SMilan.Jurik@Sun.COM 		}
100610387SMilan.Jurik@Sun.COM 		p++;
10077836SJohn.Forte@Sun.COM 
100810387SMilan.Jurik@Sun.COM 		if (inq.ui.inq_2.inq_wbus16) {
10097836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%s", *p);
10107836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, MSGSTR(40, "yes"));
10117836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "\n");
101210387SMilan.Jurik@Sun.COM 		}
101310387SMilan.Jurik@Sun.COM 		p++;
10147836SJohn.Forte@Sun.COM 
101510387SMilan.Jurik@Sun.COM 		if (inq.ui.inq_2.inq_sync) {
10167836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%s", *p);
10177836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, MSGSTR(40, "yes"));
10187836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "\n");
101910387SMilan.Jurik@Sun.COM 		}
102010387SMilan.Jurik@Sun.COM 		p++;
10217836SJohn.Forte@Sun.COM 
102210387SMilan.Jurik@Sun.COM 	}
102310387SMilan.Jurik@Sun.COM 	if (inq.ui.inq_2.inq_linked) {
10247836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", *p);
10257836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, MSGSTR(40, "yes"));
10267836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
102710387SMilan.Jurik@Sun.COM 	}
102810387SMilan.Jurik@Sun.COM 	p++;
10297836SJohn.Forte@Sun.COM 
103010387SMilan.Jurik@Sun.COM 	if (scsi_3) {
10317836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", *p++);
10327836SJohn.Forte@Sun.COM 		if (inq.ui.inq_3.inq_trandis != NULL) {
10337836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, MSGSTR(40, "yes"));
10347836SJohn.Forte@Sun.COM 		} else {
10357836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, MSGSTR(45, "no"));
10367836SJohn.Forte@Sun.COM 		}
10377836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
103810387SMilan.Jurik@Sun.COM 	}
10397836SJohn.Forte@Sun.COM 
104010387SMilan.Jurik@Sun.COM 	if (inq.ui.inq_2.inq_cmdque) {
10417836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", *p);
10427836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, MSGSTR(40, "yes"));
10437836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
104410387SMilan.Jurik@Sun.COM 	}
104510387SMilan.Jurik@Sun.COM 	p++;
10467836SJohn.Forte@Sun.COM 
104710387SMilan.Jurik@Sun.COM 	if (!scsi_3) {
104810387SMilan.Jurik@Sun.COM 		if (inq.ui.inq_2.inq_sftre) {
10497836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%s", *p);
10507836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, MSGSTR(40, "yes"));
10517836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "\n");
105210387SMilan.Jurik@Sun.COM 		}
105310387SMilan.Jurik@Sun.COM 		p++;
10547836SJohn.Forte@Sun.COM 
105510387SMilan.Jurik@Sun.COM 	}
10567836SJohn.Forte@Sun.COM 
105710387SMilan.Jurik@Sun.COM 	/*
105810387SMilan.Jurik@Sun.COM 	 * Now print the vendor-specific data.
105910387SMilan.Jurik@Sun.COM 	 */
106010387SMilan.Jurik@Sun.COM 	v_parm = inq.inq_ven_specific_1;
106110387SMilan.Jurik@Sun.COM 	if (inq.inq_len >= 32) {
10627836SJohn.Forte@Sun.COM 		length = inq.inq_len - 31;
10637836SJohn.Forte@Sun.COM 		if (strstr((char *)inq.inq_pid, "SSA") != 0) {
106410387SMilan.Jurik@Sun.COM 			(void) fprintf(stdout, MSGSTR(2189,
106510387SMilan.Jurik@Sun.COM 			    "Number of Ports, Targets:   %d,%d\n"),
106610387SMilan.Jurik@Sun.COM 			    inq.inq_ssa_ports, inq.inq_ssa_tgts);
10677836SJohn.Forte@Sun.COM 			v_parm += 20;
10687836SJohn.Forte@Sun.COM 			length -= 20;
10697836SJohn.Forte@Sun.COM 		} else if ((strstr((char *)inq.inq_pid, "SUN") != 0) ||
107010387SMilan.Jurik@Sun.COM 		    (strncmp((char *)inq.inq_vid, "SUN     ",
107110387SMilan.Jurik@Sun.COM 		    sizeof (inq.inq_vid)) == 0)) {
10727836SJohn.Forte@Sun.COM 			v_parm += 16;
10737836SJohn.Forte@Sun.COM 			length -= 16;
10747836SJohn.Forte@Sun.COM 		}
10757836SJohn.Forte@Sun.COM 		/*
10767836SJohn.Forte@Sun.COM 		 * Do hex Dump of rest of the data.
10777836SJohn.Forte@Sun.COM 		 */
10787836SJohn.Forte@Sun.COM 		if (length > 0) {
10797836SJohn.Forte@Sun.COM 			(void) fprintf(stdout,
108010387SMilan.Jurik@Sun.COM 			    MSGSTR(2190,
10817836SJohn.Forte@Sun.COM 			"              VENDOR-SPECIFIC PARAMETERS\n"));
10827836SJohn.Forte@Sun.COM 			(void) fprintf(stdout,
108310387SMilan.Jurik@Sun.COM 			    MSGSTR(2191,
108410387SMilan.Jurik@Sun.COM 			    "Byte#                  Hex Value            "
108510387SMilan.Jurik@Sun.COM 			    "                 ASCII\n"));
10867836SJohn.Forte@Sun.COM 			(void) sprintf(byte_number,
108710387SMilan.Jurik@Sun.COM 			    "%d    ", inq.inq_len - length + 5);
10887836SJohn.Forte@Sun.COM 			dump_hex_data(byte_number, v_parm,
108910387SMilan.Jurik@Sun.COM 			    MIN(length, inq.inq_res3 - v_parm), HEX_ASCII);
10907836SJohn.Forte@Sun.COM 		}
10917836SJohn.Forte@Sun.COM 		/*
10927836SJohn.Forte@Sun.COM 		 * Skip reserved bytes 56-95.
10937836SJohn.Forte@Sun.COM 		 */
10947836SJohn.Forte@Sun.COM 		length -= (inq.inq_box_name - v_parm);
10957836SJohn.Forte@Sun.COM 		if (length > 0) {
10967836SJohn.Forte@Sun.COM 			(void) sprintf(byte_number, "%d    ",
109710387SMilan.Jurik@Sun.COM 			    inq.inq_len - length + 5);
10987836SJohn.Forte@Sun.COM 			dump_hex_data(byte_number, inq.inq_box_name,
109910387SMilan.Jurik@Sun.COM 			    MIN(length, sizeof (inq.inq_box_name) +
110010387SMilan.Jurik@Sun.COM 			    sizeof (inq.inq_avu)), HEX_ASCII);
11017836SJohn.Forte@Sun.COM 		}
110210387SMilan.Jurik@Sun.COM 	}
110310387SMilan.Jurik@Sun.COM 	if (getenv("_LUX_D_DEBUG") != NULL) {
11047836SJohn.Forte@Sun.COM 		dump_hex_data("\nComplete Inquiry: ",
110510387SMilan.Jurik@Sun.COM 		    (uchar_t *)&inq,
110610387SMilan.Jurik@Sun.COM 		    MIN(inq.inq_len + 5, sizeof (inq)), HEX_ASCII);
110710387SMilan.Jurik@Sun.COM 	}
11087836SJohn.Forte@Sun.COM }
11097836SJohn.Forte@Sun.COM 
11107836SJohn.Forte@Sun.COM /*
11117836SJohn.Forte@Sun.COM  * Internal routine to clean up ../'s in paths.
11127836SJohn.Forte@Sun.COM  * returns 0 if no "../" are left.
11137836SJohn.Forte@Sun.COM  *
11147836SJohn.Forte@Sun.COM  * Wouldn't it be nice if there was a standard system library
11157836SJohn.Forte@Sun.COM  * routine to do this...?
11167836SJohn.Forte@Sun.COM  */
11177836SJohn.Forte@Sun.COM static int
cleanup_dotdot_path(char * path)11187836SJohn.Forte@Sun.COM cleanup_dotdot_path(char *path)
11197836SJohn.Forte@Sun.COM {
11207836SJohn.Forte@Sun.COM 	char holder[MAXPATHLEN];
11217836SJohn.Forte@Sun.COM 	char *dotdot;
11227836SJohn.Forte@Sun.COM 	char *previous_slash;
11237836SJohn.Forte@Sun.COM 
11247836SJohn.Forte@Sun.COM 	/* Find the first "/../" in the string */
11257836SJohn.Forte@Sun.COM 	dotdot = strstr(path, "/../");
11267836SJohn.Forte@Sun.COM 	if (dotdot == NULL) {
11277836SJohn.Forte@Sun.COM 		return (0);
11287836SJohn.Forte@Sun.COM 	}
11297836SJohn.Forte@Sun.COM 
11307836SJohn.Forte@Sun.COM 
11317836SJohn.Forte@Sun.COM 	/*
11327836SJohn.Forte@Sun.COM 	 * If the [0] character is '/' and "../" immediatly
11337836SJohn.Forte@Sun.COM 	 * follows it, then we can strip the ../
11347836SJohn.Forte@Sun.COM 	 *
11357836SJohn.Forte@Sun.COM 	 *	/../../foo/bar == /foo/bar
11367836SJohn.Forte@Sun.COM 	 *
11377836SJohn.Forte@Sun.COM 	 */
11387836SJohn.Forte@Sun.COM 	if (dotdot == path) {
11397836SJohn.Forte@Sun.COM 		strcpy(holder, &path[3]); /* strip "/.." */
11407836SJohn.Forte@Sun.COM 		strcpy(path, holder);
11417836SJohn.Forte@Sun.COM 		return (1);
11427836SJohn.Forte@Sun.COM 	}
11437836SJohn.Forte@Sun.COM 
11447836SJohn.Forte@Sun.COM 	/*
11457836SJohn.Forte@Sun.COM 	 * Now look for the LAST "/" before the "/../"
11467836SJohn.Forte@Sun.COM 	 * as this is the parent dir we can get rid of.
11477836SJohn.Forte@Sun.COM 	 * We do this by temporarily truncating the string
11487836SJohn.Forte@Sun.COM 	 * at the '/' just before "../" using the dotdot pointer.
11497836SJohn.Forte@Sun.COM 	 */
11507836SJohn.Forte@Sun.COM 	*dotdot = '\0';
11517836SJohn.Forte@Sun.COM 	previous_slash = strrchr(path, '/');
11527836SJohn.Forte@Sun.COM 	if (previous_slash == NULL) {
11537836SJohn.Forte@Sun.COM 		/*
11547836SJohn.Forte@Sun.COM 		 * hmm, somethings wrong.  path looks something
11557836SJohn.Forte@Sun.COM 		 * like "foo/../bar/" so we can't really deal with it.
11567836SJohn.Forte@Sun.COM 		 */
11577836SJohn.Forte@Sun.COM 		return (0);
11587836SJohn.Forte@Sun.COM 	}
11597836SJohn.Forte@Sun.COM 	/*
11607836SJohn.Forte@Sun.COM 	 * Now truncate the path just after the previous '/'
11617836SJohn.Forte@Sun.COM 	 * and slam everything after the "../" back on
11627836SJohn.Forte@Sun.COM 	 */
11637836SJohn.Forte@Sun.COM 	*(previous_slash+1) = '\0';
11647836SJohn.Forte@Sun.COM 	(void) strcat(path, dotdot+4);
11657836SJohn.Forte@Sun.COM 	return (1); /* We may have more "../"s */
11667836SJohn.Forte@Sun.COM }
11677836SJohn.Forte@Sun.COM 
11687836SJohn.Forte@Sun.COM /*
11697836SJohn.Forte@Sun.COM  * Follow symbolic links from the logical device name to
11707836SJohn.Forte@Sun.COM  * the /devfs physical device name.  To be complete, we
11717836SJohn.Forte@Sun.COM  * handle the case of multiple links.  This function
11727836SJohn.Forte@Sun.COM  * either returns NULL (no links, or some other error),
11737836SJohn.Forte@Sun.COM  * or the physical device name, alloc'ed on the heap.
11747836SJohn.Forte@Sun.COM  *
11757836SJohn.Forte@Sun.COM  * NOTE: If the path is relative, it will be forced into
11767836SJohn.Forte@Sun.COM  * an absolute path by pre-pending the pwd to it.
11777836SJohn.Forte@Sun.COM  */
11787836SJohn.Forte@Sun.COM char *
get_slash_devices_from_osDevName(char * osDevName,int flag)11797836SJohn.Forte@Sun.COM get_slash_devices_from_osDevName(char *osDevName, int flag)
11807836SJohn.Forte@Sun.COM {
11817836SJohn.Forte@Sun.COM 	struct stat	stbuf;
11827836SJohn.Forte@Sun.COM 	char		source[MAXPATHLEN];
11837836SJohn.Forte@Sun.COM 	char		scratch[MAXPATHLEN];
11847836SJohn.Forte@Sun.COM 	char		pwd[MAXPATHLEN];
11857836SJohn.Forte@Sun.COM 	char		*tmp, *phys_path;
11867836SJohn.Forte@Sun.COM 	int		cnt;
11877836SJohn.Forte@Sun.COM 	boolean_t	is_lstat_failed = B_TRUE;
11887836SJohn.Forte@Sun.COM 
11897836SJohn.Forte@Sun.COM 	/* return NULL if path is NULL */
11907836SJohn.Forte@Sun.COM 	if (osDevName == NULL) {
11917836SJohn.Forte@Sun.COM 		return (NULL);
11927836SJohn.Forte@Sun.COM 	}
11937836SJohn.Forte@Sun.COM 
11947836SJohn.Forte@Sun.COM 	strcpy(source, osDevName);
11957836SJohn.Forte@Sun.COM 	for (;;) {
11967836SJohn.Forte@Sun.COM 
11977836SJohn.Forte@Sun.COM 		/*
11987836SJohn.Forte@Sun.COM 		 * First make sure the path is absolute.  If not, make it.
11997836SJohn.Forte@Sun.COM 		 * If it's already an absolute path, we have no need
12007836SJohn.Forte@Sun.COM 		 * to determine the cwd, so the program should still
12017836SJohn.Forte@Sun.COM 		 * function within security-by-obscurity directories.
12027836SJohn.Forte@Sun.COM 		 */
12037836SJohn.Forte@Sun.COM 		if (source[0] != '/') {
12047836SJohn.Forte@Sun.COM 			tmp = getcwd(pwd, MAXPATHLEN);
12057836SJohn.Forte@Sun.COM 			if (tmp == NULL) {
12067836SJohn.Forte@Sun.COM 				return (NULL);
12077836SJohn.Forte@Sun.COM 			}
12087836SJohn.Forte@Sun.COM 			/*
12097836SJohn.Forte@Sun.COM 			 * Handle special case of "./foo/bar"
12107836SJohn.Forte@Sun.COM 			 */
12117836SJohn.Forte@Sun.COM 			if (source[0] == '.' && source[1] == '/') {
12127836SJohn.Forte@Sun.COM 				strcpy(scratch, source+2);
12137836SJohn.Forte@Sun.COM 			} else { /* no "./" so just take everything */
12147836SJohn.Forte@Sun.COM 				strcpy(scratch, source);
12157836SJohn.Forte@Sun.COM 			}
12167836SJohn.Forte@Sun.COM 			strcpy(source, pwd);
12177836SJohn.Forte@Sun.COM 			(void) strcat(source, "/");
12187836SJohn.Forte@Sun.COM 			(void) strcat(source, scratch);
12197836SJohn.Forte@Sun.COM 		}
12207836SJohn.Forte@Sun.COM 
12217836SJohn.Forte@Sun.COM 		/*
12227836SJohn.Forte@Sun.COM 		 * Clean up any "../"s that are in the path
12237836SJohn.Forte@Sun.COM 		 */
122410387SMilan.Jurik@Sun.COM 		while (cleanup_dotdot_path(source))
122510387SMilan.Jurik@Sun.COM 			;
12267836SJohn.Forte@Sun.COM 
12277836SJohn.Forte@Sun.COM 		/*
12287836SJohn.Forte@Sun.COM 		 * source is now an absolute path to the link we're
12297836SJohn.Forte@Sun.COM 		 * concerned with
12307836SJohn.Forte@Sun.COM 		 */
12317836SJohn.Forte@Sun.COM 		if (flag == NOT_IGNORE_DANGLING_LINK) {
12327836SJohn.Forte@Sun.COM 			/*
12337836SJohn.Forte@Sun.COM 			 * In order not to ingore dangling links, check
12347836SJohn.Forte@Sun.COM 			 * the lstat. If lstat succeeds, return the path
12357836SJohn.Forte@Sun.COM 			 * from readlink.
12367836SJohn.Forte@Sun.COM 			 * Note: osDevName input with /devices path from
12377836SJohn.Forte@Sun.COM 			 * a dangling /dev link doesn't pass lstat so
12387836SJohn.Forte@Sun.COM 			 * NULL is returned.
12397836SJohn.Forte@Sun.COM 			 */
124010387SMilan.Jurik@Sun.COM 			if (stat(source, &stbuf) == -1) {
124110387SMilan.Jurik@Sun.COM 				if (!is_lstat_failed &&
124210387SMilan.Jurik@Sun.COM 				    strstr(source, "/devices")) {
124310387SMilan.Jurik@Sun.COM 					/*
124410387SMilan.Jurik@Sun.COM 					 * lstat succeeded previously and source
124510387SMilan.Jurik@Sun.COM 					 * contains "/devices" then it is
124610387SMilan.Jurik@Sun.COM 					 * dangling node.
124710387SMilan.Jurik@Sun.COM 					 */
124810387SMilan.Jurik@Sun.COM 					phys_path = (char *)calloc(1,
124910387SMilan.Jurik@Sun.COM 					    strlen(source) + 1);
125010387SMilan.Jurik@Sun.COM 					if (phys_path != NULL) {
125110387SMilan.Jurik@Sun.COM 						(void) strncpy(phys_path,
125210387SMilan.Jurik@Sun.COM 						    source, strlen(source) + 1);
125310387SMilan.Jurik@Sun.COM 					}
125410387SMilan.Jurik@Sun.COM 					return (phys_path);
125510387SMilan.Jurik@Sun.COM 				} else if (is_lstat_failed) {
125610387SMilan.Jurik@Sun.COM 					/* check lstat result. */
125710387SMilan.Jurik@Sun.COM 					if (lstat(source, &stbuf) == -1) {
125810387SMilan.Jurik@Sun.COM 						return (NULL);
125910387SMilan.Jurik@Sun.COM 					} else {
126010387SMilan.Jurik@Sun.COM 						/* and continue */
126110387SMilan.Jurik@Sun.COM 						is_lstat_failed = B_FALSE;
126210387SMilan.Jurik@Sun.COM 					}
126310387SMilan.Jurik@Sun.COM 				} else {
126410387SMilan.Jurik@Sun.COM 					/*
126510387SMilan.Jurik@Sun.COM 					 * With algorithm that resolves a link
126610387SMilan.Jurik@Sun.COM 					 * and then issues readlink(), should
126710387SMilan.Jurik@Sun.COM 					 * not be reached here.
126810387SMilan.Jurik@Sun.COM 					 */
126910387SMilan.Jurik@Sun.COM 					return (NULL);
127010387SMilan.Jurik@Sun.COM 				}
12717836SJohn.Forte@Sun.COM 			} else {
127210387SMilan.Jurik@Sun.COM 				if (lstat(source, &stbuf) == -1) {
127310387SMilan.Jurik@Sun.COM 					/*
127410387SMilan.Jurik@Sun.COM 					 * when stat succeeds it is not
127510387SMilan.Jurik@Sun.COM 					 * a dangling node so it is not
127610387SMilan.Jurik@Sun.COM 					 * a special case.
127710387SMilan.Jurik@Sun.COM 					 */
127810387SMilan.Jurik@Sun.COM 					return (NULL);
127910387SMilan.Jurik@Sun.COM 				}
12807836SJohn.Forte@Sun.COM 			}
12817836SJohn.Forte@Sun.COM 		} else if (flag == STANDARD_DEVNAME_HANDLING) {
12827836SJohn.Forte@Sun.COM 			/*
12837836SJohn.Forte@Sun.COM 			 * See if there's a real file out there.  If not,
12847836SJohn.Forte@Sun.COM 			 * we have a dangling link and we ignore it.
12857836SJohn.Forte@Sun.COM 			 */
128610387SMilan.Jurik@Sun.COM 			if (stat(source, &stbuf) == -1) {
128710387SMilan.Jurik@Sun.COM 				return (NULL);
128810387SMilan.Jurik@Sun.COM 			}
128910387SMilan.Jurik@Sun.COM 			if (lstat(source, &stbuf) == -1) {
129010387SMilan.Jurik@Sun.COM 				return (NULL);
129110387SMilan.Jurik@Sun.COM 			}
129210387SMilan.Jurik@Sun.COM 		} else {
129310387SMilan.Jurik@Sun.COM 			/* invalid flag */
12947836SJohn.Forte@Sun.COM 			return (NULL);
12957836SJohn.Forte@Sun.COM 		}
12967836SJohn.Forte@Sun.COM 
12977836SJohn.Forte@Sun.COM 		/*
12987836SJohn.Forte@Sun.COM 		 * If the file is not a link, we're done one
12997836SJohn.Forte@Sun.COM 		 * way or the other.  If there were links,
13007836SJohn.Forte@Sun.COM 		 * return the full pathname of the resulting
13017836SJohn.Forte@Sun.COM 		 * file.
13027836SJohn.Forte@Sun.COM 		 *
13037836SJohn.Forte@Sun.COM 		 * Note:  All of our temp's are on the stack,
13047836SJohn.Forte@Sun.COM 		 * so we have to copy the final result to the heap.
13057836SJohn.Forte@Sun.COM 		 */
13067836SJohn.Forte@Sun.COM 		if (!S_ISLNK(stbuf.st_mode)) {
13077836SJohn.Forte@Sun.COM 			phys_path = (char *)calloc(1, strlen(source) + 1);
13087836SJohn.Forte@Sun.COM 			if (phys_path != NULL) {
130910387SMilan.Jurik@Sun.COM 				(void) strncpy(phys_path, source,
131010387SMilan.Jurik@Sun.COM 				    strlen(source) + 1);
13117836SJohn.Forte@Sun.COM 			}
13127836SJohn.Forte@Sun.COM 			return (phys_path);
13137836SJohn.Forte@Sun.COM 		}
13147836SJohn.Forte@Sun.COM 		cnt = readlink(source, scratch, sizeof (scratch));
13157836SJohn.Forte@Sun.COM 		if (cnt < 0) {
13167836SJohn.Forte@Sun.COM 			return (NULL);
13177836SJohn.Forte@Sun.COM 		}
13187836SJohn.Forte@Sun.COM 		/*
13197836SJohn.Forte@Sun.COM 		 * scratch is on the heap, and for some reason readlink
13207836SJohn.Forte@Sun.COM 		 * doesn't always terminate things properly so we have
13217836SJohn.Forte@Sun.COM 		 * to make certain we're properly terminated
13227836SJohn.Forte@Sun.COM 		 */
13237836SJohn.Forte@Sun.COM 		scratch[cnt] = '\0';
13247836SJohn.Forte@Sun.COM 
13257836SJohn.Forte@Sun.COM 		/*
13267836SJohn.Forte@Sun.COM 		 * Now check to see if the link is relative.  If so,
13277836SJohn.Forte@Sun.COM 		 * then we have to append it to the directory
13287836SJohn.Forte@Sun.COM 		 * which the source was in. (This is non trivial)
13297836SJohn.Forte@Sun.COM 		 */
13307836SJohn.Forte@Sun.COM 		if (scratch[0] != '/') {
13317836SJohn.Forte@Sun.COM 			tmp = strrchr(source, '/');
13327836SJohn.Forte@Sun.COM 			if (tmp == NULL) { /* Whoa!  Something's hosed! */
13337836SJohn.Forte@Sun.COM 				O_DPRINTF("Internal error... corrupt path.\n");
13347836SJohn.Forte@Sun.COM 				return (NULL);
13357836SJohn.Forte@Sun.COM 			}
13367836SJohn.Forte@Sun.COM 			/* Now strip off just the directory path */
13377836SJohn.Forte@Sun.COM 			*(tmp+1) = '\0'; /* Keeping the last '/' */
13387836SJohn.Forte@Sun.COM 			/* and append the new link */
13397836SJohn.Forte@Sun.COM 			(void) strcat(source, scratch);
13407836SJohn.Forte@Sun.COM 			/*
13417836SJohn.Forte@Sun.COM 			 * Note:  At this point, source should have "../"s
13427836SJohn.Forte@Sun.COM 			 * but we'll clean it up in the next pass through
13437836SJohn.Forte@Sun.COM 			 * the loop.
13447836SJohn.Forte@Sun.COM 			 */
13457836SJohn.Forte@Sun.COM 		} else {
13467836SJohn.Forte@Sun.COM 			/* It's an absolute link so no worries */
13477836SJohn.Forte@Sun.COM 			strcpy(source, scratch);
13487836SJohn.Forte@Sun.COM 		}
13497836SJohn.Forte@Sun.COM 	}
13507836SJohn.Forte@Sun.COM 	/* Never reach here */
13517836SJohn.Forte@Sun.COM }
13527836SJohn.Forte@Sun.COM 
13537836SJohn.Forte@Sun.COM /*
13547836SJohn.Forte@Sun.COM  * Input - Space for client_path, phci_path and paddr fields of ioc structure
13557836SJohn.Forte@Sun.COM  * need to be allocated by the caller of this routine.
13567836SJohn.Forte@Sun.COM  */
13577836SJohn.Forte@Sun.COM int
get_scsi_vhci_pathinfo(char * dev_path,sv_iocdata_t * ioc,int * path_count)13587836SJohn.Forte@Sun.COM get_scsi_vhci_pathinfo(char *dev_path, sv_iocdata_t *ioc, int *path_count)
13597836SJohn.Forte@Sun.COM {
13607836SJohn.Forte@Sun.COM 	char	*physical_path, *physical_path_s;
13617836SJohn.Forte@Sun.COM 	int	retval;
13627836SJohn.Forte@Sun.COM 	int	fd;
13637836SJohn.Forte@Sun.COM 	int	initial_path_count;
13647836SJohn.Forte@Sun.COM 	int	current_path_count;
13657836SJohn.Forte@Sun.COM 	int 	i;
13667836SJohn.Forte@Sun.COM 	char	*delimiter;
13677836SJohn.Forte@Sun.COM 	int	malloc_error = 0;
13687836SJohn.Forte@Sun.COM 	int 	prop_buf_size;
13697836SJohn.Forte@Sun.COM 	int	pathlist_retry_count = 0;
13707836SJohn.Forte@Sun.COM 
137110387SMilan.Jurik@Sun.COM 	if (strncmp(dev_path, SCSI_VHCI, strlen(SCSI_VHCI)) != NULL) {
13727836SJohn.Forte@Sun.COM 		if ((physical_path = get_slash_devices_from_osDevName(
137310387SMilan.Jurik@Sun.COM 		    dev_path, STANDARD_DEVNAME_HANDLING)) == NULL) {
13747836SJohn.Forte@Sun.COM 			return (L_INVALID_PATH);
13757836SJohn.Forte@Sun.COM 		}
13767836SJohn.Forte@Sun.COM 		if (strncmp(physical_path, SCSI_VHCI,
137710387SMilan.Jurik@Sun.COM 		    strlen(SCSI_VHCI)) != NULL) {
13787836SJohn.Forte@Sun.COM 			free(physical_path);
13797836SJohn.Forte@Sun.COM 			return (L_INVALID_PATH);
13807836SJohn.Forte@Sun.COM 		}
13817836SJohn.Forte@Sun.COM 	} else {
13827836SJohn.Forte@Sun.COM 		if ((physical_path = calloc(1, MAXPATHLEN)) == NULL) {
13837836SJohn.Forte@Sun.COM 			return (L_MALLOC_FAILED);
13847836SJohn.Forte@Sun.COM 		}
13857836SJohn.Forte@Sun.COM 		(void) strcpy(physical_path, dev_path);
13867836SJohn.Forte@Sun.COM 	}
13877836SJohn.Forte@Sun.COM 	physical_path_s = physical_path;
13887836SJohn.Forte@Sun.COM 
13897836SJohn.Forte@Sun.COM 	/* move beyond "/devices" prefix */
13907836SJohn.Forte@Sun.COM 	physical_path += DEV_PREFIX_STRLEN-1;
13917836SJohn.Forte@Sun.COM 	/* remove  :c,raw suffix */
13927836SJohn.Forte@Sun.COM 	delimiter = strrchr(physical_path, ':');
13937836SJohn.Forte@Sun.COM 	/* if we didn't find the ':' fine, else truncate */
13947836SJohn.Forte@Sun.COM 	if (delimiter != NULL) {
13957836SJohn.Forte@Sun.COM 		*delimiter = NULL;
13967836SJohn.Forte@Sun.COM 	}
13977836SJohn.Forte@Sun.COM 
13987836SJohn.Forte@Sun.COM 	/*
13997836SJohn.Forte@Sun.COM 	 * We'll call ioctl SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO
14007836SJohn.Forte@Sun.COM 	 * at least twice.  The first time will get the path count
14017836SJohn.Forte@Sun.COM 	 * and the size of the ioctl propoerty buffer.  The second
14027836SJohn.Forte@Sun.COM 	 * time will get the path_info for each path.
14037836SJohn.Forte@Sun.COM 	 *
14047836SJohn.Forte@Sun.COM 	 * It's possible that additional paths are added while this
14057836SJohn.Forte@Sun.COM 	 * code is running.  If the path count increases between the
14067836SJohn.Forte@Sun.COM 	 * 2 ioctl's above, then we'll retry (and assume all is well).
14077836SJohn.Forte@Sun.COM 	 */
14087836SJohn.Forte@Sun.COM 	(void) strcpy(ioc->client, physical_path);
14097836SJohn.Forte@Sun.COM 	ioc->buf_elem = 1;
14107836SJohn.Forte@Sun.COM 	ioc->ret_elem = (uint_t *)&(initial_path_count);
14117836SJohn.Forte@Sun.COM 	ioc->ret_buf = NULL;
14127836SJohn.Forte@Sun.COM 
14137836SJohn.Forte@Sun.COM 	/* free physical path */
14147836SJohn.Forte@Sun.COM 	free(physical_path_s);
14157836SJohn.Forte@Sun.COM 
14167836SJohn.Forte@Sun.COM 	/* 0 buf_size asks driver to return actual size needed */
14177836SJohn.Forte@Sun.COM 	/* open the ioctl file descriptor */
14187836SJohn.Forte@Sun.COM 	if ((fd = open("/devices/scsi_vhci:devctl", O_RDWR)) < 0) {
14197836SJohn.Forte@Sun.COM 		return (L_OPEN_PATH_FAIL);
14207836SJohn.Forte@Sun.COM 	}
14217836SJohn.Forte@Sun.COM 
14227836SJohn.Forte@Sun.COM 	retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, ioc);
14237836SJohn.Forte@Sun.COM 	if (retval != 0) {
14247836SJohn.Forte@Sun.COM 		close(fd);
142510387SMilan.Jurik@Sun.COM 		return (L_SCSI_VHCI_ERROR);
14267836SJohn.Forte@Sun.COM 	}
14277836SJohn.Forte@Sun.COM 	prop_buf_size = SV_PROP_MAX_BUF_SIZE;
14287836SJohn.Forte@Sun.COM 
14297836SJohn.Forte@Sun.COM 
14307836SJohn.Forte@Sun.COM 	while (pathlist_retry_count <= RETRY_PATHLIST) {
14317836SJohn.Forte@Sun.COM 		ioc->buf_elem = initial_path_count;
14327836SJohn.Forte@Sun.COM 		/* Make driver put actual # paths in variable */
14337836SJohn.Forte@Sun.COM 		ioc->ret_elem = (uint_t *)&(current_path_count);
14347836SJohn.Forte@Sun.COM 
14357836SJohn.Forte@Sun.COM 		/*
14367836SJohn.Forte@Sun.COM 		 * Allocate space for array of path_info structures.
14377836SJohn.Forte@Sun.COM 		 * Allocate enough space for # paths from get_pathcount
14387836SJohn.Forte@Sun.COM 		 */
14397836SJohn.Forte@Sun.COM 		ioc->ret_buf = (sv_path_info_t *)
144010387SMilan.Jurik@Sun.COM 		    calloc(initial_path_count, sizeof (sv_path_info_t));
14417836SJohn.Forte@Sun.COM 		if (ioc->ret_buf == NULL) {
14427836SJohn.Forte@Sun.COM 			close(fd);
14437836SJohn.Forte@Sun.COM 			return (L_MALLOC_FAILED);
14447836SJohn.Forte@Sun.COM 		}
14457836SJohn.Forte@Sun.COM 
14467836SJohn.Forte@Sun.COM 		/*
14477836SJohn.Forte@Sun.COM 		 * Allocate space for path properties returned by driver
14487836SJohn.Forte@Sun.COM 		 */
14497836SJohn.Forte@Sun.COM 		malloc_error = 0;
14507836SJohn.Forte@Sun.COM 		for (i = 0; i < initial_path_count; i++) {
14517836SJohn.Forte@Sun.COM 			ioc->ret_buf[i].ret_prop.buf_size = prop_buf_size;
14527836SJohn.Forte@Sun.COM 			if ((ioc->ret_buf[i].ret_prop.buf =
14537836SJohn.Forte@Sun.COM 			    (caddr_t)malloc(prop_buf_size)) == NULL) {
14547836SJohn.Forte@Sun.COM 				malloc_error = 1;
14557836SJohn.Forte@Sun.COM 				break;
14567836SJohn.Forte@Sun.COM 			}
14577836SJohn.Forte@Sun.COM 			if ((ioc->ret_buf[i].ret_prop.ret_buf_size =
145810387SMilan.Jurik@Sun.COM 			    (uint_t *)malloc(sizeof (uint_t))) == NULL) {
14597836SJohn.Forte@Sun.COM 				malloc_error = 1;
14607836SJohn.Forte@Sun.COM 				break;
14617836SJohn.Forte@Sun.COM 			}
14627836SJohn.Forte@Sun.COM 		}
14637836SJohn.Forte@Sun.COM 		if (malloc_error == 1) {
14647836SJohn.Forte@Sun.COM 			for (i = 0; i < initial_path_count; i++) {
14657836SJohn.Forte@Sun.COM 				free(ioc->ret_buf[i].ret_prop.buf);
14667836SJohn.Forte@Sun.COM 				free(ioc->ret_buf[i].ret_prop.ret_buf_size);
14677836SJohn.Forte@Sun.COM 			}
14687836SJohn.Forte@Sun.COM 			free(ioc->ret_buf);
14697836SJohn.Forte@Sun.COM 			close(fd);
14707836SJohn.Forte@Sun.COM 			return (L_MALLOC_FAILED);
14717836SJohn.Forte@Sun.COM 		}
14727836SJohn.Forte@Sun.COM 
14737836SJohn.Forte@Sun.COM 		retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, ioc);
14747836SJohn.Forte@Sun.COM 		if (retval != 0) {
14757836SJohn.Forte@Sun.COM 			for (i = 0; i < initial_path_count; i++) {
14767836SJohn.Forte@Sun.COM 				free(ioc->ret_buf[i].ret_prop.buf);
14777836SJohn.Forte@Sun.COM 				free(ioc->ret_buf[i].ret_prop.ret_buf_size);
14787836SJohn.Forte@Sun.COM 			}
14797836SJohn.Forte@Sun.COM 			free(ioc->ret_buf);
14807836SJohn.Forte@Sun.COM 			close(fd);
14817836SJohn.Forte@Sun.COM 			return (L_SCSI_VHCI_ERROR);
14827836SJohn.Forte@Sun.COM 		}
14837836SJohn.Forte@Sun.COM 		if (initial_path_count < current_path_count) {
14847836SJohn.Forte@Sun.COM 			/* then a new path was added */
14857836SJohn.Forte@Sun.COM 			pathlist_retry_count++;
14867836SJohn.Forte@Sun.COM 			initial_path_count = current_path_count;
14877836SJohn.Forte@Sun.COM 		} else {
14887836SJohn.Forte@Sun.COM 			break;
14897836SJohn.Forte@Sun.COM 		}
14907836SJohn.Forte@Sun.COM 	}
14917836SJohn.Forte@Sun.COM 	/* we are done with ioctl's, lose the fd */
14927836SJohn.Forte@Sun.COM 	close(fd);
14937836SJohn.Forte@Sun.COM 
14947836SJohn.Forte@Sun.COM 	/*
14957836SJohn.Forte@Sun.COM 	 * Compare the length num elements from the ioctl response
14967836SJohn.Forte@Sun.COM 	 *   and the caller's request - use smaller value.
14977836SJohn.Forte@Sun.COM 	 *
14987836SJohn.Forte@Sun.COM 	 * pathlist_p->path_count now has count returned from ioctl.
14997836SJohn.Forte@Sun.COM 	 * ioc.buf_elem has the value the caller provided.
15007836SJohn.Forte@Sun.COM 	 */
15017836SJohn.Forte@Sun.COM 	if (initial_path_count < current_path_count) {
15027836SJohn.Forte@Sun.COM 		/* More paths exist than we allocated space for */
15037836SJohn.Forte@Sun.COM 		*path_count = initial_path_count;
15047836SJohn.Forte@Sun.COM 	} else {
15057836SJohn.Forte@Sun.COM 		*path_count = current_path_count;
15067836SJohn.Forte@Sun.COM 	}
15077836SJohn.Forte@Sun.COM 
15087836SJohn.Forte@Sun.COM 	return (0);
15097836SJohn.Forte@Sun.COM }
15107836SJohn.Forte@Sun.COM 
15117836SJohn.Forte@Sun.COM int
get_mode_page(char * path,uchar_t ** pg_buf)15127836SJohn.Forte@Sun.COM get_mode_page(char *path, uchar_t **pg_buf)
15137836SJohn.Forte@Sun.COM {
151410387SMilan.Jurik@Sun.COM 	struct mode_header_g1	*mode_header_ptr;
151510387SMilan.Jurik@Sun.COM 	int		status, size, fd;
15167836SJohn.Forte@Sun.COM 
15177836SJohn.Forte@Sun.COM 	/* open controller */
15187836SJohn.Forte@Sun.COM 	if ((fd = open(path, O_NDELAY | O_RDWR)) == -1)
15197836SJohn.Forte@Sun.COM 		return (-1); /* L_OPEN_PATH_FAIL */
15207836SJohn.Forte@Sun.COM 
15217836SJohn.Forte@Sun.COM 	/*
15227836SJohn.Forte@Sun.COM 	 * Read the first part of the page to get the page size
15237836SJohn.Forte@Sun.COM 	 */
15247836SJohn.Forte@Sun.COM 	size = 20;
15257836SJohn.Forte@Sun.COM 	if ((*pg_buf = (uchar_t *)calloc(1, size)) == NULL) {
152610387SMilan.Jurik@Sun.COM 		(void) close(fd);
152710387SMilan.Jurik@Sun.COM 		return (L_MALLOC_FAILED);
15287836SJohn.Forte@Sun.COM 	}
15297836SJohn.Forte@Sun.COM 	/* read page */
15307836SJohn.Forte@Sun.COM 	if (status = scsi_mode_sense_cmd(fd, *pg_buf, size,
15317836SJohn.Forte@Sun.COM 	    0, MODEPAGE_ALLPAGES)) {
153210387SMilan.Jurik@Sun.COM 		(void) close(fd);
153310387SMilan.Jurik@Sun.COM 		(void) free(*pg_buf);
153410387SMilan.Jurik@Sun.COM 		return (status);
15357836SJohn.Forte@Sun.COM 	}
15367836SJohn.Forte@Sun.COM 	/* Now get the size for all pages */
15377836SJohn.Forte@Sun.COM 	mode_header_ptr = (struct mode_header_g1 *)(void *)*pg_buf;
15387836SJohn.Forte@Sun.COM 	size = ntohs(mode_header_ptr->length) +
153910387SMilan.Jurik@Sun.COM 	    sizeof (mode_header_ptr->length);
15407836SJohn.Forte@Sun.COM 	(void) free(*pg_buf);
15417836SJohn.Forte@Sun.COM 	if ((*pg_buf = (uchar_t *)calloc(1, size)) == NULL) {
154210387SMilan.Jurik@Sun.COM 		(void) close(fd);
154310387SMilan.Jurik@Sun.COM 		return (L_MALLOC_FAILED);
15447836SJohn.Forte@Sun.COM 	}
15457836SJohn.Forte@Sun.COM 	/* read all pages */
15467836SJohn.Forte@Sun.COM 	if (status = scsi_mode_sense_cmd(fd, *pg_buf, size,
154710387SMilan.Jurik@Sun.COM 	    0, MODEPAGE_ALLPAGES)) {
154810387SMilan.Jurik@Sun.COM 		(void) close(fd);
154910387SMilan.Jurik@Sun.COM 		(void) free(*pg_buf);
155010387SMilan.Jurik@Sun.COM 		return (status);
15517836SJohn.Forte@Sun.COM 	}
15527836SJohn.Forte@Sun.COM 	(void) close(fd);
15537836SJohn.Forte@Sun.COM 	return (0);
15547836SJohn.Forte@Sun.COM }
15557836SJohn.Forte@Sun.COM 
15567836SJohn.Forte@Sun.COM /*
15577836SJohn.Forte@Sun.COM  * Dump a structure in hexadecimal.
15587836SJohn.Forte@Sun.COM  */
15597836SJohn.Forte@Sun.COM void
dump_hex_data(char * hdr,uchar_t * src,int nbytes,int format)15607836SJohn.Forte@Sun.COM dump_hex_data(char *hdr, uchar_t *src, int nbytes, int format)
15617836SJohn.Forte@Sun.COM {
15627836SJohn.Forte@Sun.COM 	int i;
15637836SJohn.Forte@Sun.COM 	int n;
15647836SJohn.Forte@Sun.COM 	char	*p;
15657836SJohn.Forte@Sun.COM 	char	s[256];
15667836SJohn.Forte@Sun.COM 
15677836SJohn.Forte@Sun.COM 	assert(format == HEX_ONLY || format == HEX_ASCII);
15687836SJohn.Forte@Sun.COM 
15697836SJohn.Forte@Sun.COM 	(void) strcpy(s, hdr);
15707836SJohn.Forte@Sun.COM 	for (p = s; *p; p++) {
15717836SJohn.Forte@Sun.COM 		*p = ' ';
15727836SJohn.Forte@Sun.COM 	}
15737836SJohn.Forte@Sun.COM 
15747836SJohn.Forte@Sun.COM 	p = hdr;
15757836SJohn.Forte@Sun.COM 	while (nbytes > 0) {
15767836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "%s", p);
15777836SJohn.Forte@Sun.COM 		p = s;
15787836SJohn.Forte@Sun.COM 		n = MIN(nbytes, BYTES_PER_LINE);
15797836SJohn.Forte@Sun.COM 		for (i = 0; i < n; i++) {
15807836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "%02x ", src[i] & 0xff);
15817836SJohn.Forte@Sun.COM 		}
15827836SJohn.Forte@Sun.COM 		if (format == HEX_ASCII) {
15837836SJohn.Forte@Sun.COM 			for (i = BYTES_PER_LINE-n; i > 0; i--) {
15847836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, "   ");
15857836SJohn.Forte@Sun.COM 			}
15867836SJohn.Forte@Sun.COM 			(void) fprintf(stdout, "    ");
15877836SJohn.Forte@Sun.COM 			for (i = 0; i < n; i++) {
15887836SJohn.Forte@Sun.COM 				(void) fprintf(stdout, "%c",
158910387SMilan.Jurik@Sun.COM 				    isprint(src[i]) ? src[i] : '.');
15907836SJohn.Forte@Sun.COM 			}
15917836SJohn.Forte@Sun.COM 		}
15927836SJohn.Forte@Sun.COM 		(void) fprintf(stdout, "\n");
15937836SJohn.Forte@Sun.COM 		nbytes -= n;
15947836SJohn.Forte@Sun.COM 		src += n;
15957836SJohn.Forte@Sun.COM 	}
15967836SJohn.Forte@Sun.COM }
1597