OpenSolaris_b135/cmd/luxadm/g_adm.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */



#define	LUX_SF_INST_SHIFT4MINOR 6
#define	LUX_SF_MINOR2INST(x)    (x >> LUX_SF_INST_SHIFT4MINOR)

#include	<stdlib.h>
#include	<stdio.h>
#include	<sys/file.h>
#include	<sys/errno.h>
#include	<sys/types.h>
#include	<sys/stat.h>
#include	<sys/param.h>
#include	<kstat.h>
#include	<sys/mkdev.h>
#include	<locale.h>
#include	<nl_types.h>
#include	<fcntl.h>
#include	<unistd.h>
#include	<strings.h>
#include	<ctype.h>
#include	<dirent.h>
#include	<limits.h>
#include	<stdarg.h>
#include	<termio.h>		/* For password */
#include	<signal.h>
#include	<sys/scsi/scsi.h>
#include	<sys/scsi/generic/commands.h>
#include	<l_common.h>
#include	<l_error.h>
#include	<stgcom.h>
#include	<a_state.h>
#include	<devid.h>
#include	<g_state.h>
#include	"common.h"

extern char		*dtype[];
extern char		*whoami;
extern	int	Options;
extern	const	int OPTION_A;
extern	const	int OPTION_B;
extern	const	int OPTION_C;
extern	const	int OPTION_D;
extern	const	int OPTION_E;
extern	const	int OPTION_F;
extern	const	int OPTION_L;
extern	const	int OPTION_P;
extern	const	int OPTION_R;
extern	const	int OPTION_T;
extern	const	int OPTION_V;
extern	const	int OPTION_Z;
extern	const	int OPTION_Y;
extern	const	int OPTION_CAPF;
extern	const	int PVERBOSE;
extern	const	int SAVE;
extern	const	int EXPERT;

static		struct termios	termios;
static		int termio_fd;
static	void	pho_display_config(char *);
static	void	dpm_display_config(char *);
static	void	n_rem_list_entry(uchar_t,  struct gfc_map *,
		WWN_list **);
static	void	n_rem_list_entry_fabric(int, struct gfc_map *,
		WWN_list **);
static	void	n_rem_wwn_entry(uchar_t *, WWN_list **);
static	void	display_disk_info(L_inquiry, L_disk_state,
		Path_struct *, struct mode_page *, int, char *, int);
static	void	display_lun_info(L_disk_state, Path_struct *,
		struct mode_page *, int, WWN_list *, char *);
static	void	display_fc_disk(struct path_struct *, char *, gfc_map_t *,
		L_inquiry, int);
static 	void	adm_display_err(char *, int);
static	void	temperature_messages(struct l_state_struct *, int);
static	void	ctlr_messages(struct l_state_struct *, int, int);
static	void	fan_messages(struct l_state_struct *, int, int);
static	void	ps_messages(struct l_state_struct *, int, int);
static	void	abnormal_condition_display(struct l_state_struct *);
static	void	loop_messages(struct l_state_struct *, int, int);
static	void	revision_msg(struct l_state_struct *, int);
static	void	mb_messages(struct l_state_struct *, int, int);
static	void	back_plane_messages(struct l_state_struct *, int, int);
static	void	dpm_SSC100_messages(struct l_state_struct *, int, int);
static	void	mb_messages(struct l_state_struct *, int, int);
static	void	back_plane_messages(struct l_state_struct *, int, int);
static	void	dpm_SSC100_messages(struct l_state_struct *, int, int);
static	void	trans_decode(Trans_elem_st *trans);
static	void	trans_messages(struct l_state_struct *, int);
static	void	adm_print_pathlist(char *);
static	void	display_path_info(char *, char *, WWN_list *);
static void	copy_wwn_data_to_str(char *, const uchar_t *);
static void	adm_mplist_free(struct mplist_struct *);
static int	lun_display(Path_struct *path_struct, L_inquiry inq_struct,
		int verbose);
static int	non_encl_fc_disk_display(Path_struct *path_struct,
		L_inquiry inq_struct, int verbose);
static int	get_enclStatus(char *phys_path, char *encl_name, int off_flag);
static int	get_host_controller_pwwn(char *hba_path, uchar_t *pwwn);
static int	get_lun_capacity(char *devpath,
		struct scsi_capacity_16 *cap_data);
static int	get_path_status(char *devpath, int *status);
static int	get_FC4_host_controller_pwwn(char *hba_path, uchar_t *pwwn);

/*
 * Gets the device's state from the SENA IB and
 * checks whether device is offlined, bypassed
 * or if the slot is empty and prints it to the
 * stdout.
 *
 * RETURNS:
 *	0	 O.K.
 *	non-zero otherwise
 */
int
print_devState(char *devname, char *ppath, int fr_flag, int slot,
						int verbose_flag)
{
L_state		l_state;
int		err;
int		i, elem_index = 0;
uchar_t		device_off, ib_status_code, bypass_a_en, bypass_b_en;
Bp_elem_st	bpf, bpr;


	if ((err = l_get_status(ppath, &l_state, verbose_flag)) != 0) {
		(void) print_errString(err, ppath);
		return (err);
	}

	for (i = 0; i <  (int)l_state.ib_tbl.config.enc_num_elem; i++) {
		elem_index++;
		if (l_state.ib_tbl.config.type_hdr[i].type == ELM_TYP_BP) {
			break;
		}
		elem_index += l_state.ib_tbl.config.type_hdr[i].num;
	}
	(void) bcopy((const void *)
			&(l_state.ib_tbl.p2_s.element[elem_index]),
			(void *)&bpf, sizeof (bpf));
	(void) bcopy((const void *)
			&(l_state.ib_tbl.p2_s.element[elem_index + 1]),
			(void *)&bpr, sizeof (bpr));

	if (fr_flag) {
		device_off = l_state.drv_front[slot].ib_status.dev_off;
		bypass_a_en = l_state.drv_front[slot].ib_status.bypass_a_en;
		bypass_b_en = l_state.drv_front[slot].ib_status.bypass_b_en;
		ib_status_code = l_state.drv_front[slot].ib_status.code;
	} else {
		device_off = l_state.drv_rear[slot].ib_status.dev_off;
		bypass_a_en = l_state.drv_rear[slot].ib_status.bypass_a_en;
		bypass_b_en = l_state.drv_rear[slot].ib_status.bypass_b_en;
		ib_status_code = l_state.drv_rear[slot].ib_status.code;
	}
	if (device_off) {
		(void) fprintf(stdout,
				MSGSTR(2000,
				"%s is offlined and bypassed.\n"
				" Could not get device specific"
				" information.\n\n"),
				devname);
	} else if (bypass_a_en && bypass_b_en) {
		(void) fprintf(stdout,
				MSGSTR(2001,
				"%s is bypassed (Port:AB).\n"
				" Could not get device specific"
				" information.\n\n"),
				devname);
	} else if (ib_status_code == S_NOT_INSTALLED) {
		(void) fprintf(stdout,
				MSGSTR(2002,
				"Slot %s is empty.\n\n"),
				devname);
	} else if (((bpf.code != S_NOT_INSTALLED) &&
		((bpf.byp_a_enabled || bpf.en_bypass_a) &&
		(bpf.byp_b_enabled || bpf.en_bypass_b))) ||
		((bpr.code != S_NOT_INSTALLED) &&
		((bpr.byp_a_enabled || bpr.en_bypass_a) &&
		(bpr.byp_b_enabled || bpr.en_bypass_b)))) {
		(void) fprintf(stdout,
				MSGSTR(2003,
				"Backplane(Port:AB) is bypassed.\n"
				" Could not get device specific"
				" information for"
				" %s.\n\n"), devname);
	} else {
		(void) fprintf(stderr,
				MSGSTR(33,
				" Error: converting"
				" %s to physical path.\n"
				" Invalid pathname.\n"),
				devname);
	}
	return (-1);
}

/*
 * Given an error number, this functions
 * calls the get_errString() to print a
 * corresponding error message to the stderr.
 * get_errString() always returns an error
 * message, even in case of undefined error number.
 * So, there is no need to check for a NULL pointer
 * while printing the error message to the stdout.
 *
 * RETURNS: N/A
 *
 */
void
print_errString(int errnum, char *devpath)
{

char	*errStr;

	errStr = g_get_errString(errnum);

	if (devpath == NULL) {
		(void) fprintf(stderr,
				"%s \n\n", errStr);
	} else {
		(void) fprintf(stderr,
				"%s - %s.\n\n", errStr, devpath);
	}

	/* free the allocated memory for error string */
	if (errStr != NULL)
		(void) free(errStr);
}

/*
 * adm_inquiry() Display the inquiry information for
 * a SENA enclosure(s) or disk(s).
 *
 * RETURNS:
 *	none.
 */
int
adm_inquiry(char **argv)
{
L_inquiry	inq;
L_inquiry80	inq80;
size_t		serial_len;
int		path_index = 0, retval = 0;
int		slot, f_r, err = 0, argpwwn, argnwwn;
char		inq_path[MAXNAMELEN];
char		*path_phys = NULL, *ptr;
Path_struct	*path_struct;
WWN_list	*wwn_list, *wwn_list_ptr, *list_start;
char		last_logical_path[MAXPATHLEN];

	while (argv[path_index] != NULL) {
	    if ((err = l_convert_name(argv[path_index], &path_phys,
		&path_struct, Options & PVERBOSE)) != 0) {
		(void) strcpy(inq_path, argv[path_index]);
		if (((ptr = strstr(inq_path, ",")) != NULL) &&
			((*(ptr + 1) == 'f') || (*(ptr + 1) == 'r') ||
			    (*(ptr +1) == 's'))) {
			if (err != -1) {
				(void) print_errString(err, argv[path_index]);
				path_index++;
				retval++;
				continue;
			}
			*ptr = NULL;
			slot = path_struct->slot;
			f_r = path_struct->f_flag;
			path_phys = NULL;
			if ((err = l_convert_name(inq_path, &path_phys,
				&path_struct, Options & PVERBOSE)) != 0) {
				(void) fprintf(stderr,
					MSGSTR(33,
					" Error: converting"
					" %s to physical path.\n"
					" Invalid pathname.\n"),
					argv[path_index]);
				if (err != -1) {
					(void) print_errString(err,
							argv[path_index]);
				}
				path_index++;
				retval++;
				continue;
			}
			if ((err = print_devState(argv[path_index],
					path_struct->p_physical_path,
					f_r, slot, Options & PVERBOSE)) != 0) {
				path_index++;
				retval++;
				continue;
			}
		} else {
			if (err != -1) {
				(void) print_errString(err, argv[path_index]);
			} else {
			    (void) fprintf(stderr, "\n ");
			    (void) fprintf(stderr,
				MSGSTR(112, "Error: Invalid pathname (%s)"),
				argv[path_index]);
			    (void) fprintf(stderr, "\n");
			}
		}
		path_index++;
		retval++;
		continue;
	    }

	    if (strstr(argv[path_index], "/") != NULL) {
		if (err = g_get_inquiry(path_phys, &inq)) {
		    (void) fprintf(stderr, "\n");
		    (void) print_errString(err, argv[path_index]);
		    (void) fprintf(stderr, "\n");
		    path_index++;
		    retval++;
		    continue;
		}

		serial_len = sizeof (inq80.inq_serial);
		if (err = g_get_serial_number(path_phys, inq80.inq_serial,
		    &serial_len)) {
		    (void) fprintf(stderr, "\n");
		    (void) print_errString(err, argv[path_index]);
		    (void) fprintf(stderr, "\n");
		    path_index++;
		    retval++;
		    continue;
		}
		print_inq_data(argv[path_index], path_phys, inq,
		    inq80.inq_serial, serial_len);
		path_index++;
		continue;
	    }
	    if ((err = g_get_wwn_list(&wwn_list, 0)) != 0) {
		return (err);
	    }
	    g_sort_wwn_list(&wwn_list);
	    list_start = wwn_list;
	    argpwwn = argnwwn = 0;
	    (void) strcpy(last_logical_path, path_phys);
	    for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
		wwn_list_ptr = wwn_list_ptr->wwn_next) {
		if (strcasecmp(wwn_list_ptr->port_wwn_s, path_struct->argv) ==
			0) {
			list_start = wwn_list_ptr;
			argpwwn = 1;
			break;
		} else if (strcasecmp(wwn_list_ptr->node_wwn_s,
			path_struct->argv) == 0) {
			list_start = wwn_list_ptr;
			argnwwn = 1;
			break;
		}
	    }

	    if (!(argpwwn || argnwwn)) {
		/*
		 * if the wwn list is null or the arg device not found
		 * from the wwn list, still go ahead to issue inquiry.
		 */
		if (err = g_get_inquiry(path_phys, &inq)) {
		    (void) fprintf(stderr, "\n");
		    (void) print_errString(err, argv[path_index]);
		    (void) fprintf(stderr, "\n");
		    path_index++;
		    retval++;
		    continue;
		}

		serial_len = sizeof (inq80.inq_serial);
		if (err = g_get_serial_number(path_phys, inq80.inq_serial,
		    &serial_len)) {
		    (void) fprintf(stderr, "\n");
		    (void) print_errString(err, argv[path_index]);
		    (void) fprintf(stderr, "\n");
		    path_index++;
		    retval++;
		    continue;
		}
		print_inq_data(argv[path_index], path_phys, inq,
		    inq80.inq_serial, serial_len);
		(void) g_free_wwn_list(&wwn_list);
		path_index++;
		continue;
	    }

	    for (wwn_list_ptr = list_start; wwn_list_ptr != NULL;
			wwn_list_ptr = wwn_list_ptr->wwn_next) {
		if (argpwwn) {
			if (strcasecmp(wwn_list_ptr->port_wwn_s,
				path_struct->argv) != 0) {
				continue;
			}
			(void) strcpy(path_phys,
				wwn_list_ptr->physical_path);
		} else if (argnwwn) {
			if (strcasecmp(wwn_list_ptr->node_wwn_s,
				path_struct->argv) != 0) {
				continue;
			}
			if (strstr(wwn_list_ptr->logical_path,
				last_logical_path) != NULL) {
				continue;
			}
			(void) strcpy(path_phys,
				wwn_list_ptr->physical_path);
			(void) strcpy(last_logical_path,
				wwn_list_ptr->logical_path);
		}

		if (err = g_get_inquiry(path_phys, &inq)) {
		    (void) fprintf(stderr, "\n");
		    (void) print_errString(err, argv[path_index]);
		    (void) fprintf(stderr, "\n");
		    retval++;
		    break;
		}

		serial_len = sizeof (inq80.inq_serial);
		if (err = g_get_serial_number(path_phys, inq80.inq_serial,
		    &serial_len)) {
		    (void) fprintf(stderr, "\n");
		    (void) print_errString(err, argv[path_index]);
		    (void) fprintf(stderr, "\n");
		    retval++;
		    break;
		}
		print_inq_data(argv[path_index], path_phys, inq,
		    inq80.inq_serial, serial_len);

	    }

	    (void) g_free_wwn_list(&wwn_list);
	    path_index++;
	}
	return (retval);
}

/*
 *	FORCELIP expert function
 */
int
adm_forcelip(char **argv)
{
int		slot, f_r, path_index = 0, err = 0, retval = 0;
Path_struct	*path_struct = NULL;
char		*path_phys = NULL, *ptr;
char		 err_path[MAXNAMELEN];

	while (argv[path_index] != NULL) {
		if ((err = l_convert_name(argv[path_index], &path_phys,
				&path_struct, Options & PVERBOSE)) != 0) {
			(void) strcpy(err_path, argv[path_index]);
			if (err != -1) {
				(void) print_errString(err, argv[path_index]);
				path_index++;
				retval++;
				continue;
			}
			if (((ptr = strstr(err_path, ", ")) != NULL) &&
				((*(ptr + 1) == 'f') || (*(ptr + 1) == 'r') ||
							(*(ptr +1) == 's'))) {
				*ptr = NULL;
				slot = path_struct->slot;
				f_r = path_struct->f_flag;
				path_phys = NULL;
				if ((err = l_convert_name(err_path,
						&path_phys, &path_struct,
						Options & PVERBOSE)) != 0) {
					(void) fprintf(stderr, MSGSTR(33,
						" Error: converting"
						" %s to physical path.\n"
						" Invalid pathname.\n"),
							argv[path_index]);
					if (err != -1) {
						(void) print_errString(err,
							argv[path_index]);
					}
					path_index++;
					retval++;
					continue;
				}
				if ((err = print_devState(argv[path_index],
					path_struct->p_physical_path,
					f_r, slot, Options & PVERBOSE)) != 0) {
					path_index++;
					retval++;
					continue;
				}
			} else {
				(void) fprintf(stderr, "\n ");
				(void) fprintf(stderr, MSGSTR(112,
					"Error: Invalid pathname (%s)"),
							argv[path_index]);
				(void) fprintf(stderr, "\n");
			}
			path_index++;
			retval++;
			continue;
		}
		if (err = g_force_lip(path_phys, Options & PVERBOSE)) {
			(void) print_errString(err, argv[path_index]);
			path_index++;
			retval++;
			continue;
		}
		path_index++;
		if (path_struct != NULL) {
			(void) free(path_struct);
		}
	}
	return (retval);
}


/*
 *	DISPLAY function
 *
 * RETURNS:
 *	0	O.K.
 */
int
adm_display_config(char **argv)
{
L_inquiry	inq, ses_inq;
int		i, slot, f_r, path_index = 0, err = 0, opnerr = 0;
int		retval = 0;
gfc_map_t	map;
Path_struct	*path_struct;
char		*path_phys = NULL, *ptr;
char		ses_path[MAXPATHLEN], inq_path[MAXNAMELEN];


	while (argv[path_index] != NULL) {
	    VERBPRINT(MSGSTR(2108, "  Displaying information for: %s\n"),
			argv[path_index]);
		map.dev_addr = (gfc_port_dev_info_t *)NULL;
	    if ((err = l_convert_name(argv[path_index], &path_phys,
		&path_struct, Options & PVERBOSE)) != 0) {
		if (strstr(argv[path_index], SCSI_VHCI) == NULL) {

			(void) strcpy(inq_path, argv[path_index]);
			if (((ptr = strstr(inq_path, ",")) != NULL) &&
				((*(ptr + 1) == 'f') || (*(ptr + 1) == 'r') ||
				(*(ptr +1) == 's'))) {

				if (err != -1) {
					(void) print_errString(err,
						argv[path_index]);
					path_index++;
					retval++;
					continue;
				}
				*ptr = NULL;
				slot = path_struct->slot;
				f_r = path_struct->f_flag;
				if ((err = l_convert_name(inq_path, &path_phys,
					&path_struct, Options & PVERBOSE))
					!= 0) {

					(void) fprintf(stderr,
						MSGSTR(33,
						" Error: converting"
						" %s to physical path.\n"
						" Invalid pathname.\n"),
						argv[path_index]);
					if (err != -1) {
						(void) print_errString(err,
							argv[path_index]);
					}
					path_index++;
					retval++;
					continue;
				}

				if ((err = print_devState(argv[path_index],
					path_struct->p_physical_path,
					f_r, slot, Options & PVERBOSE)) != 0) {
						path_index++;
						retval++;
						continue;
				}
			} else {
				if (err != -1) {
					(void) print_errString(err,
						argv[path_index]);
				} else {
					(void) fprintf(stderr, "\n ");
					(void) fprintf(stderr,
						MSGSTR(112,
					"Error: Invalid pathname (%s)"),
						argv[path_index]);
					(void) fprintf(stderr, "\n");
				}
			}

		} else {
			if (err != -1) {
				(void) print_errString(err,
					argv[path_index]);
			} else {
				(void) fprintf(stderr, "\n ");
				(void) fprintf(stderr,
					MSGSTR(112,
				"Error: Invalid pathname (%s)"),
					argv[path_index]);
				(void) fprintf(stderr, "\n");
			}
		}

		path_index++;
		retval++;
		continue;
	    }

	/*
	 * See what kind of device we are talking to.
	 */
	if ((opnerr = g_get_inquiry(path_phys, &inq)) != 0) {
		if (opnerr == L_OPEN_PATH_FAIL) {
			/*
			 * We check only for L_OPEN_PATH_FAIL because
			 * that is the only error code returned by
			 * g_get_inquiry() which is not got from the ioctl
			 * call itself. So, we are dependent, in a way, on the
			 * implementation of g_get_inquiry().
			 *
			 */
			(void) print_errString(errno, argv[path_index]);
			path_index++;
			retval++;
			continue;
		}
	    } else if (!g_enclDiskChk((char *)inq.inq_vid,
			(char *)inq.inq_pid)) {
		    if ((err = lun_display(path_struct,
					inq, Options & PVERBOSE)) != 0) {
			    (void) print_errString(err, path_phys);
			    exit(1);
		    }
	    } else if (strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != NULL) {
		/*
		 * Display SENA enclosure.
		 */
		(void) fprintf(stdout, "\n\t\t\t\t   ");
		print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0);

		(void) fprintf(stdout, "\n");
		if (Options & OPTION_R) {
			adm_display_err(path_phys,
			    (inq.inq_dtype & DTYPE_MASK));
		} else {
			pho_display_config(path_phys);
		}
	    } else if ((((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)) &&
			(l_get_enc_type(inq) == DAK_ENC_TYPE)) {
		/*
		 *  Display for the Daktari/DPM
		 */
		(void) fprintf(stdout, "\n\t\t");
		for (i = 0; i < sizeof (inq.inq_pid); i++) {
		    (void) fprintf(stdout, "%c", inq.inq_pid[i]);
		}
		(void) fprintf(stdout, "\n");
		if (Options & OPTION_R) {
		    adm_display_err(path_phys,
			(inq.inq_dtype & DTYPE_MASK));
		} else {
		    dpm_display_config(path_phys);
		}
		/*
		 * if device is in SENA enclosure
		 *
		 * if the slot is valid, then I know this is a SENA enclosure
		 * and can continue
		 * otherwise:
		 *	I first get the ses_path, if this doesn't fail
		 *	I retrieve the inquiry data from the ses node
		 *	    and check teh PID to make sure this is a SENA
		 */
	    } else if (((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) &&
			((path_struct->slot_valid == 1) ||
			    ((g_get_dev_map(path_phys, &map,
				(Options & PVERBOSE)) == 0) &&
			    (l_get_ses_path(path_phys, ses_path,
				&map, Options & PVERBOSE) == 0) &&
			    (g_get_inquiry(ses_path, &ses_inq) == 0) &&
			    ((strstr((char *)ses_inq.inq_pid, ENCLOSURE_PROD_ID)
				!= NULL))))) {
		if (Options & OPTION_R) {
			adm_display_err(path_phys,
			(inq.inq_dtype & DTYPE_MASK));
		} else {
			display_fc_disk(path_struct, ses_path, &map, inq,
							Options & PVERBOSE);
		}

	    } else if (strstr((char *)inq.inq_pid, "SUN_SEN") != 0) {
			if (strcmp(argv[path_index], path_phys) != 0) {
				(void) fprintf(stdout, "  ");
				(void) fprintf(stdout,
				MSGSTR(5, "Physical Path:"));
				(void) fprintf(stdout, "\n  %s\n", path_phys);
			}
			(void) fprintf(stdout, MSGSTR(2109, "DEVICE is a "));
			print_chars(inq.inq_vid, sizeof (inq.inq_vid), 1);
			(void) fprintf(stdout, " ");
			print_chars(inq.inq_pid, sizeof (inq.inq_pid), 1);
			(void) fprintf(stdout, MSGSTR(2110, " card."));
			if (inq.inq_len > 31) {
				(void) fprintf(stdout, "   ");
				(void) fprintf(stdout, MSGSTR(26, "Revision:"));
				(void) fprintf(stdout, " ");
				print_chars(inq.inq_revision,
					sizeof (inq.inq_revision), 0);
			}
			(void) fprintf(stdout, "\n");
		/* if device is not in SENA or SSA enclosures. */
	    } else if ((inq.inq_dtype & DTYPE_MASK) < 0x10) {
		switch ((inq.inq_dtype & DTYPE_MASK)) {
			case DTYPE_DIRECT:
			case DTYPE_SEQUENTIAL: /* Tape */
				if (Options & OPTION_R) {
					adm_display_err(path_phys,
					(inq.inq_dtype & DTYPE_MASK));
				} else if (non_encl_fc_disk_display(path_struct,
					inq, Options & PVERBOSE) != 0) {
					(void) fprintf(stderr,
						MSGSTR(2111,
						"Error: getting the device"
						" information.\n"));
					retval++;
				}
				break;
			/* case 0x01: same as default */
			default:
				(void) fprintf(stdout, "  ");
				(void) fprintf(stdout, MSGSTR(35,
						"Device Type:"));
				(void) fprintf(stdout, "%s\n",
					dtype[inq.inq_dtype & DTYPE_MASK]);
				break;
		}
	    } else if ((inq.inq_dtype & DTYPE_MASK) < 0x1f) {
			(void) fprintf(stdout,
				MSGSTR(2112, "  Device type: Reserved"));
			(void) fprintf(stdout, "\n");
	    } else {
			(void) fprintf(stdout,
				MSGSTR(2113, "  Device type: Unknown device"));
			(void) fprintf(stdout, "\n");
	    }
	    path_index++;
	    if (map.dev_addr != NULL) {
		free((void *)map.dev_addr);
	    }
	    (void) free(path_struct);
	}
	return (retval);
}


/*
 * Powers off a list of SENA enclosure(s)
 * and disk(s) which is provided by the user.
 *
 * RETURNS:
 *	none.
 */
int
adm_power_off(char **argv, int off_flag)
{
int		path_index = 0, err = 0, retval = 0;
L_inquiry	inq;
char		*path_phys = NULL;
Path_struct	*path_struct;

	while (argv[path_index] != NULL) {
		if ((err = l_convert_name(argv[path_index], &path_phys,
			&path_struct, Options & PVERBOSE)) != 0) {
			/*
			 * In case we did not find the device
			 * in the /devices directory.
			 *
			 * Only valid for pathnames like box,f1
			 */
			if (path_struct->ib_path_flag) {
				path_phys = path_struct->p_physical_path;
			} else {
				(void) fprintf(stderr,
					MSGSTR(33,
				" Error: converting"
				" %s to physical path.\n"
				" Invalid pathname.\n"),
					argv[path_index]);
				if (err != -1) {
					(void) print_errString(err,
							argv[path_index]);
				}
				path_index++;
				retval++;
				continue;
			}
		}
		if (path_struct->ib_path_flag) {
			/*
			 * We are addressing a disk using a path
			 * format type box,f1.
			 */
			if (err = l_dev_pwr_up_down(path_phys,
			    path_struct, off_flag, Options & PVERBOSE,
			    Options & OPTION_CAPF)) {
				/*
				 * Is it Bypassed... try to give more
				 * informtaion.
				 */
				print_devState(argv[path_index],
					path_struct->p_physical_path,
					path_struct->f_flag, path_struct->slot,
					Options & PVERBOSE);
				retval++;
			}
			path_index++;
			continue;
		}

		if (err = g_get_inquiry(path_phys, &inq)) {
			(void) print_errString(err, argv[path_index]);
			path_index++;
			retval++;
			continue;
		}
		if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != 0) ||
			(strncmp((char *)inq.inq_vid, "SUN     ",
			sizeof (inq.inq_vid)) &&
			((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI))) {

			if (get_enclStatus(path_phys, argv[path_index],
						off_flag) != 0) {
				path_index++;
				retval++;
				continue;
			}
			/* power off SENA enclosure. */
			if (err = l_pho_pwr_up_down(argv[path_index], path_phys,
			    off_flag, Options & PVERBOSE,
			    Options & OPTION_CAPF)) {
				(void) print_errString(err, argv[path_index]);
				retval++;
			}
		} else if ((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) {
			if (err = l_dev_pwr_up_down(path_phys,
			    path_struct, off_flag, Options & PVERBOSE,
			    Options & OPTION_CAPF)) {
				(void) print_errString(err, argv[path_index]);
				retval++;
			}
		} else {
			/*
			 * SSA section:
			 */
			(void) print_errString(L_INVALID_PATH,
						argv[path_index]);
		}
		path_index++;
	}
	return (retval);
}



void
adm_bypass_enable(char **argv, int bypass_flag)
{
int		path_index = 0, err = 0;
L_inquiry	inq;
char		*path_phys = NULL;
Path_struct	*path_struct;

	if ((err = l_convert_name(argv[path_index], &path_phys,
		&path_struct, Options & PVERBOSE)) != 0) {
		/*
		 * In case we did not find the device
		 * in the /devices directory.
		 *
		 * Only valid for pathnames like box,f1
		 */
		if (path_struct->ib_path_flag) {
			path_phys = path_struct->p_physical_path;
		} else {
			(void) fprintf(stderr,
					MSGSTR(33,
						" Error: converting"
						" %s to physical path.\n"
						" Invalid pathname.\n"),
					argv[path_index]);
			if (err != -1) {
				(void) print_errString(err, argv[path_index]);
			}
			exit(-1);
		}
	}
	if (path_struct->ib_path_flag) {
		if (Options & OPTION_F) {
			E_USEAGE();
			exit(-1);
		}
		/*
		 * We are addressing a disk using a path
		 * format type box,f1 and no disk
		 * path was found.
		 * So set the Force flag so no reserved/busy
		 * check is performed.
		 */
		if (err = l_dev_bypass_enable(path_struct,
			bypass_flag, OPTION_CAPF,
			Options & OPTION_A,
			Options & PVERBOSE)) {
			(void) print_errString(err, argv[path_index]);
			exit(-1);
		}
		return;
	}

	if (err = g_get_inquiry(path_phys, &inq)) {
		(void) print_errString(err, argv[path_index]);
		exit(-1);
	}
	if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != 0) ||
		(strncmp((char *)inq.inq_vid, "SUN     ",
		sizeof (inq.inq_vid)) &&
		((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI))) {
		if ((!((Options & OPTION_F) ||
			(Options & OPTION_R))) ||
			((Options & OPTION_R) &&
			(Options & OPTION_F))) {
			E_USEAGE();
			exit(-1);
		}
		if (err = l_bp_bypass_enable(path_phys, bypass_flag,
			Options & OPTION_A,
			Options & OPTION_F,
			Options & OPTION_CAPF,
			Options & PVERBOSE)) {
		    (void) print_errString(err, argv[path_index]);
		    exit(-1);
		}
	} else if ((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) {
		if (Options & OPTION_F) {
			E_USEAGE();
			exit(-1);
		}
		if (err = l_dev_bypass_enable(path_struct,
			bypass_flag, Options & OPTION_CAPF,
			Options & OPTION_A,
			Options & PVERBOSE)) {
			(void) print_errString(err, argv[path_index]);
			exit(-1);
		}
	}
}

/*
 * adm_download() Download subsystem microcode.
 * Path must point to a LUX IB.
 *
 * RETURNS:
 *	None.
 */
void
adm_download(char **argv, char *file_name)
{
int		path_index = 0, err = 0;
char		*path_phys = NULL;
L_inquiry	inq;
Path_struct	*path_struct;

	while (argv[path_index] != NULL) {
		/*
		 * See what kind of device we are talking to.
		 */
		if ((err = l_convert_name(argv[path_index], &path_phys,
			&path_struct, Options & PVERBOSE)) != 0) {
			(void) fprintf(stderr,
					MSGSTR(33,
						" Error: converting"
						" %s to physical path.\n"
						" Invalid pathname.\n"),
					argv[path_index]);
			if (err != -1) {
				(void) print_errString(err, argv[path_index]);
			}
			exit(-1);
		}
		if (err = g_get_inquiry(path_phys, &inq)) {
			(void) print_errString(err, argv[path_index]);
			exit(-1);
		}
		if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != 0) ||
			(strncmp((char *)inq.inq_vid, "SUN     ",
			sizeof (inq.inq_vid)) &&
			((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI))) {
			if (err = l_download(path_phys,
				file_name, (Options & SAVE),
				(Options & PVERBOSE))) {
				(void) print_errString(err,
					(err == L_OPEN_PATH_FAIL) ?
					argv[path_index]: file_name);
				exit(-1);
			}
		} else {
			(void) fprintf(stderr,
				MSGSTR(112, "Error: Invalid pathname (%s)"),
				argv[path_index]);
		}
		path_index++;
	}
}

/*
 * display_link_status() Reads and displays the link status.
 *
 * RETURNS:
 *	none.
 */
void
display_link_status(char **argv)
{
AL_rls		*rls = NULL, *n;
int		path_index = 0, err = 0;
char		*path_phys = NULL;
Path_struct	*path_struct;


	while (argv[path_index] != NULL) {
		if ((err = l_convert_name(argv[path_index], &path_phys,
			&path_struct, Options & PVERBOSE)) != 0) {
			(void) fprintf(stderr,
					MSGSTR(33,
						" Error: converting"
						" %s to physical path.\n"
						" Invalid pathname.\n"),
					argv[path_index]);
			if (err != -1) {
				(void) print_errString(err, argv[path_index]);
			}
			exit(-1);
		}
		if (err = g_rdls(path_phys, &rls, Options & PVERBOSE)) {
		    (void) print_errString(err, argv[path_index]);
		    exit(-1);
		}
		n = rls;
		if (n != NULL) {
			(void) fprintf(stdout,
			MSGSTR(2007, "\nLink Error Status "
				"information for loop:%s\n"),
				n->driver_path);
			(void) fprintf(stdout, MSGSTR(2008, "al_pa   lnk fail "
			"   sync loss   signal loss   sequence err"
			"   invalid word   CRC\n"));
		}
		while (n) {
			if ((n->payload.rls_linkfail == 0xffffffff) &&
			    (n->payload.rls_syncfail == 0xffffffff) &&
			    (n->payload.rls_sigfail == 0xffffffff) &&
			    (n->payload.rls_primitiverr == 0xffffffff) &&
			    (n->payload.rls_invalidword == 0xffffffff) &&
			    (n->payload.rls_invalidcrc == 0xffffffff)) {
				(void) fprintf(stdout,
					"%x\t%-12d%-12d%-14d%-15d%-15d%-12d\n",
					n->al_ha,
					n->payload.rls_linkfail,
					n->payload.rls_syncfail,
					n->payload.rls_sigfail,
					n->payload.rls_primitiverr,
					n->payload.rls_invalidword,
					n->payload.rls_invalidcrc);
			} else {
				(void) fprintf(stdout,
					"%x\t%-12u%-12u%-14u%-15u%-15u%-12u\n",
					n->al_ha,
					n->payload.rls_linkfail,
					n->payload.rls_syncfail,
					n->payload.rls_sigfail,
					n->payload.rls_primitiverr,
					n->payload.rls_invalidword,
					n->payload.rls_invalidcrc);
			}
			n = n->next;
		}

		path_index++;
	}
	(void) fprintf(stdout,
		MSGSTR(2009, "NOTE: These LESB counts are not"
		" cleared by a reset, only power cycles.\n"
		"These counts must be compared"
		" to previously read counts.\n"));
}


/*
 * ib_present_chk() Check to see if IB 0 or 1 is present in the box.
 *
 * RETURN:
 *	1 if ib present
 *	0 otherwise
 */
int
ib_present_chk(struct l_state_struct *l_state, int which_one)
{
Ctlr_elem_st	ctlr;
int	i;
int	elem_index = 0;
int	result = 1;

	for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) {
	    elem_index++;		/* skip global */
	    if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_IB) {
		(void) bcopy((const void *)
			&l_state->ib_tbl.p2_s.element[elem_index + which_one],
			(void *)&ctlr, sizeof (ctlr));
		if (ctlr.code == S_NOT_INSTALLED) {
			result = 0;
		}
		break;
	    }
	    elem_index += l_state->ib_tbl.config.type_hdr[i].num;
	}
	return (result);
}

/*
 * print_individual_state() Print individual disk status.
 *
 * RETURNS:
 *	none.
 */
void
print_individual_state(int status, int port)
{
	if (status & L_OPEN_FAIL) {
		(void) fprintf(stdout, " (");
		(void) fprintf(stdout,
		MSGSTR(28, "Open Failed"));
		(void) fprintf(stdout, ")  ");
	} else if (status & L_NOT_READY) {
		(void) fprintf(stdout, " (");
		(void) fprintf(stdout,
			MSGSTR(20, "Not Ready"));
		(void) fprintf(stdout, ")    ");
	} else if (status & L_NOT_READABLE) {
		(void) fprintf(stdout, "(");
		(void) fprintf(stdout,
		MSGSTR(88, "Not Readable"));
		(void) fprintf(stdout, ")  ");
	} else if (status & L_SPUN_DWN_D) {
		(void) fprintf(stdout, " (");
		(void) fprintf(stdout,
		MSGSTR(68, "Spun Down"));
		(void) fprintf(stdout, ")    ");
	} else if (status & L_SCSI_ERR) {
		(void) fprintf(stdout, " (");
		(void) fprintf(stdout,
		MSGSTR(70, "SCSI Error"));
		(void) fprintf(stdout, ")   ");
	} else if (status & L_RESERVED) {
		if (port == PORT_A) {
			(void) fprintf(stdout,
			MSGSTR(2010,
				" (Rsrv cnflt:A) "));
		} else if (port == PORT_B) {
			(void) fprintf(stdout,
			MSGSTR(2011,
				" (Rsrv cnflt:B) "));
		} else {
			(void) fprintf(stdout,
			MSGSTR(2012,
				" (Reserve cnflt)"));
		}
	} else if (status & L_NO_LABEL) {
		(void) fprintf(stdout, "(");
		(void) fprintf(stdout,
			MSGSTR(92, "No UNIX Label"));
		(void) fprintf(stdout, ") ");
	}
}


/*
 * display_disk_msg() Displays status for
 * an individual SENA device.
 *
 * RETURNS:
 *	none.
 */
void
display_disk_msg(struct l_disk_state_struct *dsk_ptr,
	struct l_state_struct *l_state, Bp_elem_st *bp, int front_flag)
{
int	loop_flag = 0;
int	a_and_b = 0;
int	state_a = 0, state_b = 0;

	if (dsk_ptr->ib_status.code == S_NOT_INSTALLED) {
		(void) fprintf(stdout,
			MSGSTR(30, "Not Installed"));
			(void) fprintf(stdout, " ");
		if (dsk_ptr->ib_status.fault ||
			dsk_ptr->ib_status.fault_req) {
			(void) fprintf(stdout, "(");
			(void) fprintf(stdout,
				MSGSTR(2013, "Faulted"));
			(void) fprintf(stdout,
						")           ");
		} else if (dsk_ptr->ib_status.ident ||
			dsk_ptr->ib_status.rdy_to_ins ||
			dsk_ptr->ib_status.rmv) {
			(void) fprintf(stdout,
				MSGSTR(2014,
						"(LED Blinking)      "));
		} else {
			(void) fprintf(stdout,
						"                    ");
		}
	} else if (dsk_ptr->ib_status.dev_off) {
		(void) fprintf(stdout, MSGSTR(2015, "Off"));
		if (dsk_ptr->ib_status.fault || dsk_ptr->ib_status.fault_req) {
			(void) fprintf(stdout, "(");
			(void) fprintf(stdout,
				MSGSTR(2016, "Faulted"));
			(void) fprintf(stdout,
					")                      ");
		} else if (dsk_ptr->ib_status.bypass_a_en &&
			dsk_ptr->ib_status.bypass_b_en) {
			(void) fprintf(stdout,
				MSGSTR(2017,
					"(Bypassed:AB)"));
			(void) fprintf(stdout,
					"                  ");
		} else if (dsk_ptr->ib_status.bypass_a_en) {
			(void) fprintf(stdout,
				MSGSTR(2018,
					"(Bypassed: A)"));
			(void) fprintf(stdout,
					"                  ");
		} else if (dsk_ptr->ib_status.bypass_b_en) {
			(void) fprintf(stdout,
				MSGSTR(2019,
					"(Bypassed: B)"));
			(void) fprintf(stdout,
					"                  ");
		} else {
			(void) fprintf(stdout,
					"                              ");
		}
	} else {
		(void) fprintf(stdout, MSGSTR(2020, "On"));

		if (dsk_ptr->ib_status.fault || dsk_ptr->ib_status.fault_req) {
			(void) fprintf(stdout, " (");
			(void) fprintf(stdout,
				MSGSTR(2021, "Faulted"));
			(void) fprintf(stdout, ")      ");
		} else if (dsk_ptr->ib_status.bypass_a_en &&
			dsk_ptr->ib_status.bypass_b_en) {
			(void) fprintf(stdout, " ");
			(void) fprintf(stdout,
				MSGSTR(2022, "(Bypassed:AB)"));
			(void) fprintf(stdout, "  ");
		} else if (ib_present_chk(l_state, 0) &&
			dsk_ptr->ib_status.bypass_a_en) {
			/*
			 * Before printing that the port is bypassed
			 * verify that there is an IB for this port.
			 * If not then don't print.
			 */
			(void) fprintf(stdout, " ");
			(void) fprintf(stdout,
				MSGSTR(2023, "(Bypassed: A)"));
			(void) fprintf(stdout, "  ");
		} else if (ib_present_chk(l_state, 1) &&
			dsk_ptr->ib_status.bypass_b_en) {
			(void) fprintf(stdout, " ");
			(void) fprintf(stdout,
				MSGSTR(2024, "(Bypassed: B)"));
			(void) fprintf(stdout, "  ");
		} else if ((bp->code != S_NOT_INSTALLED) &&
				((bp->byp_a_enabled || bp->en_bypass_a) &&
				!(bp->byp_b_enabled || bp->en_bypass_b))) {
			(void) fprintf(stdout,
				MSGSTR(2025,
					" (Bypassed BP: A)"));
		} else if ((bp->code != S_NOT_INSTALLED) &&
				((bp->byp_b_enabled || bp->en_bypass_b) &&
				!(bp->byp_a_enabled || bp->en_bypass_a))) {
			(void) fprintf(stdout,
				MSGSTR(2026,
					"(Bypassed BP: B)"));
		} else if ((bp->code != S_NOT_INSTALLED) &&
				((bp->byp_a_enabled || bp->en_bypass_a) &&
				(bp->byp_b_enabled || bp->en_bypass_b))) {
			(void) fprintf(stdout,
				MSGSTR(2027,
					"(Bypassed BP:AB)"));
		} else {
			state_a = dsk_ptr->g_disk_state.d_state_flags[PORT_A];
			state_b = dsk_ptr->g_disk_state.d_state_flags[PORT_B];
			a_and_b = state_a & state_b;

			if (dsk_ptr->l_state_flag & L_NO_LOOP) {
				(void) fprintf(stdout,
				MSGSTR(2028,
					" (Loop not accessible)"));
				loop_flag = 1;
			} else if (dsk_ptr->l_state_flag & L_INVALID_WWN) {
				(void) fprintf(stdout,
				MSGSTR(2029,
					" (Invalid WWN)  "));
			} else if (dsk_ptr->l_state_flag & L_INVALID_MAP) {
				(void) fprintf(stdout,
				MSGSTR(2030,
					" (Login failed) "));
			} else if (dsk_ptr->l_state_flag & L_NO_PATH_FOUND) {
				(void) fprintf(stdout,
				MSGSTR(2031,
					" (No path found)"));
			} else if (a_and_b) {
				print_individual_state(a_and_b, PORT_A_B);
			} else if (state_a && (!state_b)) {
				print_individual_state(state_a, PORT_A);
			} else if ((!state_a) && state_b) {
				print_individual_state(state_b, PORT_B);
			} else if (state_a || state_b) {
				/* NOTE: Double state - should do 2 lines. */
				print_individual_state(state_a | state_b,
								PORT_A_B);
			} else {
				(void) fprintf(stdout, " (");
				(void) fprintf(stdout,
					MSGSTR(29, "O.K."));
				(void) fprintf(stdout,
					")         ");
			}
		}
		if (loop_flag) {
			(void) fprintf(stdout, "          ");
		} else if (strlen(dsk_ptr->g_disk_state.node_wwn_s)) {
			(void) fprintf(stdout, "%s",
			dsk_ptr->g_disk_state.node_wwn_s);
		} else {
			(void) fprintf(stdout, "                ");
		}
	}
	if (front_flag) {
		(void) fprintf(stdout, "    ");
	}
}



/*
 * pho_display_config() Displays device status
 * information for a SENA enclosure.
 *
 * RETURNS:
 *	none.
 */
void
pho_display_config(char *path_phys)
{
L_state		l_state;
Bp_elem_st	bpf, bpr;
int		i, j, elem_index = 0, err = 0;


	/* Get global status */
	if (err = l_get_status(path_phys, &l_state,
			(Options & PVERBOSE))) {
	    (void) print_errString(err, path_phys);
	    exit(-1);
	}

	/*
	 * Look for abnormal status.
	 */
	if (l_state.ib_tbl.p2_s.ui.ab_cond) {
		abnormal_condition_display(&l_state);
	}

	(void) fprintf(stdout,
		MSGSTR(2032, "                                 DISK STATUS \n"
		"SLOT   FRONT DISKS       (Node WWN)         "
		" REAR DISKS        (Node WWN)\n"));
	/*
	 * Print the status for each disk
	 */
	for (j = 0; j <  (int)l_state.ib_tbl.config.enc_num_elem; j++) {
		elem_index++;
		if (l_state.ib_tbl.config.type_hdr[j].type == ELM_TYP_BP)
			break;
		elem_index += l_state.ib_tbl.config.type_hdr[j].num;
	}
	(void) bcopy((const void *)
		&(l_state.ib_tbl.p2_s.element[elem_index]),
		(void *)&bpf, sizeof (bpf));
	(void) bcopy((const void *)
		&(l_state.ib_tbl.p2_s.element[elem_index + 1]),
		(void *)&bpr, sizeof (bpr));

	for (i = 0; i < (int)l_state.total_num_drv/2; i++) {
		(void) fprintf(stdout, "%-2d     ", i);
		display_disk_msg(&l_state.drv_front[i], &l_state, &bpf, 1);
		display_disk_msg(&l_state.drv_rear[i], &l_state, &bpr, 0);
		(void) fprintf(stdout, "\n");
	}



	/*
	 * Display the subsystem status.
	 */
	(void) fprintf(stdout,
		MSGSTR(2242,
	"                                SUBSYSTEM STATUS\nFW Revision:"));
	print_chars(l_state.ib_tbl.config.prod_revision,
		sizeof (l_state.ib_tbl.config.prod_revision), 1);
	(void) fprintf(stdout, MSGSTR(2034, "   Box ID:%d"),
		l_state.ib_tbl.box_id);
	(void) fprintf(stdout, "   ");
	(void) fprintf(stdout, MSGSTR(90, "Node WWN:"));
	for (i = 0; i < 8; i++) {
		(void) fprintf(stdout, "%1.2x",
		l_state.ib_tbl.config.enc_node_wwn[i]);
	}
	/* Make sure NULL terminated  although it is supposed to be */
	if (strlen((const char *)l_state.ib_tbl.enclosure_name) <=
		sizeof (l_state.ib_tbl.enclosure_name)) {
		(void) fprintf(stdout, MSGSTR(2035, "   Enclosure Name:%s\n"),
			l_state.ib_tbl.enclosure_name);
	}

	/*
	 *
	 */
	elem_index = 0;
	/* Get and print CONTROLLER messages */
	for (i = 0; i < (int)l_state.ib_tbl.config.enc_num_elem; i++) {
	    elem_index++;		/* skip global */
	    switch (l_state.ib_tbl.config.type_hdr[i].type) {
		case ELM_TYP_PS:
			ps_messages(&l_state, i, elem_index);
			break;
		case ELM_TYP_FT:
			fan_messages(&l_state, i, elem_index);
			break;
		case ELM_TYP_BP:
			back_plane_messages(&l_state, i, elem_index);
			break;
		case ELM_TYP_IB:
			ctlr_messages(&l_state, i, elem_index);
			break;
		case ELM_TYP_LN:
			/*
			 * NOTE: I just use the Photon's message
			 * string here and don't look at the
			 * language code. The string includes
			 * the language name.
			 */
			if (l_state.ib_tbl.config.type_hdr[i].text_len != 0) {
				(void) fprintf(stdout, "%s\t",
				l_state.ib_tbl.config.text[i]);
			}
			break;
		case ELM_TYP_LO:	/* Loop configuration */
			loop_messages(&l_state, i, elem_index);
			break;
		case ELM_TYP_MB:	/* Loop configuration */
			mb_messages(&l_state, i, elem_index);
			break;

	    }
		/*
		 * Calculate the index to each element.
		 */
		elem_index += l_state.ib_tbl.config.type_hdr[i].num;
	}
	(void) fprintf(stdout, "\n");
}




/*
 * dpm_display_config() Displays device status
 * information for a DAKTARI enclosure.
 *
 * RETURNS:
 *	none.
 */
void
dpm_display_config(char *path_phys)
{
L_state		l_state;
Bp_elem_st	bpf, bpr;
int		i, j, elem_index = 0, err = 0, count;


	/* Get global status */
	if (err = l_get_status(path_phys, &l_state,
			(Options & PVERBOSE))) {
	    (void) print_errString(err, path_phys);
	    exit(-1);
	}

	/*
	 * Look for abnormal status.
	 */
	if (l_state.ib_tbl.p2_s.ui.ab_cond) {
		abnormal_condition_display(&l_state);
	}

	(void) fprintf(stdout,
		MSGSTR(2247, "                 DISK STATUS \n"
		"SLOT   DISKS             (Node WWN)         \n"));
	/*
	 * Print the status for each disk
	 */
	for (j = 0; j <  (int)l_state.ib_tbl.config.enc_num_elem; j++) {
		elem_index++;
		if (l_state.ib_tbl.config.type_hdr[j].type == ELM_TYP_BP)
			break;
		elem_index += l_state.ib_tbl.config.type_hdr[j].num;
	}
	(void) bcopy((const void *)
		&(l_state.ib_tbl.p2_s.element[elem_index]),
		(void *)&bpf, sizeof (bpf));
	(void) bcopy((const void *)
		&(l_state.ib_tbl.p2_s.element[elem_index + 1]),
		(void *)&bpr, sizeof (bpr));

	for (i = 0, count = 0;
			i < (int)l_state.total_num_drv/2;
			i++, count++) {
		(void) fprintf(stdout, "%-2d     ", count);
		display_disk_msg(&l_state.drv_front[i], &l_state, &bpf, 1);
		(void) fprintf(stdout, "\n");
	}
	for (i = 0; i < (int)l_state.total_num_drv/2; i++, count++) {
		(void) fprintf(stdout, "%-2d     ", count);
		display_disk_msg(&l_state.drv_rear[i], &l_state, &bpf, 1);
		(void) fprintf(stdout, "\n");
	}


	/*
	 * Display the subsystem status.
	 */
	(void) fprintf(stdout,
		MSGSTR(2033,
	"\t\tSUBSYSTEM STATUS\nFW Revision:"));
	for (i = 0; i < sizeof (l_state.ib_tbl.config.prod_revision); i++) {
		(void) fprintf(stdout, "%c",
			l_state.ib_tbl.config.prod_revision[i]);
	}
	(void) fprintf(stdout, MSGSTR(2034, "   Box ID:%d"),
		l_state.ib_tbl.box_id);
	(void) fprintf(stdout, "\n  ");

	(void) fprintf(stdout, MSGSTR(90, "Node WWN:"));

	for (i = 0; i < 8; i++) {
		(void) fprintf(stdout, "%1.2x",
		l_state.ib_tbl.config.enc_node_wwn[i]);
	}
	/* Make sure NULL terminated  although it is supposed to be */
	if (strlen((const char *)l_state.ib_tbl.enclosure_name) <=
		sizeof (l_state.ib_tbl.enclosure_name)) {
		(void) fprintf(stdout, MSGSTR(2035, "   Enclosure Name:%s\n"),
			l_state.ib_tbl.enclosure_name);
	}

	/*
	 *
	 */
	elem_index = 0;
	/* Get and print CONTROLLER messages */
	for (i = 0; i < (int)l_state.ib_tbl.config.enc_num_elem; i++) {
	    elem_index++;		/* skip global */
	    switch (l_state.ib_tbl.config.type_hdr[i].type) {
		case ELM_TYP_PS:
			ps_messages(&l_state, i, elem_index);
			break;
		case ELM_TYP_FT:
			fan_messages(&l_state, i, elem_index);
			break;
		case ELM_TYP_BP:
			dpm_SSC100_messages(&l_state, i, elem_index);
			break;
		case ELM_TYP_IB:
			ctlr_messages(&l_state, i, elem_index);
			break;
		case ELM_TYP_LN:
			/*
			 * NOTE: I just use the Photon's message
			 * string here and don't look at the
			 * language code. The string includes
			 * the language name.
			 */
			if (l_state.ib_tbl.config.type_hdr[i].text_len != 0) {
				(void) fprintf(stdout, "%s\t",
				l_state.ib_tbl.config.text[i]);
			}
			break;
		case ELM_TYP_LO:	/* Loop configuration */
			loop_messages(&l_state, i, elem_index);
			break;
		case ELM_TYP_MB:	/* Loop configuration */
			mb_messages(&l_state, i, elem_index);
			break;
		case ELM_TYP_FL:
			trans_messages(&l_state, 1);
			break;

	    }
		/*
		 * Calculate the index to each element.
		 */
		elem_index += l_state.ib_tbl.config.type_hdr[i].num;
	}
	(void) fprintf(stdout, "\n");
}






/*
 * Change the FPM (Front Panel Module) password of the
 * subsystem associated with the IB addressed by the
 * enclosure or pathname to name.
 *
 */
void
intfix(void)
{
	if (termio_fd) {
		termios.c_lflag |= ECHO;
		ioctl(termio_fd, TCSETS, &termios);
	}
	exit(SIGINT);
}


/*
 * up_password() Changes the password for SENA enclosure.
 *
 * RETURNS:
 *	none.
 */
void
up_password(char **argv)
{
int		path_index = 0, err = 0;
char		password[1024];
char		input[1024];
int		i, j, matched, equal;
L_inquiry	inq;
void		(*sig)();
char		*path_phys = NULL;
Path_struct	*path_struct;


	if ((termio_fd = open("/dev/tty", O_RDONLY)) == -1) {
		(void) fprintf(stderr,
		MSGSTR(2036, "Error: tty open failed.\n"));
		exit(-1);
	}
	ioctl(termio_fd, TCGETS, &termios);
	sig = sigset(SIGINT, (void (*)())intfix);
	/*
	 * Make sure path valid and is to a PHO
	 * before bothering operator.
	 */
	if ((err = l_convert_name(argv[path_index], &path_phys,
		&path_struct, Options & PVERBOSE)) != 0) {
		(void) fprintf(stderr,
			MSGSTR(33,
				" Error: converting"
				" %s to physical path.\n"
				" Invalid pathname.\n"),
				argv[path_index]);
		if (err != -1) {
			(void) print_errString(err, argv[path_index]);
		}
		exit(-1);
	}
	if (err = g_get_inquiry(path_phys, &inq)) {
		(void) print_errString(err, argv[path_index]);
		exit(-1);
	}
	if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
			(!(strncmp((char *)inq.inq_vid, "SUN     ",
			sizeof (inq.inq_vid)) &&
			((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
		/*
		 * Again this is like the ssaadm code in that the name
		 * is still not defined before this code must be released.
		 */
		(void) fprintf(stderr,
		MSGSTR(2037, "Error: Enclosure is not a %s\n"),
			ENCLOSURE_PROD_ID);
		exit(-1);
	}
	(void) fprintf(stdout,
			MSGSTR(2038,
			"Changing FPM password for subsystem %s\n"),
			argv[path_index]);

	equal = 0;
	while (!equal) {
		memset(input, 0, sizeof (input));
		memset(password, 0, sizeof (password));
		(void) fprintf(stdout,
		MSGSTR(2039, "New password: "));

		termios.c_lflag &= ~ECHO;
		ioctl(termio_fd, TCSETS, &termios);

		(void) gets(input);
		(void) fprintf(stdout,
		MSGSTR(2040, "\nRe-enter new password: "));
		(void) gets(password);
		termios.c_lflag |= ECHO;
		ioctl(termio_fd, TCSETS, &termios);
		for (i = 0; input[i]; i++) {
			if (!isdigit(input[i])) {
				(void) fprintf(stderr,
			MSGSTR(2041, "\nError: Invalid password."
			" The password"
			" must be 4 decimal-digit characters.\n"));
				exit(-1);
			}
		}
		if (i && (i != 4)) {
			(void) fprintf(stderr,
			MSGSTR(2042, "\nError: Invalid password."
			" The password"
			" must be 4 decimal-digit characters.\n"));
			exit(-1);
		}
		for (j = 0; password[j]; j++) {
			if (!isdigit(password[j])) {
				(void) fprintf(stderr,
			MSGSTR(2043, "\nError: Invalid password."
			" The password"
			" must be 4 decimal-digit characters.\n"));
				exit(-1);
			}
		}
		if (i != j) {
			matched = -1;
		} else for (i = matched = 0; password[i]; i++) {
			if (password[i] == input[i]) {
				matched++;
			}
		}
		if ((matched != -1) && (matched == i)) {
			equal = 1;
		} else {
			(void) fprintf(stdout,
			MSGSTR(2044, "\npassword: They don't match;"
			" try again.\n"));
		}
	}
	(void) fprintf(stdout, "\n");
	sscanf(input, "%s", password);
	(void) signal(SIGINT, sig);	/* restore signal handler */

	/*  Send new password to IB */
	if (l_new_password(path_phys, input)) {
		(void) print_errString(err, path_phys);
		exit(-1);
	}
}

/*
 * Call g_failover to process failover command
 */
void
adm_failover(char **argv)
{
int		path_index = 0, err = 0;
char		pathclass[20];
char		*path_phys = NULL;

	(void) memset(pathclass, 0, sizeof (pathclass));
	(void) strcpy(pathclass, argv[path_index++]);
	if ((strcmp(pathclass, "primary") != 0) &&
		(strcmp(pathclass, "secondary") != 0)) {
			(void) fprintf(stderr,
			MSGSTR(2300, "Incorrect pathclass\n"));
			exit(-1);
	}

	while (argv[path_index] != NULL) {
		path_phys = g_get_physical_name(argv[path_index++]);
		if ((path_phys == NULL) ||
			(strstr(path_phys, SCSI_VHCI) == NULL)) {
				(void) fprintf(stderr,
				MSGSTR(2301, "Incorrect pathname\n"));
				exit(-1);
		}

		if (err = g_failover(path_phys, pathclass)) {
			(void) print_errString(err, NULL);
			exit(-1);
		}
	}
}



/*
 * up_encl_name() Update the enclosures logical name.
 *
 * RETURNS:
 *	none.
 */
void
up_encl_name(char **argv, int argc)
{
int		i, rval, al_pa, path_index = 0, err = 0;
L_inquiry	inq;
Box_list	*b_list = NULL;
uchar_t		node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
char		wwn1[(WWN_SIZE*2)+1], name[1024], *path_phys = NULL;
Path_struct	*path_struct;

	(void) memset(name, 0, sizeof (name));
	(void) memset(&inq, 0, sizeof (inq));
	(void) sscanf(argv[path_index++], "%s", name);
	for (i = 0; name[i]; i++) {
		if ((!isalnum(name[i]) &&
			((name[i] != '#') &&
			(name[i] != '-') &&
			(name[i] != '_') &&
			(name[i] != '.'))) || i >= 16) {
			(void) fprintf(stderr,
			MSGSTR(2045, "Error: Invalid enclosure name.\n"));
			(void) fprintf(stderr, MSGSTR(2046,
			"Usage: %s [-v] subcommand {a name consisting of"
			" 1-16 alphanumeric characters}"
			" {enclosure... | pathname...}\n"), whoami);
			exit(-1);
		}
	}

	if (((Options & PVERBOSE) && (argc != 5)) ||
		(!(Options & PVERBOSE) && (argc != 4))) {
		(void) fprintf(stderr,
		MSGSTR(114, "Error: Incorrect number of arguments.\n"));
		(void) fprintf(stderr,  MSGSTR(2047,
		"Usage: %s [-v] subcommand {a name consisting of"
		" 1-16 alphanumeric characters}"
		" {enclosure... | pathname...}\n"), whoami);
		exit(-1);
	}

	if ((err = l_convert_name(argv[path_index], &path_phys,
		&path_struct, Options & PVERBOSE)) != 0) {
		(void) fprintf(stderr,
				MSGSTR(33,
				" Error: converting"
				" %s to physical path.\n"
				" Invalid pathname.\n"),
				argv[path_index]);
		if (err != -1) {
			(void) print_errString(err, argv[path_index]);
		}
		exit(-1);
	}
	/*
	 * Make sure we are talking to an IB.
	 */
	if (err = g_get_inquiry(path_phys, &inq)) {
		(void) print_errString(err, argv[path_index]);
		exit(-1);
	}
	if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
			(!(strncmp((char *)inq.inq_vid, "SUN     ",
			sizeof (inq.inq_vid)) &&
			((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
		/*
		 * Again this is like the ssaadm code in that the name
		 * is still not defined before this code must be released.
		 */
		(void) fprintf(stderr,
		MSGSTR(2048, "Error: Pathname does not point to a %s"
		" enclosure\n"), ENCLOSURE_PROD_NAME);
		exit(-1);
	}

	if (err = g_get_wwn(path_phys, port_wwn, node_wwn, &al_pa,
		Options & PVERBOSE)) {
		(void) print_errString(err, argv[path_index]);
		exit(-1);
	}

	for (i = 0; i < WWN_SIZE; i++) {
		(void) sprintf(&wwn1[i << 1], "%02x", node_wwn[i]);
	}
	if ((err = l_get_box_list(&b_list, Options & PVERBOSE)) != 0) {
		(void) print_errString(err, argv[path_index]);
		exit(-1);
	}
	if (b_list == NULL) {
		(void) fprintf(stdout,
			MSGSTR(93, "No %s enclosures found "
			"in /dev/es\n"), ENCLOSURE_PROD_NAME);
		exit(-1);
	} else if (l_duplicate_names(b_list, wwn1, name,
		Options & PVERBOSE)) {
		(void) fprintf(stderr,
		MSGSTR(2049, "Warning: The name you selected, %s,"
		" is already being used.\n"
		"Please choose a unique name.\n"
		"You can use the \"probe\" subcommand to"
		" see all of the enclosure names.\n"),
		name);
		(void) l_free_box_list(&b_list);
		exit(-1);
	}
	(void) l_free_box_list(&b_list);

	/*  Send new name to IB */
	if (rval = l_new_name(path_phys, name)) {
		(void) print_errString(rval, path_phys);
		exit(-1);
	}
	if (Options & PVERBOSE) {
		(void) fprintf(stdout,
			MSGSTR(2050, "The enclosure has been renamed to %s\n"),
			name);
	}
}


static int
get_enclStatus(char *phys_path, char *encl_name, int off_flag)
{
int	found_pwrOnDrv = 0, slot;
int	found_pwrOffDrv = 0, err = 0;
L_state	l_state;

	if ((err = l_get_status(phys_path,
				&l_state, Options & PVERBOSE)) != 0) {
		(void) print_errString(err, encl_name);
		return (err);
	}

	if (off_flag) {
		for (slot = 0; slot < l_state.total_num_drv/2;
							slot++) {
			if (((l_state.drv_front[slot].ib_status.code !=
							S_NOT_INSTALLED) &&
			(!l_state.drv_front[slot].ib_status.dev_off)) ||
			((l_state.drv_rear[slot].ib_status.code !=
							S_NOT_INSTALLED) &&
			(!l_state.drv_rear[slot].ib_status.dev_off))) {
				found_pwrOnDrv++;
				break;
			}
		}
		if (!found_pwrOnDrv) {
			(void) fprintf(stdout,
				MSGSTR(2051,
				"Notice: Drives in enclosure"
				" \"%s\" have already been"
				" powered off.\n\n"),
				encl_name);
			return (-1);
		}
	} else {
		for (slot  = 0; slot < l_state.total_num_drv/2;
							slot++) {
			if (((l_state.drv_front[slot].ib_status.code !=
							S_NOT_INSTALLED) &&
			(l_state.drv_front[slot].ib_status.dev_off)) ||
			((l_state.drv_rear[slot].ib_status.code !=
							S_NOT_INSTALLED) &&
			(l_state.drv_rear[slot].ib_status.dev_off))) {
				found_pwrOffDrv++;
				break;
			}
		}
		if (!found_pwrOffDrv) {
			(void) fprintf(stdout,
				MSGSTR(2052,
				"Notice: Drives in enclosure"
				" \"%s\" have already been"
				" powered on.\n\n"),
				encl_name);
			return (-1);
		}
	}
	return (0);
}





/*
 * adm_led() The led_request subcommand requests the subsystem
 * to display the current state or turn off, on, or blink
 * the yellow LED associated with the disk specified by the
 * enclosure or pathname.
 *
 * RETURNS:
 *	none.
 */
void
adm_led(char **argv, int led_action)
{
int		path_index = 0, err = 0;
gfc_map_t	map;
L_inquiry	inq;
Dev_elem_st	status;
char		*path_phys = NULL;
Path_struct	*path_struct;
int		enc_t = 0;		/* enclosure type */
char		ses_path[MAXPATHLEN];
L_inquiry	ses_inq;

	while (argv[path_index] != NULL) {
		if ((err = l_convert_name(argv[path_index], &path_phys,
			&path_struct, Options & PVERBOSE)) != 0) {
			/* Make sure we have a device path. */
			if (path_struct->ib_path_flag) {
				path_phys = path_struct->p_physical_path;
			} else {
				(void) fprintf(stderr,
					MSGSTR(33,
				" Error: converting"
				" %s to physical path.\n"
				" Invalid pathname.\n"),
					argv[path_index]);
				if (err != -1) {
					(void) print_errString(err,
							argv[path_index]);
				}
				exit(-1);
			}
		}
		if (!path_struct->ib_path_flag) {
			if (err = g_get_inquiry(path_phys, &inq)) {
				(void) print_errString(err, argv[path_index]);
				exit(-1);
			}
			if ((inq.inq_dtype & DTYPE_MASK) != DTYPE_DIRECT) {
				(void) fprintf(stderr,
				MSGSTR(2053,
				"Error: pathname must be to a disk device.\n"
				" %s\n"), argv[path_index]);
				exit(-1);
			}
		}
		/*
		 * See if we are in fact talking to a loop or not.
		 */
		if (err = g_get_dev_map(path_phys, &map,
			(Options & PVERBOSE))) {
			(void) print_errString(err, argv[path_index]);

		}
		    if (led_action == L_LED_ON) {
			(void) fprintf(stderr, MSGSTR(2054,
			    "The led_on functionality is not applicable "
			    "to this subsystem.\n"));
			exit(-1);
		    }
		    if (err = l_led(path_struct, led_action, &status,
			    (Options & PVERBOSE))) {
			(void) print_errString(err, argv[path_index]);
			exit(-1);
		    }

		    /* Check to see if we have a daktari */
		    if (l_get_ses_path(path_phys, ses_path, &map,
			    (Options & PVERBOSE)) == 0) {
			if (g_get_inquiry(ses_path, &ses_inq) == 0) {
			    enc_t = l_get_enc_type(ses_inq);
			}
		    }
		    switch (led_action) {
		    case L_LED_STATUS:
			if (status.fault || status.fault_req) {
			    if (!path_struct->slot_valid) {
				(void) fprintf(stdout,
				    MSGSTR(2055, "LED state is ON for "
				    "device:\n  %s\n"), path_phys);
			    } else {
				if (enc_t == DAK_ENC_TYPE) {
				    if (path_struct->f_flag) {
					(void) fprintf(stdout,
					    MSGSTR(2236, "LED state is ON for "
					    "device in location: slot %d\n"),
					    path_struct->slot);
				    } else {
					(void) fprintf(stdout,
					    MSGSTR(2236, "LED state is ON for "
					    "device in location: slot %d\n"),
					    path_struct->slot +
							(MAX_DRIVES_DAK/2));
				    }
				} else {
				    (void) fprintf(stdout,
				    (path_struct->f_flag) ?
				    MSGSTR(2056, "LED state is ON for "
				    "device in location: front,slot %d\n")
				    : MSGSTR(2057, "LED state is ON for "
				    "device in location: rear,slot %d\n"),
				    path_struct->slot);
				    }
			    }
			} else if (status.ident || status.rdy_to_ins ||
				status.rmv) {
			    if (!path_struct->slot_valid) {
				(void) fprintf(stdout, MSGSTR(2058,
				    "LED state is BLINKING for "
				    "device:\n  %s\n"), path_phys);
			    } else {
				if (enc_t == DAK_ENC_TYPE) {
				    if (path_struct->f_flag) {
					(void) fprintf(stdout, MSGSTR(2237,
					"LED state is BLINKING for "
					"device in location: slot %d\n"),
					path_struct->slot);
				    } else {
					(void) fprintf(stdout, MSGSTR(2237,
					"LED state is BLINKING for "
					"device in location: slot %d\n"),
					path_struct->slot + (MAX_DRIVES_DAK/2));
				    }
				} else {
				    (void) fprintf(stdout,
				    (path_struct->f_flag) ?
				    MSGSTR(2059, "LED state is BLINKING for "
				    "device in location: front,slot %d\n")
				    : MSGSTR(2060, "LED state is BLINKING for "
				    "device in location: rear,slot %d\n"),
				    path_struct->slot);
				}
			    }
			} else {
			    if (!path_struct->slot_valid) {
				(void) fprintf(stdout,
				MSGSTR(2061, "LED state is OFF for "
				"device:\n  %s\n"), path_phys);
			    } else {
				if (enc_t == DAK_ENC_TYPE) {
				    if (path_struct->f_flag) {
					(void) fprintf(stdout, MSGSTR(2238,
					"LED state is OFF for "
					"device in location: slot %d\n"),
					path_struct->slot);
				    } else {
					(void) fprintf(stdout, MSGSTR(2238,
					"LED state is OFF for "
					"device in location: slot %d\n"),
					path_struct->slot + MAX_DRIVES_DAK/2);
				    }
				} else {
				    (void) fprintf(stdout,
					(path_struct->f_flag) ?
					MSGSTR(2062, "LED state is OFF for "
					"device in location: front,slot %d\n")
					: MSGSTR(2063, "LED state is OFF for "
					"device in location: rear,slot %d\n"),
					path_struct->slot);
				}
			    }
			}
			break;
		    }
		    free((void *)map.dev_addr);
		    path_index++;
	}
}





/*
 * dump() Dump information
 *
 * RETURNS:
 *	none.
 */
void
dump(char **argv)
{
uchar_t		*buf;
int		path_index = 0, err = 0;
L_inquiry	inq;
char		hdr_buf[MAXNAMELEN];
Rec_diag_hdr	*hdr, *hdr_ptr;
char		*path_phys = NULL;
Path_struct	*path_struct;

	/*
	 * get big buffer
	 */
	if ((hdr = (struct rec_diag_hdr *)calloc(1, MAX_REC_DIAG_LENGTH)) ==
								NULL) {
		(void) print_errString(L_MALLOC_FAILED, NULL);
		exit(-1);
	}
	buf = (uchar_t *)hdr;

	while (argv[path_index] != NULL) {
		if ((err = l_convert_name(argv[path_index], &path_phys,
			&path_struct, Options & PVERBOSE)) != 0) {
			(void) fprintf(stderr,
				MSGSTR(33,
					" Error: converting"
					" %s to physical path.\n"
					" Invalid pathname.\n"),
				argv[path_index]);
			if (err != -1) {
				(void) print_errString(err, argv[path_index]);
			}
			exit(-1);
		}
		if (err = g_get_inquiry(path_phys, &inq)) {
			(void) print_errString(err, argv[path_index]);
		} else {
			(void) g_dump(MSGSTR(2065, "INQUIRY data:   "),
			(uchar_t *)&inq, 5 + inq.inq_len, HEX_ASCII);
		}

		(void) memset(buf, 0, MAX_REC_DIAG_LENGTH);
		if (err = l_get_envsen(path_phys, buf, MAX_REC_DIAG_LENGTH,
			(Options & PVERBOSE))) {
		    (void) print_errString(err, argv[path_index]);
		    exit(-1);
		}
		(void) fprintf(stdout,
			MSGSTR(2066, "\t\tEnvironmental Sense Information\n"));

		/*
		 * Dump all pages.
		 */
		hdr_ptr = hdr;

		while (hdr_ptr->page_len != 0) {
			(void) sprintf(hdr_buf, MSGSTR(2067, "Page %d:   "),
				hdr_ptr->page_code);
			(void) g_dump(hdr_buf, (uchar_t *)hdr_ptr,
				HEADER_LEN + hdr_ptr->page_len, HEX_ASCII);
			hdr_ptr += ((HEADER_LEN + hdr_ptr->page_len) /
				sizeof (struct	rec_diag_hdr));
		}
		path_index++;
	}
	(void) free(buf);
}



/*
 * display_socal_stats() Display socal driver kstat information.
 *
 * RETURNS:
 *	none.
 */
void
display_socal_stats(int port, char *socal_path, struct socal_stats *fc_stats)
{
int		i;
int		header_flag = 0;
char		status_msg_buf[MAXNAMELEN];
int		num_status_entries;

	(void) fprintf(stdout, MSGSTR(2068,
		"\tInformation for FC Loop on port %d of"
		" FC100/S Host Adapter\n\tat path: %s\n"),
		port, socal_path);
	if (fc_stats->version > 1) {
		(void) fprintf(stdout, "\t");
		(void) fprintf(stdout, MSGSTR(32,
			"Information from %s"), fc_stats->drvr_name);
		(void) fprintf(stdout, "\n");
		if ((*fc_stats->node_wwn != NULL) &&
			(*fc_stats->port_wwn[port] != NULL)) {
			(void) fprintf(stdout, MSGSTR(104,
				"  Host Adapter WWN's: Node:%s"
				"  Port:%s\n"),
				fc_stats->node_wwn,
				fc_stats->port_wwn[port]);
		}
		if (*fc_stats->fw_revision != NULL) {
			(void) fprintf(stdout, MSGSTR(105,
				"  Host Adapter Firmware Revision: %s\n"),
				fc_stats->fw_revision);
		}
		if (fc_stats->parity_chk_enabled != 0) {
			(void) fprintf(stdout, MSGSTR(2069,
			"  This Host Adapter checks S-Bus parity.\n"));
		}
	}

	(void) fprintf(stdout, MSGSTR(2070,
		"  Version Resets  Req_Q_Intrpts  Qfulls"
		" Unsol_Resps Lips\n"));

	(void) fprintf(stdout,  "  %4d%8d%11d%13d%10d%7d\n",
			fc_stats->version,
			fc_stats->resets,
			fc_stats->reqq_intrs,
			fc_stats->qfulls,
			fc_stats->pstats[port].unsol_resps,
			fc_stats->pstats[port].lips);

	(void) fprintf(stdout, MSGSTR(2071,
		"  Els_rcvd  Abts"
		"     Abts_ok Offlines Loop_onlines Onlines\n"));

	(void) fprintf(stdout, "  %4d%9d%10d%9d%13d%10d\n",
			fc_stats->pstats[port].els_rcvd,
			fc_stats->pstats[port].abts,
			fc_stats->pstats[port].abts_ok,
			fc_stats->pstats[port].offlines,
			fc_stats->pstats[port].online_loops,
			fc_stats->pstats[port].onlines);

	/* If any status conditions exist then display */
	if (fc_stats->version > 1) {
		num_status_entries = FC_STATUS_ENTRIES;
	} else {
		num_status_entries = 64;
	}

	for (i = 0; i < num_status_entries; i++) {
		if (fc_stats->pstats[port].resp_status[i] != 0) {
			if (header_flag++ == 0) {
				(void) fprintf(stdout, MSGSTR(2072,
				"  Fibre Channel Transport status:\n        "
				"Status                       Value"
				"           Count\n"));
			}
			(void) l_format_fc_status_msg(status_msg_buf,
			fc_stats->pstats[port].resp_status[i], i);
			(void) fprintf(stdout, "        %s\n",
				status_msg_buf);
		}
	}
}



/*
 * display_sf_stats() Display sf driver kstat information.
 *
 * This routine is called by private loop device only
 *
 * RETURNS:
 *	none.
 */
void
display_sf_stats(char *path_phys, int dtype, struct sf_stats *sf_stats)
{
int		i, al_pa, err = 0;
gfc_map_t	map;
uchar_t		node_wwn[WWN_SIZE];
uchar_t		port_wwn[WWN_SIZE];
gfc_port_dev_info_t	*dev_addr_list;

	if (sf_stats->version > 1) {
		(void) fprintf(stdout, "\n\t");
		(void) fprintf(stdout, MSGSTR(32,
			"Information from %s"),
			sf_stats->drvr_name);
		(void) fprintf(stdout, "\n");
	} else {
		(void) fprintf(stdout,
			MSGSTR(2073, "\n\t\tInformation from sf driver:\n"));
	}

	(void) fprintf(stdout, MSGSTR(2074,
		"  Version  Lip_count  Lip_fail"
		" Alloc_fail  #_cmds "
		"Throttle_limit  Pool_size\n"));

	(void) fprintf(stdout, "  %4d%9d%12d%11d%10d%11d%12d\n",
			sf_stats->version,
			sf_stats->lip_count,
			sf_stats->lip_failures,
			sf_stats->cralloc_failures,
			sf_stats->ncmds,
			sf_stats->throttle_limit,
			sf_stats->cr_pool_size);

	(void) fprintf(stdout, MSGSTR(2075,
		"\n\t\tTARGET ERROR INFORMATION:\n"));
	(void) fprintf(stdout, MSGSTR(2076,
		"AL_PA  Els_fail Timouts Abts_fail"
		" Tsk_m_fail "
		" Data_ro_mis Dl_len_mis Logouts\n"));

	if (err = g_get_dev_map(path_phys, &map, (Options & PVERBOSE))) {
		(void) print_errString(err, path_phys);
		exit(-1);
	}

	if (dtype == DTYPE_DIRECT) {
		if (err = g_get_wwn(path_phys, port_wwn, node_wwn, &al_pa,
			Options & PVERBOSE)) {
			(void) print_errString(err, path_phys);
			exit(-1);
		}
		/* for san toleration, only need to modify the code    */
		/* such that the current sf_al_map structure replaced  */
		/* by the new gfc_map structure for private loop device */
		for (i = 0, dev_addr_list = map.dev_addr; i < map.count;
			i++, dev_addr_list++) {
			if (dev_addr_list->gfc_port_dev.priv_port.sf_al_pa
					== al_pa) {
				(void) fprintf(stdout,
				"%3x%10d%8d%10d%11d%13d%11d%9d\n",
				al_pa,
				sf_stats->tstats[i].els_failures,
				sf_stats->tstats[i].timeouts,
				sf_stats->tstats[i].abts_failures,
				sf_stats->tstats[i].task_mgmt_failures,
				sf_stats->tstats[i].data_ro_mismatches,
				sf_stats->tstats[i].dl_len_mismatches,
				sf_stats->tstats[i].logouts_recvd);
				break;
			}
		}
		if (i >= map.count) {
			(void) print_errString(L_INVALID_LOOP_MAP, path_phys);
			exit(-1);
		}
	} else {
		for (i = 0, dev_addr_list = map.dev_addr; i < map.count;
			i++, dev_addr_list++) {
			(void) fprintf(stdout,
			"%3x%10d%8d%10d%11d%13d%11d%9d\n",
			dev_addr_list->gfc_port_dev.priv_port.sf_al_pa,
			sf_stats->tstats[i].els_failures,
			sf_stats->tstats[i].timeouts,
			sf_stats->tstats[i].abts_failures,
			sf_stats->tstats[i].task_mgmt_failures,
			sf_stats->tstats[i].data_ro_mismatches,
			sf_stats->tstats[i].dl_len_mismatches,
			sf_stats->tstats[i].logouts_recvd);
		}
	}
	free((void *)map.dev_addr);
}



/*
 * adm_display_err() Displays enclosure specific
 * error information.
 *
 * RETURNS:
 *	none.
 */
static void
adm_display_err(char *path_phys, int dtype)
{
int		i, drvr_inst, sf_inst, socal_inst, port, al_pa, err = 0;
char		*char_ptr, socal_path[MAXPATHLEN], drvr_path[MAXPATHLEN];
struct		stat sbuf;
kstat_ctl_t	*kc;
kstat_t		*ifp_ks, *sf_ks, *fc_ks;
sf_stats_t	sf_stats;
socal_stats_t	fc_stats;
ifp_stats_t	ifp_stats;
int		header_flag = 0, pathcnt = 1;
char		status_msg_buf[MAXNAMELEN];
gfc_map_t	map;
uchar_t		node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
uint_t		path_type;
gfc_port_dev_info_t	*dev_addr_list;
mp_pathlist_t	pathlist;
int		p_on = 0, p_st = 0;

	if ((kc = kstat_open()) == (kstat_ctl_t *)NULL) {
		(void) fprintf(stderr,
			MSGSTR(2077, " Error: can't open kstat\n"));
		exit(-1);
	}

	if (strstr(path_phys, SCSI_VHCI)) {
		(void) strcpy(drvr_path, path_phys);
		if (err = g_get_pathlist(drvr_path, &pathlist)) {
			(void) print_errString(err, NULL);
			exit(-1);
		}
		pathcnt = pathlist.path_count;
		p_on = p_st = 0;
		for (i = 0; i < pathcnt; i++) {
			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
				if (pathlist.path_info[i].path_state ==
					MDI_PATHINFO_STATE_ONLINE) {
					p_on = i;
					break;
				} else if (pathlist.path_info[i].path_state ==
					MDI_PATHINFO_STATE_STANDBY) {
					p_st = i;
				}
			}
		}
		if (pathlist.path_info[p_on].path_state ==
		    MDI_PATHINFO_STATE_ONLINE) {
			/* on_line path */
			(void) strcpy(drvr_path,
				pathlist.path_info[p_on].path_hba);
		} else {
			/* standby or path0 */
			(void) strcpy(drvr_path,
				pathlist.path_info[p_st].path_hba);
		}
		free(pathlist.path_info);
	} else {

		(void) strcpy(drvr_path, path_phys);

		if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
			(void) print_errString(L_INVLD_PATH_NO_SLASH_FND,
				path_phys);
			exit(-1);
		}
		*char_ptr = '\0';   /* Make into nexus or HBA driver path. */
	}
	/*
	 * Each HBA and driver stack has its own structures
	 * for this, so we have to handle each one individually.
	 */
	path_type = g_get_path_type(drvr_path);

	if (path_type) { /* Quick sanity check for valid path */
		if ((err = g_get_nexus_path(drvr_path, &char_ptr)) != 0) {
			(void) print_errString(err, path_phys);
			exit(-1);
		}
		(void) strcpy(socal_path, char_ptr);

	}

	/* attach :devctl to get node stat instead of dir stat. */
	(void) strcat(drvr_path, FC_CTLR);

	if (stat(drvr_path, &sbuf) < 0) {
		(void) print_errString(L_LSTAT_ERROR, path_phys);
		exit(-1);
	}

	drvr_inst = minor(sbuf.st_rdev);


	/*
	 * first take care of ifp card.
	 */
	if (path_type & FC4_PCI_FCA) {
	    if ((ifp_ks = kstat_lookup(kc, "ifp",
			drvr_inst, "statistics")) != NULL) {

		if (kstat_read(kc, ifp_ks, &ifp_stats) < 0) {
			(void) fprintf(stderr,
				MSGSTR(2082,
				"Error: could not read ifp%d\n"), drvr_inst);
			exit(-1);
		}
		(void) fprintf(stdout, MSGSTR(2083,
			"\tInformation for FC Loop of"
			" FC100/P Host Adapter\n\tat path: %s\n"),
			drvr_path);
		if (ifp_stats.version > 1) {
			(void) fprintf(stdout, "\t");
			(void) fprintf(stdout, MSGSTR(32,
				"Information from %s"),
				ifp_stats.drvr_name);
			(void) fprintf(stdout, "\n");
			if ((*ifp_stats.node_wwn != NULL) &&
				(*ifp_stats.port_wwn != NULL)) {
				(void) fprintf(stdout, MSGSTR(104,
					"  Host Adapter WWN's: Node:%s"
					"  Port:%s\n"),
					ifp_stats.node_wwn,
					ifp_stats.port_wwn);
			}
			if (*ifp_stats.fw_revision != NULL) {
				(void) fprintf(stdout, MSGSTR(105,
				"  Host Adapter Firmware Revision: %s\n"),
				ifp_stats.fw_revision);
			}
			if (ifp_stats.parity_chk_enabled != 0) {
				(void) fprintf(stdout, MSGSTR(2084,
				"  This Host Adapter checks "
				"PCI-Bus parity.\n"));
			}
		}

		(void) fprintf(stdout, MSGSTR(2085,
			"        Version Lips\n"));
		(void) fprintf(stdout, "  %10d%7d\n",
				ifp_stats.version,
				ifp_stats.lip_count);
		/* If any status conditions exist then display */
		for (i = 0; i < FC_STATUS_ENTRIES; i++) {
			if (ifp_stats.resp_status[i] != 0) {
				if (header_flag++ == 0) {
					(void) fprintf(stdout, MSGSTR(2086,
					"  Fibre Channel Transport "
					"status:\n        "
					"Status           "
					"            Value"
					"           Count\n"));
				}
				(void) l_format_ifp_status_msg(
					status_msg_buf,
					ifp_stats.resp_status[i], i);
					(void) fprintf(stdout, "        %s\n",
					status_msg_buf);
			}
		}

		(void) fprintf(stdout, MSGSTR(2087,
			"\n\t\tTARGET ERROR INFORMATION:\n"));
		(void) fprintf(stdout, MSGSTR(2088,
			"AL_PA  logouts_recvd  task_mgmt_failures"
			"  data_ro_mismatches  data_len_mismatch\n"));

		if (err = g_get_dev_map(path_phys, &map,
					(Options & PVERBOSE))) {
			(void) print_errString(err, path_phys);
			exit(-1);
		}


		if (dtype == DTYPE_DIRECT) {
			if (err = g_get_wwn(path_phys, port_wwn,
				node_wwn, &al_pa,
				Options & PVERBOSE)) {
				(void) print_errString(err,
				path_phys);
				exit(-1);
			}
			for (i = 0, dev_addr_list = map.dev_addr;
				i < map.count; i++,
				dev_addr_list++) {
				if (dev_addr_list->gfc_port_dev.
					priv_port.sf_al_pa
					== al_pa) {
					(void) fprintf
					(stdout,
					"%3x%14d%18d%20d%20d\n",
					al_pa,
					ifp_stats.tstats[i].
						logouts_recvd,
					ifp_stats.tstats[i].
						task_mgmt_failures,
					ifp_stats.tstats[i].
						data_ro_mismatches,
					ifp_stats.tstats[i].
						dl_len_mismatches);
					break;
				}
			}
			if (i >= map.count) {

				(void) print_errString(
				L_INVALID_LOOP_MAP, path_phys);
				exit(-1);
			}

		} else {
			for (i = 0, dev_addr_list = map.dev_addr;
				i < map.count; i++,
				dev_addr_list++) {
				(void) fprintf(stdout,
				"%3x%14d%18d%20d%20d\n",
				dev_addr_list->gfc_port_dev.
					priv_port.sf_al_pa,
				ifp_stats.tstats[i].logouts_recvd,
				ifp_stats.tstats[i].task_mgmt_failures,
				ifp_stats.tstats[i].data_ro_mismatches,
				ifp_stats.tstats[i].dl_len_mismatches);
			}
		}

		free((void *)map.dev_addr);
	    }
	} else if (path_type & FC4_SF_XPORT) {
	/*
	 * process cards with sf xport nodes.
	 */
	    if (stat(socal_path, &sbuf) < 0) {
		(void) print_errString(L_LSTAT_ERROR, path_phys);
		exit(-1);
	    }
	    socal_inst = minor(sbuf.st_rdev)/2;
	    port = socal_inst%2;

	    sf_inst = LUX_SF_MINOR2INST(minor(sbuf.st_rdev));
	    if (!(sf_ks = kstat_lookup(kc, "sf", sf_inst,
		"statistics"))) {
		(void) fprintf(stderr,
			MSGSTR(2078,
		" Error: could not lookup driver stats for sf%d\n"),
			sf_inst);
		exit(-1);
	    }
	    if (!(fc_ks = kstat_lookup(kc, "socal", socal_inst,
					"statistics"))) {
		(void) fprintf(stderr,
			MSGSTR(2079,
		" Error: could not lookup driver stats for socal%d\n"),
			socal_inst);
		exit(-1);
	    }
	    if (kstat_read(kc, sf_ks, &sf_stats) < 0) {
		(void) fprintf(stderr,
			MSGSTR(2080,
		" Error: could not read driver stats for sf%d\n"),
			sf_inst);
		exit(-1);
	    }
	    if (kstat_read(kc, fc_ks, &fc_stats) < 0) {
		(void) fprintf(stderr,
			MSGSTR(2081,
		" Error: could not read driver stats for socal%d\n"),
			socal_inst);
		exit(-1);
	    }
	    (void) display_socal_stats(port, socal_path, &fc_stats);
	    (void) display_sf_stats(path_phys, dtype, &sf_stats);
	} else if ((path_type & FC_FCA_MASK) == FC_PCI_FCA) {
		fprintf(stderr, MSGSTR(2252,
			"\n WARNING!! display -r on qlc is"
			" currently not supported.\n"));
	} else {
		fprintf(stderr, MSGSTR(2253,
			"\n WARNING!! display -r is not supported on path\n"
			" %s\n"), drvr_path);
	}
	(void) kstat_close(kc);

}



/*ARGSUSED*/
/*
 * adm_display_verbose_disk() Gets the mode page information
 * for a SENA disk and prints that information.
 *
 * RETURNS:
 *	none.
 */
void
adm_display_verbose_disk(char *path, int verbose)
{
uchar_t		*pg_buf;
Mode_header_10	*mode_header_ptr;
Mp_01		*pg1_buf;
Mp_04		*pg4_buf;
struct mode_page *pg_hdr;
int		offset, hdr_printed = 0, err = 0;

	if ((err = l_get_mode_pg(path, &pg_buf, verbose)) == 0) {

		mode_header_ptr = (struct mode_header_10_struct *)(int)pg_buf;
		pg_hdr = ((struct mode_page *)((int)pg_buf +
		    (uchar_t)sizeof (struct mode_header_10_struct) +
		    (uchar_t *)(uintptr_t)(mode_header_ptr->bdesc_length)));
		offset = sizeof (struct mode_header_10_struct) +
		    mode_header_ptr->bdesc_length;
		while (offset < (mode_header_ptr->length +
			sizeof (mode_header_ptr->length))) {
			switch (pg_hdr->code) {
				case 0x01:
				pg1_buf = (struct mode_page_01_struct *)
					(int)pg_hdr;
				P_DPRINTF("  adm_display_verbose_disk:"
					"Mode Sense page 1 found.\n");
				if (hdr_printed++ == 0) {
					(void) fprintf(stdout,
						MSGSTR(2089,
						"  Mode Sense data:\n"));
				}
				(void) fprintf(stdout,
					MSGSTR(2090,
					"    AWRE:\t\t\t%d\n"
					"    ARRE:\t\t\t%d\n"
					"    Read Retry Count:\t\t"
					"%d\n"
					"    Write Retry Count:\t\t"
					"%d\n"),
					pg1_buf->awre,
					pg1_buf->arre,
					pg1_buf->read_retry_count,
					pg1_buf->write_retry_count);
				break;
				case MODEPAGE_GEOMETRY:
				pg4_buf = (struct mode_page_04_struct *)
					(int)pg_hdr;
				P_DPRINTF("  adm_display_verbose_disk:"
					"Mode Sense page 4 found.\n");
				if (hdr_printed++ == 0) {
					(void) fprintf(stdout,
						MSGSTR(2091,
						"  Mode Sense data:\n"));
				}
				if (pg4_buf->rpm) {
					(void) fprintf(stdout,
						MSGSTR(2092,
						"    Medium rotation rate:\t"
						"%d RPM\n"), pg4_buf->rpm);
				}
				break;
			}
			offset += pg_hdr->length + sizeof (struct mode_page);
			pg_hdr = ((struct mode_page *)((int)pg_buf +
				(uchar_t)offset));
		}





	} else if (getenv("_LUX_P_DEBUG") != NULL) {
			(void) print_errString(err, path);
	}
}

/*
 * Print out the port_wwn or node_wwn
 */
void
print_wwn(FILE *fd, uchar_t *pn_wwn)
{

	(void) fprintf(fd,
		" %1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
		pn_wwn[0], pn_wwn[1], pn_wwn[2], pn_wwn[3],
		pn_wwn[4], pn_wwn[5], pn_wwn[6], pn_wwn[7]);
}

/*
 * Print out the fabric dev port_id, hard_addr, port_wwn and node_wwn
 */
void
print_fabric_prop(int pos, uchar_t *port_wwn, uchar_t *node_wwn, int port_addr,
	int hard_addr)
{
	(void) fprintf(stdout, "%-4d %-6x  %-6x   ",
		pos, port_addr, hard_addr);
	print_wwn(stdout, port_wwn);
	print_wwn(stdout, node_wwn);
}

/*
 * Print out the private loop dev port_id, hard_addr, port_wwn and node_wwn
 */
void
print_private_loop_prop(int pos, uchar_t *port_wwn, uchar_t *node_wwn,
	int port_addr, int hard_addr)
{
	(void) fprintf(stdout, "%-3d   %-2x  %-2x    %-2x    ",
		pos, port_addr, g_sf_alpa_to_switch[port_addr], hard_addr);
	print_wwn(stdout, port_wwn);
	print_wwn(stdout, node_wwn);
}

/*
 * Get the device map from
 * fc nexus driver and prints the map.
 *
 * RETURNS:
 *	none.
 */
void
dump_map(char **argv)
{
int		i = 0, path_index = 0, pathcnt = 1;
int		limited_map_flag = 0, err = 0;
char		*path_phys = NULL;
Path_struct	*path_struct;
struct lilpmap	limited_map;
uint_t		dev_type;
char		temp2path[MAXPATHLEN];
mp_pathlist_t	pathlist;
int		p_pw = 0, p_on = 0, p_st = 0;
gfc_dev_t	map_root, map_dev;
int 		*port_addr, *hard_addr, pos = 0, count;
uchar_t		*hba_port_wwn, *port_wwn, *node_wwn, *dtype_prop;
uint_t		map_topo;

	while (argv[path_index] != NULL) {
		if ((err = l_convert_name(argv[path_index], &path_phys,
			&path_struct, Options & PVERBOSE)) != 0) {
			(void) fprintf(stderr,
				MSGSTR(33,
					" Error: converting"
					" %s to physical path.\n"
					" Invalid pathname.\n"),
				argv[path_index]);
			if (err != -1) {
				(void) print_errString(err, argv[path_index]);
			}
			exit(-1);
		}

		if (strstr(path_phys, SCSI_VHCI) != NULL) {
			/* obtain phci */
			(void) strcpy(temp2path, path_phys);
			if (err = g_get_pathlist(temp2path, &pathlist)) {
				(void) print_errString(err, NULL);
				exit(-1);
			}
			pathcnt = pathlist.path_count;
			p_pw = p_on = p_st = 0;
			for (i = 0; i < pathcnt; i++) {
				if (pathlist.path_info[i].path_state <
					MAXPATHSTATE) {
					if (strstr(pathlist.path_info[i].
						path_addr,
						path_struct->argv) != NULL) {
						p_pw = i;
						break;
					}
					if (pathlist.path_info[i].path_state ==
						MDI_PATHINFO_STATE_ONLINE) {
						p_on = i;
					}
					if (pathlist.path_info[i].path_state ==
						MDI_PATHINFO_STATE_STANDBY) {
						p_st = i;
					}
				}
			}
			if (strstr(pathlist.path_info[p_pw].path_addr,
				path_struct->argv) != NULL) {
				/* matching input pwwn */
				(void) strcpy(temp2path,
					pathlist.path_info[p_pw].path_hba);
			} else if (pathlist.path_info[p_on].path_state ==
				MDI_PATHINFO_STATE_ONLINE) {
				/* on_line path */
				(void) strcpy(temp2path,
					pathlist.path_info[p_on].path_hba);
			} else {
				/* standby or path0 */
				(void) strcpy(temp2path,
					pathlist.path_info[p_st].path_hba);
			}
			free(pathlist.path_info);
			(void) strcat(temp2path, FC_CTLR);
		} else {
			(void) strcpy(temp2path, path_phys);
		}

		if ((dev_type = g_get_path_type(temp2path)) == 0) {
			(void) print_errString(L_INVALID_PATH,
						argv[path_index]);
			exit(-1);
		}

		if ((map_root = g_dev_map_init(temp2path, &err,
			MAP_FORMAT_LILP)) == NULL) {
		    if (dev_type & FC_FCA_MASK) {
			(void) print_errString(err, argv[path_index]);
			exit(-1);
		    } else {
			/*
			 * This did not work so try the FCIO_GETMAP
			 * type ioctl.
			 */
			if (err = g_get_limited_map(path_phys,
				&limited_map, (Options & PVERBOSE))) {
				(void) print_errString(err,
						argv[path_index]);
				exit(-1);
			}
			limited_map_flag++;
		    }

		}

		if (limited_map_flag) {
		    (void) fprintf(stdout,
			MSGSTR(2093,
			"Host Adapter AL_PA: %x\n"),
			limited_map.lilp_myalpa);

		    (void) fprintf(stdout,
			MSGSTR(2094,
			"Pos AL_PA\n"));
		    for (i = 0; i < (uint_t)limited_map.lilp_length; i++) {
			(void) fprintf(stdout, "%-3d   %-2x\n",
				i, limited_map.lilp_list[i]);
		    }
		} else {
		    if ((err = g_dev_prop_lookup_bytes(map_root,
			PORT_WWN_PROP, &count, &hba_port_wwn)) != 0) {
			g_dev_map_fini(map_root);
			(void) print_errString(err, argv[path_index]);
			exit(-1);
		    }
		    if ((err = g_get_map_topology(
				map_root, &map_topo)) != 0) {
			(void) print_errString(err, argv[path_index]);
			exit(-1);
		    }

		    if ((map_dev = g_get_first_dev(map_root, &err)) == NULL) {
			if (err == L_NO_SUCH_DEV_FOUND) {
			    g_dev_map_fini(map_root);
			    (void) fprintf(stderr,
			    MSGSTR(2308, " No devices are found on %s.\n"),
			    argv[path_index]);
			    exit(-1);
			} else {
			    g_dev_map_fini(map_root);
			    (void) print_errString(err, argv[path_index]);
			    exit(-1);
			}
		    }

		    switch (map_topo) {
		    case FC_TOP_FABRIC:
		    case FC_TOP_PUBLIC_LOOP:
		    case FC_TOP_PT_PT:
			(void) fprintf(stdout,
			MSGSTR(2095, "Pos  Port_ID Hard_Addr Port WWN"
			"         Node WWN         Type\n"));
			while (map_dev) {
			    if ((err = g_dev_prop_lookup_ints(
				map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
				g_dev_map_fini(map_root);
				(void) print_errString(err, argv[path_index]);
				exit(-1);
			    }
			    if ((err = g_dev_prop_lookup_bytes(map_dev,
				PORT_WWN_PROP, &count, &port_wwn)) != 0) {
				g_dev_map_fini(map_root);
				(void) print_errString(err, argv[path_index]);
				exit(-1);
			    }
			    if ((err = g_dev_prop_lookup_bytes(map_dev,
				NODE_WWN_PROP, &count, &node_wwn)) != 0) {
				g_dev_map_fini(map_root);
				(void) print_errString(err, argv[path_index]);
				exit(-1);
			    }
			    if ((err = g_dev_prop_lookup_ints(
				map_dev, HARD_ADDR_PROP, &hard_addr)) != 0) {
				g_dev_map_fini(map_root);
				(void) print_errString(err, argv[path_index]);
				exit(-1);
			    }
			    print_fabric_prop(pos++, port_wwn,
					node_wwn, *port_addr, *hard_addr);
			    if ((err =  g_dev_prop_lookup_bytes(map_dev,
				INQ_DTYPE_PROP, &count, &dtype_prop)) != 0) {
				(void) fprintf(stdout,
				MSGSTR(2307, " Failed to get the type.\n"));
			    } else {
				print_fabric_dtype_prop(hba_port_wwn, port_wwn,
					*dtype_prop);
			    }

			    if (((map_dev = g_get_next_dev(
				map_dev, &err)) == NULL) &&
				(err != L_NO_SUCH_DEV_FOUND)) {
				g_dev_map_fini(map_root);
				(void) print_errString(err, argv[path_index]);
				exit(-1);
			    }
			}
			break;
		    case FC_TOP_PRIVATE_LOOP:
			(void) fprintf(stdout,
			MSGSTR(2295,
			"Pos AL_PA ID Hard_Addr "
			"Port WWN         Node WWN         Type\n"));

			while (map_dev) {
			    if ((err = g_dev_prop_lookup_ints(
				map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
				g_dev_map_fini(map_root);
				(void) print_errString(err, argv[path_index]);
				exit(-1);
			    }
			    if ((err = g_dev_prop_lookup_bytes(map_dev,
				PORT_WWN_PROP, &count, &port_wwn)) != 0) {
				g_dev_map_fini(map_root);
				(void) print_errString(err, argv[path_index]);
				exit(-1);
			    }
			    if ((err = g_dev_prop_lookup_bytes(map_dev,
				NODE_WWN_PROP, &count, &node_wwn)) != 0) {
				g_dev_map_fini(map_root);
				(void) print_errString(err, argv[path_index]);
				exit(-1);
			    }
			    if ((err = g_dev_prop_lookup_ints(
				map_dev, HARD_ADDR_PROP, &hard_addr)) != 0) {
				g_dev_map_fini(map_root);
				(void) print_errString(err, argv[path_index]);
				exit(-1);
			    }
			    print_private_loop_prop(pos++, port_wwn,
					node_wwn, *port_addr, *hard_addr);
			    if ((err =  g_dev_prop_lookup_bytes(map_dev,
				INQ_DTYPE_PROP, &count, &dtype_prop)) != 0) {
				(void) fprintf(stdout,
				MSGSTR(2307, " Failed to get the type.\n"));
			    } else {
				print_private_loop_dtype_prop(hba_port_wwn,
					port_wwn, *dtype_prop);
			    }

			    if (((map_dev = g_get_next_dev(
				map_dev, &err)) == NULL) &&
				(err != L_NO_SUCH_DEV_FOUND)) {
				g_dev_map_fini(map_root);
				(void) print_errString(err, argv[path_index]);
				exit(-1);
			    }
			}
			break;
		    default:
			(void) print_errString(L_UNEXPECTED_FC_TOPOLOGY,
			argv[path_index]);
			exit(-1);
		    }
		    g_dev_map_fini(map_root);
		}
		limited_map_flag = 0;
		path_index++;
	}
}

/*
 * Gets a list of non-SENA fcal devices
 * found on the system.
 *
 * OUTPUT:
 *	wwn_list pointer
 *			NULL: No non-enclosure devices found.
 *			!NULL: Devices found
 *                      wwn_list points to a linked list of wwn's.
 * RETURNS:
 *	0	O.K.
 */
int
n_get_non_encl_list(WWN_list **wwn_list_ptr, int verbose)
{
int		i, j, k, err, found_ib = 0, pathcnt = 1;
WWN_list	*wwn_list;
Box_list	*b_list = NULL;
gfc_map_t	map;
uchar_t		box_id;
gfc_port_dev_info_t	*dev_addr_list;
char		phci_path[MAXPATHLEN], oldphci_path[MAXPATHLEN];
mp_pathlist_t	pathlist;


	/*
	 * Only interested in devices that are not part of
	 * a Photon enclosure.
	 */
	if ((err = l_get_box_list(&b_list, verbose)) != 0) {
		return (err);	/* Failure */
	}

	if (err = g_get_wwn_list(&wwn_list, verbose)) {
		(void) l_free_box_list(&b_list);
		return (err);
	}

	while (b_list != NULL) {

		pathcnt = 1;
		if (strstr(b_list->b_physical_path, SCSI_VHCI) != NULL) {
			(void) strcpy(phci_path, b_list->b_physical_path);
			if (err = g_get_pathlist(phci_path, &pathlist)) {
				(void) print_errString(err, NULL);
				exit(-1);
			}
			pathcnt = pathlist.path_count;
		}

		for (k = 0; k < pathcnt; k++) {

		if ((k > 0) && (strstr(oldphci_path,
			pathlist.path_info[k].path_hba))) {
				continue;
		}

		if (strstr(b_list->b_physical_path, SCSI_VHCI) == NULL) {
			if ((err = g_get_dev_map(b_list->b_physical_path,
				&map, verbose)) != 0) {
				(void) g_free_wwn_list(&wwn_list);
				(void) l_free_box_list(&b_list);
				return (err);
			}
		} else {
			(void) strcpy(phci_path,
				pathlist.path_info[k].path_hba);
			(void) strcpy(oldphci_path, phci_path);
			(void) strcat(phci_path, FC_CTLR);
			if (g_get_dev_map(phci_path, &map, verbose)) {
				continue;
			}
			if (pathcnt == 1) {
				free(pathlist.path_info);
			}
		}


		switch (map.hba_addr.port_topology) {
		case FC_TOP_FABRIC:
		case FC_TOP_PUBLIC_LOOP:

			for (i = 0, dev_addr_list = map.dev_addr;
				i < map.count; i++, dev_addr_list++) {
				for (found_ib = 1, j = 0; j < WWN_SIZE;
					j++) {
					if (b_list->b_node_wwn[j] !=
						dev_addr_list->gfc_port_dev.
						pub_port.dev_nwwn.raw_wwn[j]) {
						found_ib = 0;
					}
				}
				if (found_ib) {
					(void) n_rem_list_entry_fabric(
					dev_addr_list->gfc_port_dev.
					pub_port.dev_did.port_id, &map,
					&wwn_list);
				}
			}
			break;

		case FC_TOP_PRIVATE_LOOP:

			for (i = 0, dev_addr_list = map.dev_addr;
				i < map.count; i++, dev_addr_list++) {
				for (found_ib = 1, j = 0; j < WWN_SIZE;
					j++) {
					if (b_list->b_node_wwn[j] !=
						dev_addr_list->gfc_port_dev.
						priv_port.sf_node_wwn[j]) {
							found_ib = 0;
					}
				}
				if (found_ib) {
					box_id = g_sf_alpa_to_switch
						[dev_addr_list->gfc_port_dev.
						priv_port.sf_al_pa] &
						BOX_ID_MASK;
					/* This function has been added */
					/* here only to keep from having */
					/* to tab over farther */
					(void) n_rem_list_entry(box_id, &map,
						&wwn_list);
					if (wwn_list == NULL) {
						/* Return the list */
						*wwn_list_ptr = NULL;
						break;
					}
				}
			}
			break;
		case FC_TOP_PT_PT:
			(void) free((void *)map.dev_addr);
			return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
		default:
			(void) free((void *)map.dev_addr);
			return (L_UNEXPECTED_FC_TOPOLOGY);
		}
		free((void *)map.dev_addr);

		}
		if (pathcnt > 1) {
			free(pathlist.path_info);
		}

		b_list = b_list->box_next;
	}
	/* Return the list */
	*wwn_list_ptr = wwn_list;
	(void) l_free_box_list(&b_list);
	return (0);
}



/*
 * n_rem_list_entry() We found an IB so remove disks that
 * are in the Photon from the individual device list.
 *
 * OUTPUT:
 *	wwn_list - removes the fcal disks that are in SENA enclosure
 *
 * RETURNS:
 *	none
 */
void
n_rem_list_entry(uchar_t box_id,  struct gfc_map *map,
	struct	wwn_list_struct **wwn_list)
{
int		k;
gfc_port_dev_info_t	*dev_addr_list;

	N_DPRINTF("  n_rem_list_entry: Removing devices"
		" with box_id=0x%x from device list.\n", box_id);


		for (k = 0, dev_addr_list = map->dev_addr; k < map->count;
			k++, dev_addr_list++) {
			if ((g_sf_alpa_to_switch[dev_addr_list->gfc_port_dev.
				priv_port.sf_hard_address] & BOX_ID_MASK)
				== box_id) {
				n_rem_wwn_entry(dev_addr_list->gfc_port_dev.
					priv_port.sf_node_wwn, wwn_list);
			}
		}

}



/*
 * n_rem_list_entry_fabric() We found an IB so remove disks that
 * are in the Photon from the individual device list.
 *
 * OUTPUT:
 *	wwn_list - removes the fcal disks that are in SENA enclosure
 *
 * RETURNS:
 *	none
 */
void
n_rem_list_entry_fabric(int pa,  struct gfc_map *map,
	struct	wwn_list_struct **wwn_list)
{
int		k;
gfc_port_dev_info_t	*dev_addr_ptr;

	N_DPRINTF("  n_rem_list_entry: Removing devices"
		" with the same domain and area ID as"
		" 0x%x PA from device list.\n", pa);
	for (k = 0, dev_addr_ptr = map->dev_addr; k < map->count;
				k++, dev_addr_ptr++) {

		/* matching the domain and area id with input alpa, */
		/* ignoring last 8 bits. */
		if ((dev_addr_ptr->gfc_port_dev.pub_port.dev_did.port_id |
				0xff) == (pa | 0xff)) {
			n_rem_wwn_entry(dev_addr_ptr->
				gfc_port_dev.pub_port.dev_nwwn.raw_wwn,
				wwn_list);
		}
	}
}


/*
 * n_rem_wwn_entry() removes input wwn from wwn_list.
 *
 * OUTPUT:
 *	wwn_list - removes the input wwn from wwn_list if found.
 *
 * RETURNS:
 *	none
 */
void
n_rem_wwn_entry(uchar_t node_wwn[], struct  wwn_list_struct **wwn_list)
{
int		l, found_dev;
WWN_list	*inner, *l1;

	inner = *wwn_list;
	while (inner != NULL) {
		for (found_dev = 1, l = 0; l < WWN_SIZE; l++) {
			if (inner->w_node_wwn[l] != node_wwn[l]) {
				found_dev = 0;
			}
		}
		if (found_dev) {
			/* Remove this entry from the list */
			if (inner->wwn_prev != NULL) {
				inner->wwn_prev->wwn_next =
					inner->wwn_next;
			} else {
				*wwn_list = inner->wwn_next;
			}
			if (inner->wwn_next != NULL) {
				inner->wwn_next->wwn_prev =
					inner->wwn_prev;
			}
			l1 = inner;
			N_DPRINTF("  n_rem_wwn_entry: "
				"Removing Logical=%s "
				"Current=0x%x, "
				"Prev=0x%x, Next=0x%x\n",
				l1->logical_path,
				l1,
				l1->wwn_prev,
				l1->wwn_next);
			inner = inner->wwn_next;
			if ((l1->wwn_prev == NULL) &&
				(l1->wwn_next) == NULL) {
				(void) free(l1->physical_path);
				(void) free(l1->logical_path);
				(void) free(l1);
				*wwn_list = NULL;
				N_DPRINTF("  n_rem_list_entry: "
				"No non-Photon "
				"devices left"
				" in the list.\n");
				return;
			}
				(void) free(l1->physical_path);
				(void) free(l1->logical_path);
				(void) free(l1);
		} else {
			inner = inner->wwn_next;
		}
	}
}


/*
 * non_encl_probe() Finds and displays a list of
 * non-SENA fcal devices which is found on the
 * system.
 *
 * RETURNS:
 *	none.
 */
void
non_encl_probe()
{
WWN_list	*wwn_list, *wwn_listh, *inner, *l1;
int		err = 0;
char		lun_a[MAXPATHLEN], lun_b[MAXPATHLEN], temppath[MAXPATHLEN];
char		*tempptra, *tempptrb, *tempptr;
mp_pathlist_t	pathlist;
int		compare_result, retr_outer = 0;
ddi_devid_t	devid1 = NULL, devid2 = NULL;
di_node_t	root = DI_NODE_NIL;

	if (err = n_get_non_encl_list(&wwn_list, (Options & PVERBOSE))) {
		(void) print_errString(err, NULL);
		exit(-1);
	}

	g_sort_wwn_list(&wwn_list);

	wwn_listh = wwn_list;

	if (wwn_list != NULL) {
		if (wwn_list->wwn_next != NULL) {
			(void) fprintf(stdout,
			    MSGSTR(2098, "\nFound Fibre Channel device(s):\n"));
		} else {
			(void) fprintf(stdout,
			    MSGSTR(2099, "\nFound Fibre Channel device:\n"));
		}
	} else {
		return;
	}

	while (wwn_list != NULL) {
	    if (strstr(wwn_list->physical_path, SCSI_VHCI) != NULL) {
		(void) strcpy(temppath, wwn_list->physical_path);
		if ((!g_get_pathlist(temppath,
		    &pathlist)) &&
		    ((tempptra = strchr(pathlist.path_info[0].
		    path_addr, ','))) != NULL) {
			tempptra++;
			(void) strcpy(lun_a, tempptra);
			free(pathlist.path_info);
		}
	    } else {
		if ((((tempptr = strstr(wwn_list->physical_path,
		    SLSH_DRV_NAME_ST)) != NULL) ||
		    ((tempptr = strstr(wwn_list->physical_path,
		    SLSH_DRV_NAME_SSD)) != NULL)) &&
		    ((tempptra = strchr(tempptr, ',')) != NULL)) {
			tempptra++;
			(void) strcpy(lun_a, tempptra);
		}
	    }
	    (void) fprintf(stdout, "  ");
	    (void) fprintf(stdout, MSGSTR(90, "Node WWN:"));
	    (void) fprintf(stdout, "%s  ", wwn_list->node_wwn_s);

	    if (wwn_list->device_type < 0x10) {
		(void) fprintf(stdout, MSGSTR(35, "Device Type:"));
		(void) fprintf(stdout, "%s",
		dtype[wwn_list->device_type]);
	    } else if (wwn_list->device_type < 0x1f) {
			(void) fprintf(stdout, MSGSTR(2100,
			"Type:Reserved"));
	    } else {
			(void) fprintf(stdout, MSGSTR(2101,
			"Type:Unknown"));
	    }
	    (void) fprintf(stdout, "\n    ");
	    (void) fprintf(stdout, MSGSTR(31, "Logical Path:%s"),
			wwn_list->logical_path);
	    (void) fprintf(stdout, "\n");

	    if (Options & OPTION_P) {
		(void) fprintf(stdout, "    ");
		(void) fprintf(stdout,
		MSGSTR(5, "Physical Path:"));
		(void) fprintf(stdout, "\n     %s\n", wwn_list->physical_path);
	    }
	    inner = wwn_list->wwn_next;

	    while (inner != NULL) {
		if (strcmp(inner->node_wwn_s, wwn_list->node_wwn_s) == 0) {

		    if (tempptra != NULL) {
			if (strstr(inner->physical_path,
			    SCSI_VHCI) != NULL) {
			    (void) strcpy(temppath,
			    inner->physical_path);

			    if ((!g_get_pathlist(temppath, &pathlist)) &&
				((tempptrb = strchr(
				pathlist.path_info[0].path_addr, ','))) !=
				    NULL) {
				tempptrb++;
				(void) strcpy(lun_b, tempptrb);
				free(pathlist.path_info);
			    }
			} else {
			    if ((((tempptr = strstr(inner->physical_path,
				SLSH_DRV_NAME_ST)) != NULL) ||
				((tempptr = strstr(inner->physical_path,
				SLSH_DRV_NAME_SSD)) != NULL)) &&
				((tempptrb = strchr(tempptr, ',')) != NULL)) {
				tempptrb++;
				(void) strcpy(lun_b, tempptrb);
			    }
			}
		    }

		    if (((tempptra == NULL) || (strcmp(lun_a, lun_b)) == 0)) {

			/*
			 * Have we retrieved a snapshot yet?
			 */
			if (root == DI_NODE_NIL) {
			    if ((root = di_init("/", DINFOCPYALL)) ==
				DI_NODE_NIL) {
				(void) fprintf(stdout,
				    MSGSTR(2319,
				    "\nFailed to get device tree snapshot:\n"));
				exit(1);
			    }
			}

			/* Apply devid to ssd devices only */
			if (!retr_outer && strstr(wwn_list->physical_path,
			    SLSH_DRV_NAME_SSD) != NULL) {
			    if ((err = g_devid_get(wwn_list->physical_path,
				&devid1, root, SSD_DRVR_NAME)) != 0) {
				(void) print_errString(err,
				    wwn_list->physical_path);
			    }
			/*
			 * Try retrieve of devid only once. If it fails
			 * don't try it again but print error,
			 * There should be a devid prop.
			 */
			    retr_outer = 1;
			}
			/*
			 * Apply devid to block devices only.
			 * Get devid of inner path and compare
			 * with outer path's devid.
			 */
			if ((strstr(inner->physical_path,
			    SLSH_DRV_NAME_SSD) != NULL) &&
			    devid1 != NULL) {

			    if ((err = g_devid_get(inner->physical_path,
				&devid2, root, SSD_DRVR_NAME)) != 0) {

				(void) print_errString(err,
				    inner->physical_path);
				compare_result = 0;
			    } else {
				compare_result = devid_compare(devid1, devid2);
			    }
			} else {
			    /* devid isn't applied */
			    compare_result = 0;
			}

			if (compare_result == 0) {

			    if (strcmp(wwn_list->logical_path,
				inner->logical_path)) {
				(void) fprintf(stdout, "    ");
				(void) fprintf(stdout,
				    MSGSTR(31, "Logical Path:%s"),
					inner->logical_path);
				(void) fprintf(stdout, "\n");

				if (Options & OPTION_P) {
				    (void) fprintf(stdout, "    ");
				    (void) fprintf(stdout, MSGSTR(5,
					"Physical Path:"));
				    (void) fprintf(stdout, "\n     %s\n",
					inner->physical_path);
				}
			    }

			    /* Remove this entry from the list */
			    if (inner->wwn_prev != NULL) {
				inner->wwn_prev->wwn_next =
				inner->wwn_next;
			    }

			    if (inner->wwn_next != NULL) {
				inner->wwn_next->wwn_prev =
				inner->wwn_prev;
			    }
			    free(inner->physical_path);
			    free(inner->logical_path);
			    l1 = inner;
			    inner = inner->wwn_next;
			    (void) free(l1);

			} else {
			    inner = inner->wwn_next;
			} /* End if (compare_result == 0) */

		    } else {
			inner = inner->wwn_next;
		    }
		} else {
		    inner = inner->wwn_next;
		}
		devid2 = NULL;
	    }
	    wwn_list = wwn_list->wwn_next;
	    retr_outer = 0;
	    devid1 = NULL;
	} /* End while (wwn_list != NULL) */

	(void) g_free_wwn_list(&wwn_listh);
	(void) di_fini(root);
}

void
pho_probe()
{

Box_list	*b_list, *o_list, *c_list;
int		multi_path_flag, multi_print_flag;
int		duplicate_names_found = 0, err = 0;

	b_list = o_list = c_list = NULL;
	if ((err = l_get_box_list(&b_list, Options & PVERBOSE)) != 0) {
		(void) print_errString(err, NULL);
		exit(-1);
	}
	if (b_list == NULL) {
		(void) fprintf(stdout,
			MSGSTR(93, "No %s enclosures found "
			"in /dev/es\n"), ENCLOSURE_PROD_NAME);
	} else {
		o_list = b_list;
		if (b_list->box_next != NULL) {
			(void) fprintf(stdout, MSGSTR(2102,
				"Found Enclosure(s)"));
		} else {
			(void) fprintf(stdout, MSGSTR(2103, "Found Enclosure"));
		}
		(void) fprintf(stdout, ":\n");
		while (b_list != NULL) {
			/* Don't re-print multiple paths */
			c_list = o_list;
			multi_print_flag = 0;
			while (c_list != b_list) {
				if (strcmp(c_list->b_node_wwn_s,
					b_list->b_node_wwn_s) == 0) {
					multi_print_flag = 1;
					break;
				}
				c_list = c_list->box_next;
			}
			if (multi_print_flag) {
				b_list = b_list->box_next;
				continue;
			}
			(void) fprintf(stdout,
			MSGSTR(2104, "%s   Name:%s   Node WWN:%s   "),
			b_list->prod_id_s, b_list->b_name,
				b_list->b_node_wwn_s);
			/*
			 * Print logical path on same line if not multipathed.
			 */
			multi_path_flag = 0;
			c_list = o_list;
			while (c_list != NULL) {
				if ((c_list != b_list) &&
					(strcmp(c_list->b_node_wwn_s,
					b_list->b_node_wwn_s) == 0)) {
					multi_path_flag = 1;
				}
				c_list = c_list->box_next;
			}
			if (multi_path_flag) {
				(void) fprintf(stdout, "\n  ");
			}
			(void) fprintf(stdout,
			MSGSTR(31, "Logical Path:%s"),
			b_list->logical_path);

			if (Options & OPTION_P) {
				(void) fprintf(stdout, "\n  ");
				(void) fprintf(stdout,
				MSGSTR(5, "Physical Path:"));
				(void) fprintf(stdout, "%s",
				b_list->b_physical_path);
			}
			c_list = o_list;
			while (c_list != NULL) {
				if ((c_list != b_list) &&
				(strcmp(c_list->b_node_wwn_s,
					b_list->b_node_wwn_s) == 0)) {
					(void) fprintf(stdout, "\n  ");
					(void) fprintf(stdout,
					MSGSTR(31, "Logical Path:%s"),
					c_list->logical_path);
					if (Options & OPTION_P) {
						(void) fprintf(stdout, "\n  ");
						(void) fprintf(stdout,
						MSGSTR(5, "Physical Path:"));
						(void) fprintf(stdout, "%s",
						c_list->b_physical_path);
					}
				}
				c_list = c_list->box_next;
			}
			(void) fprintf(stdout, "\n");
			/* Check for duplicate names */
			if (l_duplicate_names(o_list, b_list->b_node_wwn_s,
				(char *)b_list->b_name,
				Options & PVERBOSE)) {
				duplicate_names_found++;
			}
			b_list = b_list->box_next;
		}
	}
	if (duplicate_names_found) {
		(void) fprintf(stdout,
			MSGSTR(2105, "\nWARNING: There are enclosures with "
			"the same names.\n"
			"You can not use the \"enclosure\""
			" name to specify these subsystems.\n"
			"Please use the \"enclosure_name\""
			" subcommand to select unique names.\n\n"));
	}
	(void) l_free_box_list(&b_list);
}

/*
 * display_port_status() Prints the device's
 * port status.
 *
 * RETURNS:
 *	none.
 */
void
display_port_status(int d_state_flag)
{

	if (d_state_flag & L_OPEN_FAIL) {
		(void) fprintf(stdout, MSGSTR(28, "Open Failed"));
	} else if (d_state_flag & L_NOT_READY) {
		(void) fprintf(stdout, MSGSTR(20, "Not Ready"));
	} else if (d_state_flag & L_NOT_READABLE) {
		(void) fprintf(stdout, MSGSTR(88, "Not Readable"));
	} else if (d_state_flag & L_SPUN_DWN_D) {
		(void) fprintf(stdout, MSGSTR(68, "Spun Down"));
	} else if (d_state_flag & L_SCSI_ERR) {
		(void) fprintf(stdout, MSGSTR(70, "SCSI Error"));
	} else if (d_state_flag & L_RESERVED) {
		(void) fprintf(stdout, MSGSTR(73, "Reservation conflict"));
	} else if (d_state_flag & L_NO_LABEL) {
		(void) fprintf(stdout, MSGSTR(92, "No UNIX Label"));
	} else {
		(void) fprintf(stdout, MSGSTR(29, "O.K."));
	}
	(void) fprintf(stdout, "\n");
}

/*
 * Displays individual SENA
 * FC disk information.
 *
 * Caller to this routine should free the storage due to
 * the use of g_get_dev_map
 *
 * RETURNS:
 *	none.
 */
void
display_fc_disk(struct path_struct *path_struct, char *ses_path,
	gfc_map_t *map, L_inquiry inq, int verbose)
{
static WWN_list		*wwn_list = NULL;
static char		path_phys[MAXPATHLEN];
static L_disk_state	l_disk_state;
static L_inquiry	local_inq;
static uchar_t		node_wwn[WWN_SIZE];
char			same_path_phys = B_FALSE; /* To chk for repeat args */
uchar_t			port_wwn[WWN_SIZE], *pg_buf;
char			logical_path[MAXPATHLEN];
int			al_pa, port_a_flag = 0;
int			offset, mode_data_avail = 0;
int			no_path_flag = 0, err = 0;
L_state			l_state;
Mode_header_10		*mode_header_ptr = NULL;
struct mode_page	*pg_hdr;

	/*
	 * Do a quick check to see if its the same path as in last call.
	 * path_phys is a static array and so dont worry about its
	 * initialization.
	 */
	if (strcmp(path_phys, path_struct->p_physical_path) == 0)
		same_path_phys = B_TRUE;

	(void) strcpy(path_phys, path_struct->p_physical_path);
	(void) memset((char *)logical_path, 0, sizeof (logical_path));

	/*
	 * slot_valid is 1 when argument is of the form 'enclosure,[f|r]<n>'.
	 * If slot_valid != 1, g_get_dev_map and l_get_ses_path would
	 * already have been called
	 */
	if (path_struct->slot_valid == 1) {
		/* Get the location information. */
		if (err = g_get_dev_map(path_phys, map, (Options & PVERBOSE))) {
			(void) print_errString(err, path_phys);
			exit(-1);
		}
		if (err = l_get_ses_path(path_phys, ses_path, map,
			(Options & PVERBOSE))) {
			(void) print_errString(err, path_phys);
			exit(-1);
		}
	}

	/*
	 * Get the WWN for our disk if we already haven't or if there was an
	 * error earlier
	 */
	if (same_path_phys == B_FALSE) {
		if (err = g_get_wwn(path_phys, port_wwn, node_wwn,
			&al_pa, (Options & PVERBOSE))) {
			(void) print_errString(err, path_phys);
			exit(-1);
		}

		if (err = g_get_inquiry(ses_path, &local_inq)) {
			(void) print_errString(err, ses_path);
			exit(-1);
		}
	}

	/*
	 * We are interested only a couple of ib_tbl fields and
	 * those get filled using l_get_ib_status.
	 * Note that NOT ALL of ib_tbl fields get filled here
	 */
	if ((err = l_get_ib_status(ses_path, &l_state,
				Options & PVERBOSE)) != 0) {
		(void) print_errString(err, ses_path);
		exit(-1);
	}

	/*
	 * Get path to all the FC disk and tape devices.
	 * if we haven't already done so in a previous pass
	 */
	if ((wwn_list == NULL) && (err = g_get_wwn_list(&wwn_list, verbose))) {
		(void) print_errString(err, ses_path);
		exit(-1);   /* Failure */
	}

	/*
	 * Get the disk status if it is a different path_phys from
	 * last time.
	 */
	if (same_path_phys == B_FALSE) {
		(void) memset(&l_disk_state, 0,
				sizeof (struct l_disk_state_struct));
		if (err = l_get_disk_status(path_phys, &l_disk_state,
				wwn_list, (Options & PVERBOSE))) {
			(void) print_errString(err, path_phys);
			exit(-1);
		}
	}

	if (l_disk_state.l_state_flag & L_NO_PATH_FOUND) {
		(void) fprintf(stderr, MSGSTR(2106,
			"\nWARNING: No path found "
			"in /dev/rdsk directory\n"
			"  Please check the logical links in /dev/rdsk\n"
			"  (It may be necessary to run the \"disks\" "
			"program.)\n\n"));

		/* Just call to get the status directly. */
		if (err = l_get_port(ses_path, &port_a_flag, verbose)) {
			(void) print_errString(err, ses_path);
			exit(-1);
		}
		if (err = l_get_disk_port_status(path_phys,
			&l_disk_state, port_a_flag,
			(Options & PVERBOSE))) {
			(void) print_errString(err, path_phys);
			exit(-1);
		}
		no_path_flag++;
	}

	if (strlen(l_disk_state.g_disk_state.node_wwn_s) == 0) {
		(void) sprintf(l_disk_state.g_disk_state.node_wwn_s,
			"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
			node_wwn[0], node_wwn[1], node_wwn[2], node_wwn[3],
			node_wwn[4], node_wwn[5], node_wwn[6], node_wwn[7]);
	}

	/* get mode page information for FC device */
	if (l_get_mode_pg(path_phys, &pg_buf, Options & PVERBOSE) == 0) {
		mode_header_ptr = (struct mode_header_10_struct *)(int)pg_buf;
		pg_hdr = ((struct mode_page *)((int)pg_buf +
			(uchar_t)sizeof (struct mode_header_10_struct) +
			(uchar_t *)(uintptr_t)(mode_header_ptr->bdesc_length)));
		offset = sizeof (struct mode_header_10_struct) +
			mode_header_ptr->bdesc_length;
		while (offset < (mode_header_ptr->length +
			sizeof (mode_header_ptr->length)) &&
						!mode_data_avail) {
			if (pg_hdr->code == MODEPAGE_CACHING) {
				mode_data_avail++;
				break;
			}
			offset += pg_hdr->length + sizeof (struct mode_page);
			pg_hdr = ((struct mode_page *)((int)pg_buf +
				(uchar_t)offset));
		}
	}

	switch ((inq.inq_dtype & DTYPE_MASK)) {
	case DTYPE_DIRECT:
	    fprintf(stdout, MSGSTR(121, "DEVICE PROPERTIES for disk: %s\n"),
		path_struct->argv);
	    break;
	case DTYPE_SEQUENTIAL: /* Tape */
	    fprintf(stdout, MSGSTR(2249, "DEVICE PROPERTIES for tape: %s\n"),
		path_struct->argv);
	    break;
	default:
	    fprintf(stdout, MSGSTR(2250, "DEVICE PROPERTIES for: %s\n"),
		path_struct->argv);
	    break;
	}

	if (l_disk_state.g_disk_state.port_a_valid) {
		(void) fprintf(stdout, "  ");
		(void) fprintf(stdout, MSGSTR(141, "Status(Port A):"));
		(void) fprintf(stdout, "\t");
		display_port_status(
			l_disk_state.g_disk_state.d_state_flags[PORT_A]);
	} else {
		if (path_struct->f_flag) {
			if ((ib_present_chk(&l_state, 0) == 1) &&
		(l_state.drv_front[path_struct->slot].ib_status.bypass_a_en)) {
				(void) fprintf(stdout,
					MSGSTR(66,
					"  Status(Port A):\tBYPASSED\n"));
			}
		} else {
			if ((ib_present_chk(&l_state, 0) == 1) &&
		(l_state.drv_rear[path_struct->slot].ib_status.bypass_a_en)) {
				(void) fprintf(stdout,
					MSGSTR(66,
					"  Status(Port A):\tBYPASSED\n"));
			}
		}
	}

	if (l_disk_state.g_disk_state.port_b_valid) {
		(void) fprintf(stdout, "  ");
		(void) fprintf(stdout, MSGSTR(142, "Status(Port B):"));
		(void) fprintf(stdout, "\t");
	display_port_status(l_disk_state.g_disk_state.d_state_flags[PORT_B]);
	} else {
		if (path_struct->f_flag) {
			if ((ib_present_chk(&l_state, 1) == 1) &&
		(l_state.drv_front[path_struct->slot].ib_status.bypass_b_en)) {
				(void) fprintf(stdout,
					MSGSTR(65,
					"  Status(Port B):\tBYPASSED\n"));
			}
		} else {
			if ((ib_present_chk(&l_state, 1) == 1) &&
		(l_state.drv_rear[path_struct->slot].ib_status.bypass_b_en)) {
				(void) fprintf(stdout,
					MSGSTR(65,
					"  Status(Port B):\tBYPASSED\n"));
			}
		}
	}

	if (no_path_flag) {
		(void) fprintf(stdout, "  ");
		if (port_a_flag != NULL) {
			(void) fprintf(stdout, MSGSTR(142, "Status(Port B):"));
		} else {
			(void) fprintf(stdout, MSGSTR(141, "Status(Port A):"));
		}
		(void) fprintf(stdout, "\t");
		display_port_status(
		l_disk_state.g_disk_state.d_state_flags[port_a_flag]);
	} else if ((!l_disk_state.g_disk_state.port_a_valid) &&
			(!l_disk_state.g_disk_state.port_b_valid)) {
		(void) fprintf(stdout, MSGSTR(2107, "  Status:\t\t"
		"No state available.\n"));
	}

	(void) display_disk_info(inq, l_disk_state, path_struct, pg_hdr,
		mode_data_avail, (char *)local_inq.inq_box_name, verbose);
}





/*
 * non_encl_fc_disk_display() Prints the device specific
 * information for an individual fcal device.
 *
 * RETURNS:
 *	none.
 */
static int
non_encl_fc_disk_display(Path_struct *path_struct,
				L_inquiry inq_struct, int verbose)
{

char			phys_path[MAXPATHLEN];
uchar_t			node_wwn[WWN_SIZE], port_wwn[WWN_SIZE], *pg_buf = NULL;
L_disk_state		l_disk_state;
struct dlist		*mlist;
int			i = 0, al_pa, offset, mode_data_avail = 0, err = 0;
int			path_a_found = 0, path_b_found = 0, argpwwn = 0,
			argnwwn = 0, pathcnt = 1;
L_inquiry		local_inq;
Mode_header_10		*mode_header_ptr;
struct mode_page	*pg_hdr;
WWN_list		*wwn_list, *wwn_list_ptr, *list_start;
char			temppath[MAXPATHLEN], last_logical_path[MAXPATHLEN];
mp_pathlist_t		pathlist;

	(void) strcpy(phys_path, path_struct->p_physical_path);

	/* Get path to all the FC disk and tape devices. */
	if (err = g_get_wwn_list(&wwn_list, verbose)) {
		return (err);
	}

	g_sort_wwn_list(&wwn_list);

	list_start = wwn_list;
	(void) strcpy(last_logical_path, phys_path);

	for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
		wwn_list_ptr = wwn_list_ptr->wwn_next) {
		if (strcasecmp(wwn_list_ptr->port_wwn_s,
			path_struct->argv) == 0) {
			list_start = wwn_list_ptr;
			argpwwn = 1;
			break;
		} else if (strcasecmp(wwn_list_ptr->node_wwn_s,
			path_struct->argv) == 0) {
			list_start = wwn_list_ptr;
			argnwwn = 1;
			break;
		}
	}

	for (wwn_list_ptr = list_start; wwn_list_ptr != NULL;
		wwn_list_ptr = wwn_list_ptr->wwn_next) {


	if (argpwwn) {
		if (strcasecmp(wwn_list_ptr->port_wwn_s,
			path_struct->argv) != 0) {
			continue;
		}
		(void) strcpy(phys_path, wwn_list_ptr->physical_path);
		path_a_found = 0;
		path_b_found = 0;
		mode_data_avail = 0;
	} else if (argnwwn) {
		if (strstr(wwn_list_ptr->logical_path,
			last_logical_path) != NULL) {
			continue;
		}
		if (strcasecmp(wwn_list_ptr->node_wwn_s,
			path_struct->argv) != 0) {
			continue;
		}
		(void) strcpy(phys_path, wwn_list_ptr->physical_path);
		(void) strcpy(last_logical_path,
			wwn_list_ptr->logical_path);
		path_a_found = 0;
		path_b_found = 0;
		mode_data_avail = 0;
	}

	(void) memset(&l_disk_state, 0, sizeof (struct l_disk_state_struct));

	if ((err = g_get_multipath(phys_path,
		&(l_disk_state.g_disk_state.multipath_list),
		wwn_list, verbose)) != 0) {
		return (err);
	}
	mlist = l_disk_state.g_disk_state.multipath_list;
	if (mlist == NULL) {
		l_disk_state.l_state_flag = L_NO_PATH_FOUND;
		N_DPRINTF(" non_encl_fc_disk_display: Error finding"
			" multiple paths to the disk.\n");
		(void) g_free_wwn_list(&wwn_list);
		return (-1);
	}

	/* get mode page information for FC device */
	if (l_get_mode_pg(phys_path, &pg_buf, verbose) == 0) {
		mode_header_ptr = (struct mode_header_10_struct *)(int)pg_buf;
		pg_hdr = ((struct mode_page *)((int)pg_buf +
			(uchar_t)sizeof (struct mode_header_10_struct) +
			(uchar_t *)(uintptr_t)(mode_header_ptr->bdesc_length)));
		offset = sizeof (struct mode_header_10_struct) +
			mode_header_ptr->bdesc_length;
		while (offset < (mode_header_ptr->length +
			sizeof (mode_header_ptr->length)) &&
						!mode_data_avail) {
			if (pg_hdr->code == MODEPAGE_CACHING) {
				mode_data_avail++;
				break;
			}
			offset += pg_hdr->length + sizeof (struct mode_page);
			pg_hdr = ((struct mode_page *)((int)pg_buf +
				(uchar_t)offset));
		}
	}

	switch ((inq_struct.inq_dtype & DTYPE_MASK)) {
	case DTYPE_DIRECT:
	    fprintf(stdout, MSGSTR(121, "DEVICE PROPERTIES for disk: %s\n"),
		path_struct->argv);
	    break;
	case DTYPE_SEQUENTIAL: /* Tape */
	    fprintf(stdout, MSGSTR(2249, "DEVICE PROPERTIES for tape: %s\n"),
		path_struct->argv);
	    break;
	default:
	    fprintf(stdout, MSGSTR(2250, "DEVICE PROPERTIES for: %s\n"),
		path_struct->argv);
	    break;
	}
	while ((mlist != NULL) && (!(path_a_found && path_b_found))) {
		(void) strcpy(phys_path, mlist->dev_path);
		if (err = g_get_inquiry(phys_path, &local_inq)) {
			(void) fprintf(stderr,
				MSGSTR(2114,
				"non_encl_fc_disk_display: Inquiry failed\n"));
			(void) print_errString(err, phys_path);
			(void) g_free_multipath(
				l_disk_state.g_disk_state.multipath_list);
			(void) g_free_wwn_list(&wwn_list);
			return (-1);
		}
		if ((err = g_get_wwn(mlist->dev_path, port_wwn, node_wwn,
					&al_pa, verbose)) != 0) {
			(void) print_errString(err, mlist->dev_path);
			(void) g_free_multipath(
				l_disk_state.g_disk_state.multipath_list);
			(void) g_free_wwn_list(&wwn_list);
			return (-1);
		}
		if (strlen(l_disk_state.g_disk_state.node_wwn_s) == 0) {
			(void) sprintf(l_disk_state.g_disk_state.node_wwn_s,
			"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
			node_wwn[0], node_wwn[1], node_wwn[2], node_wwn[3],
			node_wwn[4], node_wwn[5], node_wwn[6], node_wwn[7]);
		}
		if ((err = l_get_disk_port_status(phys_path, &l_disk_state,
				(local_inq.inq_port) ? FC_PORT_B : FC_PORT_A,
				verbose)) != 0) {
			(void) print_errString(err, phys_path);
			(void) g_free_multipath(
				l_disk_state.g_disk_state.multipath_list);
			exit(-1);
		}

		if ((!local_inq.inq_port) && (!path_a_found)) {
			(void) sprintf(l_disk_state.g_disk_state.port_a_wwn_s,
				"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
			port_wwn[0], port_wwn[1], port_wwn[2], port_wwn[3],
			port_wwn[4], port_wwn[5], port_wwn[6], port_wwn[7]);
		path_a_found = l_disk_state.g_disk_state.port_a_valid = 1;
		}
		if ((local_inq.inq_port) && (!path_b_found)) {
		path_b_found = l_disk_state.g_disk_state.port_b_valid = 1;
			(void) sprintf(l_disk_state.g_disk_state.port_b_wwn_s,
				"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
			port_wwn[0], port_wwn[1], port_wwn[2], port_wwn[3],
			port_wwn[4], port_wwn[5], port_wwn[6], port_wwn[7]);
		}

		if ((strstr(mlist->dev_path, SCSI_VHCI) != NULL) &&
			(!l_get_disk_port_status(phys_path, &l_disk_state,
			(!local_inq.inq_port) ? FC_PORT_B : FC_PORT_A,
			verbose))) {
			(void) strcpy(temppath, mlist->dev_path);
			if (err = g_get_pathlist(temppath, &pathlist)) {
				(void) print_errString(err, NULL);
				exit(-1);
			}
			pathcnt = pathlist.path_count;
			if (pathcnt > 1) {
				for (i = 0; i < pathcnt; i++) {
					if ((!path_a_found) &&
						(path_b_found) &&
						(strstr(pathlist.path_info[i].
						path_addr,
						l_disk_state.g_disk_state.
						port_b_wwn_s) == NULL)) {

						(void) strncpy(l_disk_state.
						g_disk_state.port_a_wwn_s,
						pathlist.path_info[i].
						path_addr, 16);
						path_a_found = l_disk_state.
						g_disk_state.port_a_valid = 1;
					}
					if ((path_a_found) &&
						(!path_b_found) &&
						(strstr(pathlist.path_info[i].
						path_addr,
						l_disk_state.g_disk_state.
						port_a_wwn_s) == NULL)) {

						(void) strncpy(l_disk_state.
						g_disk_state.port_b_wwn_s,
						pathlist.path_info[i].
						path_addr, 16);
						path_b_found = l_disk_state.
						g_disk_state.port_b_valid = 1;
					}
					if ((path_a_found) && (path_b_found)) {
						break;
					}
				}
			}
			free(pathlist.path_info);
		}

		mlist = mlist->next;
	}

	if (l_disk_state.g_disk_state.port_a_valid) {
		(void) fprintf(stdout, "  ");
		(void) fprintf(stdout, MSGSTR(141, "Status(Port A):"));
		(void) fprintf(stdout, "\t");
	display_port_status(l_disk_state.g_disk_state.d_state_flags[FC_PORT_A]);
	}

	if (l_disk_state.g_disk_state.port_b_valid) {
		(void) fprintf(stdout, "  ");
		(void) fprintf(stdout, MSGSTR(142, "Status(Port B):"));
		(void) fprintf(stdout, "\t");
	display_port_status(l_disk_state.g_disk_state.d_state_flags[FC_PORT_B]);
	}

	(void) display_disk_info(local_inq, l_disk_state, path_struct,
				pg_hdr, mode_data_avail, NULL, verbose);
	(void) g_free_multipath(l_disk_state.g_disk_state.multipath_list);

	if (!(argpwwn || argnwwn)) {
		break;
	}

	}
	(void) g_free_wwn_list(&wwn_list);
	return (0);
}



/*
 * display_disk_info() Prints the device specific information
 * for any FC_AL disk device.
 *
 * RETURNS:
 *	none.
 */
void
display_disk_info(L_inquiry inq, L_disk_state l_disk_state,
		Path_struct *path_struct, struct mode_page *pg_hdr,
		int mode_data_avail, char *name_buf, int options)
{
float		num_blks;
struct dlist	*mlist;
int		port_a, port_b;
struct	my_mode_caching	*pg8_buf;
L_inquiry	enc_inq;
char		*enc_phys_path;
Path_struct	*enc_path_struct;
int		enc_type = 0;
L_inquiry80	inq80;
size_t		serial_len;
int		err;

	serial_len = sizeof (inq80.inq_serial);
	err = g_get_serial_number(path_struct->p_physical_path,
	    inq80.inq_serial, &serial_len);
	if (err) {
		fprintf(stderr, "\n");
		print_errString(err, path_struct->p_physical_path);
		fprintf(stderr, "\n");
		exit(1);
	}
	(void) fprintf(stdout, "  ");
	(void) fprintf(stdout, MSGSTR(3, "Vendor:"));
	(void) fprintf(stdout, "\t\t");
	print_chars(inq.inq_vid, sizeof (inq.inq_vid), 0);

	(void) fprintf(stdout, MSGSTR(2115, "\n  Product ID:\t\t"));
	print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0);

	(void) fprintf(stdout, MSGSTR(2116, "\n  WWN(Node):\t\t%s"),
				l_disk_state.g_disk_state.node_wwn_s);

	if (l_disk_state.g_disk_state.port_a_valid) {
		(void) fprintf(stdout, MSGSTR(2117, "\n  WWN(Port A):\t\t%s"),
				l_disk_state.g_disk_state.port_a_wwn_s);
	}
	if (l_disk_state.g_disk_state.port_b_valid) {
		(void) fprintf(stdout, MSGSTR(2118, "\n  WWN(Port B):\t\t%s"),
				l_disk_state.g_disk_state.port_b_wwn_s);
	}
	(void) fprintf(stdout, "\n  ");
	(void) fprintf(stdout, MSGSTR(2119, "Revision:"));
	(void) fprintf(stdout, "\t\t");
	print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0);

	(void) fprintf(stdout, "\n  ");
	(void) fprintf(stdout, MSGSTR(17, "Serial Num:"));
	(void) fprintf(stdout, "\t\t");
	print_chars(inq80.inq_serial, serial_len, 0);
	num_blks = l_disk_state.g_disk_state.num_blocks;
	if (num_blks) {
		num_blks /= 2048;	/* get Mbytes */
		(void) fprintf(stdout, "\n  ");
		(void) fprintf(stdout,
			MSGSTR(60,
		"Unformatted capacity:\t%6.3f MBytes"), num_blks);
	}
	(void) fprintf(stdout, "\n");

	if (l_disk_state.g_disk_state.persistent_reserv_flag) {
		(void) fprintf(stdout,
			MSGSTR(2120, "  Persistent Reserve:\t"));
		if (l_disk_state.g_disk_state.persistent_active) {
			(void) fprintf(stdout,
				MSGSTR(39, "Active"));
				(void) fprintf(stdout, "\n");
		}
		if (l_disk_state.g_disk_state.persistent_registered) {
			(void) fprintf(stdout,
				MSGSTR(2121, "Found Registered Keys"));
		} else {
			(void) fprintf(stdout,
				MSGSTR(87, "Not being used"));
		}
		(void) fprintf(stdout, "\n");
	}

	if ((mode_data_avail) && (pg_hdr->code == MODEPAGE_CACHING)) {
		pg8_buf = (struct my_mode_caching *)(int)pg_hdr;
		if (pg8_buf->wce) {
			(void) fprintf(stdout,
				MSGSTR(2122,
				"  Write Cache:\t\t"
				"Enabled\n"));
		}
		if (pg8_buf->rcd == 0) {
			(void) fprintf(stdout,
				MSGSTR(2123,
				"  Read Cache:\t\t"
				"Enabled\n"));
			(void) fprintf(stdout,
				MSGSTR(2320,
				"    Minimum prefetch:"
				"\t0x%x\n"
				"    Maximum prefetch:"
				"\t0x%x\n"),
				pg8_buf->min_prefetch,
				pg8_buf->max_prefetch);
		}
	}

	/*
	 * When /dev/rdsk/cxtxdxsx form of input is specified
	 * for display command the initial library version didn't
	 * display Location information.  The change is made
	 * to display the same Location info as the non-library version.
	 */

	if (name_buf != NULL) {
	    fprintf(stdout, MSGSTR(2125, "  Location:\t\t"));
	    if (path_struct->slot_valid) {
		/*
		 * We have to do another inquiry on the enclosure (name_buf)
		 * to determine if this device is within a daktari, or
		 * a two sided device.
		 */
		if (!l_convert_name(name_buf, &enc_phys_path,
			&enc_path_struct, 0)) {
		    if (!g_get_inquiry(enc_phys_path, &enc_inq)) {
			enc_type = l_get_enc_type(enc_inq);
		    }
		}
		/* If either of the above fail, we just assume the default */
		free(enc_phys_path);
		free(enc_path_struct);
		if (enc_type == DAK_ENC_TYPE) {
			if (path_struct->f_flag) {
				(void) fprintf(stdout, MSGSTR(2239,
				    "In slot %d in the enclosure named: %s\n"),
				    path_struct->slot, name_buf);
			} else {
				(void) fprintf(stdout, MSGSTR(2239,
				    "In slot %d in the enclosure named: %s\n"),
				    path_struct->slot + (MAX_DRIVES_DAK/2),
								name_buf);
			}
		} else	{  /* Default enclosure type */
		    (void) fprintf(stdout, path_struct->f_flag ?
				MSGSTR(2126,
			"In slot %d in the Front of the enclosure named: %s\n")
				: MSGSTR(2127,
			"In slot %d in the Rear of the enclosure named: %s\n"),
				path_struct->slot, name_buf);
		}
	    } else {
		(void) fprintf(stdout, MSGSTR(2228,
			"In the enclosure named: %s\n"),
			name_buf);
	    }
	}

	(void) fprintf(stdout, "  %s\t\t%s\n",
			MSGSTR(35, "Device Type:"),
			dtype[inq.inq_dtype & DTYPE_MASK]);

	mlist = l_disk_state.g_disk_state.multipath_list;
	(void) fprintf(stdout, MSGSTR(2128, "  Path(s):\n"));
	if (strstr(mlist->dev_path, SCSI_VHCI) != NULL) {
		(void) fprintf(stdout, "  %s\n  %s\n",
			mlist->logical_path, mlist->dev_path);
		(void) adm_print_pathlist(mlist->dev_path);
	} else {
		while (mlist) {
			(void) fprintf(stdout, "  %s\n  %s\n",
				mlist->logical_path, mlist->dev_path);
			mlist = mlist->next;
		}
	}

	if (Options & OPTION_V) {
		if (path_struct->slot_valid) {
			port_a = PORT_A;
			port_b = PORT_B;
		} else {
			port_a = FC_PORT_A;
			port_b = FC_PORT_B;
		}
		/* Only bother if the state is O.K. */
		if ((l_disk_state.g_disk_state.port_a_valid) &&
			(l_disk_state.g_disk_state.d_state_flags[port_a] == 0))
		adm_display_verbose_disk(path_struct->p_physical_path, options);
		else if ((l_disk_state.g_disk_state.port_b_valid) &&
			(l_disk_state.g_disk_state.d_state_flags[port_b] == 0))
		adm_display_verbose_disk(path_struct->p_physical_path, options);
	}
	(void) fprintf(stdout, "\n");

}



/*
 * temp_decode() Display temperature bytes 1-3 state.
 *
 * RETURNS:
 *	none.
 */
void
temp_decode(Temp_elem_st *temp)
{
	if (temp->ot_fail) {
		(void) fprintf(stdout, MSGSTR(2129,
			": FAILURE - Over Temperature"));
	}
	if (temp->ut_fail) {
		(void) fprintf(stdout, MSGSTR(2130,
			": FAILURE - Under Temperature"));
	}
	if (temp->ot_warn) {
		(void) fprintf(stdout, MSGSTR(2131,
			": WARNING - Over Temperature"));
	}
	if (temp->ut_warn) {
		(void) fprintf(stdout, MSGSTR(2132,
			": WARNING - Under Temperature"));
	}
}



/*
 * disp_degree() Display temperature in Degrees Celsius.
 *
 * RETURNS:
 *	none.
 */
void
disp_degree(Temp_elem_st *temp)
{
int	t;

	t = temp->degrees;
	t -= 20;	/* re-adjust */
	/*
	 * NL_Comment
	 * The %c is the degree symbol.
	 */
	(void) fprintf(stdout, ":%1.2d%cC ", t, 186);
}



/*
 * trans_decode() Display tranceivers state.
 *
 * RETURNS:
 *	none.
 */
void
trans_decode(Trans_elem_st *trans)
{
	if (trans->disabled) {
		(void) fprintf(stdout, ": ");
		(void) fprintf(stdout, MSGSTR(34,
			"Disabled"));
	}
	if (trans->lol) {
		(void) fprintf(stdout, MSGSTR(2133,
			": Not receiving a signal"));
	}
	if (trans->lsr_fail) {
		(void) fprintf(stdout, MSGSTR(2134,
			": Laser failed"));
	}
}



/*
 * trans_messages() Display tranceiver status.
 *
 * NOTE: The decoding of the status assumes that the elements
 * are in order with the first two elements are for the
 * "A" IB. It also assumes the tranceivers are numbered
 * 0 and 1.
 *
 * RETURNS:
 *	none.
 */
void
trans_messages(struct l_state_struct *l_state, int ib_a_flag)
{
Trans_elem_st	trans;
int	i, j, k;
int	count = 0;
int	elem_index = 0;

	/* Get and print messages */
	for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) {
	    elem_index++;
	    if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_FL) {

		if (l_state->ib_tbl.config.type_hdr[i].text_len != 0) {
			(void) fprintf(stdout, "\n\t\t%s\n",
			l_state->ib_tbl.config.text[i]);
		}
		count = k = 0;

		for (j = 0; j <
			(int)l_state->ib_tbl.config.type_hdr[i].num; j++) {
			/*
			 * Only display the status for the selected IB.
			 */
		    if ((count < 2 && ib_a_flag) ||
				(count >= 2 && !ib_a_flag)) {
			(void) bcopy((const void *)
				&l_state->ib_tbl.p2_s.element[elem_index + j],
				(void *)&trans, sizeof (trans));

			if (k == 0) {
				(void) fprintf(stdout, "\t\t%d ", k);
			} else {
				(void) fprintf(stdout, "\n\t\t%d ", k);
			}
			if (trans.code == S_OK) {
				(void) fprintf(stdout,
				MSGSTR(29, "O.K."));
				revision_msg(l_state, elem_index + j);
			} else if ((trans.code == S_CRITICAL) ||
				(trans.code == S_NONCRITICAL)) {
				(void) fprintf(stdout,
				MSGSTR(2135, "Failed"));
				revision_msg(l_state, elem_index + j);
				trans_decode(&trans);
			} else if (trans.code == S_NOT_INSTALLED) {
				(void) fprintf(stdout,
				MSGSTR(30, "Not Installed"));
			} else if (trans.code == S_NOT_AVAILABLE) {
				(void) fprintf(stdout,
				MSGSTR(34, "Disabled"));
				revision_msg(l_state, elem_index + j);
			} else {
				(void) fprintf(stdout,
				MSGSTR(4, "Unknown status"));
			}
			k++;
		    }
		    count++;
		}
	    }
		/*
		 * Calculate the index to each element.
		 */
		elem_index += l_state->ib_tbl.config.type_hdr[i].num;
	}
	(void) fprintf(stdout, "\n");
}



/*
 * temperature_messages() Display temperature status.
 *
 * RETURNS:
 *	none.
 */
void
temperature_messages(struct l_state_struct *l_state, int rear_flag)
{
Temp_elem_st	temp;
int	i, j, last_ok = 0;
int	all_ok = 1;
int	elem_index = 0;

	/* Get and print messages */
	for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) {
	    elem_index++;	/* skip global */
	    if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_TS) {
		if (!rear_flag) {
		rear_flag = 1;		/* only do front or rear backplane */
		if (l_state->ib_tbl.config.type_hdr[i].text_len != 0) {
			(void) fprintf(stdout, "\t  %s",
			l_state->ib_tbl.config.text[i]);
		}

		/*
		 * Check global status and if not all O.K.
		 * then print individually.
		 */
		(void) bcopy((const void *)&l_state->ib_tbl.p2_s.element[i],
			(void *)&temp, sizeof (temp));
		for (j = 0; j <
			(int)l_state->ib_tbl.config.type_hdr[i].num; j++) {
			(void) bcopy((const void *)
			&l_state->ib_tbl.p2_s.element[elem_index + j],
				(void *)&temp, sizeof (temp));

			if ((j == 0) && (temp.code == S_OK) &&
				(!(temp.ot_fail || temp.ot_warn ||
					temp.ut_fail || temp.ut_warn))) {
				(void) fprintf(stdout, "\n\t  %d", j);
			} else if ((j == 6) && (temp.code == S_OK) &&
				all_ok) {
				(void) fprintf(stdout, "\n\t  %d", j);
			} else if (last_ok && (temp.code == S_OK)) {
				(void) fprintf(stdout, "%d", j);
			} else {
				(void) fprintf(stdout, "\n\t\t%d", j);
			}
			if (temp.code == S_OK) {
				disp_degree(&temp);
				if (temp.ot_fail || temp.ot_warn ||
					temp.ut_fail || temp.ut_warn) {
					temp_decode(&temp);
					all_ok = 0;
					last_ok = 0;
				} else {
					last_ok++;
				}
			} else if (temp.code == S_CRITICAL) {
				(void) fprintf(stdout,
				MSGSTR(122, "Critical failure"));
				last_ok = 0;
				all_ok = 0;
			} else if (temp.code == S_NONCRITICAL) {
				(void) fprintf(stdout,
				MSGSTR(89, "Non-Critical Failure"));
				last_ok = 0;
				all_ok = 0;
			} else if (temp.code == S_NOT_INSTALLED) {
				(void) fprintf(stdout,
				MSGSTR(30, "Not Installed"));
				last_ok = 0;
				all_ok = 0;
			} else if (temp.code == S_NOT_AVAILABLE) {
				(void) fprintf(stdout,
				MSGSTR(34, "Disabled"));
				last_ok = 0;
				all_ok = 0;
			} else {
				(void) fprintf(stdout,
				MSGSTR(4, "Unknown status"));
				last_ok = 0;
				all_ok = 0;
			}
		}
		if (all_ok) {
			(void) fprintf(stdout,
			MSGSTR(2136, " (All temperatures are "
			"NORMAL.)"));
		}
		all_ok = 1;
		(void) fprintf(stdout, "\n");
	    } else {
		rear_flag = 0;
	    }
	    }
	    elem_index += l_state->ib_tbl.config.type_hdr[i].num;
	}
}



/*
 * ib_decode() Display IB byte 3 state.
 *
 * RETURNS:
 *	none.
 */
void
ib_decode(Ctlr_elem_st *ctlr)
{
	if (ctlr->overtemp_alart) {
		(void) fprintf(stdout, MSGSTR(2137,
			" - IB Over Temperature Alert "));
	}
	if (ctlr->ib_loop_1_fail) {
		(void) fprintf(stdout, MSGSTR(2138,
			" - IB Loop 1 has failed "));
	}
	if (ctlr->ib_loop_0_fail) {
		(void) fprintf(stdout, MSGSTR(2139,
			" - IB Loop 0 has failed "));
	}
}



/*
 * mb_messages() Display motherboard
 * (interconnect assembly) messages.
 *
 * RETURNS:
 *	none.
 */
void
mb_messages(struct l_state_struct *l_state, int index, int elem_index)
{
int		j;
Interconnect_st	interconnect;

	if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) {
		(void) fprintf(stdout, "%s\n",
		l_state->ib_tbl.config.text[index]);
	}
	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num;
			j++) {
		(void) bcopy((const void *)
			&l_state->ib_tbl.p2_s.element[elem_index + j],
			(void *)&interconnect, sizeof (interconnect));
		(void) fprintf(stdout, "\t");

		if (interconnect.code == S_OK) {
			(void) fprintf(stdout,
			MSGSTR(29, "O.K."));
			revision_msg(l_state, elem_index + j);
		} else if (interconnect.code == S_NOT_INSTALLED) {
			(void) fprintf(stdout,
			MSGSTR(30, "Not Installed"));
		} else if (interconnect.code == S_CRITICAL) {
			if (interconnect.eprom_fail != NULL) {
				(void) fprintf(stdout, MSGSTR(2140,
					"Critical Failure: EEPROM failure"));
			} else {
				(void) fprintf(stdout, MSGSTR(2141,
					"Critical Failure: Unknown failure"));
			}
			revision_msg(l_state, elem_index + j);
		} else if (interconnect.code == S_NONCRITICAL) {
			if (interconnect.eprom_fail != NULL) {
				(void) fprintf(stdout, MSGSTR(2142,
				"Non-Critical Failure: EEPROM failure"));
			} else {
				(void) fprintf(stdout, MSGSTR(2143,
				"Non-Critical Failure: Unknown failure"));
			}
			revision_msg(l_state, elem_index + j);
		} else if (interconnect.code == S_NOT_AVAILABLE) {
			(void) fprintf(stdout,
			MSGSTR(34, "Disabled"));
			revision_msg(l_state, elem_index + j);
		} else {
			(void) fprintf(stdout,
			MSGSTR(4, "Unknown status"));
		}
		(void) fprintf(stdout, "\n");
	}


}



/*
 * back_plane_messages() Display back_plane messages
 * including the temperature's.
 *
 * RETURNS:
 *	none.
 */
void
back_plane_messages(struct l_state_struct *l_state, int index, int elem_index)
{
Bp_elem_st	bp;
int		j;
char		status_string[MAXPATHLEN];

	if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) {
		(void) fprintf(stdout, "%s\n",
		l_state->ib_tbl.config.text[index]);
	}
	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num;
			j++) {
		(void) bcopy((const void *)
			&l_state->ib_tbl.p2_s.element[elem_index + j],
			(void *)&bp, sizeof (bp));
		if (j == 0) {
			(void) fprintf(stdout,
				MSGSTR(2144, "\tFront Backplane: "));
		} else {
			(void) fprintf(stdout,
				MSGSTR(2145, "\tRear Backplane:  "));
		}

		(void) l_element_msg_string(bp.code, status_string);
		(void) fprintf(stdout, "%s", status_string);

		if (bp.code != S_NOT_INSTALLED) {
			revision_msg(l_state, elem_index + j);
			if ((bp.byp_a_enabled || bp.en_bypass_a) &&
				!(bp.byp_b_enabled || bp.en_bypass_b)) {
				(void) fprintf(stdout, " (");
				(void) fprintf(stdout,
				MSGSTR(130, "Bypass A enabled"));
				(void) fprintf(stdout, ")");
			} else if ((bp.byp_b_enabled || bp.en_bypass_b) &&
				!(bp.byp_a_enabled || bp.en_bypass_a)) {
				(void) fprintf(stdout, " (");
				(void) fprintf(stdout,
				MSGSTR(129, "Bypass B enabled"));
				(void) fprintf(stdout, ")");
			/* This case covers where a and b are bypassed */
			} else if (bp.byp_b_enabled || bp.en_bypass_b) {
				(void) fprintf(stdout,
				MSGSTR(2146, " (Bypass's A & B enabled)"));
			}
			(void) fprintf(stdout, "\n");
			temperature_messages(l_state, j);
		} else {
			(void) fprintf(stdout, "\n");
		}
	}
}


/*
 * dpm_SSC100_messages() Display SSC100 messages
 * including the temperature's.
 *
 * RETURNS:
 *	none.
 */
void
dpm_SSC100_messages(struct l_state_struct *l_state, int index, int elem_index)
{
Bp_elem_st	bp;
int		j;
char		status_string[MAXPATHLEN];

	if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) {
		(void) fprintf(stdout, "%s\n",
		l_state->ib_tbl.config.text[index]);
	}
	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num;
			j++) {
		(void) bcopy((const void *)
			&l_state->ib_tbl.p2_s.element[elem_index + j],
			(void *)&bp, sizeof (bp));
		(void) fprintf(stdout, MSGSTR(2246, "    SSC100 #%d:    "), j);

		(void) l_element_msg_string(bp.code, status_string);
		(void) fprintf(stdout, "%s", status_string);

		if (bp.code != S_NOT_INSTALLED) {
			revision_msg(l_state, elem_index + j);
			if ((bp.byp_a_enabled || bp.en_bypass_a) &&
				!(bp.byp_b_enabled || bp.en_bypass_b)) {
				(void) fprintf(stdout, " (");
				(void) fprintf(stdout,
				MSGSTR(130, "Bypass A enabled"));
				(void) fprintf(stdout, ")");
			} else if ((bp.byp_b_enabled || bp.en_bypass_b) &&
				!(bp.byp_a_enabled || bp.en_bypass_a)) {
				(void) fprintf(stdout, " (");
				(void) fprintf(stdout,
				MSGSTR(129, "Bypass B enabled"));
				(void) fprintf(stdout, ")");
			/* This case covers where a and b are bypassed */
			} else if (bp.byp_b_enabled || bp.en_bypass_b) {
				(void) fprintf(stdout,
				MSGSTR(2146, " (Bypass's A & B enabled)"));
			}
			(void) fprintf(stdout, "\n");
		} else {
			(void) fprintf(stdout, "\n");
		}
	}
	temperature_messages(l_state, 0);
}




/*
 * loop_messages() Display loop messages.
 *
 * RETURNS:
 *	none.
 */
void
loop_messages(struct l_state_struct *l_state, int index, int elem_index)
{
Loop_elem_st	loop;
int		j;

	if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) {
		(void) fprintf(stdout, "%s\n",
		l_state->ib_tbl.config.text[index]);
	}
	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num;
			j++) {
		(void) bcopy((const void *)
			&l_state->ib_tbl.p2_s.element[elem_index + j],
			(void *)&loop, sizeof (loop));

		(void) fprintf(stdout, "\t");
		if (j == 0) {
			if (loop.code == S_NOT_INSTALLED) {
				(void) fprintf(stdout,
				MSGSTR(2147, "Loop A is not installed"));
			} else {
				if (loop.split) {
					(void) fprintf(stdout, MSGSTR(2148,
				"Loop A is configured as two separate loops."));
				} else {
					(void) fprintf(stdout, MSGSTR(2149,
				"Loop A is configured as a single loop."));
				}
			}
		} else {
			if (loop.code == S_NOT_INSTALLED) {
				(void) fprintf(stdout,
				MSGSTR(2150, "Loop B is not installed"));
			} else {
				if (loop.split) {
					(void) fprintf(stdout, MSGSTR(2151,
				"Loop B is configured as two separate loops."));
				} else {
					(void) fprintf(stdout, MSGSTR(2152,
				"Loop B is configured as a single loop."));
				}
			}
		}
		(void) fprintf(stdout, "\n");
	}
}



/*
 * ctlr_messages() Display ESI Controller status.
 *
 * RETURNS:
 *	none.
 */
void
ctlr_messages(struct l_state_struct *l_state, int index, int elem_index)
{
Ctlr_elem_st	ctlr;
int		j;
int		ib_a_flag = 1;

	if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) {
		(void) fprintf(stdout, "%s\n",
		l_state->ib_tbl.config.text[index]);
	}
	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num;
			j++) {
		(void) bcopy((const void *)
			&l_state->ib_tbl.p2_s.element[elem_index + j],
			(void *)&ctlr, sizeof (ctlr));
		if (j == 0) {
			(void) fprintf(stdout, MSGSTR(2153, "\tA: "));
		} else {
			(void) fprintf(stdout, MSGSTR(2154, "\tB: "));
			ib_a_flag = 0;
		}
		if (ctlr.code == S_OK) {
			(void) fprintf(stdout, MSGSTR(29, "O.K."));
			/* If any byte 3 bits set display */
			ib_decode(&ctlr);
			/* Display Version message */
			revision_msg(l_state, elem_index + j);
			/*
			 * Display the tranciver module state for this
			 * IB.
			 */
			trans_messages(l_state, ib_a_flag);
		} else if (ctlr.code == S_CRITICAL) {
			(void) fprintf(stdout,
			MSGSTR(122, "Critical failure"));
			ib_decode(&ctlr);
			(void) fprintf(stdout, "\n");
		} else if (ctlr.code == S_NONCRITICAL) {
			(void) fprintf(stdout,
			MSGSTR(89, "Non-Critical Failure"));
			ib_decode(&ctlr);
			(void) fprintf(stdout, "\n");
		} else if (ctlr.code == S_NOT_INSTALLED) {
			(void) fprintf(stdout,
			MSGSTR(30, "Not Installed"));
			(void) fprintf(stdout, "\n");
		} else if (ctlr.code == S_NOT_AVAILABLE) {
			(void) fprintf(stdout,
			MSGSTR(34, "Disabled"));
			(void) fprintf(stdout, "\n");
		} else {
			(void) fprintf(stdout,
			MSGSTR(4, "Unknown status"));
			(void) fprintf(stdout, "\n");
		}
	}
}



/*
 * fan_decode() Display Fans bytes 1-3 state.
 *
 * RETURNS:
 *	none.
 */
void
fan_decode(Fan_elem_st *fan)
{
	if (fan->fail) {
		(void) fprintf(stdout, MSGSTR(2155,
			":Yellow LED is on"));
	}
	if (fan->speed == 0) {
		(void) fprintf(stdout, MSGSTR(2156,
			":Fan stopped"));
	} else if (fan->speed < S_HI_SPEED) {
		(void) fprintf(stdout, MSGSTR(2157,
			":Fan speed Low"));
	} else {
		(void) fprintf(stdout, MSGSTR(2158,
			":Fan speed Hi"));
	}
}

/*
 * fan_messages() Display Fan status.
 *
 * RETURNS:
 *	none.
 */
void
fan_messages(struct l_state_struct *l_state, int hdr_index, int elem_index)
{
Fan_elem_st	fan;
int	j;

	/* Get and print messages */
	if (l_state->ib_tbl.config.type_hdr[hdr_index].text_len != 0) {
		(void) fprintf(stdout, "%s\n",
		l_state->ib_tbl.config.text[hdr_index]);
	}
	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[hdr_index].num;
			j++) {
		(void) bcopy((const void *)
			&l_state->ib_tbl.p2_s.element[elem_index + j],
			(void *)&fan, sizeof (fan));
		(void) fprintf(stdout, "\t%d ", j);
		if (fan.code == S_OK) {
			(void) fprintf(stdout, MSGSTR(29, "O.K."));
			revision_msg(l_state, elem_index + j);
		} else if (fan.code == S_CRITICAL) {
			(void) fprintf(stdout,
			MSGSTR(122, "Critical failure"));
			fan_decode(&fan);
			revision_msg(l_state, elem_index + j);
		} else if (fan.code == S_NONCRITICAL) {
			(void) fprintf(stdout,
			MSGSTR(89, "Non-Critical Failure"));
			fan_decode(&fan);
			revision_msg(l_state, elem_index + j);
		} else if (fan.code == S_NOT_INSTALLED) {
			(void) fprintf(stdout,
			MSGSTR(30, "Not Installed"));
		} else if (fan.code == S_NOT_AVAILABLE) {
			(void) fprintf(stdout,
			MSGSTR(34, "Disabled"));
			revision_msg(l_state, elem_index + j);
		} else {
			(void) fprintf(stdout,
			MSGSTR(4, "Unknown status"));
		}
	}
	(void) fprintf(stdout, "\n");
}



/*
 * ps_decode() Display Power Supply bytes 1-3 state.
 *
 * RETURNS:
 *	none.
 */
void
ps_decode(Ps_elem_st *ps)
{
	if (ps->dc_over) {
		(void) fprintf(stdout, MSGSTR(2159,
			": DC Voltage too high"));
	}
	if (ps->dc_under) {
		(void) fprintf(stdout, MSGSTR(2160,
			": DC Voltage too low"));
	}
	if (ps->dc_over_i) {
		(void) fprintf(stdout, MSGSTR(2161,
			": DC Current too high"));
	}
	if (ps->ovrtmp_fail || ps->temp_warn) {
		(void) fprintf(stdout, MSGSTR(2162,
			": Temperature too high"));
	}
	if (ps->ac_fail) {
		(void) fprintf(stdout, MSGSTR(2163,
			": AC Failed"));
	}
	if (ps->dc_fail) {
		(void) fprintf(stdout, MSGSTR(2164,
			": DC Failed"));
	}
}



/*
 * revision_msg() Print the revision message from page 7.
 *
 * RETURNS:
 *	none.
 */
void
revision_msg(struct l_state_struct *l_state, int index)
{
	if (strlen((const char *)
		l_state->ib_tbl.p7_s.element_desc[index].desc_string)) {
		(void) fprintf(stdout, "(%s)",
		l_state->ib_tbl.p7_s.element_desc[index].desc_string);
	}
}



/*
 * ps_messages() Display Power Supply status.
 *
 * RETURNS:
 *	none.
 */
void
ps_messages(struct l_state_struct *l_state, int	index, int elem_index)
{
Ps_elem_st	ps;
int	j;

	/* Get and print Power Supply messages */

	if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) {
		(void) fprintf(stdout, "%s\n",
		l_state->ib_tbl.config.text[index]);
	}

	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num;
		j++) {
		(void) bcopy((const void *)
			&l_state->ib_tbl.p2_s.element[elem_index + j],
			(void *)&ps, sizeof (ps));
		(void) fprintf(stdout, "\t%d ", j);
		if (ps.code == S_OK) {
			(void) fprintf(stdout, MSGSTR(29, "O.K."));
			revision_msg(l_state, elem_index + j);
		} else if (ps.code == S_CRITICAL) {
			(void) fprintf(stdout,
			MSGSTR(122, "Critical failure"));
			ps_decode(&ps);
			revision_msg(l_state, elem_index + j);
		} else if (ps.code == S_NONCRITICAL) {
			(void) fprintf(stdout,
			MSGSTR(89, "Non-Critical Failure"));
			ps_decode(&ps);
			revision_msg(l_state, elem_index + j);
		} else if (ps.code == S_NOT_INSTALLED) {
			(void) fprintf(stdout,
			MSGSTR(30, "Not Installed"));
		} else if (ps.code == S_NOT_AVAILABLE) {
			(void) fprintf(stdout,
			MSGSTR(34, "Disabled"));
			revision_msg(l_state, elem_index + j);
		} else {
			(void) fprintf(stdout,
			MSGSTR(4, "Unknown status"));
		}

	}
	(void) fprintf(stdout, "\n");
}



/*
 * abnormal_condition() Display any abnormal condition messages.
 *
 * RETURNS:
 *	none.
 */
void
abnormal_condition_display(struct l_state_struct *l_state)
{

	(void) fprintf(stdout, "\n");
	if (l_state->ib_tbl.p2_s.ui.crit) {
		(void) fprintf(stdout,
			MSGSTR(2165, "                         "
			"CRITICAL CONDITION DETECTED\n"));
	}
	if (l_state->ib_tbl.p2_s.ui.non_crit) {
		(void) fprintf(stdout,
			MSGSTR(2166, "                   "
			"WARNING: NON-CRITICAL CONDITION DETECTED\n"));
	}
	if (l_state->ib_tbl.p2_s.ui.invop) {
		(void) fprintf(stdout,
			MSGSTR(2167, "                      "
			"WARNING: Invalid Operation bit set.\n"
			"\tThis means an Enclosure Control page"
			" or an Array Control page with an invalid\n"
			"\tformat has previously been transmitted to the"
			" Enclosure Services card by a\n\tSend Diagnostic"
			" SCSI command.\n"));
	}
	(void) fprintf(stdout, "\n");
}





/*
 * adm_start() Spin up the given list
 * of SENA devices.
 *
 * RETURNS:
 *	none.
 */
int
adm_start(char **argv)
{
char		*path_phys = NULL;
Path_struct	*path_struct;
int		err = 0, retval = 0;

	while (*argv != NULL) {
		if ((err = l_convert_name(*argv, &path_phys,
			&path_struct, Options & PVERBOSE)) != 0) {
			(void) fprintf(stderr, MSGSTR(33,
				" Error: converting"
				" %s to physical path.\n"
				" Invalid pathname.\n"),
				*argv);
		if (err != -1) {
			(void) print_errString(err, *argv);
		}
		(argv)++;
		retval++;
		continue;
	    }
	    VERBPRINT(MSGSTR(101, "Issuing start to:\n %s\n"), *argv);
	    if (err = g_start(path_phys))  {
		(void) print_errString(err, *argv);
		(argv)++;
		retval++;
		continue;
	    }
	    (argv)++;
	}
	return (retval);
}



/*
 * adm_stop() Spin down a
 * given list of SENA devices.
 *
 * RETURNS:
 *	none.
 */
int
adm_stop(char **argv)
{
char		*path_phys = NULL;
Path_struct	*path_struct;
int		err = 0, retval = 0;

	while (*argv != NULL) {
		if ((err = l_convert_name(*argv, &path_phys,
		    &path_struct, Options & PVERBOSE)) != 0) {
			(void) fprintf(stderr,
			    MSGSTR(33,
			    " Error: converting"
			    " %s to physical path.\n"
			    " Invalid pathname.\n"),
			    *argv);
			if (err != -1) {
				(void) print_errString(err, *argv);
			}
			(argv)++;
			retval++;
			continue;
		}

		/*
		 * scsi stop is not supported for tape drives.
		 * The scsi unload op code for tape is the same as a
		 * scsi stop for disk so this command will eject the tape.
		 * If an eject is the desired behavior then remove the
		 * following if block. ('mt offline' will give you
		 * the same eject functionality).
		 */
		if (strstr(path_phys, SLSH_DRV_NAME_ST)) {
			errno = ENOTSUP;
			(void) print_errString(0, path_phys);
			(argv)++;
			continue;
		}

		VERBPRINT(MSGSTR(100, "Issuing stop to:\n %s\n"), *argv);
			if (err = g_stop(path_phys, 1))  {
			(void) print_errString(err, *argv);
			(argv)++;
			retval++;
			continue;
		}
		(argv)++;
	}
	return (retval);
}


/*
 * On a SOC+ chip, the port is either put into (offline) or pulled out
 * of (online) a loopback mode since the laser cannot be turned on or off.
 * As of this writing, this feature is yet to be supported by the ifp
 * driver on a QLogic card.
 *
 * INPUT :
 *	Command line args and flag - LUX_P_ONLINE or LUX_P_OFFLINE
 *	The path that is passed has to be the physical path to the port.
 *	For example :
 *	/devices/sbus@2,0/SUNW,socal@2,0:0
 *	/devices/io-unit@f,e0200000/sbi@0,0/SUNW,socal@2,0:0
 *	/devices/pci@1f,4000/SUNW,ifp@2:devctl
 * RETURNS :
 *	Nothing
 */
int
adm_port_offline_online(char *argv[], int flag)
{
	int		err, retval = 0;
	char		*path_phys = NULL;
	char		*nexus_path_ptr = NULL;
	Path_struct	*path_struct = NULL;

	while (*argv != NULL) {
		if ((err = l_convert_name(*argv, &path_phys,
			&path_struct, Options & PVERBOSE)) != 0) {
			(void) fprintf(stderr,
				MSGSTR(33,
					" Error: converting"
					" %s to physical path.\n"
					" Invalid pathname.\n"),
				*argv);
			if (err != -1) {
				(void) print_errString(err, *argv);
			}
			argv++;
			retval++;
			continue;
		}

		/* Get the nexus path - need this to print messages */
		if ((err = g_get_nexus_path(path_phys, &nexus_path_ptr)) != 0) {
			(void) print_errString(err, *argv);
			retval++;
			goto cleanup_and_go;
		}

		if (flag == LUX_P_OFFLINE) {
			if ((err = g_port_offline(nexus_path_ptr))) {
				(void) print_errString(err, nexus_path_ptr);
				retval++;
				goto cleanup_and_go;
			}
			fprintf(stdout,
				MSGSTR(2223, "Port %s has been disabled\n"),
					nexus_path_ptr);
		} else if (flag == LUX_P_ONLINE) {
			if ((err = g_port_online(nexus_path_ptr))) {
				(void) print_errString(err, nexus_path_ptr);
				retval++;
				goto cleanup_and_go;
			}
			fprintf(stdout,
				MSGSTR(2224, "Port %s has been enabled\n"),
					nexus_path_ptr);
		} else {
			(void) fprintf(stderr,
					MSGSTR(2225,
					"Unknown action requested "
					"on port - %d\nIgnoring."),
					flag);
			retval++;
		}
cleanup_and_go:
		free(path_phys);
		free(path_struct);
		free(nexus_path_ptr);
		argv++;
	}
	return (retval);
}

/*
 * Expert level subcommand 'luxadm -e port'
 * which displays all FC ports on a host and state information for
 * connectivity (CONNECTED or NOT CONNECTED) indicating whether there
 * are devices attached to the port.
 *
 * Sample output for ifp:
 *
 * /devices/pci@1f,4000/SUNW,ifp@2:devctl 		CONNECTED
 * /devices/pci@1f,2000/SUNW,ifp@1:devctl		NOT CONNECTED
 *
 * Sample output for socal:
 *
 * /devices/sbus@2,0/SUNW,socal@d,10000:0               CONNECTED
 * /devices/sbus@2,0/SUNW,socal@d,10000:1               NOT CONNECTED
 * /devices/sbus@2,0/SUNW,socal@2,0:0                   NOT CONNECTED
 * /devices/sbus@2,0/SUNW,socal@2,0:1                   CONNECTED
 *
 * Note: for socal the path returned is not a devctl path as there is no
 * devctl path for socal.
 *
 * Sample output for fp:
 *
 * /devices/sbus@2,0/SUNW,qlc@5/fp@0,0:devctl        CONNECTED
 * /devices/sbus@2,0/SUNW,qlc@4/fp@1,0:devctl        CONNECTED
 */
int
adm_display_port(int verbose)
{
	/*
	 * If another port driver needs to be searched, add it here
	 */
	static char *portdrvr_list[] = {"socal",
					"fp",
					"ifp",
					NULL};
	portlist_t portlist;
	int x = 0, err = 0, retval = 0;
	int port_state;

	portlist.hbacnt = 0;

	/*
	 * Look for all HBA ports as listed in portdrvr_list[]
	 */
	while (portdrvr_list[x]) {
		if (err = g_get_port_path(portdrvr_list[x], &portlist)) {
			if (err != L_PORT_DRIVER_NOT_FOUND &&
			    err != L_PHYS_PATH_NOT_FOUND) {
				(void) print_errString(err, portdrvr_list[x]);
				retval++;
			}
		}
		x++;
	}


	/*
	 * For each port path found get the connection state.
	 * If there are devices attached the state is considered connected.
	 */
	for (x = 0; x < portlist.hbacnt; x++) {
		if (err = g_get_port_state(portlist.physpath[x],
			    &port_state, verbose)) {
			(void) print_errString(err, portlist.physpath[x]);
			retval++;
		} else {
			fprintf(stdout, "%-65s  ", portlist.physpath[x]);
			if (port_state == PORT_CONNECTED) {
				(void) fprintf(stdout,
						MSGSTR(2233,
						"CONNECTED\n"));
			} else {
				(void) fprintf(stdout,
						MSGSTR(2234,
						"NOT CONNECTED\n"));
			}
		}
	}
	g_free_portlist(&portlist);
	return (retval);
}

/*
 * Expert level subcommand 'luxadm -e external_loopback <portpath>
 *				      internal_loopback
 *				      no_loopback
 * Does just what you would think. Sets port in designated loopback
 * mode.
 * INPUT:  portpath - path to device on which to set loopback mode
 *	   flag     - loopback mode to set. Values are:
 *			EXT_LOOPBACK
 *			INT_LOOPBACK
 *			NO_LOOPBACK
 *
 * RETURN: 0 on success
 *         non-zero on failure
 */
int
adm_port_loopback(char *portpath, int flag)
{
	int		err;
	char		*path_phys = NULL;
	Path_struct	*path_struct = NULL;
	int		cmd;

	if ((err = l_convert_name(portpath, &path_phys,
		&path_struct, Options & PVERBOSE)) != 0) {
		(void) fprintf(stderr,
			MSGSTR(33,
				" Error: converting"
				" %s to physical path.\n"
				" Invalid pathname.\n"),
			portpath);
		if (err != -1) {
			(void) print_errString(err, portpath);
		}
		return (-1);
	}

	switch (flag) {
		case EXT_LOOPBACK:
			cmd = EXT_LPBACK;
			break;
		case INT_LOOPBACK:
			cmd = INT_LPBACK;
			break;
		case NO_LOOPBACK:
			cmd = NO_LPBACK;
			break;
		default:
			(void) fprintf(stderr,
					MSGSTR(2225,
					"Unknown action requested "
					"on port - %d\nIgnoring."),
					flag);
			free(path_phys);
			free(path_struct);
			return (-1);
	}


	if ((err = g_loopback_mode(path_phys, cmd)) != 0) {
		(void) print_errString(err, portpath);
		free(path_phys);
		free(path_struct);
		return (-1);
	} else {
		switch (flag) {
			case EXT_LOOPBACK:
				(void) fprintf(stdout,
						MSGSTR(2230,
						"External loopback mode set "
						"on:\n%s\n"),
						portpath);
				break;
			case INT_LOOPBACK:
				(void) fprintf(stdout,
						MSGSTR(2231,
						"Internal loopback mode set "
						"on:\n%s\n"),
						portpath);
				break;
			case NO_LOOPBACK:
				(void) fprintf(stdout,
						MSGSTR(2232,
						"Loopback mode unset "
						"on:\n%s\n"),
						portpath);
				break;
			default:
				fprintf(stderr,
					MSGSTR(2248, "Undefined command\n"));
				break;
		}
	}
	free(path_phys);
	free(path_struct);
	return (0);
}



/*
 * To print the pathlist and mpxio path attributes
 */
void
adm_print_pathlist(char *dev_path)
{
	int		i, pathcnt = 1;
	mp_pathlist_t	pathlist;
	int		retval = 0;
	char		temppath[MAXPATHLEN];
	char		wwns[(WWN_SIZE *2) +1];
	uchar_t		wwn_data[WWN_SIZE];
	int		err;
	int		state, ext_state = 0;
	char	*path_state[5];

	path_state[0] = MSGSTR(2400, "INIT");
	path_state[1] = MSGSTR(2401, "ONLINE");
	path_state[2] = MSGSTR(2402, "STANDBY");
	path_state[3] = MSGSTR(2403, "FAULT");
	path_state[4] = MSGSTR(2404, "OFFLINE");

	(void) strcpy(temppath, dev_path);
	retval = g_get_pathlist(temppath, &pathlist);
	if (retval != 0) {
		(void) print_errString(retval, NULL);
		exit(-1);
	}
	pathcnt = pathlist.path_count;
	for (i = 0; i < pathcnt; i++) {
		(void) fprintf(stdout,
		MSGSTR(2303, "   Controller      \t%s\n"),
			pathlist.path_info[i].path_hba);

		(void) fprintf(stdout,
		MSGSTR(2304, "    Device Address\t\t%s\n"),
			pathlist.path_info[i].path_addr);

		if ((err = get_host_controller_pwwn(
				pathlist.path_info[i].path_hba,
				(uchar_t *)&wwn_data)) != 0) {
			if (err != ENOTSUP) {
				(void) print_errString(err,
					pathlist.path_info[i].path_hba);
				exit(1);
			}
		}

		if (!err) {
			copy_wwn_data_to_str(wwns, wwn_data);
			(void) fprintf(stdout,
			    MSGSTR(2326, "    Host controller port WWN\t%s\n"),
				wwns);
		}

		(void) fprintf(stdout,
		MSGSTR(2305, "    Class\t\t\t%s\n"),
			pathlist.path_info[i].path_class);
		if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
			(void) fprintf(stdout,
			MSGSTR(2306, "    State\t\t\t%s\n"),
			path_state[pathlist.path_info[i].path_state]);
		}
		if ((err = g_stms_get_path_state(dev_path,
				pathlist.path_info[i].path_hba, &state,
				&ext_state)) != 0) {
			(void) print_errString(err,
				pathlist.path_info[i].path_hba);
			exit(1);
		} else {
			if ((ext_state & MDI_PATHINFO_STATE_USER_DISABLE)
				== MDI_PATHINFO_STATE_USER_DISABLE) {
				ext_state = 0;
				fprintf(stdout,
				MSGSTR(2327,
				"    I/Os disabled on this %s path\n\n"),
				path_state[pathlist.path_info[i].path_state]);
			}
		}
	}
	/* Free memory for per path info properties */
	free(pathlist.path_info);
}

/*
 * compare_multipath
 * compares path with all paths in pathlist
 * If there is a match, 0 is returned, otherwise 1 is returned
 */
int
compare_multipath(char *path, struct mplist_struct *pathlist)
{

	while (pathlist != NULL) {
		if (strncmp(path, pathlist->devpath, MAXPATHLEN) == 0) {
			return (0);
		}
		pathlist = pathlist->next;
	}
	return (1);
}

/*
 * lun_display() Prints the
 * information for an individual lun.
 *
 * RETURNS:
 *	none.
 */
static int
lun_display(Path_struct *path_struct, L_inquiry inq_struct, int verbose)
{

char			phys_path[MAXPATHLEN], last_logical_path[MAXPATHLEN];
uchar_t			*pg_buf = NULL;
L_disk_state		l_disk_state;
struct dlist		*mlist;
int			offset, mode_data_avail, err = 0;
Mode_header_10		*mode_header_ptr;
struct mode_page	*pg_hdr;
WWN_list		*wwn_list, *list_start, *wwn_list_ptr;
WWN_list		*wwn_list_find;
int			found = 0;
int			argpwwn = 0, argnwwn = 0;
struct mplist_struct	*mplistp, *mpl, *mpln;
struct dlist		*dlist;



	strcpy(phys_path, path_struct->p_physical_path);
	strcpy(last_logical_path, phys_path);

	mplistp = mpl = mpln = (struct mplist_struct *)NULL;
	/*
	 * Get path to all the FC disk and tape devices.
	 * If there is no slash in the argument in this routine, we assume
	 * it is a wwn argument.
	 */
	if (strstr(path_struct->argv, "/") != NULL) {
		if ((err = g_devices_get_all(&wwn_list)) != 0) {
			return (err);
		}
	} else {
		if ((err = g_get_wwn_list(&wwn_list, verbose)) != 0) {
			return (err);
		}
	}

	g_sort_wwn_list(&wwn_list);

	list_start = wwn_list;

	for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
		wwn_list_ptr = wwn_list_ptr->wwn_next) {
		if (strcasecmp(wwn_list_ptr->port_wwn_s,
			path_struct->argv) == 0) {
			list_start = wwn_list_ptr;
			argpwwn = 1;
			break;
		} else if (strcasecmp(wwn_list_ptr->node_wwn_s,
			path_struct->argv) == 0) {
			list_start = wwn_list_ptr;
			argnwwn = 1;
			break;
		}
	}

	for (wwn_list_ptr = list_start; wwn_list_ptr != NULL;
		wwn_list_ptr = wwn_list_ptr->wwn_next) {


	if (argpwwn) {
		if (strcasecmp(wwn_list_ptr->port_wwn_s,
			path_struct->argv) != 0) {
			continue;
		}
		(void) strcpy(phys_path, wwn_list_ptr->physical_path);
	} else if (argnwwn) {
		if (strstr(wwn_list_ptr->logical_path,
			last_logical_path) != NULL) {
			continue;
		}
		if (strcasecmp(wwn_list_ptr->node_wwn_s,
			path_struct->argv) != 0) {
			continue;
		}
		(void) strcpy(phys_path, wwn_list_ptr->physical_path);
		(void) strcpy(last_logical_path,
			wwn_list_ptr->logical_path);
	}

	if (argnwwn || argpwwn) {
		if (compare_multipath(wwn_list_ptr->logical_path,
			mplistp) == 0) {
			continue;
		}
	}

	mode_data_avail = 0;

	(void) memset(&l_disk_state, 0, sizeof (struct l_disk_state_struct));

	/*
	 * Don't call g_get_multipath if this is a SCSI_VHCI device
	 * dlist gets alloc'ed here to retain the free at the end
	 */
	if (strstr(phys_path, SCSI_VHCI) == NULL) {
		if ((err = g_get_multipath(phys_path,
				    &(l_disk_state.g_disk_state.multipath_list),
				    wwn_list, verbose)) != 0) {
			return (err);
		}

		mlist = l_disk_state.g_disk_state.multipath_list;
		if (mlist == NULL) {
			l_disk_state.l_state_flag = L_NO_PATH_FOUND;
			N_DPRINTF(" lun_display: Error finding"
			    " multiple paths to the disk.\n");
			(void) g_free_wwn_list(&wwn_list);
			return (L_NO_VALID_PATH);
		}
	} else {
		/* Search for match on physical path name */
		for (wwn_list_find = list_start; wwn_list_find != NULL;
		    wwn_list_find = wwn_list_find->wwn_next) {
			if (strncmp(wwn_list_find->physical_path, phys_path,
				    strlen(wwn_list_find->physical_path))
				    == 0) {
				found++;
				break;
			}
		}

		if (!found) {
			return (L_NO_VALID_PATH);
		} else {
			found = 0;
		}

		if ((dlist = (struct dlist *)
			    calloc(1, sizeof (struct dlist))) == NULL) {
			    return (L_MALLOC_FAILED);
		}
		if ((dlist->logical_path = (char *)calloc(1,
			    strlen(wwn_list_find->logical_path) + 1)) == NULL) {
			return (L_MALLOC_FAILED);
		}
		if ((dlist->dev_path = (char *)calloc(1,
			    strlen(phys_path) + 1)) == NULL) {
			return (L_MALLOC_FAILED);
		}
		strncpy(dlist->logical_path, wwn_list_find->logical_path,
		    strlen(wwn_list_find->logical_path));
		strncpy(dlist->dev_path, phys_path, strlen(phys_path));
		l_disk_state.g_disk_state.multipath_list = dlist;
	}

	if (argnwwn || argpwwn) {
		for (mlist = l_disk_state.g_disk_state.multipath_list;
		    mlist != NULL; mlist = mlist->next) {
			/* add the path to the list for compare */
			if ((mpl = (struct mplist_struct *)
				    calloc(1, sizeof (struct mplist_struct)))
			    == NULL) {
				adm_mplist_free(mplistp);
				return (L_MALLOC_FAILED);
			}

			mpl->devpath = (char *)calloc(1, MAXPATHLEN+1);
			if (mpl->devpath == NULL) {
				adm_mplist_free(mplistp);
				return (L_MALLOC_FAILED);
			}
			strncpy(mpl->devpath, mlist->logical_path,
			    strlen(mlist->logical_path));
			if (mplistp == NULL) {
				mplistp = mpln = mpl;
			} else {
				mpln->next = mpl;
				mpln = mpl;
			}
		}
	}

	/* get mode page information for FC device */
	if (l_get_mode_pg(phys_path, &pg_buf, verbose) == 0) {
		mode_header_ptr = (struct mode_header_10_struct *)
					(void *)pg_buf;
		offset = sizeof (struct mode_header_10_struct) +
			mode_header_ptr->bdesc_length;
		pg_hdr = (struct mode_page *)&pg_buf[offset];

		while (offset < (mode_header_ptr->length +
			sizeof (mode_header_ptr->length)) &&
						!mode_data_avail) {
			if (pg_hdr->code == MODEPAGE_CACHING) {
				mode_data_avail++;
				break;
			}
			offset += pg_hdr->length + sizeof (struct mode_page);
			pg_hdr = (struct mode_page *)&pg_buf[offset];
		}
	}

	switch ((inq_struct.inq_dtype & DTYPE_MASK)) {
	case DTYPE_DIRECT:
	    fprintf(stdout, MSGSTR(121, "DEVICE PROPERTIES for disk: %s\n"),
		path_struct->argv);
	    break;
	case DTYPE_SEQUENTIAL: /* Tape */
	    fprintf(stdout, MSGSTR(2249, "DEVICE PROPERTIES for tape: %s\n"),
		path_struct->argv);
	    break;
	default:
	    fprintf(stdout, MSGSTR(2250, "DEVICE PROPERTIES for: %s\n"),
		path_struct->argv);
	    break;
	}

	(void) display_lun_info(l_disk_state, path_struct, pg_hdr,
			mode_data_avail, wwn_list, phys_path);

	(void) g_free_multipath(l_disk_state.g_disk_state.multipath_list);

	if (!(argpwwn || argnwwn)) {
		break;
	}

	} /* End for wwn_list_ptr = list_start... */

	(void) g_free_wwn_list(&wwn_list);
	adm_mplist_free(mplistp);
	return (0);
}

/*
 * display_lun_info() Prints the device specific information
 * for a lun.
 *
 * RETURNS:
 *	none.
 */
void
display_lun_info(L_disk_state l_disk_state, Path_struct *path_struct,
		struct mode_page *pg_hdr, int mode_data_avail, WWN_list
		*wwn_list, char *phys_path)
{
float		lunMbytes;
struct scsi_capacity_16 cap_data;
struct dlist	*mlist;
struct	my_mode_caching	*pg8_buf;
int		err;
L_inquiry	inq;
hrtime_t	start_time, end_time;
char		*envdb = NULL;
int		peripheral_qual;
L_inquiry80	inq80;
size_t		serial_len = sizeof (inq80.inq_serial);

	if ((envdb = getenv("_LUX_T_DEBUG")) != NULL) {
		start_time = gethrtime();
	}

	memset(&cap_data, 0, sizeof (cap_data));

	if (err = g_get_inquiry(phys_path, &inq)) {
	    fprintf(stderr, "\n");
	    print_errString(err, phys_path);
	    fprintf(stderr, "\n");
	    exit(1);
	}

	if (err = g_get_serial_number(phys_path, inq80.inq_serial,
	    &serial_len)) {
		fprintf(stderr, "\n");
		print_errString(err, phys_path);
		fprintf(stderr, "\n");
		exit(1);
	}
	/*
	 * check to see if the peripheral qualifier is zero
	 * if it is non-zero, we will return with an error.
	 */
	peripheral_qual = inq.inq_dtype & ~DTYPE_MASK;
	if (peripheral_qual != DPQ_POSSIBLE) {
		fprintf(stderr, MSGSTR(2254, "\n Error: Logical Unit "
			    "(%s) is not available.\n"), phys_path);
		exit(1);
	}

	fprintf(stdout, "  ");
	fprintf(stdout, MSGSTR(3, "Vendor:"));
	fprintf(stdout, "\t\t");
	print_chars(inq.inq_vid, sizeof (inq.inq_vid), 0);
	fprintf(stdout, MSGSTR(2115, "\n  Product ID:\t\t"));
	print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0);

	fprintf(stdout, "\n  ");
	fprintf(stdout, MSGSTR(2119, "Revision:"));
	fprintf(stdout, "\t\t");
	print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0);

	fprintf(stdout, "\n  ");
	fprintf(stdout, MSGSTR(17, "Serial Num:"));
	fprintf(stdout, "\t\t");
	print_chars(inq80.inq_serial, serial_len, 0);

	if ((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) {
		if ((err = get_lun_capacity(phys_path, &cap_data)) != 0) {
			print_errString(err, phys_path);
			exit(1);
		}

		if (cap_data.sc_capacity > 0 && cap_data.sc_lbasize > 0) {
			lunMbytes = cap_data.sc_capacity + 1;
			lunMbytes *= cap_data.sc_lbasize;
			lunMbytes /= (float)(1024*1024);
			fprintf(stdout, "\n  ");
			fprintf(stdout, MSGSTR(60,
			"Unformatted capacity:\t%6.3f MBytes"), lunMbytes);
		}
	}

	fprintf(stdout, "\n");

	if ((mode_data_avail) && (pg_hdr->code == MODEPAGE_CACHING)) {
		pg8_buf = (struct my_mode_caching *)(void *)pg_hdr;
		if (pg8_buf->wce) {
			fprintf(stdout, MSGSTR(2122, "  Write Cache:\t\t"
				"Enabled\n"));
		}
		if (pg8_buf->rcd == 0) {
			fprintf(stdout, MSGSTR(2123, "  Read Cache:\t\t"
				"Enabled\n"));
			fprintf(stdout, MSGSTR(2124, "    Minimum prefetch:"
				"\t0x%x\n    Maximum prefetch:\t0x%x\n"),
				pg8_buf->min_prefetch,
				pg8_buf->max_prefetch);
		}
	}

	fprintf(stdout, "  %s\t\t%s\n", MSGSTR(35, "Device Type:"),
			dtype[inq.inq_dtype & DTYPE_MASK]);


	fprintf(stdout, MSGSTR(2128, "  Path(s):\n"));
	fprintf(stdout, "\n");

	if ((mlist = l_disk_state.g_disk_state.multipath_list) == NULL) {
		fprintf(stderr, MSGSTR(2323, "Error: No paths found (%s)"),
			path_struct->argv);
		exit(1);
	}


	if (strstr(mlist->dev_path, SCSI_VHCI) != NULL) {
		fprintf(stdout, "  %s\n  %s\n",
			mlist->logical_path, mlist->dev_path);
		adm_print_pathlist(mlist->dev_path);
	} else {
		/*
		 * first display user's requested path
		 * This will avoid duplicate inquiries as well
		 */
		for (mlist = l_disk_state.g_disk_state.multipath_list;
			mlist != NULL; mlist = mlist->next) {
		    if ((strcmp(mlist->dev_path, path_struct->p_physical_path))
				== 0) {
			display_path_info(mlist->dev_path, mlist->logical_path,
				wwn_list);
			break;
		    }
		}

		/*
		 * Now display rest of paths
		 * skipping one already displayed
		 */
		for (mlist = l_disk_state.g_disk_state.multipath_list;
			mlist != NULL; mlist = mlist->next) {
		    if ((strcmp(mlist->dev_path, path_struct->p_physical_path))
				== 0) {
			continue;
		    }
		    if (err = g_get_inquiry(mlist->dev_path, &inq)) {
			fprintf(stderr, "\n");
			print_errString(err, mlist->dev_path);
			fprintf(stderr, "\n");
			exit(1);
		    }
		    display_path_info(mlist->dev_path, mlist->logical_path,
				wwn_list);
		}
	}
	fprintf(stdout, "\n");

	if (envdb != NULL) {
		end_time = gethrtime();
		fprintf(stdout, "      display_lun_info: "
		"\t\tTime = %lld millisec\n",
		(end_time - start_time)/1000000);
	}
}

/*
 * display_path_info() Prints the path specific information
 * for a lun.
 * Note: Only applies to ssd nodes currently
 *
 * RETURNS:
 *	none.
 */
static void
display_path_info(char *devpath, char *logicalpath, WWN_list *wwn_list)
{
WWN_list	*wwn_list_walk;
int		err;
uchar_t		wwn_data[WWN_SIZE];
char		wwns[(WWN_SIZE *2) +1];
char		drvr_path[MAXPATHLEN];
char		*cptr;
int		status;

	fprintf(stdout, "  %s\n", logicalpath);
	fprintf(stdout, "  %s\n", devpath);
	fprintf(stdout, "    %s\t\t", MSGSTR(2321, "LUN path port WWN:"));

	/*
	 * Walk the wwn list passed in and print the
	 * port wwn matching the device path
	 */
	for (wwn_list_walk = wwn_list; wwn_list_walk != NULL;
		wwn_list_walk = wwn_list_walk->wwn_next) {
		if (strcmp(wwn_list_walk->physical_path, devpath) == 0) {
			fprintf(stdout, "%s", wwn_list_walk->port_wwn_s);
			break;
		}
	}
	/*
	 * newline here in case port wwn not found
	 */
	fprintf(stdout, "\n");

	drvr_path[0] = '\0';
	(void) strcat(drvr_path, devpath);
	if (((cptr = strstr(drvr_path, SLSH_DRV_NAME_SSD)) != NULL) ||
		((cptr = strstr(drvr_path, SLSH_DRV_NAME_ST)) != NULL)) {;
		*cptr = '\0';
	} else {
		fprintf(stderr, MSGSTR(2324, "Error: Incorrect path (%s)\n"),
				drvr_path);
		exit(1);
	}
	*cptr = '\0';

	if ((err = get_host_controller_pwwn(drvr_path,
			(uchar_t *)&wwn_data)) != 0) {
		print_errString(err, drvr_path);
		exit(1);
	}

	copy_wwn_data_to_str(wwns, wwn_data);
	fprintf(stdout, "    %s\t%s\n",
		MSGSTR(2322, "Host controller port WWN:"), wwns);

	/*
	 * Determine path status
	 */
	if ((err = get_path_status(devpath, &status)) != 0) {
		print_errString(err, devpath);
		exit(1);
	} else {
		fprintf(stdout, "    %s\t\t", MSGSTR(2329, "Path status:"));
		display_port_status(status);
	}
}

/*
 * Retrieves the lun capacity
 */
static int
get_lun_capacity(char *devpath, struct scsi_capacity_16 *cap_data)
{
int	fd;

	if (devpath == NULL || cap_data == NULL) {
		return (L_INVALID_PATH);
	}

	if ((fd = g_object_open(devpath, O_RDONLY | O_NDELAY)) == -1) {
		return (L_OPEN_PATH_FAIL);
	} else {
		(void) g_scsi_read_capacity_1016_cmd(fd, cap_data,
			sizeof (struct scsi_capacity_16));
		close(fd);
	}
	return (0);
}

/*
 * Retrieves the reservation status
 */
static int
get_path_status(char *devpath, int *status)
{
int	fd, mystatus = 0;


	if (devpath == NULL || status == NULL) {
		return (L_INVALID_PATH);
	}

	*status = 0;
	if ((fd = g_object_open(devpath, O_RDONLY | O_NDELAY)) == -1) {
		return (L_OPEN_PATH_FAIL);
	} else {
		if ((mystatus = g_scsi_tur(fd)) != 0) {
			if ((mystatus & L_SCSI_ERROR) &&
				((mystatus & ~L_SCSI_ERROR) == STATUS_CHECK)) {
				*status = L_NOT_READY;
			} else if ((mystatus & L_SCSI_ERROR) &&
				((mystatus & ~L_SCSI_ERROR) ==
					STATUS_RESERVATION_CONFLICT)) {
				*status = L_RESERVED;
			} else {
				*status = L_SCSI_ERR;
			}
		}
	}
	close(fd);
	return (0);
}

/*
 * Description:
 *	Retrieves the port wwn associated with the hba node
 *
 * hba_path: /devices/pci@8,600000/SUNW,qlc@4/fp@0,0
 * pwwn: ptr to a uchar_t array of size WWN_SIZE
 */
static int
get_host_controller_pwwn(char *hba_path, uchar_t *pwwn)
{
char *cptr, *portptr;
int found = 0, err, devlen;
char my_hba_path[MAXPATHLEN];
di_node_t node;
di_prom_prop_t promprop;
uchar_t *port_wwn_data = NULL;
int di_ret;
di_prom_handle_t ph;
char *promname;
uchar_t *promdata;
uint_t path_type;
fc_port_dev_t hba_port;

	if (hba_path == NULL || pwwn == NULL) {
		return (L_INVALID_PATH);
	}

	if ((path_type = g_get_path_type(hba_path)) == 0) {
		return (L_INVALID_PATH);
	}

	/*
	 * ifp nodes do not have a port-wwn prom property
	 * so handle them via FC4 device map
	 */
	if (path_type & FC4_XPORT_MASK) {
		if ((err = get_FC4_host_controller_pwwn(hba_path, pwwn)) != 0) {
			return (err);
		} else {
			return (0);
		}
	/* For Leadville path get the port wwn through g_get_host param. */
	} else if ((path_type & FC_GEN_XPORT) &&
		((path_type & FC_FCA_MASK) == FC_FCA_MASK)) {
		/*
		 * For Leadville path, get the port wwn through
		 * g_get_host param. This is a general solution
		 * to support 3rd party vendor Leadville FCA.
		 */
		my_hba_path[0] = '\0';
		(void) strlcat(my_hba_path, hba_path, sizeof (my_hba_path));
		(void) snprintf(my_hba_path, sizeof (my_hba_path), "%s%s",
			hba_path, FC_CTLR);
		if ((err = g_get_host_params(
			my_hba_path, &hba_port, 0)) != 0) {
			return (err);
		} else {
			(void) memcpy(pwwn, &hba_port.dev_pwwn.raw_wwn[0],
			    WWN_SIZE);
			return (0);
		}
	} else if ((path_type & FC_FCA_MASK) == FC_PCI_FCA) {
		/*
		 * Get port WWN through prom property
		 */
		my_hba_path[0] = '\0';
		(void) strlcat(my_hba_path, hba_path, sizeof (my_hba_path));
		/*
		 * sanity check for /devices mount point
		 */
		if (strlen(my_hba_path) > (devlen = strlen("/devices"))) {
			cptr = &my_hba_path[devlen];
		} else {
			return (L_INVALID_PATH);
		}

		/*
		 * Now strip off the trailing "/fp@"
		 */
		if ((portptr = strstr(cptr, "/fp@")) != NULL) {
			*portptr = '\0';
		}

		if ((node = di_init(cptr, DINFOCPYALL)) == DI_NODE_NIL) {
			return (L_DEV_SNAPSHOT_FAILED);
		}

		if (di_nodeid(node) == DI_SID_NODEID) {
			di_ret = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
				"port-wwn", &port_wwn_data);
			if (di_ret == -1 || port_wwn_data == NULL) {
				di_fini(node);
				return (L_NO_WWN_PROP_FOUND);
			} else {
				(void) memcpy(pwwn, port_wwn_data, WWN_SIZE);
				found++;
			}
		} else if (di_nodeid(node) == DI_PROM_NODEID) {
		    if ((ph = di_prom_init()) == DI_PROM_HANDLE_NIL) {
			di_fini(node);
			return (L_PROM_INIT_FAILED);
		    }

		    for (promprop = di_prom_prop_next(ph, node,
			DI_PROM_PROP_NIL);
			promprop != DI_PROM_PROP_NIL;
			promprop = di_prom_prop_next(ph, node, promprop)) {
			if (((promname = di_prom_prop_name(
				promprop)) != NULL) &&
				(strcmp(promname, "port-wwn") == 0) &&
				(di_prom_prop_data(promprop,
					&promdata) == WWN_SIZE)) {
				/* Found port-wwn */
				(void) memcpy(pwwn, promdata, WWN_SIZE);
				found++;
				break;
			}
		    }
		    di_prom_fini(ph);
		}

		di_fini(node);
		if (found) {
			return (0);
		} else {
			return (L_INVALID_PATH);
		}
	} else {
		return (L_INVALID_PATH_TYPE);
	}
}


/*
 * Description:
 *    Retrieve pwwn via SFIOCGMAP
 */
static int
get_FC4_host_controller_pwwn(char *hba_path, uchar_t *pwwn)
{
sf_al_map_t sf_map;
char my_hba_path[MAXPATHLEN];
int fd;

	if (hba_path == NULL || pwwn == NULL) {
		return (L_INVALID_PATH);
	}

	(void) snprintf(my_hba_path, sizeof (my_hba_path), "%s%s",
			hba_path, FC_CTLR);

	if ((fd = g_object_open(my_hba_path, O_NDELAY | O_RDONLY)) == -1) {
		return (errno);
	}

	memset(&sf_map, 0, sizeof (sf_al_map_t));

	if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
		close(fd);
		return (L_SFIOCGMAP_IOCTL_FAIL);
	}

	close(fd);

	if (sf_map.sf_count == 0) {
		close(fd);
		return (L_SFIOCGMAP_IOCTL_FAIL);
	}

	(void) memcpy(pwwn, &sf_map.sf_hba_addr.sf_port_wwn[0], WWN_SIZE);

	return (0);
}

/*
 * from_ptr: ptr to uchar_t array of size WWN_SIZE
 * to_ptr: char ptr to string of size WWN_SIZE*2+1
 */
void
copy_wwn_data_to_str(char *to_ptr, const uchar_t *from_ptr)
{
	if ((to_ptr == NULL) || (from_ptr == NULL))
		return;

	sprintf(to_ptr, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
	from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
	from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
}

/*
 * Frees a previously allocated mplist_struct
 */
void
adm_mplist_free(struct mplist_struct *mplistp)
{
struct mplist_struct *mplistn;

	while (mplistp != NULL) {
		mplistn = mplistp->next;
		if (mplistp->devpath != NULL) {
			free(mplistp->devpath);
			mplistp->devpath = NULL;
		}
		free(mplistp);
		mplistp = mplistn;
	}
}

int
adm_reserve(char *path)
{
	char	*path_phys = NULL;
	int	err;
	if ((path_phys =
		    g_get_physical_name(path)) == NULL) {

		(void) fprintf(stderr, "%s: ", whoami);
		(void) fprintf(stderr,
			MSGSTR(112, "Error: Invalid pathname (%s)"),
			path);
		(void) fprintf(stderr, "\n");
		return (1);
	}

	if ((err = g_reserve(path_phys)) != 0) {
	    (void) print_errString(err, path);
	    return (1);
	}
	return (0);
}

int
adm_release(char *path)
{
	char	*path_phys = NULL;
	int	err;
	if ((path_phys =
		    g_get_physical_name(path)) == NULL) {

		(void) fprintf(stderr, "%s: ", whoami);
		(void) fprintf(stderr,
			MSGSTR(112, "Error: Invalid pathname (%s)"),
			path);
		(void) fprintf(stderr, "\n");
		return (1);
	}

	if ((err = g_release(path_phys)) != 0) {
	    (void) print_errString(err, path);
	    return (1);
	}
	return (0);
}

void
i18n_catopen() {
    (void) g_i18n_catopen();
}

int adm_check_file(char **path, int flag) {
	int err;
	if (err = l_check_file(*path, flag)) {
	    (void) print_errString(err, *path);
	    return (-1);
	}

	(void) fprintf(stdout, MSGSTR(2212, "Download file O.K. \n\n"));
	return (0);
}

/*
 * Print out private loop dev dtype
 */
void
print_private_loop_dtype_prop(uchar_t *hba_port_wwn, uchar_t *port_wwn,
	uchar_t dtype_prop)
{
	if ((dtype_prop & DTYPE_MASK) < 0x10) {
		(void) fprintf(stdout, " 0x%-2x (%s",
		(dtype_prop & DTYPE_MASK), dtype[(dtype_prop & DTYPE_MASK)]);
	} else if ((dtype_prop & DTYPE_MASK) < 0x1f) {
		(void) fprintf(stdout,
		MSGSTR(2243, " 0x%-2x (Reserved"),
		(dtype_prop & DTYPE_MASK));
	} else {
		(void) fprintf(stdout, MSGSTR(2245,
		" 0x%-2x (Unknown Type"), (dtype_prop & DTYPE_MASK));
	}
	/* Check to see if this is the HBA */
	if (wwnConversion(hba_port_wwn) == wwnConversion(port_wwn)) {
		/* MATCH */
		(void) fprintf(stdout, MSGSTR(2244,
		",Host Bus Adapter)\n"));
	} else {
		(void) fprintf(stdout, ")\n");
	}
}