1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27
28#define	LUX_SF_INST_SHIFT4MINOR 6
29#define	LUX_SF_MINOR2INST(x)    (x >> LUX_SF_INST_SHIFT4MINOR)
30
31#include	<stdlib.h>
32#include	<stdio.h>
33#include	<sys/file.h>
34#include	<sys/errno.h>
35#include	<sys/types.h>
36#include	<sys/stat.h>
37#include	<sys/param.h>
38#include	<kstat.h>
39#include	<sys/mkdev.h>
40#include	<locale.h>
41#include	<nl_types.h>
42#include	<fcntl.h>
43#include	<unistd.h>
44#include	<strings.h>
45#include	<ctype.h>
46#include	<dirent.h>
47#include	<limits.h>
48#include	<stdarg.h>
49#include	<termio.h>		/* For password */
50#include	<signal.h>
51#include	<sys/scsi/scsi.h>
52#include	<sys/scsi/generic/commands.h>
53#include	<l_common.h>
54#include	<l_error.h>
55#include	<stgcom.h>
56#include	<a_state.h>
57#include	<devid.h>
58#include	<g_state.h>
59#include	"common.h"
60
61extern char		*dtype[];
62extern char		*whoami;
63extern	int	Options;
64extern	const	int OPTION_A;
65extern	const	int OPTION_B;
66extern	const	int OPTION_C;
67extern	const	int OPTION_D;
68extern	const	int OPTION_E;
69extern	const	int OPTION_F;
70extern	const	int OPTION_L;
71extern	const	int OPTION_P;
72extern	const	int OPTION_R;
73extern	const	int OPTION_T;
74extern	const	int OPTION_V;
75extern	const	int OPTION_Z;
76extern	const	int OPTION_Y;
77extern	const	int OPTION_CAPF;
78extern	const	int PVERBOSE;
79extern	const	int SAVE;
80extern	const	int EXPERT;
81
82static		struct termios	termios;
83static		int termio_fd;
84static	void	pho_display_config(char *);
85static	void	dpm_display_config(char *);
86static	void	n_rem_list_entry(uchar_t,  struct gfc_map *,
87		WWN_list **);
88static	void	n_rem_list_entry_fabric(int, struct gfc_map *,
89		WWN_list **);
90static	void	n_rem_wwn_entry(uchar_t *, WWN_list **);
91static	void	display_disk_info(L_inquiry, L_disk_state,
92		Path_struct *, struct mode_page *, int, char *, int);
93static	void	display_lun_info(L_disk_state, Path_struct *,
94		struct mode_page *, int, WWN_list *, char *);
95static	void	display_fc_disk(struct path_struct *, char *, gfc_map_t *,
96		L_inquiry, int);
97static	void	adm_display_err(char *, int);
98static	void	temperature_messages(struct l_state_struct *, int);
99static	void	ctlr_messages(struct l_state_struct *, int, int);
100static	void	fan_messages(struct l_state_struct *, int, int);
101static	void	ps_messages(struct l_state_struct *, int, int);
102static	void	abnormal_condition_display(struct l_state_struct *);
103static	void	loop_messages(struct l_state_struct *, int, int);
104static	void	revision_msg(struct l_state_struct *, int);
105static	void	mb_messages(struct l_state_struct *, int, int);
106static	void	back_plane_messages(struct l_state_struct *, int, int);
107static	void	dpm_SSC100_messages(struct l_state_struct *, int, int);
108static	void	mb_messages(struct l_state_struct *, int, int);
109static	void	back_plane_messages(struct l_state_struct *, int, int);
110static	void	dpm_SSC100_messages(struct l_state_struct *, int, int);
111static	void	trans_decode(Trans_elem_st *trans);
112static	void	trans_messages(struct l_state_struct *, int);
113static	void	adm_print_pathlist(char *);
114static	void	display_path_info(char *, char *, WWN_list *);
115static void	copy_wwn_data_to_str(char *, const uchar_t *);
116static void	adm_mplist_free(struct mplist_struct *);
117static int	lun_display(Path_struct *path_struct, L_inquiry inq_struct,
118		int verbose);
119static int	non_encl_fc_disk_display(Path_struct *path_struct,
120		L_inquiry inq_struct, int verbose);
121static int	get_enclStatus(char *phys_path, char *encl_name, int off_flag);
122static int	get_host_controller_pwwn(char *hba_path, uchar_t *pwwn);
123static int	get_lun_capacity(char *devpath,
124		struct scsi_capacity_16 *cap_data);
125static int	get_path_status(char *devpath, int *status);
126static int	get_FC4_host_controller_pwwn(char *hba_path, uchar_t *pwwn);
127
128/*
129 * Gets the device's state from the SENA IB and
130 * checks whether device is offlined, bypassed
131 * or if the slot is empty and prints it to the
132 * stdout.
133 *
134 * RETURNS:
135 *	0	 O.K.
136 *	non-zero otherwise
137 */
138int
139print_devState(char *devname, char *ppath, int fr_flag, int slot,
140						int verbose_flag)
141{
142L_state		l_state;
143int		err;
144int		i, elem_index = 0;
145uchar_t		device_off, ib_status_code, bypass_a_en, bypass_b_en;
146Bp_elem_st	bpf, bpr;
147
148
149	if ((err = l_get_status(ppath, &l_state, verbose_flag)) != 0) {
150		(void) print_errString(err, ppath);
151		return (err);
152	}
153
154	for (i = 0; i <  (int)l_state.ib_tbl.config.enc_num_elem; i++) {
155		elem_index++;
156		if (l_state.ib_tbl.config.type_hdr[i].type == ELM_TYP_BP) {
157			break;
158		}
159		elem_index += l_state.ib_tbl.config.type_hdr[i].num;
160	}
161	(void) bcopy((const void *)
162			&(l_state.ib_tbl.p2_s.element[elem_index]),
163			(void *)&bpf, sizeof (bpf));
164	(void) bcopy((const void *)
165			&(l_state.ib_tbl.p2_s.element[elem_index + 1]),
166			(void *)&bpr, sizeof (bpr));
167
168	if (fr_flag) {
169		device_off = l_state.drv_front[slot].ib_status.dev_off;
170		bypass_a_en = l_state.drv_front[slot].ib_status.bypass_a_en;
171		bypass_b_en = l_state.drv_front[slot].ib_status.bypass_b_en;
172		ib_status_code = l_state.drv_front[slot].ib_status.code;
173	} else {
174		device_off = l_state.drv_rear[slot].ib_status.dev_off;
175		bypass_a_en = l_state.drv_rear[slot].ib_status.bypass_a_en;
176		bypass_b_en = l_state.drv_rear[slot].ib_status.bypass_b_en;
177		ib_status_code = l_state.drv_rear[slot].ib_status.code;
178	}
179	if (device_off) {
180		(void) fprintf(stdout,
181				MSGSTR(2000,
182				"%s is offlined and bypassed.\n"
183				" Could not get device specific"
184				" information.\n\n"),
185				devname);
186	} else if (bypass_a_en && bypass_b_en) {
187		(void) fprintf(stdout,
188				MSGSTR(2001,
189				"%s is bypassed (Port:AB).\n"
190				" Could not get device specific"
191				" information.\n\n"),
192				devname);
193	} else if (ib_status_code == S_NOT_INSTALLED) {
194		(void) fprintf(stdout,
195				MSGSTR(2002,
196				"Slot %s is empty.\n\n"),
197				devname);
198	} else if (((bpf.code != S_NOT_INSTALLED) &&
199		((bpf.byp_a_enabled || bpf.en_bypass_a) &&
200		(bpf.byp_b_enabled || bpf.en_bypass_b))) ||
201		((bpr.code != S_NOT_INSTALLED) &&
202		((bpr.byp_a_enabled || bpr.en_bypass_a) &&
203		(bpr.byp_b_enabled || bpr.en_bypass_b)))) {
204		(void) fprintf(stdout,
205				MSGSTR(2003,
206				"Backplane(Port:AB) is bypassed.\n"
207				" Could not get device specific"
208				" information for"
209				" %s.\n\n"), devname);
210	} else {
211		(void) fprintf(stderr,
212				MSGSTR(33,
213				" Error: converting"
214				" %s to physical path.\n"
215				" Invalid pathname.\n"),
216				devname);
217	}
218	return (-1);
219}
220
221/*
222 * Given an error number, this functions
223 * calls the get_errString() to print a
224 * corresponding error message to the stderr.
225 * get_errString() always returns an error
226 * message, even in case of undefined error number.
227 * So, there is no need to check for a NULL pointer
228 * while printing the error message to the stdout.
229 *
230 * RETURNS: N/A
231 *
232 */
233void
234print_errString(int errnum, char *devpath)
235{
236
237char	*errStr;
238
239	errStr = g_get_errString(errnum);
240
241	if (devpath == NULL) {
242		(void) fprintf(stderr,
243				"%s \n\n", errStr);
244	} else {
245		(void) fprintf(stderr,
246				"%s - %s.\n\n", errStr, devpath);
247	}
248
249	/* free the allocated memory for error string */
250	if (errStr != NULL)
251		(void) free(errStr);
252}
253
254/*
255 * adm_inquiry() Display the inquiry information for
256 * a SENA enclosure(s) or disk(s).
257 *
258 * RETURNS:
259 *	none.
260 */
261int
262adm_inquiry(char **argv)
263{
264L_inquiry	inq;
265L_inquiry80	inq80;
266size_t		serial_len;
267int		path_index = 0, retval = 0;
268int		slot, f_r, err = 0, argpwwn, argnwwn;
269char		inq_path[MAXNAMELEN];
270char		*path_phys = NULL, *ptr;
271Path_struct	*path_struct;
272WWN_list	*wwn_list, *wwn_list_ptr, *list_start;
273char		last_logical_path[MAXPATHLEN];
274
275	while (argv[path_index] != NULL) {
276	    if ((err = l_convert_name(argv[path_index], &path_phys,
277		&path_struct, Options & PVERBOSE)) != 0) {
278		(void) strcpy(inq_path, argv[path_index]);
279		if (((ptr = strstr(inq_path, ",")) != NULL) &&
280			((*(ptr + 1) == 'f') || (*(ptr + 1) == 'r') ||
281			    (*(ptr +1) == 's'))) {
282			if (err != -1) {
283				(void) print_errString(err, argv[path_index]);
284				path_index++;
285				retval++;
286				continue;
287			}
288			*ptr = '\0';
289			slot = path_struct->slot;
290			f_r = path_struct->f_flag;
291			path_phys = NULL;
292			if ((err = l_convert_name(inq_path, &path_phys,
293				&path_struct, Options & PVERBOSE)) != 0) {
294				(void) fprintf(stderr,
295					MSGSTR(33,
296					" Error: converting"
297					" %s to physical path.\n"
298					" Invalid pathname.\n"),
299					argv[path_index]);
300				if (err != -1) {
301					(void) print_errString(err,
302							argv[path_index]);
303				}
304				path_index++;
305				retval++;
306				continue;
307			}
308			if ((err = print_devState(argv[path_index],
309					path_struct->p_physical_path,
310					f_r, slot, Options & PVERBOSE)) != 0) {
311				path_index++;
312				retval++;
313				continue;
314			}
315		} else {
316			if (err != -1) {
317				(void) print_errString(err, argv[path_index]);
318			} else {
319			    (void) fprintf(stderr, "\n ");
320			    (void) fprintf(stderr,
321				MSGSTR(112, "Error: Invalid pathname (%s)"),
322				argv[path_index]);
323			    (void) fprintf(stderr, "\n");
324			}
325		}
326		path_index++;
327		retval++;
328		continue;
329	    }
330
331	    if (strstr(argv[path_index], "/") != NULL) {
332		if (err = g_get_inquiry(path_phys, &inq)) {
333		    (void) fprintf(stderr, "\n");
334		    (void) print_errString(err, argv[path_index]);
335		    (void) fprintf(stderr, "\n");
336		    path_index++;
337		    retval++;
338		    continue;
339		}
340
341		serial_len = sizeof (inq80.inq_serial);
342		if (err = g_get_serial_number(path_phys, inq80.inq_serial,
343		    &serial_len)) {
344		    (void) fprintf(stderr, "\n");
345		    (void) print_errString(err, argv[path_index]);
346		    (void) fprintf(stderr, "\n");
347		    path_index++;
348		    retval++;
349		    continue;
350		}
351		print_inq_data(argv[path_index], path_phys, inq,
352		    inq80.inq_serial, serial_len);
353		path_index++;
354		continue;
355	    }
356	    if ((err = g_get_wwn_list(&wwn_list, 0)) != 0) {
357		return (err);
358	    }
359	    g_sort_wwn_list(&wwn_list);
360	    list_start = wwn_list;
361	    argpwwn = argnwwn = 0;
362	    (void) strcpy(last_logical_path, path_phys);
363	    for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
364		wwn_list_ptr = wwn_list_ptr->wwn_next) {
365		if (strcasecmp(wwn_list_ptr->port_wwn_s, path_struct->argv) ==
366			0) {
367			list_start = wwn_list_ptr;
368			argpwwn = 1;
369			break;
370		} else if (strcasecmp(wwn_list_ptr->node_wwn_s,
371			path_struct->argv) == 0) {
372			list_start = wwn_list_ptr;
373			argnwwn = 1;
374			break;
375		}
376	    }
377
378	    if (!(argpwwn || argnwwn)) {
379		/*
380		 * if the wwn list is null or the arg device not found
381		 * from the wwn list, still go ahead to issue inquiry.
382		 */
383		if (err = g_get_inquiry(path_phys, &inq)) {
384		    (void) fprintf(stderr, "\n");
385		    (void) print_errString(err, argv[path_index]);
386		    (void) fprintf(stderr, "\n");
387		    path_index++;
388		    retval++;
389		    continue;
390		}
391
392		serial_len = sizeof (inq80.inq_serial);
393		if (err = g_get_serial_number(path_phys, inq80.inq_serial,
394		    &serial_len)) {
395		    (void) fprintf(stderr, "\n");
396		    (void) print_errString(err, argv[path_index]);
397		    (void) fprintf(stderr, "\n");
398		    path_index++;
399		    retval++;
400		    continue;
401		}
402		print_inq_data(argv[path_index], path_phys, inq,
403		    inq80.inq_serial, serial_len);
404		(void) g_free_wwn_list(&wwn_list);
405		path_index++;
406		continue;
407	    }
408
409	    for (wwn_list_ptr = list_start; wwn_list_ptr != NULL;
410			wwn_list_ptr = wwn_list_ptr->wwn_next) {
411		if (argpwwn) {
412			if (strcasecmp(wwn_list_ptr->port_wwn_s,
413				path_struct->argv) != 0) {
414				continue;
415			}
416			(void) strcpy(path_phys,
417				wwn_list_ptr->physical_path);
418		} else if (argnwwn) {
419			if (strcasecmp(wwn_list_ptr->node_wwn_s,
420				path_struct->argv) != 0) {
421				continue;
422			}
423			if (strstr(wwn_list_ptr->logical_path,
424				last_logical_path) != NULL) {
425				continue;
426			}
427			(void) strcpy(path_phys,
428				wwn_list_ptr->physical_path);
429			(void) strcpy(last_logical_path,
430				wwn_list_ptr->logical_path);
431		}
432
433		if (err = g_get_inquiry(path_phys, &inq)) {
434		    (void) fprintf(stderr, "\n");
435		    (void) print_errString(err, argv[path_index]);
436		    (void) fprintf(stderr, "\n");
437		    retval++;
438		    break;
439		}
440
441		serial_len = sizeof (inq80.inq_serial);
442		if (err = g_get_serial_number(path_phys, inq80.inq_serial,
443		    &serial_len)) {
444		    (void) fprintf(stderr, "\n");
445		    (void) print_errString(err, argv[path_index]);
446		    (void) fprintf(stderr, "\n");
447		    retval++;
448		    break;
449		}
450		print_inq_data(argv[path_index], path_phys, inq,
451		    inq80.inq_serial, serial_len);
452
453	    }
454
455	    (void) g_free_wwn_list(&wwn_list);
456	    path_index++;
457	}
458	return (retval);
459}
460
461/*
462 *	FORCELIP expert function
463 */
464int
465adm_forcelip(char **argv)
466{
467int		slot, f_r, path_index = 0, err = 0, retval = 0;
468Path_struct	*path_struct = NULL;
469char		*path_phys = NULL, *ptr;
470char		 err_path[MAXNAMELEN];
471
472	while (argv[path_index] != NULL) {
473		if ((err = l_convert_name(argv[path_index], &path_phys,
474				&path_struct, Options & PVERBOSE)) != 0) {
475			(void) strcpy(err_path, argv[path_index]);
476			if (err != -1) {
477				(void) print_errString(err, argv[path_index]);
478				path_index++;
479				retval++;
480				continue;
481			}
482			if (((ptr = strstr(err_path, ", ")) != NULL) &&
483				((*(ptr + 1) == 'f') || (*(ptr + 1) == 'r') ||
484							(*(ptr +1) == 's'))) {
485				*ptr = '\0';
486				slot = path_struct->slot;
487				f_r = path_struct->f_flag;
488				path_phys = NULL;
489				if ((err = l_convert_name(err_path,
490						&path_phys, &path_struct,
491						Options & PVERBOSE)) != 0) {
492					(void) fprintf(stderr, MSGSTR(33,
493						" Error: converting"
494						" %s to physical path.\n"
495						" Invalid pathname.\n"),
496							argv[path_index]);
497					if (err != -1) {
498						(void) print_errString(err,
499							argv[path_index]);
500					}
501					path_index++;
502					retval++;
503					continue;
504				}
505				if ((err = print_devState(argv[path_index],
506					path_struct->p_physical_path,
507					f_r, slot, Options & PVERBOSE)) != 0) {
508					path_index++;
509					retval++;
510					continue;
511				}
512			} else {
513				(void) fprintf(stderr, "\n ");
514				(void) fprintf(stderr, MSGSTR(112,
515					"Error: Invalid pathname (%s)"),
516							argv[path_index]);
517				(void) fprintf(stderr, "\n");
518			}
519			path_index++;
520			retval++;
521			continue;
522		}
523		if (err = g_force_lip(path_phys, Options & PVERBOSE)) {
524			(void) print_errString(err, argv[path_index]);
525			path_index++;
526			retval++;
527			continue;
528		}
529		path_index++;
530		if (path_struct != NULL) {
531			(void) free(path_struct);
532		}
533	}
534	return (retval);
535}
536
537
538/*
539 *	DISPLAY function
540 *
541 * RETURNS:
542 *	0	O.K.
543 */
544int
545adm_display_config(char **argv)
546{
547L_inquiry	inq, ses_inq;
548int		i, slot, f_r, path_index = 0, err = 0, opnerr = 0;
549int		retval = 0;
550gfc_map_t	map;
551Path_struct	*path_struct;
552char		*path_phys = NULL, *ptr;
553char		ses_path[MAXPATHLEN], inq_path[MAXNAMELEN];
554
555
556	while (argv[path_index] != NULL) {
557	    VERBPRINT(MSGSTR(2108, "  Displaying information for: %s\n"),
558			argv[path_index]);
559		map.dev_addr = (gfc_port_dev_info_t *)NULL;
560	    if ((err = l_convert_name(argv[path_index], &path_phys,
561		&path_struct, Options & PVERBOSE)) != 0) {
562		if (strstr(argv[path_index], SCSI_VHCI) == NULL) {
563
564			(void) strcpy(inq_path, argv[path_index]);
565			if (((ptr = strstr(inq_path, ",")) != NULL) &&
566				((*(ptr + 1) == 'f') || (*(ptr + 1) == 'r') ||
567				(*(ptr +1) == 's'))) {
568
569				if (err != -1) {
570					(void) print_errString(err,
571						argv[path_index]);
572					path_index++;
573					retval++;
574					continue;
575				}
576				*ptr = '\0';
577				slot = path_struct->slot;
578				f_r = path_struct->f_flag;
579				if ((err = l_convert_name(inq_path, &path_phys,
580					&path_struct, Options & PVERBOSE))
581					!= 0) {
582
583					(void) fprintf(stderr,
584						MSGSTR(33,
585						" Error: converting"
586						" %s to physical path.\n"
587						" Invalid pathname.\n"),
588						argv[path_index]);
589					if (err != -1) {
590						(void) print_errString(err,
591							argv[path_index]);
592					}
593					path_index++;
594					retval++;
595					continue;
596				}
597
598				if ((err = print_devState(argv[path_index],
599					path_struct->p_physical_path,
600					f_r, slot, Options & PVERBOSE)) != 0) {
601						path_index++;
602						retval++;
603						continue;
604				}
605			} else {
606				if (err != -1) {
607					(void) print_errString(err,
608						argv[path_index]);
609				} else {
610					(void) fprintf(stderr, "\n ");
611					(void) fprintf(stderr,
612						MSGSTR(112,
613					"Error: Invalid pathname (%s)"),
614						argv[path_index]);
615					(void) fprintf(stderr, "\n");
616				}
617			}
618
619		} else {
620			if (err != -1) {
621				(void) print_errString(err,
622					argv[path_index]);
623			} else {
624				(void) fprintf(stderr, "\n ");
625				(void) fprintf(stderr,
626					MSGSTR(112,
627				"Error: Invalid pathname (%s)"),
628					argv[path_index]);
629				(void) fprintf(stderr, "\n");
630			}
631		}
632
633		path_index++;
634		retval++;
635		continue;
636	    }
637
638	/*
639	 * See what kind of device we are talking to.
640	 */
641	if ((opnerr = g_get_inquiry(path_phys, &inq)) != 0) {
642		if (opnerr == L_OPEN_PATH_FAIL) {
643			/*
644			 * We check only for L_OPEN_PATH_FAIL because
645			 * that is the only error code returned by
646			 * g_get_inquiry() which is not got from the ioctl
647			 * call itself. So, we are dependent, in a way, on the
648			 * implementation of g_get_inquiry().
649			 *
650			 */
651			(void) print_errString(errno, argv[path_index]);
652			path_index++;
653			retval++;
654			continue;
655		}
656	    } else if (!g_enclDiskChk((char *)inq.inq_vid,
657			(char *)inq.inq_pid)) {
658		    if ((err = lun_display(path_struct,
659					inq, Options & PVERBOSE)) != 0) {
660			    (void) print_errString(err, path_phys);
661			    exit(1);
662		    }
663	    } else if (strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != NULL) {
664		/*
665		 * Display SENA enclosure.
666		 */
667		(void) fprintf(stdout, "\n\t\t\t\t   ");
668		print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0);
669
670		(void) fprintf(stdout, "\n");
671		if (Options & OPTION_R) {
672			adm_display_err(path_phys,
673			    (inq.inq_dtype & DTYPE_MASK));
674		} else {
675			pho_display_config(path_phys);
676		}
677	    } else if ((((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)) &&
678			(l_get_enc_type(inq) == DAK_ENC_TYPE)) {
679		/*
680		 *  Display for the Daktari/DPM
681		 */
682		(void) fprintf(stdout, "\n\t\t");
683		for (i = 0; i < sizeof (inq.inq_pid); i++) {
684		    (void) fprintf(stdout, "%c", inq.inq_pid[i]);
685		}
686		(void) fprintf(stdout, "\n");
687		if (Options & OPTION_R) {
688		    adm_display_err(path_phys,
689			(inq.inq_dtype & DTYPE_MASK));
690		} else {
691		    dpm_display_config(path_phys);
692		}
693		/*
694		 * if device is in SENA enclosure
695		 *
696		 * if the slot is valid, then I know this is a SENA enclosure
697		 * and can continue
698		 * otherwise:
699		 *	I first get the ses_path, if this doesn't fail
700		 *	I retrieve the inquiry data from the ses node
701		 *	    and check teh PID to make sure this is a SENA
702		 */
703	    } else if (((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) &&
704			((path_struct->slot_valid == 1) ||
705			    ((g_get_dev_map(path_phys, &map,
706				(Options & PVERBOSE)) == 0) &&
707			    (l_get_ses_path(path_phys, ses_path,
708				&map, Options & PVERBOSE) == 0) &&
709			    (g_get_inquiry(ses_path, &ses_inq) == 0) &&
710			    ((strstr((char *)ses_inq.inq_pid, ENCLOSURE_PROD_ID)
711				!= NULL))))) {
712		if (Options & OPTION_R) {
713			adm_display_err(path_phys,
714			(inq.inq_dtype & DTYPE_MASK));
715		} else {
716			display_fc_disk(path_struct, ses_path, &map, inq,
717							Options & PVERBOSE);
718		}
719
720	    } else if (strstr((char *)inq.inq_pid, "SUN_SEN") != 0) {
721			if (strcmp(argv[path_index], path_phys) != 0) {
722				(void) fprintf(stdout, "  ");
723				(void) fprintf(stdout,
724				MSGSTR(5, "Physical Path:"));
725				(void) fprintf(stdout, "\n  %s\n", path_phys);
726			}
727			(void) fprintf(stdout, MSGSTR(2109, "DEVICE is a "));
728			print_chars(inq.inq_vid, sizeof (inq.inq_vid), 1);
729			(void) fprintf(stdout, " ");
730			print_chars(inq.inq_pid, sizeof (inq.inq_pid), 1);
731			(void) fprintf(stdout, MSGSTR(2110, " card."));
732			if (inq.inq_len > 31) {
733				(void) fprintf(stdout, "   ");
734				(void) fprintf(stdout, MSGSTR(26, "Revision:"));
735				(void) fprintf(stdout, " ");
736				print_chars(inq.inq_revision,
737					sizeof (inq.inq_revision), 0);
738			}
739			(void) fprintf(stdout, "\n");
740		/* if device is not in SENA or SSA enclosures. */
741	    } else if ((inq.inq_dtype & DTYPE_MASK) < 0x10) {
742		switch ((inq.inq_dtype & DTYPE_MASK)) {
743			case DTYPE_DIRECT:
744			case DTYPE_SEQUENTIAL: /* Tape */
745				if (Options & OPTION_R) {
746					adm_display_err(path_phys,
747					(inq.inq_dtype & DTYPE_MASK));
748				} else if (non_encl_fc_disk_display(path_struct,
749					inq, Options & PVERBOSE) != 0) {
750					(void) fprintf(stderr,
751						MSGSTR(2111,
752						"Error: getting the device"
753						" information.\n"));
754					retval++;
755				}
756				break;
757			/* case 0x01: same as default */
758			default:
759				(void) fprintf(stdout, "  ");
760				(void) fprintf(stdout, MSGSTR(35,
761						"Device Type:"));
762				(void) fprintf(stdout, "%s\n",
763					dtype[inq.inq_dtype & DTYPE_MASK]);
764				break;
765		}
766	    } else if ((inq.inq_dtype & DTYPE_MASK) < 0x1f) {
767			(void) fprintf(stdout,
768				MSGSTR(2112, "  Device type: Reserved"));
769			(void) fprintf(stdout, "\n");
770	    } else {
771			(void) fprintf(stdout,
772				MSGSTR(2113, "  Device type: Unknown device"));
773			(void) fprintf(stdout, "\n");
774	    }
775	    path_index++;
776	    if (map.dev_addr != NULL) {
777		free((void *)map.dev_addr);
778	    }
779	    (void) free(path_struct);
780	}
781	return (retval);
782}
783
784
785/*
786 * Powers off a list of SENA enclosure(s)
787 * and disk(s) which is provided by the user.
788 *
789 * RETURNS:
790 *	none.
791 */
792int
793adm_power_off(char **argv, int off_flag)
794{
795int		path_index = 0, err = 0, retval = 0;
796L_inquiry	inq;
797char		*path_phys = NULL;
798Path_struct	*path_struct;
799
800	while (argv[path_index] != NULL) {
801		if ((err = l_convert_name(argv[path_index], &path_phys,
802			&path_struct, Options & PVERBOSE)) != 0) {
803			/*
804			 * In case we did not find the device
805			 * in the /devices directory.
806			 *
807			 * Only valid for pathnames like box,f1
808			 */
809			if (path_struct->ib_path_flag) {
810				path_phys = path_struct->p_physical_path;
811			} else {
812				(void) fprintf(stderr,
813					MSGSTR(33,
814				" Error: converting"
815				" %s to physical path.\n"
816				" Invalid pathname.\n"),
817					argv[path_index]);
818				if (err != -1) {
819					(void) print_errString(err,
820							argv[path_index]);
821				}
822				path_index++;
823				retval++;
824				continue;
825			}
826		}
827		if (path_struct->ib_path_flag) {
828			/*
829			 * We are addressing a disk using a path
830			 * format type box,f1.
831			 */
832			if (err = l_dev_pwr_up_down(path_phys,
833			    path_struct, off_flag, Options & PVERBOSE,
834			    Options & OPTION_CAPF)) {
835				/*
836				 * Is it Bypassed... try to give more
837				 * informtaion.
838				 */
839				print_devState(argv[path_index],
840					path_struct->p_physical_path,
841					path_struct->f_flag, path_struct->slot,
842					Options & PVERBOSE);
843				retval++;
844			}
845			path_index++;
846			continue;
847		}
848
849		if (err = g_get_inquiry(path_phys, &inq)) {
850			(void) print_errString(err, argv[path_index]);
851			path_index++;
852			retval++;
853			continue;
854		}
855		if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != 0) ||
856			(strncmp((char *)inq.inq_vid, "SUN     ",
857			sizeof (inq.inq_vid)) &&
858			((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI))) {
859
860			if (get_enclStatus(path_phys, argv[path_index],
861						off_flag) != 0) {
862				path_index++;
863				retval++;
864				continue;
865			}
866			/* power off SENA enclosure. */
867			if (err = l_pho_pwr_up_down(argv[path_index], path_phys,
868			    off_flag, Options & PVERBOSE,
869			    Options & OPTION_CAPF)) {
870				(void) print_errString(err, argv[path_index]);
871				retval++;
872			}
873		} else if ((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) {
874			if (err = l_dev_pwr_up_down(path_phys,
875			    path_struct, off_flag, Options & PVERBOSE,
876			    Options & OPTION_CAPF)) {
877				(void) print_errString(err, argv[path_index]);
878				retval++;
879			}
880		} else {
881			/*
882			 * SSA section:
883			 */
884			(void) print_errString(L_INVALID_PATH,
885						argv[path_index]);
886		}
887		path_index++;
888	}
889	return (retval);
890}
891
892
893
894void
895adm_bypass_enable(char **argv, int bypass_flag)
896{
897int		path_index = 0, err = 0;
898L_inquiry	inq;
899char		*path_phys = NULL;
900Path_struct	*path_struct;
901
902	if ((err = l_convert_name(argv[path_index], &path_phys,
903		&path_struct, Options & PVERBOSE)) != 0) {
904		/*
905		 * In case we did not find the device
906		 * in the /devices directory.
907		 *
908		 * Only valid for pathnames like box,f1
909		 */
910		if (path_struct->ib_path_flag) {
911			path_phys = path_struct->p_physical_path;
912		} else {
913			(void) fprintf(stderr,
914					MSGSTR(33,
915						" Error: converting"
916						" %s to physical path.\n"
917						" Invalid pathname.\n"),
918					argv[path_index]);
919			if (err != -1) {
920				(void) print_errString(err, argv[path_index]);
921			}
922			exit(-1);
923		}
924	}
925	if (path_struct->ib_path_flag) {
926		if (Options & OPTION_F) {
927			E_USEAGE();
928			exit(-1);
929		}
930		/*
931		 * We are addressing a disk using a path
932		 * format type box,f1 and no disk
933		 * path was found.
934		 * So set the Force flag so no reserved/busy
935		 * check is performed.
936		 */
937		if (err = l_dev_bypass_enable(path_struct,
938			bypass_flag, OPTION_CAPF,
939			Options & OPTION_A,
940			Options & PVERBOSE)) {
941			(void) print_errString(err, argv[path_index]);
942			exit(-1);
943		}
944		return;
945	}
946
947	if (err = g_get_inquiry(path_phys, &inq)) {
948		(void) print_errString(err, argv[path_index]);
949		exit(-1);
950	}
951	if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != 0) ||
952		(strncmp((char *)inq.inq_vid, "SUN     ",
953		sizeof (inq.inq_vid)) &&
954		((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI))) {
955		if ((!((Options & OPTION_F) ||
956			(Options & OPTION_R))) ||
957			((Options & OPTION_R) &&
958			(Options & OPTION_F))) {
959			E_USEAGE();
960			exit(-1);
961		}
962		if (err = l_bp_bypass_enable(path_phys, bypass_flag,
963			Options & OPTION_A,
964			Options & OPTION_F,
965			Options & OPTION_CAPF,
966			Options & PVERBOSE)) {
967		    (void) print_errString(err, argv[path_index]);
968		    exit(-1);
969		}
970	} else if ((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) {
971		if (Options & OPTION_F) {
972			E_USEAGE();
973			exit(-1);
974		}
975		if (err = l_dev_bypass_enable(path_struct,
976			bypass_flag, Options & OPTION_CAPF,
977			Options & OPTION_A,
978			Options & PVERBOSE)) {
979			(void) print_errString(err, argv[path_index]);
980			exit(-1);
981		}
982	}
983}
984
985/*
986 * adm_download() Download subsystem microcode.
987 * Path must point to a LUX IB.
988 *
989 * RETURNS:
990 *	None.
991 */
992void
993adm_download(char **argv, char *file_name)
994{
995int		path_index = 0, err = 0;
996char		*path_phys = NULL;
997L_inquiry	inq;
998Path_struct	*path_struct;
999
1000	while (argv[path_index] != NULL) {
1001		/*
1002		 * See what kind of device we are talking to.
1003		 */
1004		if ((err = l_convert_name(argv[path_index], &path_phys,
1005			&path_struct, Options & PVERBOSE)) != 0) {
1006			(void) fprintf(stderr,
1007					MSGSTR(33,
1008						" Error: converting"
1009						" %s to physical path.\n"
1010						" Invalid pathname.\n"),
1011					argv[path_index]);
1012			if (err != -1) {
1013				(void) print_errString(err, argv[path_index]);
1014			}
1015			exit(-1);
1016		}
1017		if (err = g_get_inquiry(path_phys, &inq)) {
1018			(void) print_errString(err, argv[path_index]);
1019			exit(-1);
1020		}
1021		if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != 0) ||
1022			(strncmp((char *)inq.inq_vid, "SUN     ",
1023			sizeof (inq.inq_vid)) &&
1024			((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI))) {
1025			if (err = l_download(path_phys,
1026				file_name, (Options & SAVE),
1027				(Options & PVERBOSE))) {
1028				(void) print_errString(err,
1029					(err == L_OPEN_PATH_FAIL) ?
1030					argv[path_index]: file_name);
1031				exit(-1);
1032			}
1033		} else {
1034			(void) fprintf(stderr,
1035				MSGSTR(112, "Error: Invalid pathname (%s)"),
1036				argv[path_index]);
1037		}
1038		path_index++;
1039	}
1040}
1041
1042/*
1043 * display_link_status() Reads and displays the link status.
1044 *
1045 * RETURNS:
1046 *	none.
1047 */
1048void
1049display_link_status(char **argv)
1050{
1051AL_rls		*rls = NULL, *n;
1052int		path_index = 0, err = 0;
1053char		*path_phys = NULL;
1054Path_struct	*path_struct;
1055
1056
1057	while (argv[path_index] != NULL) {
1058		if ((err = l_convert_name(argv[path_index], &path_phys,
1059			&path_struct, Options & PVERBOSE)) != 0) {
1060			(void) fprintf(stderr,
1061					MSGSTR(33,
1062						" Error: converting"
1063						" %s to physical path.\n"
1064						" Invalid pathname.\n"),
1065					argv[path_index]);
1066			if (err != -1) {
1067				(void) print_errString(err, argv[path_index]);
1068			}
1069			exit(-1);
1070		}
1071		if (err = g_rdls(path_phys, &rls, Options & PVERBOSE)) {
1072		    (void) print_errString(err, argv[path_index]);
1073		    exit(-1);
1074		}
1075		n = rls;
1076		if (n != NULL) {
1077			(void) fprintf(stdout,
1078			MSGSTR(2007, "\nLink Error Status "
1079				"information for loop:%s\n"),
1080				n->driver_path);
1081			(void) fprintf(stdout, MSGSTR(2008, "al_pa   lnk fail "
1082			"   sync loss   signal loss   sequence err"
1083			"   invalid word   CRC\n"));
1084		}
1085		while (n) {
1086			if ((n->payload.rls_linkfail == 0xffffffff) &&
1087			    (n->payload.rls_syncfail == 0xffffffff) &&
1088			    (n->payload.rls_sigfail == 0xffffffff) &&
1089			    (n->payload.rls_primitiverr == 0xffffffff) &&
1090			    (n->payload.rls_invalidword == 0xffffffff) &&
1091			    (n->payload.rls_invalidcrc == 0xffffffff)) {
1092				(void) fprintf(stdout,
1093					"%x\t%-12d%-12d%-14d%-15d%-15d%-12d\n",
1094					n->al_ha,
1095					n->payload.rls_linkfail,
1096					n->payload.rls_syncfail,
1097					n->payload.rls_sigfail,
1098					n->payload.rls_primitiverr,
1099					n->payload.rls_invalidword,
1100					n->payload.rls_invalidcrc);
1101			} else {
1102				(void) fprintf(stdout,
1103					"%x\t%-12u%-12u%-14u%-15u%-15u%-12u\n",
1104					n->al_ha,
1105					n->payload.rls_linkfail,
1106					n->payload.rls_syncfail,
1107					n->payload.rls_sigfail,
1108					n->payload.rls_primitiverr,
1109					n->payload.rls_invalidword,
1110					n->payload.rls_invalidcrc);
1111			}
1112			n = n->next;
1113		}
1114
1115		path_index++;
1116	}
1117	(void) fprintf(stdout,
1118		MSGSTR(2009, "NOTE: These LESB counts are not"
1119		" cleared by a reset, only power cycles.\n"
1120		"These counts must be compared"
1121		" to previously read counts.\n"));
1122}
1123
1124
1125/*
1126 * ib_present_chk() Check to see if IB 0 or 1 is present in the box.
1127 *
1128 * RETURN:
1129 *	1 if ib present
1130 *	0 otherwise
1131 */
1132int
1133ib_present_chk(struct l_state_struct *l_state, int which_one)
1134{
1135Ctlr_elem_st	ctlr;
1136int	i;
1137int	elem_index = 0;
1138int	result = 1;
1139
1140	for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) {
1141	    elem_index++;		/* skip global */
1142	    if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_IB) {
1143		(void) bcopy((const void *)
1144			&l_state->ib_tbl.p2_s.element[elem_index + which_one],
1145			(void *)&ctlr, sizeof (ctlr));
1146		if (ctlr.code == S_NOT_INSTALLED) {
1147			result = 0;
1148		}
1149		break;
1150	    }
1151	    elem_index += l_state->ib_tbl.config.type_hdr[i].num;
1152	}
1153	return (result);
1154}
1155
1156/*
1157 * print_individual_state() Print individual disk status.
1158 *
1159 * RETURNS:
1160 *	none.
1161 */
1162void
1163print_individual_state(int status, int port)
1164{
1165	if (status & L_OPEN_FAIL) {
1166		(void) fprintf(stdout, " (");
1167		(void) fprintf(stdout,
1168		MSGSTR(28, "Open Failed"));
1169		(void) fprintf(stdout, ")  ");
1170	} else if (status & L_NOT_READY) {
1171		(void) fprintf(stdout, " (");
1172		(void) fprintf(stdout,
1173			MSGSTR(20, "Not Ready"));
1174		(void) fprintf(stdout, ")    ");
1175	} else if (status & L_NOT_READABLE) {
1176		(void) fprintf(stdout, "(");
1177		(void) fprintf(stdout,
1178		MSGSTR(88, "Not Readable"));
1179		(void) fprintf(stdout, ")  ");
1180	} else if (status & L_SPUN_DWN_D) {
1181		(void) fprintf(stdout, " (");
1182		(void) fprintf(stdout,
1183		MSGSTR(68, "Spun Down"));
1184		(void) fprintf(stdout, ")    ");
1185	} else if (status & L_SCSI_ERR) {
1186		(void) fprintf(stdout, " (");
1187		(void) fprintf(stdout,
1188		MSGSTR(70, "SCSI Error"));
1189		(void) fprintf(stdout, ")   ");
1190	} else if (status & L_RESERVED) {
1191		if (port == PORT_A) {
1192			(void) fprintf(stdout,
1193			MSGSTR(2010,
1194				" (Rsrv cnflt:A) "));
1195		} else if (port == PORT_B) {
1196			(void) fprintf(stdout,
1197			MSGSTR(2011,
1198				" (Rsrv cnflt:B) "));
1199		} else {
1200			(void) fprintf(stdout,
1201			MSGSTR(2012,
1202				" (Reserve cnflt)"));
1203		}
1204	} else if (status & L_NO_LABEL) {
1205		(void) fprintf(stdout, "(");
1206		(void) fprintf(stdout,
1207			MSGSTR(92, "No UNIX Label"));
1208		(void) fprintf(stdout, ") ");
1209	}
1210}
1211
1212
1213/*
1214 * display_disk_msg() Displays status for
1215 * an individual SENA device.
1216 *
1217 * RETURNS:
1218 *	none.
1219 */
1220void
1221display_disk_msg(struct l_disk_state_struct *dsk_ptr,
1222	struct l_state_struct *l_state, Bp_elem_st *bp, int front_flag)
1223{
1224int	loop_flag = 0;
1225int	a_and_b = 0;
1226int	state_a = 0, state_b = 0;
1227
1228	if (dsk_ptr->ib_status.code == S_NOT_INSTALLED) {
1229		(void) fprintf(stdout,
1230			MSGSTR(30, "Not Installed"));
1231			(void) fprintf(stdout, " ");
1232		if (dsk_ptr->ib_status.fault ||
1233			dsk_ptr->ib_status.fault_req) {
1234			(void) fprintf(stdout, "(");
1235			(void) fprintf(stdout,
1236				MSGSTR(2013, "Faulted"));
1237			(void) fprintf(stdout,
1238						")           ");
1239		} else if (dsk_ptr->ib_status.ident ||
1240			dsk_ptr->ib_status.rdy_to_ins ||
1241			dsk_ptr->ib_status.rmv) {
1242			(void) fprintf(stdout,
1243				MSGSTR(2014,
1244						"(LED Blinking)      "));
1245		} else {
1246			(void) fprintf(stdout,
1247						"                    ");
1248		}
1249	} else if (dsk_ptr->ib_status.dev_off) {
1250		(void) fprintf(stdout, MSGSTR(2015, "Off"));
1251		if (dsk_ptr->ib_status.fault || dsk_ptr->ib_status.fault_req) {
1252			(void) fprintf(stdout, "(");
1253			(void) fprintf(stdout,
1254				MSGSTR(2016, "Faulted"));
1255			(void) fprintf(stdout,
1256					")                      ");
1257		} else if (dsk_ptr->ib_status.bypass_a_en &&
1258			dsk_ptr->ib_status.bypass_b_en) {
1259			(void) fprintf(stdout,
1260				MSGSTR(2017,
1261					"(Bypassed:AB)"));
1262			(void) fprintf(stdout,
1263					"                  ");
1264		} else if (dsk_ptr->ib_status.bypass_a_en) {
1265			(void) fprintf(stdout,
1266				MSGSTR(2018,
1267					"(Bypassed: A)"));
1268			(void) fprintf(stdout,
1269					"                  ");
1270		} else if (dsk_ptr->ib_status.bypass_b_en) {
1271			(void) fprintf(stdout,
1272				MSGSTR(2019,
1273					"(Bypassed: B)"));
1274			(void) fprintf(stdout,
1275					"                  ");
1276		} else {
1277			(void) fprintf(stdout,
1278					"                              ");
1279		}
1280	} else {
1281		(void) fprintf(stdout, MSGSTR(2020, "On"));
1282
1283		if (dsk_ptr->ib_status.fault || dsk_ptr->ib_status.fault_req) {
1284			(void) fprintf(stdout, " (");
1285			(void) fprintf(stdout,
1286				MSGSTR(2021, "Faulted"));
1287			(void) fprintf(stdout, ")      ");
1288		} else if (dsk_ptr->ib_status.bypass_a_en &&
1289			dsk_ptr->ib_status.bypass_b_en) {
1290			(void) fprintf(stdout, " ");
1291			(void) fprintf(stdout,
1292				MSGSTR(2022, "(Bypassed:AB)"));
1293			(void) fprintf(stdout, "  ");
1294		} else if (ib_present_chk(l_state, 0) &&
1295			dsk_ptr->ib_status.bypass_a_en) {
1296			/*
1297			 * Before printing that the port is bypassed
1298			 * verify that there is an IB for this port.
1299			 * If not then don't print.
1300			 */
1301			(void) fprintf(stdout, " ");
1302			(void) fprintf(stdout,
1303				MSGSTR(2023, "(Bypassed: A)"));
1304			(void) fprintf(stdout, "  ");
1305		} else if (ib_present_chk(l_state, 1) &&
1306			dsk_ptr->ib_status.bypass_b_en) {
1307			(void) fprintf(stdout, " ");
1308			(void) fprintf(stdout,
1309				MSGSTR(2024, "(Bypassed: B)"));
1310			(void) fprintf(stdout, "  ");
1311		} else if ((bp->code != S_NOT_INSTALLED) &&
1312				((bp->byp_a_enabled || bp->en_bypass_a) &&
1313				!(bp->byp_b_enabled || bp->en_bypass_b))) {
1314			(void) fprintf(stdout,
1315				MSGSTR(2025,
1316					" (Bypassed BP: A)"));
1317		} else if ((bp->code != S_NOT_INSTALLED) &&
1318				((bp->byp_b_enabled || bp->en_bypass_b) &&
1319				!(bp->byp_a_enabled || bp->en_bypass_a))) {
1320			(void) fprintf(stdout,
1321				MSGSTR(2026,
1322					"(Bypassed BP: B)"));
1323		} else if ((bp->code != S_NOT_INSTALLED) &&
1324				((bp->byp_a_enabled || bp->en_bypass_a) &&
1325				(bp->byp_b_enabled || bp->en_bypass_b))) {
1326			(void) fprintf(stdout,
1327				MSGSTR(2027,
1328					"(Bypassed BP:AB)"));
1329		} else {
1330			state_a = dsk_ptr->g_disk_state.d_state_flags[PORT_A];
1331			state_b = dsk_ptr->g_disk_state.d_state_flags[PORT_B];
1332			a_and_b = state_a & state_b;
1333
1334			if (dsk_ptr->l_state_flag & L_NO_LOOP) {
1335				(void) fprintf(stdout,
1336				MSGSTR(2028,
1337					" (Loop not accessible)"));
1338				loop_flag = 1;
1339			} else if (dsk_ptr->l_state_flag & L_INVALID_WWN) {
1340				(void) fprintf(stdout,
1341				MSGSTR(2029,
1342					" (Invalid WWN)  "));
1343			} else if (dsk_ptr->l_state_flag & L_INVALID_MAP) {
1344				(void) fprintf(stdout,
1345				MSGSTR(2030,
1346					" (Login failed) "));
1347			} else if (dsk_ptr->l_state_flag & L_NO_PATH_FOUND) {
1348				(void) fprintf(stdout,
1349				MSGSTR(2031,
1350					" (No path found)"));
1351			} else if (a_and_b) {
1352				print_individual_state(a_and_b, PORT_A_B);
1353			} else if (state_a && (!state_b)) {
1354				print_individual_state(state_a, PORT_A);
1355			} else if ((!state_a) && state_b) {
1356				print_individual_state(state_b, PORT_B);
1357			} else if (state_a || state_b) {
1358				/* NOTE: Double state - should do 2 lines. */
1359				print_individual_state(state_a | state_b,
1360								PORT_A_B);
1361			} else {
1362				(void) fprintf(stdout, " (");
1363				(void) fprintf(stdout,
1364					MSGSTR(29, "O.K."));
1365				(void) fprintf(stdout,
1366					")         ");
1367			}
1368		}
1369		if (loop_flag) {
1370			(void) fprintf(stdout, "          ");
1371		} else if (strlen(dsk_ptr->g_disk_state.node_wwn_s)) {
1372			(void) fprintf(stdout, "%s",
1373			dsk_ptr->g_disk_state.node_wwn_s);
1374		} else {
1375			(void) fprintf(stdout, "                ");
1376		}
1377	}
1378	if (front_flag) {
1379		(void) fprintf(stdout, "    ");
1380	}
1381}
1382
1383
1384
1385/*
1386 * pho_display_config() Displays device status
1387 * information for a SENA enclosure.
1388 *
1389 * RETURNS:
1390 *	none.
1391 */
1392void
1393pho_display_config(char *path_phys)
1394{
1395L_state		l_state;
1396Bp_elem_st	bpf, bpr;
1397int		i, j, elem_index = 0, err = 0;
1398
1399
1400	/* Get global status */
1401	if (err = l_get_status(path_phys, &l_state,
1402			(Options & PVERBOSE))) {
1403	    (void) print_errString(err, path_phys);
1404	    exit(-1);
1405	}
1406
1407	/*
1408	 * Look for abnormal status.
1409	 */
1410	if (l_state.ib_tbl.p2_s.ui.ab_cond) {
1411		abnormal_condition_display(&l_state);
1412	}
1413
1414	(void) fprintf(stdout,
1415		MSGSTR(2032, "                                 DISK STATUS \n"
1416		"SLOT   FRONT DISKS       (Node WWN)         "
1417		" REAR DISKS        (Node WWN)\n"));
1418	/*
1419	 * Print the status for each disk
1420	 */
1421	for (j = 0; j <  (int)l_state.ib_tbl.config.enc_num_elem; j++) {
1422		elem_index++;
1423		if (l_state.ib_tbl.config.type_hdr[j].type == ELM_TYP_BP)
1424			break;
1425		elem_index += l_state.ib_tbl.config.type_hdr[j].num;
1426	}
1427	(void) bcopy((const void *)
1428		&(l_state.ib_tbl.p2_s.element[elem_index]),
1429		(void *)&bpf, sizeof (bpf));
1430	(void) bcopy((const void *)
1431		&(l_state.ib_tbl.p2_s.element[elem_index + 1]),
1432		(void *)&bpr, sizeof (bpr));
1433
1434	for (i = 0; i < (int)l_state.total_num_drv/2; i++) {
1435		(void) fprintf(stdout, "%-2d     ", i);
1436		display_disk_msg(&l_state.drv_front[i], &l_state, &bpf, 1);
1437		display_disk_msg(&l_state.drv_rear[i], &l_state, &bpr, 0);
1438		(void) fprintf(stdout, "\n");
1439	}
1440
1441
1442
1443	/*
1444	 * Display the subsystem status.
1445	 */
1446	(void) fprintf(stdout,
1447		MSGSTR(2242,
1448	"                                SUBSYSTEM STATUS\nFW Revision:"));
1449	print_chars(l_state.ib_tbl.config.prod_revision,
1450		sizeof (l_state.ib_tbl.config.prod_revision), 1);
1451	(void) fprintf(stdout, MSGSTR(2034, "   Box ID:%d"),
1452		l_state.ib_tbl.box_id);
1453	(void) fprintf(stdout, "   ");
1454	(void) fprintf(stdout, MSGSTR(90, "Node WWN:"));
1455	for (i = 0; i < 8; i++) {
1456		(void) fprintf(stdout, "%1.2x",
1457		l_state.ib_tbl.config.enc_node_wwn[i]);
1458	}
1459	/* Make sure NULL terminated  although it is supposed to be */
1460	if (strlen((const char *)l_state.ib_tbl.enclosure_name) <=
1461		sizeof (l_state.ib_tbl.enclosure_name)) {
1462		(void) fprintf(stdout, MSGSTR(2035, "   Enclosure Name:%s\n"),
1463			l_state.ib_tbl.enclosure_name);
1464	}
1465
1466	/*
1467	 *
1468	 */
1469	elem_index = 0;
1470	/* Get and print CONTROLLER messages */
1471	for (i = 0; i < (int)l_state.ib_tbl.config.enc_num_elem; i++) {
1472	    elem_index++;		/* skip global */
1473	    switch (l_state.ib_tbl.config.type_hdr[i].type) {
1474		case ELM_TYP_PS:
1475			ps_messages(&l_state, i, elem_index);
1476			break;
1477		case ELM_TYP_FT:
1478			fan_messages(&l_state, i, elem_index);
1479			break;
1480		case ELM_TYP_BP:
1481			back_plane_messages(&l_state, i, elem_index);
1482			break;
1483		case ELM_TYP_IB:
1484			ctlr_messages(&l_state, i, elem_index);
1485			break;
1486		case ELM_TYP_LN:
1487			/*
1488			 * NOTE: I just use the Photon's message
1489			 * string here and don't look at the
1490			 * language code. The string includes
1491			 * the language name.
1492			 */
1493			if (l_state.ib_tbl.config.type_hdr[i].text_len != 0) {
1494				(void) fprintf(stdout, "%s\t",
1495				l_state.ib_tbl.config.text[i]);
1496			}
1497			break;
1498		case ELM_TYP_LO:	/* Loop configuration */
1499			loop_messages(&l_state, i, elem_index);
1500			break;
1501		case ELM_TYP_MB:	/* Loop configuration */
1502			mb_messages(&l_state, i, elem_index);
1503			break;
1504
1505	    }
1506		/*
1507		 * Calculate the index to each element.
1508		 */
1509		elem_index += l_state.ib_tbl.config.type_hdr[i].num;
1510	}
1511	(void) fprintf(stdout, "\n");
1512}
1513
1514
1515
1516
1517/*
1518 * dpm_display_config() Displays device status
1519 * information for a DAKTARI enclosure.
1520 *
1521 * RETURNS:
1522 *	none.
1523 */
1524void
1525dpm_display_config(char *path_phys)
1526{
1527L_state		l_state;
1528Bp_elem_st	bpf, bpr;
1529int		i, j, elem_index = 0, err = 0, count;
1530
1531
1532	/* Get global status */
1533	if (err = l_get_status(path_phys, &l_state,
1534			(Options & PVERBOSE))) {
1535	    (void) print_errString(err, path_phys);
1536	    exit(-1);
1537	}
1538
1539	/*
1540	 * Look for abnormal status.
1541	 */
1542	if (l_state.ib_tbl.p2_s.ui.ab_cond) {
1543		abnormal_condition_display(&l_state);
1544	}
1545
1546	(void) fprintf(stdout,
1547		MSGSTR(2247, "                 DISK STATUS \n"
1548		"SLOT   DISKS             (Node WWN)         \n"));
1549	/*
1550	 * Print the status for each disk
1551	 */
1552	for (j = 0; j <  (int)l_state.ib_tbl.config.enc_num_elem; j++) {
1553		elem_index++;
1554		if (l_state.ib_tbl.config.type_hdr[j].type == ELM_TYP_BP)
1555			break;
1556		elem_index += l_state.ib_tbl.config.type_hdr[j].num;
1557	}
1558	(void) bcopy((const void *)
1559		&(l_state.ib_tbl.p2_s.element[elem_index]),
1560		(void *)&bpf, sizeof (bpf));
1561	(void) bcopy((const void *)
1562		&(l_state.ib_tbl.p2_s.element[elem_index + 1]),
1563		(void *)&bpr, sizeof (bpr));
1564
1565	for (i = 0, count = 0;
1566			i < (int)l_state.total_num_drv/2;
1567			i++, count++) {
1568		(void) fprintf(stdout, "%-2d     ", count);
1569		display_disk_msg(&l_state.drv_front[i], &l_state, &bpf, 1);
1570		(void) fprintf(stdout, "\n");
1571	}
1572	for (i = 0; i < (int)l_state.total_num_drv/2; i++, count++) {
1573		(void) fprintf(stdout, "%-2d     ", count);
1574		display_disk_msg(&l_state.drv_rear[i], &l_state, &bpf, 1);
1575		(void) fprintf(stdout, "\n");
1576	}
1577
1578
1579	/*
1580	 * Display the subsystem status.
1581	 */
1582	(void) fprintf(stdout,
1583		MSGSTR(2033,
1584	"\t\tSUBSYSTEM STATUS\nFW Revision:"));
1585	for (i = 0; i < sizeof (l_state.ib_tbl.config.prod_revision); i++) {
1586		(void) fprintf(stdout, "%c",
1587			l_state.ib_tbl.config.prod_revision[i]);
1588	}
1589	(void) fprintf(stdout, MSGSTR(2034, "   Box ID:%d"),
1590		l_state.ib_tbl.box_id);
1591	(void) fprintf(stdout, "\n  ");
1592
1593	(void) fprintf(stdout, MSGSTR(90, "Node WWN:"));
1594
1595	for (i = 0; i < 8; i++) {
1596		(void) fprintf(stdout, "%1.2x",
1597		l_state.ib_tbl.config.enc_node_wwn[i]);
1598	}
1599	/* Make sure NULL terminated  although it is supposed to be */
1600	if (strlen((const char *)l_state.ib_tbl.enclosure_name) <=
1601		sizeof (l_state.ib_tbl.enclosure_name)) {
1602		(void) fprintf(stdout, MSGSTR(2035, "   Enclosure Name:%s\n"),
1603			l_state.ib_tbl.enclosure_name);
1604	}
1605
1606	/*
1607	 *
1608	 */
1609	elem_index = 0;
1610	/* Get and print CONTROLLER messages */
1611	for (i = 0; i < (int)l_state.ib_tbl.config.enc_num_elem; i++) {
1612	    elem_index++;		/* skip global */
1613	    switch (l_state.ib_tbl.config.type_hdr[i].type) {
1614		case ELM_TYP_PS:
1615			ps_messages(&l_state, i, elem_index);
1616			break;
1617		case ELM_TYP_FT:
1618			fan_messages(&l_state, i, elem_index);
1619			break;
1620		case ELM_TYP_BP:
1621			dpm_SSC100_messages(&l_state, i, elem_index);
1622			break;
1623		case ELM_TYP_IB:
1624			ctlr_messages(&l_state, i, elem_index);
1625			break;
1626		case ELM_TYP_LN:
1627			/*
1628			 * NOTE: I just use the Photon's message
1629			 * string here and don't look at the
1630			 * language code. The string includes
1631			 * the language name.
1632			 */
1633			if (l_state.ib_tbl.config.type_hdr[i].text_len != 0) {
1634				(void) fprintf(stdout, "%s\t",
1635				l_state.ib_tbl.config.text[i]);
1636			}
1637			break;
1638		case ELM_TYP_LO:	/* Loop configuration */
1639			loop_messages(&l_state, i, elem_index);
1640			break;
1641		case ELM_TYP_MB:	/* Loop configuration */
1642			mb_messages(&l_state, i, elem_index);
1643			break;
1644		case ELM_TYP_FL:
1645			trans_messages(&l_state, 1);
1646			break;
1647
1648	    }
1649		/*
1650		 * Calculate the index to each element.
1651		 */
1652		elem_index += l_state.ib_tbl.config.type_hdr[i].num;
1653	}
1654	(void) fprintf(stdout, "\n");
1655}
1656
1657
1658
1659
1660
1661
1662/*
1663 * Change the FPM (Front Panel Module) password of the
1664 * subsystem associated with the IB addressed by the
1665 * enclosure or pathname to name.
1666 *
1667 */
1668void
1669intfix(void)
1670{
1671	if (termio_fd) {
1672		termios.c_lflag |= ECHO;
1673		ioctl(termio_fd, TCSETS, &termios);
1674	}
1675	exit(SIGINT);
1676}
1677
1678
1679/*
1680 * up_password() Changes the password for SENA enclosure.
1681 *
1682 * RETURNS:
1683 *	none.
1684 */
1685void
1686up_password(char **argv)
1687{
1688int		path_index = 0, err = 0;
1689char		password[1024];
1690char		input[1024];
1691int		i, j, matched, equal;
1692L_inquiry	inq;
1693void		(*sig)();
1694char		*path_phys = NULL;
1695Path_struct	*path_struct;
1696
1697
1698	if ((termio_fd = open("/dev/tty", O_RDONLY)) == -1) {
1699		(void) fprintf(stderr,
1700		MSGSTR(2036, "Error: tty open failed.\n"));
1701		exit(-1);
1702	}
1703	ioctl(termio_fd, TCGETS, &termios);
1704	sig = sigset(SIGINT, (void (*)())intfix);
1705	/*
1706	 * Make sure path valid and is to a PHO
1707	 * before bothering operator.
1708	 */
1709	if ((err = l_convert_name(argv[path_index], &path_phys,
1710		&path_struct, Options & PVERBOSE)) != 0) {
1711		(void) fprintf(stderr,
1712			MSGSTR(33,
1713				" Error: converting"
1714				" %s to physical path.\n"
1715				" Invalid pathname.\n"),
1716				argv[path_index]);
1717		if (err != -1) {
1718			(void) print_errString(err, argv[path_index]);
1719		}
1720		exit(-1);
1721	}
1722	if (err = g_get_inquiry(path_phys, &inq)) {
1723		(void) print_errString(err, argv[path_index]);
1724		exit(-1);
1725	}
1726	if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
1727			(!(strncmp((char *)inq.inq_vid, "SUN     ",
1728			sizeof (inq.inq_vid)) &&
1729			((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
1730		/*
1731		 * Again this is like the ssaadm code in that the name
1732		 * is still not defined before this code must be released.
1733		 */
1734		(void) fprintf(stderr,
1735		MSGSTR(2037, "Error: Enclosure is not a %s\n"),
1736			ENCLOSURE_PROD_ID);
1737		exit(-1);
1738	}
1739	(void) fprintf(stdout,
1740			MSGSTR(2038,
1741			"Changing FPM password for subsystem %s\n"),
1742			argv[path_index]);
1743
1744	equal = 0;
1745	while (!equal) {
1746		memset(input, 0, sizeof (input));
1747		memset(password, 0, sizeof (password));
1748		(void) fprintf(stdout,
1749		MSGSTR(2039, "New password: "));
1750
1751		termios.c_lflag &= ~ECHO;
1752		ioctl(termio_fd, TCSETS, &termios);
1753
1754		(void) gets(input);
1755		(void) fprintf(stdout,
1756		MSGSTR(2040, "\nRe-enter new password: "));
1757		(void) gets(password);
1758		termios.c_lflag |= ECHO;
1759		ioctl(termio_fd, TCSETS, &termios);
1760		for (i = 0; input[i]; i++) {
1761			if (!isdigit(input[i])) {
1762				(void) fprintf(stderr,
1763			MSGSTR(2041, "\nError: Invalid password."
1764			" The password"
1765			" must be 4 decimal-digit characters.\n"));
1766				exit(-1);
1767			}
1768		}
1769		if (i && (i != 4)) {
1770			(void) fprintf(stderr,
1771			MSGSTR(2042, "\nError: Invalid password."
1772			" The password"
1773			" must be 4 decimal-digit characters.\n"));
1774			exit(-1);
1775		}
1776		for (j = 0; password[j]; j++) {
1777			if (!isdigit(password[j])) {
1778				(void) fprintf(stderr,
1779			MSGSTR(2043, "\nError: Invalid password."
1780			" The password"
1781			" must be 4 decimal-digit characters.\n"));
1782				exit(-1);
1783			}
1784		}
1785		if (i != j) {
1786			matched = -1;
1787		} else for (i = matched = 0; password[i]; i++) {
1788			if (password[i] == input[i]) {
1789				matched++;
1790			}
1791		}
1792		if ((matched != -1) && (matched == i)) {
1793			equal = 1;
1794		} else {
1795			(void) fprintf(stdout,
1796			MSGSTR(2044, "\npassword: They don't match;"
1797			" try again.\n"));
1798		}
1799	}
1800	(void) fprintf(stdout, "\n");
1801	sscanf(input, "%s", password);
1802	(void) signal(SIGINT, sig);	/* restore signal handler */
1803
1804	/*  Send new password to IB */
1805	if (l_new_password(path_phys, input)) {
1806		(void) print_errString(err, path_phys);
1807		exit(-1);
1808	}
1809}
1810
1811/*
1812 * Call g_failover to process failover command
1813 */
1814void
1815adm_failover(char **argv)
1816{
1817int		path_index = 0, err = 0;
1818char		pathclass[20];
1819char		*path_phys = NULL;
1820
1821	(void) memset(pathclass, 0, sizeof (pathclass));
1822	(void) strcpy(pathclass, argv[path_index++]);
1823	if ((strcmp(pathclass, "primary") != 0) &&
1824		(strcmp(pathclass, "secondary") != 0)) {
1825			(void) fprintf(stderr,
1826			MSGSTR(2300, "Incorrect pathclass\n"));
1827			exit(-1);
1828	}
1829
1830	while (argv[path_index] != NULL) {
1831		path_phys = g_get_physical_name(argv[path_index++]);
1832		if ((path_phys == NULL) ||
1833			(strstr(path_phys, SCSI_VHCI) == NULL)) {
1834				(void) fprintf(stderr,
1835				MSGSTR(2301, "Incorrect pathname\n"));
1836				exit(-1);
1837		}
1838
1839		if (err = g_failover(path_phys, pathclass)) {
1840			(void) print_errString(err, NULL);
1841			exit(-1);
1842		}
1843	}
1844}
1845
1846
1847
1848/*
1849 * up_encl_name() Update the enclosures logical name.
1850 *
1851 * RETURNS:
1852 *	none.
1853 */
1854void
1855up_encl_name(char **argv, int argc)
1856{
1857int		i, rval, al_pa, path_index = 0, err = 0;
1858L_inquiry	inq;
1859Box_list	*b_list = NULL;
1860uchar_t		node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
1861char		wwn1[(WWN_SIZE*2)+1], name[1024], *path_phys = NULL;
1862Path_struct	*path_struct;
1863
1864	(void) memset(name, 0, sizeof (name));
1865	(void) memset(&inq, 0, sizeof (inq));
1866	(void) sscanf(argv[path_index++], "%s", name);
1867	for (i = 0; name[i]; i++) {
1868		if ((!isalnum(name[i]) &&
1869			((name[i] != '#') &&
1870			(name[i] != '-') &&
1871			(name[i] != '_') &&
1872			(name[i] != '.'))) || i >= 16) {
1873			(void) fprintf(stderr,
1874			MSGSTR(2045, "Error: Invalid enclosure name.\n"));
1875			(void) fprintf(stderr, MSGSTR(2046,
1876			"Usage: %s [-v] subcommand {a name consisting of"
1877			" 1-16 alphanumeric characters}"
1878			" {enclosure... | pathname...}\n"), whoami);
1879			exit(-1);
1880		}
1881	}
1882
1883	if (((Options & PVERBOSE) && (argc != 5)) ||
1884		(!(Options & PVERBOSE) && (argc != 4))) {
1885		(void) fprintf(stderr,
1886		MSGSTR(114, "Error: Incorrect number of arguments.\n"));
1887		(void) fprintf(stderr,  MSGSTR(2047,
1888		"Usage: %s [-v] subcommand {a name consisting of"
1889		" 1-16 alphanumeric characters}"
1890		" {enclosure... | pathname...}\n"), whoami);
1891		exit(-1);
1892	}
1893
1894	if ((err = l_convert_name(argv[path_index], &path_phys,
1895		&path_struct, Options & PVERBOSE)) != 0) {
1896		(void) fprintf(stderr,
1897				MSGSTR(33,
1898				" Error: converting"
1899				" %s to physical path.\n"
1900				" Invalid pathname.\n"),
1901				argv[path_index]);
1902		if (err != -1) {
1903			(void) print_errString(err, argv[path_index]);
1904		}
1905		exit(-1);
1906	}
1907	/*
1908	 * Make sure we are talking to an IB.
1909	 */
1910	if (err = g_get_inquiry(path_phys, &inq)) {
1911		(void) print_errString(err, argv[path_index]);
1912		exit(-1);
1913	}
1914	if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
1915			(!(strncmp((char *)inq.inq_vid, "SUN     ",
1916			sizeof (inq.inq_vid)) &&
1917			((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
1918		/*
1919		 * Again this is like the ssaadm code in that the name
1920		 * is still not defined before this code must be released.
1921		 */
1922		(void) fprintf(stderr,
1923		MSGSTR(2048, "Error: Pathname does not point to a %s"
1924		" enclosure\n"), ENCLOSURE_PROD_NAME);
1925		exit(-1);
1926	}
1927
1928	if (err = g_get_wwn(path_phys, port_wwn, node_wwn, &al_pa,
1929		Options & PVERBOSE)) {
1930		(void) print_errString(err, argv[path_index]);
1931		exit(-1);
1932	}
1933
1934	for (i = 0; i < WWN_SIZE; i++) {
1935		(void) sprintf(&wwn1[i << 1], "%02x", node_wwn[i]);
1936	}
1937	if ((err = l_get_box_list(&b_list, Options & PVERBOSE)) != 0) {
1938		(void) print_errString(err, argv[path_index]);
1939		exit(-1);
1940	}
1941	if (b_list == NULL) {
1942		(void) fprintf(stdout,
1943			MSGSTR(93, "No %s enclosures found "
1944			"in /dev/es\n"), ENCLOSURE_PROD_NAME);
1945		exit(-1);
1946	} else if (l_duplicate_names(b_list, wwn1, name,
1947		Options & PVERBOSE)) {
1948		(void) fprintf(stderr,
1949		MSGSTR(2049, "Warning: The name you selected, %s,"
1950		" is already being used.\n"
1951		"Please choose a unique name.\n"
1952		"You can use the \"probe\" subcommand to"
1953		" see all of the enclosure names.\n"),
1954		name);
1955		(void) l_free_box_list(&b_list);
1956		exit(-1);
1957	}
1958	(void) l_free_box_list(&b_list);
1959
1960	/*  Send new name to IB */
1961	if (rval = l_new_name(path_phys, name)) {
1962		(void) print_errString(rval, path_phys);
1963		exit(-1);
1964	}
1965	if (Options & PVERBOSE) {
1966		(void) fprintf(stdout,
1967			MSGSTR(2050, "The enclosure has been renamed to %s\n"),
1968			name);
1969	}
1970}
1971
1972
1973static int
1974get_enclStatus(char *phys_path, char *encl_name, int off_flag)
1975{
1976int	found_pwrOnDrv = 0, slot;
1977int	found_pwrOffDrv = 0, err = 0;
1978L_state	l_state;
1979
1980	if ((err = l_get_status(phys_path,
1981				&l_state, Options & PVERBOSE)) != 0) {
1982		(void) print_errString(err, encl_name);
1983		return (err);
1984	}
1985
1986	if (off_flag) {
1987		for (slot = 0; slot < l_state.total_num_drv/2;
1988							slot++) {
1989			if (((l_state.drv_front[slot].ib_status.code !=
1990							S_NOT_INSTALLED) &&
1991			(!l_state.drv_front[slot].ib_status.dev_off)) ||
1992			((l_state.drv_rear[slot].ib_status.code !=
1993							S_NOT_INSTALLED) &&
1994			(!l_state.drv_rear[slot].ib_status.dev_off))) {
1995				found_pwrOnDrv++;
1996				break;
1997			}
1998		}
1999		if (!found_pwrOnDrv) {
2000			(void) fprintf(stdout,
2001				MSGSTR(2051,
2002				"Notice: Drives in enclosure"
2003				" \"%s\" have already been"
2004				" powered off.\n\n"),
2005				encl_name);
2006			return (-1);
2007		}
2008	} else {
2009		for (slot  = 0; slot < l_state.total_num_drv/2;
2010							slot++) {
2011			if (((l_state.drv_front[slot].ib_status.code !=
2012							S_NOT_INSTALLED) &&
2013			(l_state.drv_front[slot].ib_status.dev_off)) ||
2014			((l_state.drv_rear[slot].ib_status.code !=
2015							S_NOT_INSTALLED) &&
2016			(l_state.drv_rear[slot].ib_status.dev_off))) {
2017				found_pwrOffDrv++;
2018				break;
2019			}
2020		}
2021		if (!found_pwrOffDrv) {
2022			(void) fprintf(stdout,
2023				MSGSTR(2052,
2024				"Notice: Drives in enclosure"
2025				" \"%s\" have already been"
2026				" powered on.\n\n"),
2027				encl_name);
2028			return (-1);
2029		}
2030	}
2031	return (0);
2032}
2033
2034
2035
2036
2037
2038/*
2039 * adm_led() The led_request subcommand requests the subsystem
2040 * to display the current state or turn off, on, or blink
2041 * the yellow LED associated with the disk specified by the
2042 * enclosure or pathname.
2043 *
2044 * RETURNS:
2045 *	none.
2046 */
2047void
2048adm_led(char **argv, int led_action)
2049{
2050int		path_index = 0, err = 0;
2051gfc_map_t	map;
2052L_inquiry	inq;
2053Dev_elem_st	status;
2054char		*path_phys = NULL;
2055Path_struct	*path_struct;
2056int		enc_t = 0;		/* enclosure type */
2057char		ses_path[MAXPATHLEN];
2058L_inquiry	ses_inq;
2059
2060	while (argv[path_index] != NULL) {
2061		if ((err = l_convert_name(argv[path_index], &path_phys,
2062			&path_struct, Options & PVERBOSE)) != 0) {
2063			/* Make sure we have a device path. */
2064			if (path_struct->ib_path_flag) {
2065				path_phys = path_struct->p_physical_path;
2066			} else {
2067				(void) fprintf(stderr,
2068					MSGSTR(33,
2069				" Error: converting"
2070				" %s to physical path.\n"
2071				" Invalid pathname.\n"),
2072					argv[path_index]);
2073				if (err != -1) {
2074					(void) print_errString(err,
2075							argv[path_index]);
2076				}
2077				exit(-1);
2078			}
2079		}
2080		if (!path_struct->ib_path_flag) {
2081			if (err = g_get_inquiry(path_phys, &inq)) {
2082				(void) print_errString(err, argv[path_index]);
2083				exit(-1);
2084			}
2085			if ((inq.inq_dtype & DTYPE_MASK) != DTYPE_DIRECT) {
2086				(void) fprintf(stderr,
2087				MSGSTR(2053,
2088				"Error: pathname must be to a disk device.\n"
2089				" %s\n"), argv[path_index]);
2090				exit(-1);
2091			}
2092		}
2093		/*
2094		 * See if we are in fact talking to a loop or not.
2095		 */
2096		if (err = g_get_dev_map(path_phys, &map,
2097			(Options & PVERBOSE))) {
2098			(void) print_errString(err, argv[path_index]);
2099
2100		}
2101		    if (led_action == L_LED_ON) {
2102			(void) fprintf(stderr, MSGSTR(2054,
2103			    "The led_on functionality is not applicable "
2104			    "to this subsystem.\n"));
2105			exit(-1);
2106		    }
2107		    if (err = l_led(path_struct, led_action, &status,
2108			    (Options & PVERBOSE))) {
2109			(void) print_errString(err, argv[path_index]);
2110			exit(-1);
2111		    }
2112
2113		    /* Check to see if we have a daktari */
2114		    if (l_get_ses_path(path_phys, ses_path, &map,
2115			    (Options & PVERBOSE)) == 0) {
2116			if (g_get_inquiry(ses_path, &ses_inq) == 0) {
2117			    enc_t = l_get_enc_type(ses_inq);
2118			}
2119		    }
2120		    switch (led_action) {
2121		    case L_LED_STATUS:
2122			if (status.fault || status.fault_req) {
2123			    if (!path_struct->slot_valid) {
2124				(void) fprintf(stdout,
2125				    MSGSTR(2055, "LED state is ON for "
2126				    "device:\n  %s\n"), path_phys);
2127			    } else {
2128				if (enc_t == DAK_ENC_TYPE) {
2129				    if (path_struct->f_flag) {
2130					(void) fprintf(stdout,
2131					    MSGSTR(2236, "LED state is ON for "
2132					    "device in location: slot %d\n"),
2133					    path_struct->slot);
2134				    } else {
2135					(void) fprintf(stdout,
2136					    MSGSTR(2236, "LED state is ON for "
2137					    "device in location: slot %d\n"),
2138					    path_struct->slot +
2139							(MAX_DRIVES_DAK/2));
2140				    }
2141				} else {
2142				    (void) fprintf(stdout,
2143				    (path_struct->f_flag) ?
2144				    MSGSTR(2056, "LED state is ON for "
2145				    "device in location: front,slot %d\n")
2146				    : MSGSTR(2057, "LED state is ON for "
2147				    "device in location: rear,slot %d\n"),
2148				    path_struct->slot);
2149				    }
2150			    }
2151			} else if (status.ident || status.rdy_to_ins ||
2152				status.rmv) {
2153			    if (!path_struct->slot_valid) {
2154				(void) fprintf(stdout, MSGSTR(2058,
2155				    "LED state is BLINKING for "
2156				    "device:\n  %s\n"), path_phys);
2157			    } else {
2158				if (enc_t == DAK_ENC_TYPE) {
2159				    if (path_struct->f_flag) {
2160					(void) fprintf(stdout, MSGSTR(2237,
2161					"LED state is BLINKING for "
2162					"device in location: slot %d\n"),
2163					path_struct->slot);
2164				    } else {
2165					(void) fprintf(stdout, MSGSTR(2237,
2166					"LED state is BLINKING for "
2167					"device in location: slot %d\n"),
2168					path_struct->slot + (MAX_DRIVES_DAK/2));
2169				    }
2170				} else {
2171				    (void) fprintf(stdout,
2172				    (path_struct->f_flag) ?
2173				    MSGSTR(2059, "LED state is BLINKING for "
2174				    "device in location: front,slot %d\n")
2175				    : MSGSTR(2060, "LED state is BLINKING for "
2176				    "device in location: rear,slot %d\n"),
2177				    path_struct->slot);
2178				}
2179			    }
2180			} else {
2181			    if (!path_struct->slot_valid) {
2182				(void) fprintf(stdout,
2183				MSGSTR(2061, "LED state is OFF for "
2184				"device:\n  %s\n"), path_phys);
2185			    } else {
2186				if (enc_t == DAK_ENC_TYPE) {
2187				    if (path_struct->f_flag) {
2188					(void) fprintf(stdout, MSGSTR(2238,
2189					"LED state is OFF for "
2190					"device in location: slot %d\n"),
2191					path_struct->slot);
2192				    } else {
2193					(void) fprintf(stdout, MSGSTR(2238,
2194					"LED state is OFF for "
2195					"device in location: slot %d\n"),
2196					path_struct->slot + MAX_DRIVES_DAK/2);
2197				    }
2198				} else {
2199				    (void) fprintf(stdout,
2200					(path_struct->f_flag) ?
2201					MSGSTR(2062, "LED state is OFF for "
2202					"device in location: front,slot %d\n")
2203					: MSGSTR(2063, "LED state is OFF for "
2204					"device in location: rear,slot %d\n"),
2205					path_struct->slot);
2206				}
2207			    }
2208			}
2209			break;
2210		    }
2211		    free((void *)map.dev_addr);
2212		    path_index++;
2213	}
2214}
2215
2216
2217
2218
2219
2220/*
2221 * dump() Dump information
2222 *
2223 * RETURNS:
2224 *	none.
2225 */
2226void
2227dump(char **argv)
2228{
2229uchar_t		*buf;
2230int		path_index = 0, err = 0;
2231L_inquiry	inq;
2232char		hdr_buf[MAXNAMELEN];
2233Rec_diag_hdr	*hdr, *hdr_ptr;
2234char		*path_phys = NULL;
2235Path_struct	*path_struct;
2236
2237	/*
2238	 * get big buffer
2239	 */
2240	if ((hdr = (struct rec_diag_hdr *)calloc(1, MAX_REC_DIAG_LENGTH)) ==
2241								NULL) {
2242		(void) print_errString(L_MALLOC_FAILED, NULL);
2243		exit(-1);
2244	}
2245	buf = (uchar_t *)hdr;
2246
2247	while (argv[path_index] != NULL) {
2248		if ((err = l_convert_name(argv[path_index], &path_phys,
2249			&path_struct, Options & PVERBOSE)) != 0) {
2250			(void) fprintf(stderr,
2251				MSGSTR(33,
2252					" Error: converting"
2253					" %s to physical path.\n"
2254					" Invalid pathname.\n"),
2255				argv[path_index]);
2256			if (err != -1) {
2257				(void) print_errString(err, argv[path_index]);
2258			}
2259			exit(-1);
2260		}
2261		if (err = g_get_inquiry(path_phys, &inq)) {
2262			(void) print_errString(err, argv[path_index]);
2263		} else {
2264			(void) g_dump(MSGSTR(2065, "INQUIRY data:   "),
2265			(uchar_t *)&inq, 5 + inq.inq_len, HEX_ASCII);
2266		}
2267
2268		(void) memset(buf, 0, MAX_REC_DIAG_LENGTH);
2269		if (err = l_get_envsen(path_phys, buf, MAX_REC_DIAG_LENGTH,
2270			(Options & PVERBOSE))) {
2271		    (void) print_errString(err, argv[path_index]);
2272		    exit(-1);
2273		}
2274		(void) fprintf(stdout,
2275			MSGSTR(2066, "\t\tEnvironmental Sense Information\n"));
2276
2277		/*
2278		 * Dump all pages.
2279		 */
2280		hdr_ptr = hdr;
2281
2282		while (hdr_ptr->page_len != 0) {
2283			(void) sprintf(hdr_buf, MSGSTR(2067, "Page %d:   "),
2284				hdr_ptr->page_code);
2285			(void) g_dump(hdr_buf, (uchar_t *)hdr_ptr,
2286				HEADER_LEN + hdr_ptr->page_len, HEX_ASCII);
2287			hdr_ptr += ((HEADER_LEN + hdr_ptr->page_len) /
2288				sizeof (struct	rec_diag_hdr));
2289		}
2290		path_index++;
2291	}
2292	(void) free(buf);
2293}
2294
2295
2296
2297/*
2298 * display_socal_stats() Display socal driver kstat information.
2299 *
2300 * RETURNS:
2301 *	none.
2302 */
2303void
2304display_socal_stats(int port, char *socal_path, struct socal_stats *fc_stats)
2305{
2306int		i;
2307int		header_flag = 0;
2308char		status_msg_buf[MAXNAMELEN];
2309int		num_status_entries;
2310
2311	(void) fprintf(stdout, MSGSTR(2068,
2312		"\tInformation for FC Loop on port %d of"
2313		" FC100/S Host Adapter\n\tat path: %s\n"),
2314		port, socal_path);
2315	if (fc_stats->version > 1) {
2316		(void) fprintf(stdout, "\t");
2317		(void) fprintf(stdout, MSGSTR(32,
2318			"Information from %s"), fc_stats->drvr_name);
2319		(void) fprintf(stdout, "\n");
2320		if ((*fc_stats->node_wwn != '\0') &&
2321			(*fc_stats->port_wwn[port] != '\0')) {
2322			(void) fprintf(stdout, MSGSTR(104,
2323				"  Host Adapter WWN's: Node:%s"
2324				"  Port:%s\n"),
2325				fc_stats->node_wwn,
2326				fc_stats->port_wwn[port]);
2327		}
2328		if (*fc_stats->fw_revision != '\0') {
2329			(void) fprintf(stdout, MSGSTR(105,
2330				"  Host Adapter Firmware Revision: %s\n"),
2331				fc_stats->fw_revision);
2332		}
2333		if (fc_stats->parity_chk_enabled != 0) {
2334			(void) fprintf(stdout, MSGSTR(2069,
2335			"  This Host Adapter checks S-Bus parity.\n"));
2336		}
2337	}
2338
2339	(void) fprintf(stdout, MSGSTR(2070,
2340		"  Version Resets  Req_Q_Intrpts  Qfulls"
2341		" Unsol_Resps Lips\n"));
2342
2343	(void) fprintf(stdout,  "  %4d%8d%11d%13d%10d%7d\n",
2344			fc_stats->version,
2345			fc_stats->resets,
2346			fc_stats->reqq_intrs,
2347			fc_stats->qfulls,
2348			fc_stats->pstats[port].unsol_resps,
2349			fc_stats->pstats[port].lips);
2350
2351	(void) fprintf(stdout, MSGSTR(2071,
2352		"  Els_rcvd  Abts"
2353		"     Abts_ok Offlines Loop_onlines Onlines\n"));
2354
2355	(void) fprintf(stdout, "  %4d%9d%10d%9d%13d%10d\n",
2356			fc_stats->pstats[port].els_rcvd,
2357			fc_stats->pstats[port].abts,
2358			fc_stats->pstats[port].abts_ok,
2359			fc_stats->pstats[port].offlines,
2360			fc_stats->pstats[port].online_loops,
2361			fc_stats->pstats[port].onlines);
2362
2363	/* If any status conditions exist then display */
2364	if (fc_stats->version > 1) {
2365		num_status_entries = FC_STATUS_ENTRIES;
2366	} else {
2367		num_status_entries = 64;
2368	}
2369
2370	for (i = 0; i < num_status_entries; i++) {
2371		if (fc_stats->pstats[port].resp_status[i] != 0) {
2372			if (header_flag++ == 0) {
2373				(void) fprintf(stdout, MSGSTR(2072,
2374				"  Fibre Channel Transport status:\n        "
2375				"Status                       Value"
2376				"           Count\n"));
2377			}
2378			(void) l_format_fc_status_msg(status_msg_buf,
2379			fc_stats->pstats[port].resp_status[i], i);
2380			(void) fprintf(stdout, "        %s\n",
2381				status_msg_buf);
2382		}
2383	}
2384}
2385
2386
2387
2388/*
2389 * display_sf_stats() Display sf driver kstat information.
2390 *
2391 * This routine is called by private loop device only
2392 *
2393 * RETURNS:
2394 *	none.
2395 */
2396void
2397display_sf_stats(char *path_phys, int dtype, struct sf_stats *sf_stats)
2398{
2399int		i, al_pa, err = 0;
2400gfc_map_t	map;
2401uchar_t		node_wwn[WWN_SIZE];
2402uchar_t		port_wwn[WWN_SIZE];
2403gfc_port_dev_info_t	*dev_addr_list;
2404
2405	if (sf_stats->version > 1) {
2406		(void) fprintf(stdout, "\n\t");
2407		(void) fprintf(stdout, MSGSTR(32,
2408			"Information from %s"),
2409			sf_stats->drvr_name);
2410		(void) fprintf(stdout, "\n");
2411	} else {
2412		(void) fprintf(stdout,
2413			MSGSTR(2073, "\n\t\tInformation from sf driver:\n"));
2414	}
2415
2416	(void) fprintf(stdout, MSGSTR(2074,
2417		"  Version  Lip_count  Lip_fail"
2418		" Alloc_fail  #_cmds "
2419		"Throttle_limit  Pool_size\n"));
2420
2421	(void) fprintf(stdout, "  %4d%9d%12d%11d%10d%11d%12d\n",
2422			sf_stats->version,
2423			sf_stats->lip_count,
2424			sf_stats->lip_failures,
2425			sf_stats->cralloc_failures,
2426			sf_stats->ncmds,
2427			sf_stats->throttle_limit,
2428			sf_stats->cr_pool_size);
2429
2430	(void) fprintf(stdout, MSGSTR(2075,
2431		"\n\t\tTARGET ERROR INFORMATION:\n"));
2432	(void) fprintf(stdout, MSGSTR(2076,
2433		"AL_PA  Els_fail Timouts Abts_fail"
2434		" Tsk_m_fail "
2435		" Data_ro_mis Dl_len_mis Logouts\n"));
2436
2437	if (err = g_get_dev_map(path_phys, &map, (Options & PVERBOSE))) {
2438		(void) print_errString(err, path_phys);
2439		exit(-1);
2440	}
2441
2442	if (dtype == DTYPE_DIRECT) {
2443		if (err = g_get_wwn(path_phys, port_wwn, node_wwn, &al_pa,
2444			Options & PVERBOSE)) {
2445			(void) print_errString(err, path_phys);
2446			exit(-1);
2447		}
2448		/* for san toleration, only need to modify the code    */
2449		/* such that the current sf_al_map structure replaced  */
2450		/* by the new gfc_map structure for private loop device */
2451		for (i = 0, dev_addr_list = map.dev_addr; i < map.count;
2452			i++, dev_addr_list++) {
2453			if (dev_addr_list->gfc_port_dev.priv_port.sf_al_pa
2454					== al_pa) {
2455				(void) fprintf(stdout,
2456				"%3x%10d%8d%10d%11d%13d%11d%9d\n",
2457				al_pa,
2458				sf_stats->tstats[i].els_failures,
2459				sf_stats->tstats[i].timeouts,
2460				sf_stats->tstats[i].abts_failures,
2461				sf_stats->tstats[i].task_mgmt_failures,
2462				sf_stats->tstats[i].data_ro_mismatches,
2463				sf_stats->tstats[i].dl_len_mismatches,
2464				sf_stats->tstats[i].logouts_recvd);
2465				break;
2466			}
2467		}
2468		if (i >= map.count) {
2469			(void) print_errString(L_INVALID_LOOP_MAP, path_phys);
2470			exit(-1);
2471		}
2472	} else {
2473		for (i = 0, dev_addr_list = map.dev_addr; i < map.count;
2474			i++, dev_addr_list++) {
2475			(void) fprintf(stdout,
2476			"%3x%10d%8d%10d%11d%13d%11d%9d\n",
2477			dev_addr_list->gfc_port_dev.priv_port.sf_al_pa,
2478			sf_stats->tstats[i].els_failures,
2479			sf_stats->tstats[i].timeouts,
2480			sf_stats->tstats[i].abts_failures,
2481			sf_stats->tstats[i].task_mgmt_failures,
2482			sf_stats->tstats[i].data_ro_mismatches,
2483			sf_stats->tstats[i].dl_len_mismatches,
2484			sf_stats->tstats[i].logouts_recvd);
2485		}
2486	}
2487	free((void *)map.dev_addr);
2488}
2489
2490
2491
2492/*
2493 * adm_display_err() Displays enclosure specific
2494 * error information.
2495 *
2496 * RETURNS:
2497 *	none.
2498 */
2499static void
2500adm_display_err(char *path_phys, int dtype)
2501{
2502int		i, drvr_inst, sf_inst, socal_inst, port, al_pa, err = 0;
2503char		*char_ptr, socal_path[MAXPATHLEN], drvr_path[MAXPATHLEN];
2504struct		stat sbuf;
2505kstat_ctl_t	*kc;
2506kstat_t		*ifp_ks, *sf_ks, *fc_ks;
2507sf_stats_t	sf_stats;
2508socal_stats_t	fc_stats;
2509ifp_stats_t	ifp_stats;
2510int		header_flag = 0, pathcnt = 1;
2511char		status_msg_buf[MAXNAMELEN];
2512gfc_map_t	map;
2513uchar_t		node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
2514uint_t		path_type;
2515gfc_port_dev_info_t	*dev_addr_list;
2516mp_pathlist_t	pathlist;
2517int		p_on = 0, p_st = 0;
2518
2519	if ((kc = kstat_open()) == (kstat_ctl_t *)NULL) {
2520		(void) fprintf(stderr,
2521			MSGSTR(2077, " Error: can't open kstat\n"));
2522		exit(-1);
2523	}
2524
2525	if (strstr(path_phys, SCSI_VHCI)) {
2526		(void) strcpy(drvr_path, path_phys);
2527		if (err = g_get_pathlist(drvr_path, &pathlist)) {
2528			(void) print_errString(err, NULL);
2529			exit(-1);
2530		}
2531		pathcnt = pathlist.path_count;
2532		p_on = p_st = 0;
2533		for (i = 0; i < pathcnt; i++) {
2534			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
2535				if (pathlist.path_info[i].path_state ==
2536					MDI_PATHINFO_STATE_ONLINE) {
2537					p_on = i;
2538					break;
2539				} else if (pathlist.path_info[i].path_state ==
2540					MDI_PATHINFO_STATE_STANDBY) {
2541					p_st = i;
2542				}
2543			}
2544		}
2545		if (pathlist.path_info[p_on].path_state ==
2546		    MDI_PATHINFO_STATE_ONLINE) {
2547			/* on_line path */
2548			(void) strcpy(drvr_path,
2549				pathlist.path_info[p_on].path_hba);
2550		} else {
2551			/* standby or path0 */
2552			(void) strcpy(drvr_path,
2553				pathlist.path_info[p_st].path_hba);
2554		}
2555		free(pathlist.path_info);
2556	} else {
2557
2558		(void) strcpy(drvr_path, path_phys);
2559
2560		if ((char_ptr = strrchr(drvr_path, '/')) == NULL) {
2561			(void) print_errString(L_INVLD_PATH_NO_SLASH_FND,
2562				path_phys);
2563			exit(-1);
2564		}
2565		*char_ptr = '\0';   /* Make into nexus or HBA driver path. */
2566	}
2567	/*
2568	 * Each HBA and driver stack has its own structures
2569	 * for this, so we have to handle each one individually.
2570	 */
2571	path_type = g_get_path_type(drvr_path);
2572
2573	if (path_type) { /* Quick sanity check for valid path */
2574		if ((err = g_get_nexus_path(drvr_path, &char_ptr)) != 0) {
2575			(void) print_errString(err, path_phys);
2576			exit(-1);
2577		}
2578		(void) strcpy(socal_path, char_ptr);
2579
2580	}
2581
2582	/* attach :devctl to get node stat instead of dir stat. */
2583	(void) strcat(drvr_path, FC_CTLR);
2584
2585	if (stat(drvr_path, &sbuf) < 0) {
2586		(void) print_errString(L_LSTAT_ERROR, path_phys);
2587		exit(-1);
2588	}
2589
2590	drvr_inst = minor(sbuf.st_rdev);
2591
2592
2593	/*
2594	 * first take care of ifp card.
2595	 */
2596	if (path_type & FC4_PCI_FCA) {
2597	    if ((ifp_ks = kstat_lookup(kc, "ifp",
2598			drvr_inst, "statistics")) != NULL) {
2599
2600		if (kstat_read(kc, ifp_ks, &ifp_stats) < 0) {
2601			(void) fprintf(stderr,
2602				MSGSTR(2082,
2603				"Error: could not read ifp%d\n"), drvr_inst);
2604			exit(-1);
2605		}
2606		(void) fprintf(stdout, MSGSTR(2083,
2607			"\tInformation for FC Loop of"
2608			" FC100/P Host Adapter\n\tat path: %s\n"),
2609			drvr_path);
2610		if (ifp_stats.version > 1) {
2611			(void) fprintf(stdout, "\t");
2612			(void) fprintf(stdout, MSGSTR(32,
2613				"Information from %s"),
2614				ifp_stats.drvr_name);
2615			(void) fprintf(stdout, "\n");
2616			if ((*ifp_stats.node_wwn != '\0') &&
2617				(*ifp_stats.port_wwn != '\0')) {
2618				(void) fprintf(stdout, MSGSTR(104,
2619					"  Host Adapter WWN's: Node:%s"
2620					"  Port:%s\n"),
2621					ifp_stats.node_wwn,
2622					ifp_stats.port_wwn);
2623			}
2624			if (*ifp_stats.fw_revision != 0) {
2625				(void) fprintf(stdout, MSGSTR(105,
2626				"  Host Adapter Firmware Revision: %s\n"),
2627				ifp_stats.fw_revision);
2628			}
2629			if (ifp_stats.parity_chk_enabled != 0) {
2630				(void) fprintf(stdout, MSGSTR(2084,
2631				"  This Host Adapter checks "
2632				"PCI-Bus parity.\n"));
2633			}
2634		}
2635
2636		(void) fprintf(stdout, MSGSTR(2085,
2637			"        Version Lips\n"));
2638		(void) fprintf(stdout, "  %10d%7d\n",
2639				ifp_stats.version,
2640				ifp_stats.lip_count);
2641		/* If any status conditions exist then display */
2642		for (i = 0; i < FC_STATUS_ENTRIES; i++) {
2643			if (ifp_stats.resp_status[i] != 0) {
2644				if (header_flag++ == 0) {
2645					(void) fprintf(stdout, MSGSTR(2086,
2646					"  Fibre Channel Transport "
2647					"status:\n        "
2648					"Status           "
2649					"            Value"
2650					"           Count\n"));
2651				}
2652				(void) l_format_ifp_status_msg(
2653					status_msg_buf,
2654					ifp_stats.resp_status[i], i);
2655					(void) fprintf(stdout, "        %s\n",
2656					status_msg_buf);
2657			}
2658		}
2659
2660		(void) fprintf(stdout, MSGSTR(2087,
2661			"\n\t\tTARGET ERROR INFORMATION:\n"));
2662		(void) fprintf(stdout, MSGSTR(2088,
2663			"AL_PA  logouts_recvd  task_mgmt_failures"
2664			"  data_ro_mismatches  data_len_mismatch\n"));
2665
2666		if (err = g_get_dev_map(path_phys, &map,
2667					(Options & PVERBOSE))) {
2668			(void) print_errString(err, path_phys);
2669			exit(-1);
2670		}
2671
2672
2673		if (dtype == DTYPE_DIRECT) {
2674			if (err = g_get_wwn(path_phys, port_wwn,
2675				node_wwn, &al_pa,
2676				Options & PVERBOSE)) {
2677				(void) print_errString(err,
2678				path_phys);
2679				exit(-1);
2680			}
2681			for (i = 0, dev_addr_list = map.dev_addr;
2682				i < map.count; i++,
2683				dev_addr_list++) {
2684				if (dev_addr_list->gfc_port_dev.
2685					priv_port.sf_al_pa
2686					== al_pa) {
2687					(void) fprintf
2688					(stdout,
2689					"%3x%14d%18d%20d%20d\n",
2690					al_pa,
2691					ifp_stats.tstats[i].
2692						logouts_recvd,
2693					ifp_stats.tstats[i].
2694						task_mgmt_failures,
2695					ifp_stats.tstats[i].
2696						data_ro_mismatches,
2697					ifp_stats.tstats[i].
2698						dl_len_mismatches);
2699					break;
2700				}
2701			}
2702			if (i >= map.count) {
2703
2704				(void) print_errString(
2705				L_INVALID_LOOP_MAP, path_phys);
2706				exit(-1);
2707			}
2708
2709		} else {
2710			for (i = 0, dev_addr_list = map.dev_addr;
2711				i < map.count; i++,
2712				dev_addr_list++) {
2713				(void) fprintf(stdout,
2714				"%3x%14d%18d%20d%20d\n",
2715				dev_addr_list->gfc_port_dev.
2716					priv_port.sf_al_pa,
2717				ifp_stats.tstats[i].logouts_recvd,
2718				ifp_stats.tstats[i].task_mgmt_failures,
2719				ifp_stats.tstats[i].data_ro_mismatches,
2720				ifp_stats.tstats[i].dl_len_mismatches);
2721			}
2722		}
2723
2724		free((void *)map.dev_addr);
2725	    }
2726	} else if (path_type & FC4_SF_XPORT) {
2727	/*
2728	 * process cards with sf xport nodes.
2729	 */
2730	    if (stat(socal_path, &sbuf) < 0) {
2731		(void) print_errString(L_LSTAT_ERROR, path_phys);
2732		exit(-1);
2733	    }
2734	    socal_inst = minor(sbuf.st_rdev)/2;
2735	    port = socal_inst%2;
2736
2737	    sf_inst = LUX_SF_MINOR2INST(minor(sbuf.st_rdev));
2738	    if (!(sf_ks = kstat_lookup(kc, "sf", sf_inst,
2739		"statistics"))) {
2740		(void) fprintf(stderr,
2741			MSGSTR(2078,
2742		" Error: could not lookup driver stats for sf%d\n"),
2743			sf_inst);
2744		exit(-1);
2745	    }
2746	    if (!(fc_ks = kstat_lookup(kc, "socal", socal_inst,
2747					"statistics"))) {
2748		(void) fprintf(stderr,
2749			MSGSTR(2079,
2750		" Error: could not lookup driver stats for socal%d\n"),
2751			socal_inst);
2752		exit(-1);
2753	    }
2754	    if (kstat_read(kc, sf_ks, &sf_stats) < 0) {
2755		(void) fprintf(stderr,
2756			MSGSTR(2080,
2757		" Error: could not read driver stats for sf%d\n"),
2758			sf_inst);
2759		exit(-1);
2760	    }
2761	    if (kstat_read(kc, fc_ks, &fc_stats) < 0) {
2762		(void) fprintf(stderr,
2763			MSGSTR(2081,
2764		" Error: could not read driver stats for socal%d\n"),
2765			socal_inst);
2766		exit(-1);
2767	    }
2768	    (void) display_socal_stats(port, socal_path, &fc_stats);
2769	    (void) display_sf_stats(path_phys, dtype, &sf_stats);
2770	} else if ((path_type & FC_FCA_MASK) == FC_PCI_FCA) {
2771		fprintf(stderr, MSGSTR(2252,
2772			"\n WARNING!! display -r on qlc is"
2773			" currently not supported.\n"));
2774	} else {
2775		fprintf(stderr, MSGSTR(2253,
2776			"\n WARNING!! display -r is not supported on path\n"
2777			" %s\n"), drvr_path);
2778	}
2779	(void) kstat_close(kc);
2780
2781}
2782
2783
2784
2785/*ARGSUSED*/
2786/*
2787 * adm_display_verbose_disk() Gets the mode page information
2788 * for a SENA disk and prints that information.
2789 *
2790 * RETURNS:
2791 *	none.
2792 */
2793void
2794adm_display_verbose_disk(char *path, int verbose)
2795{
2796uchar_t		*pg_buf;
2797Mode_header_10	*mode_header_ptr;
2798Mp_01		*pg1_buf;
2799Mp_04		*pg4_buf;
2800struct mode_page *pg_hdr;
2801int		offset, hdr_printed = 0, err = 0;
2802
2803	if ((err = l_get_mode_pg(path, &pg_buf, verbose)) == 0) {
2804
2805		mode_header_ptr = (struct mode_header_10_struct *)(int)pg_buf;
2806		pg_hdr = ((struct mode_page *)((int)pg_buf +
2807		    (uchar_t)sizeof (struct mode_header_10_struct) +
2808		    (uchar_t *)(uintptr_t)(mode_header_ptr->bdesc_length)));
2809		offset = sizeof (struct mode_header_10_struct) +
2810		    mode_header_ptr->bdesc_length;
2811		while (offset < (mode_header_ptr->length +
2812			sizeof (mode_header_ptr->length))) {
2813			switch (pg_hdr->code) {
2814				case 0x01:
2815				pg1_buf = (struct mode_page_01_struct *)
2816					(int)pg_hdr;
2817				P_DPRINTF("  adm_display_verbose_disk:"
2818					"Mode Sense page 1 found.\n");
2819				if (hdr_printed++ == 0) {
2820					(void) fprintf(stdout,
2821						MSGSTR(2089,
2822						"  Mode Sense data:\n"));
2823				}
2824				(void) fprintf(stdout,
2825					MSGSTR(2090,
2826					"    AWRE:\t\t\t%d\n"
2827					"    ARRE:\t\t\t%d\n"
2828					"    Read Retry Count:\t\t"
2829					"%d\n"
2830					"    Write Retry Count:\t\t"
2831					"%d\n"),
2832					pg1_buf->awre,
2833					pg1_buf->arre,
2834					pg1_buf->read_retry_count,
2835					pg1_buf->write_retry_count);
2836				break;
2837				case MODEPAGE_GEOMETRY:
2838				pg4_buf = (struct mode_page_04_struct *)
2839					(int)pg_hdr;
2840				P_DPRINTF("  adm_display_verbose_disk:"
2841					"Mode Sense page 4 found.\n");
2842				if (hdr_printed++ == 0) {
2843					(void) fprintf(stdout,
2844						MSGSTR(2091,
2845						"  Mode Sense data:\n"));
2846				}
2847				if (pg4_buf->rpm) {
2848					(void) fprintf(stdout,
2849						MSGSTR(2092,
2850						"    Medium rotation rate:\t"
2851						"%d RPM\n"), pg4_buf->rpm);
2852				}
2853				break;
2854			}
2855			offset += pg_hdr->length + sizeof (struct mode_page);
2856			pg_hdr = ((struct mode_page *)((int)pg_buf +
2857				(uchar_t)offset));
2858		}
2859
2860
2861
2862
2863
2864	} else if (getenv("_LUX_P_DEBUG") != NULL) {
2865			(void) print_errString(err, path);
2866	}
2867}
2868
2869/*
2870 * Print out the port_wwn or node_wwn
2871 */
2872void
2873print_wwn(FILE *fd, uchar_t *pn_wwn)
2874{
2875
2876	(void) fprintf(fd,
2877		" %1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
2878		pn_wwn[0], pn_wwn[1], pn_wwn[2], pn_wwn[3],
2879		pn_wwn[4], pn_wwn[5], pn_wwn[6], pn_wwn[7]);
2880}
2881
2882/*
2883 * Print out the fabric dev port_id, hard_addr, port_wwn and node_wwn
2884 */
2885void
2886print_fabric_prop(int pos, uchar_t *port_wwn, uchar_t *node_wwn, int port_addr,
2887	int hard_addr)
2888{
2889	(void) fprintf(stdout, "%-4d %-6x  %-6x   ",
2890		pos, port_addr, hard_addr);
2891	print_wwn(stdout, port_wwn);
2892	print_wwn(stdout, node_wwn);
2893}
2894
2895/*
2896 * Print out the private loop dev port_id, hard_addr, port_wwn and node_wwn
2897 */
2898void
2899print_private_loop_prop(int pos, uchar_t *port_wwn, uchar_t *node_wwn,
2900	int port_addr, int hard_addr)
2901{
2902	(void) fprintf(stdout, "%-3d   %-2x  %-2x    %-2x    ",
2903		pos, port_addr, g_sf_alpa_to_switch[port_addr], hard_addr);
2904	print_wwn(stdout, port_wwn);
2905	print_wwn(stdout, node_wwn);
2906}
2907
2908/*
2909 * Get the device map from
2910 * fc nexus driver and prints the map.
2911 *
2912 * RETURNS:
2913 *	none.
2914 */
2915void
2916dump_map(char **argv)
2917{
2918int		i = 0, path_index = 0, pathcnt = 1;
2919int		limited_map_flag = 0, err = 0;
2920char		*path_phys = NULL;
2921Path_struct	*path_struct;
2922struct lilpmap	limited_map;
2923uint_t		dev_type;
2924char		temp2path[MAXPATHLEN];
2925mp_pathlist_t	pathlist;
2926int		p_pw = 0, p_on = 0, p_st = 0;
2927gfc_dev_t	map_root, map_dev;
2928int		*port_addr, *hard_addr, pos = 0, count;
2929uchar_t		*hba_port_wwn, *port_wwn, *node_wwn, *dtype_prop;
2930uint_t		map_topo;
2931
2932	while (argv[path_index] != NULL) {
2933		if ((err = l_convert_name(argv[path_index], &path_phys,
2934			&path_struct, Options & PVERBOSE)) != 0) {
2935			(void) fprintf(stderr,
2936				MSGSTR(33,
2937					" Error: converting"
2938					" %s to physical path.\n"
2939					" Invalid pathname.\n"),
2940				argv[path_index]);
2941			if (err != -1) {
2942				(void) print_errString(err, argv[path_index]);
2943			}
2944			exit(-1);
2945		}
2946
2947		if (strstr(path_phys, SCSI_VHCI) != NULL) {
2948			/* obtain phci */
2949			(void) strcpy(temp2path, path_phys);
2950			if (err = g_get_pathlist(temp2path, &pathlist)) {
2951				(void) print_errString(err, NULL);
2952				exit(-1);
2953			}
2954			pathcnt = pathlist.path_count;
2955			p_pw = p_on = p_st = 0;
2956			for (i = 0; i < pathcnt; i++) {
2957				if (pathlist.path_info[i].path_state <
2958					MAXPATHSTATE) {
2959					if (strstr(pathlist.path_info[i].
2960						path_addr,
2961						path_struct->argv) != NULL) {
2962						p_pw = i;
2963						break;
2964					}
2965					if (pathlist.path_info[i].path_state ==
2966						MDI_PATHINFO_STATE_ONLINE) {
2967						p_on = i;
2968					}
2969					if (pathlist.path_info[i].path_state ==
2970						MDI_PATHINFO_STATE_STANDBY) {
2971						p_st = i;
2972					}
2973				}
2974			}
2975			if (strstr(pathlist.path_info[p_pw].path_addr,
2976				path_struct->argv) != NULL) {
2977				/* matching input pwwn */
2978				(void) strcpy(temp2path,
2979					pathlist.path_info[p_pw].path_hba);
2980			} else if (pathlist.path_info[p_on].path_state ==
2981				MDI_PATHINFO_STATE_ONLINE) {
2982				/* on_line path */
2983				(void) strcpy(temp2path,
2984					pathlist.path_info[p_on].path_hba);
2985			} else {
2986				/* standby or path0 */
2987				(void) strcpy(temp2path,
2988					pathlist.path_info[p_st].path_hba);
2989			}
2990			free(pathlist.path_info);
2991			(void) strcat(temp2path, FC_CTLR);
2992		} else {
2993			(void) strcpy(temp2path, path_phys);
2994		}
2995
2996		if ((dev_type = g_get_path_type(temp2path)) == 0) {
2997			(void) print_errString(L_INVALID_PATH,
2998						argv[path_index]);
2999			exit(-1);
3000		}
3001
3002		if ((map_root = g_dev_map_init(temp2path, &err,
3003			MAP_FORMAT_LILP)) == NULL) {
3004		    if (dev_type & FC_FCA_MASK) {
3005			(void) print_errString(err, argv[path_index]);
3006			exit(-1);
3007		    } else {
3008			/*
3009			 * This did not work so try the FCIO_GETMAP
3010			 * type ioctl.
3011			 */
3012			if (err = g_get_limited_map(path_phys,
3013				&limited_map, (Options & PVERBOSE))) {
3014				(void) print_errString(err,
3015						argv[path_index]);
3016				exit(-1);
3017			}
3018			limited_map_flag++;
3019		    }
3020
3021		}
3022
3023		if (limited_map_flag) {
3024		    (void) fprintf(stdout,
3025			MSGSTR(2093,
3026			"Host Adapter AL_PA: %x\n"),
3027			limited_map.lilp_myalpa);
3028
3029		    (void) fprintf(stdout,
3030			MSGSTR(2094,
3031			"Pos AL_PA\n"));
3032		    for (i = 0; i < (uint_t)limited_map.lilp_length; i++) {
3033			(void) fprintf(stdout, "%-3d   %-2x\n",
3034				i, limited_map.lilp_list[i]);
3035		    }
3036		} else {
3037		    if ((err = g_dev_prop_lookup_bytes(map_root,
3038			PORT_WWN_PROP, &count, &hba_port_wwn)) != 0) {
3039			g_dev_map_fini(map_root);
3040			(void) print_errString(err, argv[path_index]);
3041			exit(-1);
3042		    }
3043		    if ((err = g_get_map_topology(
3044				map_root, &map_topo)) != 0) {
3045			(void) print_errString(err, argv[path_index]);
3046			exit(-1);
3047		    }
3048
3049		    if ((map_dev = g_get_first_dev(map_root, &err)) == NULL) {
3050			if (err == L_NO_SUCH_DEV_FOUND) {
3051			    g_dev_map_fini(map_root);
3052			    (void) fprintf(stderr,
3053			    MSGSTR(2308, " No devices are found on %s.\n"),
3054			    argv[path_index]);
3055			    exit(-1);
3056			} else {
3057			    g_dev_map_fini(map_root);
3058			    (void) print_errString(err, argv[path_index]);
3059			    exit(-1);
3060			}
3061		    }
3062
3063		    switch (map_topo) {
3064		    case FC_TOP_FABRIC:
3065		    case FC_TOP_PUBLIC_LOOP:
3066		    case FC_TOP_PT_PT:
3067			(void) fprintf(stdout,
3068			MSGSTR(2095, "Pos  Port_ID Hard_Addr Port WWN"
3069			"         Node WWN         Type\n"));
3070			while (map_dev) {
3071			    if ((err = g_dev_prop_lookup_ints(
3072				map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
3073				g_dev_map_fini(map_root);
3074				(void) print_errString(err, argv[path_index]);
3075				exit(-1);
3076			    }
3077			    if ((err = g_dev_prop_lookup_bytes(map_dev,
3078				PORT_WWN_PROP, &count, &port_wwn)) != 0) {
3079				g_dev_map_fini(map_root);
3080				(void) print_errString(err, argv[path_index]);
3081				exit(-1);
3082			    }
3083			    if ((err = g_dev_prop_lookup_bytes(map_dev,
3084				NODE_WWN_PROP, &count, &node_wwn)) != 0) {
3085				g_dev_map_fini(map_root);
3086				(void) print_errString(err, argv[path_index]);
3087				exit(-1);
3088			    }
3089			    if ((err = g_dev_prop_lookup_ints(
3090				map_dev, HARD_ADDR_PROP, &hard_addr)) != 0) {
3091				g_dev_map_fini(map_root);
3092				(void) print_errString(err, argv[path_index]);
3093				exit(-1);
3094			    }
3095			    print_fabric_prop(pos++, port_wwn,
3096					node_wwn, *port_addr, *hard_addr);
3097			    if ((err =  g_dev_prop_lookup_bytes(map_dev,
3098				INQ_DTYPE_PROP, &count, &dtype_prop)) != 0) {
3099				(void) fprintf(stdout,
3100				MSGSTR(2307, " Failed to get the type.\n"));
3101			    } else {
3102				print_fabric_dtype_prop(hba_port_wwn, port_wwn,
3103					*dtype_prop);
3104			    }
3105
3106			    if (((map_dev = g_get_next_dev(
3107				map_dev, &err)) == NULL) &&
3108				(err != L_NO_SUCH_DEV_FOUND)) {
3109				g_dev_map_fini(map_root);
3110				(void) print_errString(err, argv[path_index]);
3111				exit(-1);
3112			    }
3113			}
3114			break;
3115		    case FC_TOP_PRIVATE_LOOP:
3116			(void) fprintf(stdout,
3117			MSGSTR(2295,
3118			"Pos AL_PA ID Hard_Addr "
3119			"Port WWN         Node WWN         Type\n"));
3120
3121			while (map_dev) {
3122			    if ((err = g_dev_prop_lookup_ints(
3123				map_dev, PORT_ADDR_PROP, &port_addr)) != 0) {
3124				g_dev_map_fini(map_root);
3125				(void) print_errString(err, argv[path_index]);
3126				exit(-1);
3127			    }
3128			    if ((err = g_dev_prop_lookup_bytes(map_dev,
3129				PORT_WWN_PROP, &count, &port_wwn)) != 0) {
3130				g_dev_map_fini(map_root);
3131				(void) print_errString(err, argv[path_index]);
3132				exit(-1);
3133			    }
3134			    if ((err = g_dev_prop_lookup_bytes(map_dev,
3135				NODE_WWN_PROP, &count, &node_wwn)) != 0) {
3136				g_dev_map_fini(map_root);
3137				(void) print_errString(err, argv[path_index]);
3138				exit(-1);
3139			    }
3140			    if ((err = g_dev_prop_lookup_ints(
3141				map_dev, HARD_ADDR_PROP, &hard_addr)) != 0) {
3142				g_dev_map_fini(map_root);
3143				(void) print_errString(err, argv[path_index]);
3144				exit(-1);
3145			    }
3146			    print_private_loop_prop(pos++, port_wwn,
3147					node_wwn, *port_addr, *hard_addr);
3148			    if ((err =  g_dev_prop_lookup_bytes(map_dev,
3149				INQ_DTYPE_PROP, &count, &dtype_prop)) != 0) {
3150				(void) fprintf(stdout,
3151				MSGSTR(2307, " Failed to get the type.\n"));
3152			    } else {
3153				print_private_loop_dtype_prop(hba_port_wwn,
3154					port_wwn, *dtype_prop);
3155			    }
3156
3157			    if (((map_dev = g_get_next_dev(
3158				map_dev, &err)) == NULL) &&
3159				(err != L_NO_SUCH_DEV_FOUND)) {
3160				g_dev_map_fini(map_root);
3161				(void) print_errString(err, argv[path_index]);
3162				exit(-1);
3163			    }
3164			}
3165			break;
3166		    default:
3167			(void) print_errString(L_UNEXPECTED_FC_TOPOLOGY,
3168			argv[path_index]);
3169			exit(-1);
3170		    }
3171		    g_dev_map_fini(map_root);
3172		}
3173		limited_map_flag = 0;
3174		path_index++;
3175	}
3176}
3177
3178/*
3179 * Gets a list of non-SENA fcal devices
3180 * found on the system.
3181 *
3182 * OUTPUT:
3183 *	wwn_list pointer
3184 *			NULL: No non-enclosure devices found.
3185 *			!NULL: Devices found
3186 *                      wwn_list points to a linked list of wwn's.
3187 * RETURNS:
3188 *	0	O.K.
3189 */
3190int
3191n_get_non_encl_list(WWN_list **wwn_list_ptr, int verbose)
3192{
3193int		i, j, k, err, found_ib = 0, pathcnt = 1;
3194WWN_list	*wwn_list;
3195Box_list	*b_list = NULL;
3196gfc_map_t	map;
3197uchar_t		box_id;
3198gfc_port_dev_info_t	*dev_addr_list;
3199char		phci_path[MAXPATHLEN], oldphci_path[MAXPATHLEN];
3200mp_pathlist_t	pathlist;
3201
3202
3203	/*
3204	 * Only interested in devices that are not part of
3205	 * a Photon enclosure.
3206	 */
3207	if ((err = l_get_box_list(&b_list, verbose)) != 0) {
3208		return (err);	/* Failure */
3209	}
3210
3211	if (err = g_get_wwn_list(&wwn_list, verbose)) {
3212		(void) l_free_box_list(&b_list);
3213		return (err);
3214	}
3215
3216	while (b_list != NULL) {
3217
3218		pathcnt = 1;
3219		if (strstr(b_list->b_physical_path, SCSI_VHCI) != NULL) {
3220			(void) strcpy(phci_path, b_list->b_physical_path);
3221			if (err = g_get_pathlist(phci_path, &pathlist)) {
3222				(void) print_errString(err, NULL);
3223				exit(-1);
3224			}
3225			pathcnt = pathlist.path_count;
3226		}
3227
3228		for (k = 0; k < pathcnt; k++) {
3229
3230		if ((k > 0) && (strstr(oldphci_path,
3231			pathlist.path_info[k].path_hba))) {
3232				continue;
3233		}
3234
3235		if (strstr(b_list->b_physical_path, SCSI_VHCI) == NULL) {
3236			if ((err = g_get_dev_map(b_list->b_physical_path,
3237				&map, verbose)) != 0) {
3238				(void) g_free_wwn_list(&wwn_list);
3239				(void) l_free_box_list(&b_list);
3240				return (err);
3241			}
3242		} else {
3243			(void) strcpy(phci_path,
3244				pathlist.path_info[k].path_hba);
3245			(void) strcpy(oldphci_path, phci_path);
3246			(void) strcat(phci_path, FC_CTLR);
3247			if (g_get_dev_map(phci_path, &map, verbose)) {
3248				continue;
3249			}
3250			if (pathcnt == 1) {
3251				free(pathlist.path_info);
3252			}
3253		}
3254
3255
3256		switch (map.hba_addr.port_topology) {
3257		case FC_TOP_FABRIC:
3258		case FC_TOP_PUBLIC_LOOP:
3259
3260			for (i = 0, dev_addr_list = map.dev_addr;
3261				i < map.count; i++, dev_addr_list++) {
3262				for (found_ib = 1, j = 0; j < WWN_SIZE;
3263					j++) {
3264					if (b_list->b_node_wwn[j] !=
3265						dev_addr_list->gfc_port_dev.
3266						pub_port.dev_nwwn.raw_wwn[j]) {
3267						found_ib = 0;
3268					}
3269				}
3270				if (found_ib) {
3271					(void) n_rem_list_entry_fabric(
3272					dev_addr_list->gfc_port_dev.
3273					pub_port.dev_did.port_id, &map,
3274					&wwn_list);
3275				}
3276			}
3277			break;
3278
3279		case FC_TOP_PRIVATE_LOOP:
3280
3281			for (i = 0, dev_addr_list = map.dev_addr;
3282				i < map.count; i++, dev_addr_list++) {
3283				for (found_ib = 1, j = 0; j < WWN_SIZE;
3284					j++) {
3285					if (b_list->b_node_wwn[j] !=
3286						dev_addr_list->gfc_port_dev.
3287						priv_port.sf_node_wwn[j]) {
3288							found_ib = 0;
3289					}
3290				}
3291				if (found_ib) {
3292					box_id = g_sf_alpa_to_switch
3293						[dev_addr_list->gfc_port_dev.
3294						priv_port.sf_al_pa] &
3295						BOX_ID_MASK;
3296					/* This function has been added */
3297					/* here only to keep from having */
3298					/* to tab over farther */
3299					(void) n_rem_list_entry(box_id, &map,
3300						&wwn_list);
3301					if (wwn_list == NULL) {
3302						/* Return the list */
3303						*wwn_list_ptr = NULL;
3304						break;
3305					}
3306				}
3307			}
3308			break;
3309		case FC_TOP_PT_PT:
3310			(void) free((void *)map.dev_addr);
3311			return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
3312		default:
3313			(void) free((void *)map.dev_addr);
3314			return (L_UNEXPECTED_FC_TOPOLOGY);
3315		}
3316		free((void *)map.dev_addr);
3317
3318		}
3319		if (pathcnt > 1) {
3320			free(pathlist.path_info);
3321		}
3322
3323		b_list = b_list->box_next;
3324	}
3325	/* Return the list */
3326	*wwn_list_ptr = wwn_list;
3327	(void) l_free_box_list(&b_list);
3328	return (0);
3329}
3330
3331
3332
3333/*
3334 * n_rem_list_entry() We found an IB so remove disks that
3335 * are in the Photon from the individual device list.
3336 *
3337 * OUTPUT:
3338 *	wwn_list - removes the fcal disks that are in SENA enclosure
3339 *
3340 * RETURNS:
3341 *	none
3342 */
3343void
3344n_rem_list_entry(uchar_t box_id,  struct gfc_map *map,
3345	struct	wwn_list_struct **wwn_list)
3346{
3347int		k;
3348gfc_port_dev_info_t	*dev_addr_list;
3349
3350	N_DPRINTF("  n_rem_list_entry: Removing devices"
3351		" with box_id=0x%x from device list.\n", box_id);
3352
3353
3354		for (k = 0, dev_addr_list = map->dev_addr; k < map->count;
3355			k++, dev_addr_list++) {
3356			if ((g_sf_alpa_to_switch[dev_addr_list->gfc_port_dev.
3357				priv_port.sf_hard_address] & BOX_ID_MASK)
3358				== box_id) {
3359				n_rem_wwn_entry(dev_addr_list->gfc_port_dev.
3360					priv_port.sf_node_wwn, wwn_list);
3361			}
3362		}
3363
3364}
3365
3366
3367
3368/*
3369 * n_rem_list_entry_fabric() We found an IB so remove disks that
3370 * are in the Photon from the individual device list.
3371 *
3372 * OUTPUT:
3373 *	wwn_list - removes the fcal disks that are in SENA enclosure
3374 *
3375 * RETURNS:
3376 *	none
3377 */
3378void
3379n_rem_list_entry_fabric(int pa,  struct gfc_map *map,
3380	struct	wwn_list_struct **wwn_list)
3381{
3382int		k;
3383gfc_port_dev_info_t	*dev_addr_ptr;
3384
3385	N_DPRINTF("  n_rem_list_entry: Removing devices"
3386		" with the same domain and area ID as"
3387		" 0x%x PA from device list.\n", pa);
3388	for (k = 0, dev_addr_ptr = map->dev_addr; k < map->count;
3389				k++, dev_addr_ptr++) {
3390
3391		/* matching the domain and area id with input alpa, */
3392		/* ignoring last 8 bits. */
3393		if ((dev_addr_ptr->gfc_port_dev.pub_port.dev_did.port_id |
3394				0xff) == (pa | 0xff)) {
3395			n_rem_wwn_entry(dev_addr_ptr->
3396				gfc_port_dev.pub_port.dev_nwwn.raw_wwn,
3397				wwn_list);
3398		}
3399	}
3400}
3401
3402
3403/*
3404 * n_rem_wwn_entry() removes input wwn from wwn_list.
3405 *
3406 * OUTPUT:
3407 *	wwn_list - removes the input wwn from wwn_list if found.
3408 *
3409 * RETURNS:
3410 *	none
3411 */
3412void
3413n_rem_wwn_entry(uchar_t node_wwn[], struct  wwn_list_struct **wwn_list)
3414{
3415int		l, found_dev;
3416WWN_list	*inner, *l1;
3417
3418	inner = *wwn_list;
3419	while (inner != NULL) {
3420		for (found_dev = 1, l = 0; l < WWN_SIZE; l++) {
3421			if (inner->w_node_wwn[l] != node_wwn[l]) {
3422				found_dev = 0;
3423			}
3424		}
3425		if (found_dev) {
3426			/* Remove this entry from the list */
3427			if (inner->wwn_prev != NULL) {
3428				inner->wwn_prev->wwn_next =
3429					inner->wwn_next;
3430			} else {
3431				*wwn_list = inner->wwn_next;
3432			}
3433			if (inner->wwn_next != NULL) {
3434				inner->wwn_next->wwn_prev =
3435					inner->wwn_prev;
3436			}
3437			l1 = inner;
3438			N_DPRINTF("  n_rem_wwn_entry: "
3439				"Removing Logical=%s "
3440				"Current=0x%x, "
3441				"Prev=0x%x, Next=0x%x\n",
3442				l1->logical_path,
3443				l1,
3444				l1->wwn_prev,
3445				l1->wwn_next);
3446			inner = inner->wwn_next;
3447			if ((l1->wwn_prev == NULL) &&
3448				(l1->wwn_next) == NULL) {
3449				(void) free(l1->physical_path);
3450				(void) free(l1->logical_path);
3451				(void) free(l1);
3452				*wwn_list = NULL;
3453				N_DPRINTF("  n_rem_list_entry: "
3454				"No non-Photon "
3455				"devices left"
3456				" in the list.\n");
3457				return;
3458			}
3459				(void) free(l1->physical_path);
3460				(void) free(l1->logical_path);
3461				(void) free(l1);
3462		} else {
3463			inner = inner->wwn_next;
3464		}
3465	}
3466}
3467
3468
3469/*
3470 * non_encl_probe() Finds and displays a list of
3471 * non-SENA fcal devices which is found on the
3472 * system.
3473 *
3474 * RETURNS:
3475 *	none.
3476 */
3477void
3478non_encl_probe()
3479{
3480WWN_list	*wwn_list, *wwn_listh, *inner, *l1;
3481int		err = 0;
3482char		lun_a[MAXPATHLEN], lun_b[MAXPATHLEN], temppath[MAXPATHLEN];
3483char		*tempptra, *tempptrb, *tempptr;
3484mp_pathlist_t	pathlist;
3485int		compare_result, retr_outer = 0;
3486ddi_devid_t	devid1 = NULL, devid2 = NULL;
3487di_node_t	root = DI_NODE_NIL;
3488
3489	if (err = n_get_non_encl_list(&wwn_list, (Options & PVERBOSE))) {
3490		(void) print_errString(err, NULL);
3491		exit(-1);
3492	}
3493
3494	g_sort_wwn_list(&wwn_list);
3495
3496	wwn_listh = wwn_list;
3497
3498	if (wwn_list != NULL) {
3499		if (wwn_list->wwn_next != NULL) {
3500			(void) fprintf(stdout,
3501			    MSGSTR(2098, "\nFound Fibre Channel device(s):\n"));
3502		} else {
3503			(void) fprintf(stdout,
3504			    MSGSTR(2099, "\nFound Fibre Channel device:\n"));
3505		}
3506	} else {
3507		return;
3508	}
3509
3510	while (wwn_list != NULL) {
3511	    if (strstr(wwn_list->physical_path, SCSI_VHCI) != NULL) {
3512		(void) strcpy(temppath, wwn_list->physical_path);
3513		if ((!g_get_pathlist(temppath,
3514		    &pathlist)) &&
3515		    ((tempptra = strchr(pathlist.path_info[0].
3516		    path_addr, ','))) != NULL) {
3517			tempptra++;
3518			(void) strcpy(lun_a, tempptra);
3519			free(pathlist.path_info);
3520		}
3521	    } else {
3522		if ((((tempptr = strstr(wwn_list->physical_path,
3523		    SLSH_DRV_NAME_ST)) != NULL) ||
3524		    ((tempptr = strstr(wwn_list->physical_path,
3525		    SLSH_DRV_NAME_SSD)) != NULL)) &&
3526		    ((tempptra = strchr(tempptr, ',')) != NULL)) {
3527			tempptra++;
3528			(void) strcpy(lun_a, tempptra);
3529		}
3530	    }
3531	    (void) fprintf(stdout, "  ");
3532	    (void) fprintf(stdout, MSGSTR(90, "Node WWN:"));
3533	    (void) fprintf(stdout, "%s  ", wwn_list->node_wwn_s);
3534
3535	    if (wwn_list->device_type < 0x10) {
3536		(void) fprintf(stdout, MSGSTR(35, "Device Type:"));
3537		(void) fprintf(stdout, "%s",
3538		dtype[wwn_list->device_type]);
3539	    } else if (wwn_list->device_type < 0x1f) {
3540			(void) fprintf(stdout, MSGSTR(2100,
3541			"Type:Reserved"));
3542	    } else {
3543			(void) fprintf(stdout, MSGSTR(2101,
3544			"Type:Unknown"));
3545	    }
3546	    (void) fprintf(stdout, "\n    ");
3547	    (void) fprintf(stdout, MSGSTR(31, "Logical Path:%s"),
3548			wwn_list->logical_path);
3549	    (void) fprintf(stdout, "\n");
3550
3551	    if (Options & OPTION_P) {
3552		(void) fprintf(stdout, "    ");
3553		(void) fprintf(stdout,
3554		MSGSTR(5, "Physical Path:"));
3555		(void) fprintf(stdout, "\n     %s\n", wwn_list->physical_path);
3556	    }
3557	    inner = wwn_list->wwn_next;
3558
3559	    while (inner != NULL) {
3560		if (strcmp(inner->node_wwn_s, wwn_list->node_wwn_s) == 0) {
3561
3562		    if (tempptra != NULL) {
3563			if (strstr(inner->physical_path,
3564			    SCSI_VHCI) != NULL) {
3565			    (void) strcpy(temppath,
3566			    inner->physical_path);
3567
3568			    if ((!g_get_pathlist(temppath, &pathlist)) &&
3569				((tempptrb = strchr(
3570				pathlist.path_info[0].path_addr, ','))) !=
3571				    NULL) {
3572				tempptrb++;
3573				(void) strcpy(lun_b, tempptrb);
3574				free(pathlist.path_info);
3575			    }
3576			} else {
3577			    if ((((tempptr = strstr(inner->physical_path,
3578				SLSH_DRV_NAME_ST)) != NULL) ||
3579				((tempptr = strstr(inner->physical_path,
3580				SLSH_DRV_NAME_SSD)) != NULL)) &&
3581				((tempptrb = strchr(tempptr, ',')) != NULL)) {
3582				tempptrb++;
3583				(void) strcpy(lun_b, tempptrb);
3584			    }
3585			}
3586		    }
3587
3588		    if (((tempptra == NULL) || (strcmp(lun_a, lun_b)) == 0)) {
3589
3590			/*
3591			 * Have we retrieved a snapshot yet?
3592			 */
3593			if (root == DI_NODE_NIL) {
3594			    if ((root = di_init("/", DINFOCPYALL)) ==
3595				DI_NODE_NIL) {
3596				(void) fprintf(stdout,
3597				    MSGSTR(2319,
3598				    "\nFailed to get device tree snapshot:\n"));
3599				exit(1);
3600			    }
3601			}
3602
3603			/* Apply devid to ssd devices only */
3604			if (!retr_outer && strstr(wwn_list->physical_path,
3605			    SLSH_DRV_NAME_SSD) != NULL) {
3606			    if ((err = g_devid_get(wwn_list->physical_path,
3607				&devid1, root, SSD_DRVR_NAME)) != 0) {
3608				(void) print_errString(err,
3609				    wwn_list->physical_path);
3610			    }
3611			/*
3612			 * Try retrieve of devid only once. If it fails
3613			 * don't try it again but print error,
3614			 * There should be a devid prop.
3615			 */
3616			    retr_outer = 1;
3617			}
3618			/*
3619			 * Apply devid to block devices only.
3620			 * Get devid of inner path and compare
3621			 * with outer path's devid.
3622			 */
3623			if ((strstr(inner->physical_path,
3624			    SLSH_DRV_NAME_SSD) != NULL) &&
3625			    devid1 != NULL) {
3626
3627			    if ((err = g_devid_get(inner->physical_path,
3628				&devid2, root, SSD_DRVR_NAME)) != 0) {
3629
3630				(void) print_errString(err,
3631				    inner->physical_path);
3632				compare_result = 0;
3633			    } else {
3634				compare_result = devid_compare(devid1, devid2);
3635			    }
3636			} else {
3637			    /* devid isn't applied */
3638			    compare_result = 0;
3639			}
3640
3641			if (compare_result == 0) {
3642
3643			    if (strcmp(wwn_list->logical_path,
3644				inner->logical_path)) {
3645				(void) fprintf(stdout, "    ");
3646				(void) fprintf(stdout,
3647				    MSGSTR(31, "Logical Path:%s"),
3648					inner->logical_path);
3649				(void) fprintf(stdout, "\n");
3650
3651				if (Options & OPTION_P) {
3652				    (void) fprintf(stdout, "    ");
3653				    (void) fprintf(stdout, MSGSTR(5,
3654					"Physical Path:"));
3655				    (void) fprintf(stdout, "\n     %s\n",
3656					inner->physical_path);
3657				}
3658			    }
3659
3660			    /* Remove this entry from the list */
3661			    if (inner->wwn_prev != NULL) {
3662				inner->wwn_prev->wwn_next =
3663				inner->wwn_next;
3664			    }
3665
3666			    if (inner->wwn_next != NULL) {
3667				inner->wwn_next->wwn_prev =
3668				inner->wwn_prev;
3669			    }
3670			    free(inner->physical_path);
3671			    free(inner->logical_path);
3672			    l1 = inner;
3673			    inner = inner->wwn_next;
3674			    (void) free(l1);
3675
3676			} else {
3677			    inner = inner->wwn_next;
3678			} /* End if (compare_result == 0) */
3679
3680		    } else {
3681			inner = inner->wwn_next;
3682		    }
3683		} else {
3684		    inner = inner->wwn_next;
3685		}
3686		devid2 = NULL;
3687	    }
3688	    wwn_list = wwn_list->wwn_next;
3689	    retr_outer = 0;
3690	    devid1 = NULL;
3691	} /* End while (wwn_list != NULL) */
3692
3693	(void) g_free_wwn_list(&wwn_listh);
3694	(void) di_fini(root);
3695}
3696
3697void
3698pho_probe()
3699{
3700
3701Box_list	*b_list, *o_list, *c_list;
3702int		multi_path_flag, multi_print_flag;
3703int		duplicate_names_found = 0, err = 0;
3704
3705	b_list = o_list = c_list = NULL;
3706	if ((err = l_get_box_list(&b_list, Options & PVERBOSE)) != 0) {
3707		(void) print_errString(err, NULL);
3708		exit(-1);
3709	}
3710	if (b_list == NULL) {
3711		(void) fprintf(stdout,
3712			MSGSTR(93, "No %s enclosures found "
3713			"in /dev/es\n"), ENCLOSURE_PROD_NAME);
3714	} else {
3715		o_list = b_list;
3716		if (b_list->box_next != NULL) {
3717			(void) fprintf(stdout, MSGSTR(2102,
3718				"Found Enclosure(s)"));
3719		} else {
3720			(void) fprintf(stdout, MSGSTR(2103, "Found Enclosure"));
3721		}
3722		(void) fprintf(stdout, ":\n");
3723		while (b_list != NULL) {
3724			/* Don't re-print multiple paths */
3725			c_list = o_list;
3726			multi_print_flag = 0;
3727			while (c_list != b_list) {
3728				if (strcmp(c_list->b_node_wwn_s,
3729					b_list->b_node_wwn_s) == 0) {
3730					multi_print_flag = 1;
3731					break;
3732				}
3733				c_list = c_list->box_next;
3734			}
3735			if (multi_print_flag) {
3736				b_list = b_list->box_next;
3737				continue;
3738			}
3739			(void) fprintf(stdout,
3740			MSGSTR(2104, "%s   Name:%s   Node WWN:%s   "),
3741			b_list->prod_id_s, b_list->b_name,
3742				b_list->b_node_wwn_s);
3743			/*
3744			 * Print logical path on same line if not multipathed.
3745			 */
3746			multi_path_flag = 0;
3747			c_list = o_list;
3748			while (c_list != NULL) {
3749				if ((c_list != b_list) &&
3750					(strcmp(c_list->b_node_wwn_s,
3751					b_list->b_node_wwn_s) == 0)) {
3752					multi_path_flag = 1;
3753				}
3754				c_list = c_list->box_next;
3755			}
3756			if (multi_path_flag) {
3757				(void) fprintf(stdout, "\n  ");
3758			}
3759			(void) fprintf(stdout,
3760			MSGSTR(31, "Logical Path:%s"),
3761			b_list->logical_path);
3762
3763			if (Options & OPTION_P) {
3764				(void) fprintf(stdout, "\n  ");
3765				(void) fprintf(stdout,
3766				MSGSTR(5, "Physical Path:"));
3767				(void) fprintf(stdout, "%s",
3768				b_list->b_physical_path);
3769			}
3770			c_list = o_list;
3771			while (c_list != NULL) {
3772				if ((c_list != b_list) &&
3773				(strcmp(c_list->b_node_wwn_s,
3774					b_list->b_node_wwn_s) == 0)) {
3775					(void) fprintf(stdout, "\n  ");
3776					(void) fprintf(stdout,
3777					MSGSTR(31, "Logical Path:%s"),
3778					c_list->logical_path);
3779					if (Options & OPTION_P) {
3780						(void) fprintf(stdout, "\n  ");
3781						(void) fprintf(stdout,
3782						MSGSTR(5, "Physical Path:"));
3783						(void) fprintf(stdout, "%s",
3784						c_list->b_physical_path);
3785					}
3786				}
3787				c_list = c_list->box_next;
3788			}
3789			(void) fprintf(stdout, "\n");
3790			/* Check for duplicate names */
3791			if (l_duplicate_names(o_list, b_list->b_node_wwn_s,
3792				(char *)b_list->b_name,
3793				Options & PVERBOSE)) {
3794				duplicate_names_found++;
3795			}
3796			b_list = b_list->box_next;
3797		}
3798	}
3799	if (duplicate_names_found) {
3800		(void) fprintf(stdout,
3801			MSGSTR(2105, "\nWARNING: There are enclosures with "
3802			"the same names.\n"
3803			"You can not use the \"enclosure\""
3804			" name to specify these subsystems.\n"
3805			"Please use the \"enclosure_name\""
3806			" subcommand to select unique names.\n\n"));
3807	}
3808	(void) l_free_box_list(&b_list);
3809}
3810
3811/*
3812 * display_port_status() Prints the device's
3813 * port status.
3814 *
3815 * RETURNS:
3816 *	none.
3817 */
3818void
3819display_port_status(int d_state_flag)
3820{
3821
3822	if (d_state_flag & L_OPEN_FAIL) {
3823		(void) fprintf(stdout, MSGSTR(28, "Open Failed"));
3824	} else if (d_state_flag & L_NOT_READY) {
3825		(void) fprintf(stdout, MSGSTR(20, "Not Ready"));
3826	} else if (d_state_flag & L_NOT_READABLE) {
3827		(void) fprintf(stdout, MSGSTR(88, "Not Readable"));
3828	} else if (d_state_flag & L_SPUN_DWN_D) {
3829		(void) fprintf(stdout, MSGSTR(68, "Spun Down"));
3830	} else if (d_state_flag & L_SCSI_ERR) {
3831		(void) fprintf(stdout, MSGSTR(70, "SCSI Error"));
3832	} else if (d_state_flag & L_RESERVED) {
3833		(void) fprintf(stdout, MSGSTR(73, "Reservation conflict"));
3834	} else if (d_state_flag & L_NO_LABEL) {
3835		(void) fprintf(stdout, MSGSTR(92, "No UNIX Label"));
3836	} else {
3837		(void) fprintf(stdout, MSGSTR(29, "O.K."));
3838	}
3839	(void) fprintf(stdout, "\n");
3840}
3841
3842/*
3843 * Displays individual SENA
3844 * FC disk information.
3845 *
3846 * Caller to this routine should free the storage due to
3847 * the use of g_get_dev_map
3848 *
3849 * RETURNS:
3850 *	none.
3851 */
3852void
3853display_fc_disk(struct path_struct *path_struct, char *ses_path,
3854	gfc_map_t *map, L_inquiry inq, int verbose)
3855{
3856static WWN_list		*wwn_list = NULL;
3857static char		path_phys[MAXPATHLEN];
3858static L_disk_state	l_disk_state;
3859static L_inquiry	local_inq;
3860static uchar_t		node_wwn[WWN_SIZE];
3861char			same_path_phys = B_FALSE; /* To chk for repeat args */
3862uchar_t			port_wwn[WWN_SIZE], *pg_buf;
3863char			logical_path[MAXPATHLEN];
3864int			al_pa, port_a_flag = 0;
3865int			offset, mode_data_avail = 0;
3866int			no_path_flag = 0, err = 0;
3867L_state			l_state;
3868Mode_header_10		*mode_header_ptr = NULL;
3869struct mode_page	*pg_hdr;
3870
3871	/*
3872	 * Do a quick check to see if its the same path as in last call.
3873	 * path_phys is a static array and so dont worry about its
3874	 * initialization.
3875	 */
3876	if (strcmp(path_phys, path_struct->p_physical_path) == 0)
3877		same_path_phys = B_TRUE;
3878
3879	(void) strcpy(path_phys, path_struct->p_physical_path);
3880	(void) memset((char *)logical_path, 0, sizeof (logical_path));
3881
3882	/*
3883	 * slot_valid is 1 when argument is of the form 'enclosure,[f|r]<n>'.
3884	 * If slot_valid != 1, g_get_dev_map and l_get_ses_path would
3885	 * already have been called
3886	 */
3887	if (path_struct->slot_valid == 1) {
3888		/* Get the location information. */
3889		if (err = g_get_dev_map(path_phys, map, (Options & PVERBOSE))) {
3890			(void) print_errString(err, path_phys);
3891			exit(-1);
3892		}
3893		if (err = l_get_ses_path(path_phys, ses_path, map,
3894			(Options & PVERBOSE))) {
3895			(void) print_errString(err, path_phys);
3896			exit(-1);
3897		}
3898	}
3899
3900	/*
3901	 * Get the WWN for our disk if we already haven't or if there was an
3902	 * error earlier
3903	 */
3904	if (same_path_phys == B_FALSE) {
3905		if (err = g_get_wwn(path_phys, port_wwn, node_wwn,
3906			&al_pa, (Options & PVERBOSE))) {
3907			(void) print_errString(err, path_phys);
3908			exit(-1);
3909		}
3910
3911		if (err = g_get_inquiry(ses_path, &local_inq)) {
3912			(void) print_errString(err, ses_path);
3913			exit(-1);
3914		}
3915	}
3916
3917	/*
3918	 * We are interested only a couple of ib_tbl fields and
3919	 * those get filled using l_get_ib_status.
3920	 * Note that NOT ALL of ib_tbl fields get filled here
3921	 */
3922	if ((err = l_get_ib_status(ses_path, &l_state,
3923				Options & PVERBOSE)) != 0) {
3924		(void) print_errString(err, ses_path);
3925		exit(-1);
3926	}
3927
3928	/*
3929	 * Get path to all the FC disk and tape devices.
3930	 * if we haven't already done so in a previous pass
3931	 */
3932	if ((wwn_list == NULL) && (err = g_get_wwn_list(&wwn_list, verbose))) {
3933		(void) print_errString(err, ses_path);
3934		exit(-1);   /* Failure */
3935	}
3936
3937	/*
3938	 * Get the disk status if it is a different path_phys from
3939	 * last time.
3940	 */
3941	if (same_path_phys == B_FALSE) {
3942		(void) memset(&l_disk_state, 0,
3943				sizeof (struct l_disk_state_struct));
3944		if (err = l_get_disk_status(path_phys, &l_disk_state,
3945				wwn_list, (Options & PVERBOSE))) {
3946			(void) print_errString(err, path_phys);
3947			exit(-1);
3948		}
3949	}
3950
3951	if (l_disk_state.l_state_flag & L_NO_PATH_FOUND) {
3952		(void) fprintf(stderr, MSGSTR(2106,
3953			"\nWARNING: No path found "
3954			"in /dev/rdsk directory\n"
3955			"  Please check the logical links in /dev/rdsk\n"
3956			"  (It may be necessary to run the \"disks\" "
3957			"program.)\n\n"));
3958
3959		/* Just call to get the status directly. */
3960		if (err = l_get_port(ses_path, &port_a_flag, verbose)) {
3961			(void) print_errString(err, ses_path);
3962			exit(-1);
3963		}
3964		if (err = l_get_disk_port_status(path_phys,
3965			&l_disk_state, port_a_flag,
3966			(Options & PVERBOSE))) {
3967			(void) print_errString(err, path_phys);
3968			exit(-1);
3969		}
3970		no_path_flag++;
3971	}
3972
3973	if (strlen(l_disk_state.g_disk_state.node_wwn_s) == 0) {
3974		(void) sprintf(l_disk_state.g_disk_state.node_wwn_s,
3975			"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
3976			node_wwn[0], node_wwn[1], node_wwn[2], node_wwn[3],
3977			node_wwn[4], node_wwn[5], node_wwn[6], node_wwn[7]);
3978	}
3979
3980	/* get mode page information for FC device */
3981	if (l_get_mode_pg(path_phys, &pg_buf, Options & PVERBOSE) == 0) {
3982		mode_header_ptr = (struct mode_header_10_struct *)(int)pg_buf;
3983		pg_hdr = ((struct mode_page *)((int)pg_buf +
3984			(uchar_t)sizeof (struct mode_header_10_struct) +
3985			(uchar_t *)(uintptr_t)(mode_header_ptr->bdesc_length)));
3986		offset = sizeof (struct mode_header_10_struct) +
3987			mode_header_ptr->bdesc_length;
3988		while (offset < (mode_header_ptr->length +
3989			sizeof (mode_header_ptr->length)) &&
3990						!mode_data_avail) {
3991			if (pg_hdr->code == MODEPAGE_CACHING) {
3992				mode_data_avail++;
3993				break;
3994			}
3995			offset += pg_hdr->length + sizeof (struct mode_page);
3996			pg_hdr = ((struct mode_page *)((int)pg_buf +
3997				(uchar_t)offset));
3998		}
3999	}
4000
4001	switch ((inq.inq_dtype & DTYPE_MASK)) {
4002	case DTYPE_DIRECT:
4003	    fprintf(stdout, MSGSTR(121, "DEVICE PROPERTIES for disk: %s\n"),
4004		path_struct->argv);
4005	    break;
4006	case DTYPE_SEQUENTIAL: /* Tape */
4007	    fprintf(stdout, MSGSTR(2249, "DEVICE PROPERTIES for tape: %s\n"),
4008		path_struct->argv);
4009	    break;
4010	default:
4011	    fprintf(stdout, MSGSTR(2250, "DEVICE PROPERTIES for: %s\n"),
4012		path_struct->argv);
4013	    break;
4014	}
4015
4016	if (l_disk_state.g_disk_state.port_a_valid) {
4017		(void) fprintf(stdout, "  ");
4018		(void) fprintf(stdout, MSGSTR(141, "Status(Port A):"));
4019		(void) fprintf(stdout, "\t");
4020		display_port_status(
4021			l_disk_state.g_disk_state.d_state_flags[PORT_A]);
4022	} else {
4023		if (path_struct->f_flag) {
4024			if ((ib_present_chk(&l_state, 0) == 1) &&
4025		(l_state.drv_front[path_struct->slot].ib_status.bypass_a_en)) {
4026				(void) fprintf(stdout,
4027					MSGSTR(66,
4028					"  Status(Port A):\tBYPASSED\n"));
4029			}
4030		} else {
4031			if ((ib_present_chk(&l_state, 0) == 1) &&
4032		(l_state.drv_rear[path_struct->slot].ib_status.bypass_a_en)) {
4033				(void) fprintf(stdout,
4034					MSGSTR(66,
4035					"  Status(Port A):\tBYPASSED\n"));
4036			}
4037		}
4038	}
4039
4040	if (l_disk_state.g_disk_state.port_b_valid) {
4041		(void) fprintf(stdout, "  ");
4042		(void) fprintf(stdout, MSGSTR(142, "Status(Port B):"));
4043		(void) fprintf(stdout, "\t");
4044	display_port_status(l_disk_state.g_disk_state.d_state_flags[PORT_B]);
4045	} else {
4046		if (path_struct->f_flag) {
4047			if ((ib_present_chk(&l_state, 1) == 1) &&
4048		(l_state.drv_front[path_struct->slot].ib_status.bypass_b_en)) {
4049				(void) fprintf(stdout,
4050					MSGSTR(65,
4051					"  Status(Port B):\tBYPASSED\n"));
4052			}
4053		} else {
4054			if ((ib_present_chk(&l_state, 1) == 1) &&
4055		(l_state.drv_rear[path_struct->slot].ib_status.bypass_b_en)) {
4056				(void) fprintf(stdout,
4057					MSGSTR(65,
4058					"  Status(Port B):\tBYPASSED\n"));
4059			}
4060		}
4061	}
4062
4063	if (no_path_flag) {
4064		(void) fprintf(stdout, "  ");
4065		if (port_a_flag != 0) {
4066			(void) fprintf(stdout, MSGSTR(142, "Status(Port B):"));
4067		} else {
4068			(void) fprintf(stdout, MSGSTR(141, "Status(Port A):"));
4069		}
4070		(void) fprintf(stdout, "\t");
4071		display_port_status(
4072		l_disk_state.g_disk_state.d_state_flags[port_a_flag]);
4073	} else if ((!l_disk_state.g_disk_state.port_a_valid) &&
4074			(!l_disk_state.g_disk_state.port_b_valid)) {
4075		(void) fprintf(stdout, MSGSTR(2107, "  Status:\t\t"
4076		"No state available.\n"));
4077	}
4078
4079	(void) display_disk_info(inq, l_disk_state, path_struct, pg_hdr,
4080		mode_data_avail, (char *)local_inq.inq_box_name, verbose);
4081}
4082
4083
4084
4085
4086
4087/*
4088 * non_encl_fc_disk_display() Prints the device specific
4089 * information for an individual fcal device.
4090 *
4091 * RETURNS:
4092 *	none.
4093 */
4094static int
4095non_encl_fc_disk_display(Path_struct *path_struct,
4096				L_inquiry inq_struct, int verbose)
4097{
4098
4099char			phys_path[MAXPATHLEN];
4100uchar_t			node_wwn[WWN_SIZE], port_wwn[WWN_SIZE], *pg_buf = NULL;
4101L_disk_state		l_disk_state;
4102struct dlist		*mlist;
4103int			i = 0, al_pa, offset, mode_data_avail = 0, err = 0;
4104int			path_a_found = 0, path_b_found = 0, argpwwn = 0,
4105			argnwwn = 0, pathcnt = 1;
4106L_inquiry		local_inq;
4107Mode_header_10		*mode_header_ptr;
4108struct mode_page	*pg_hdr;
4109WWN_list		*wwn_list, *wwn_list_ptr, *list_start;
4110char			temppath[MAXPATHLEN], last_logical_path[MAXPATHLEN];
4111mp_pathlist_t		pathlist;
4112
4113	(void) strcpy(phys_path, path_struct->p_physical_path);
4114
4115	/* Get path to all the FC disk and tape devices. */
4116	if (err = g_get_wwn_list(&wwn_list, verbose)) {
4117		return (err);
4118	}
4119
4120	g_sort_wwn_list(&wwn_list);
4121
4122	list_start = wwn_list;
4123	(void) strcpy(last_logical_path, phys_path);
4124
4125	for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
4126		wwn_list_ptr = wwn_list_ptr->wwn_next) {
4127		if (strcasecmp(wwn_list_ptr->port_wwn_s,
4128			path_struct->argv) == 0) {
4129			list_start = wwn_list_ptr;
4130			argpwwn = 1;
4131			break;
4132		} else if (strcasecmp(wwn_list_ptr->node_wwn_s,
4133			path_struct->argv) == 0) {
4134			list_start = wwn_list_ptr;
4135			argnwwn = 1;
4136			break;
4137		}
4138	}
4139
4140	for (wwn_list_ptr = list_start; wwn_list_ptr != NULL;
4141		wwn_list_ptr = wwn_list_ptr->wwn_next) {
4142
4143
4144	if (argpwwn) {
4145		if (strcasecmp(wwn_list_ptr->port_wwn_s,
4146			path_struct->argv) != 0) {
4147			continue;
4148		}
4149		(void) strcpy(phys_path, wwn_list_ptr->physical_path);
4150		path_a_found = 0;
4151		path_b_found = 0;
4152		mode_data_avail = 0;
4153	} else if (argnwwn) {
4154		if (strstr(wwn_list_ptr->logical_path,
4155			last_logical_path) != NULL) {
4156			continue;
4157		}
4158		if (strcasecmp(wwn_list_ptr->node_wwn_s,
4159			path_struct->argv) != 0) {
4160			continue;
4161		}
4162		(void) strcpy(phys_path, wwn_list_ptr->physical_path);
4163		(void) strcpy(last_logical_path,
4164			wwn_list_ptr->logical_path);
4165		path_a_found = 0;
4166		path_b_found = 0;
4167		mode_data_avail = 0;
4168	}
4169
4170	(void) memset(&l_disk_state, 0, sizeof (struct l_disk_state_struct));
4171
4172	if ((err = g_get_multipath(phys_path,
4173		&(l_disk_state.g_disk_state.multipath_list),
4174		wwn_list, verbose)) != 0) {
4175		return (err);
4176	}
4177	mlist = l_disk_state.g_disk_state.multipath_list;
4178	if (mlist == NULL) {
4179		l_disk_state.l_state_flag = L_NO_PATH_FOUND;
4180		N_DPRINTF(" non_encl_fc_disk_display: Error finding"
4181			" multiple paths to the disk.\n");
4182		(void) g_free_wwn_list(&wwn_list);
4183		return (-1);
4184	}
4185
4186	/* get mode page information for FC device */
4187	if (l_get_mode_pg(phys_path, &pg_buf, verbose) == 0) {
4188		mode_header_ptr = (struct mode_header_10_struct *)(int)pg_buf;
4189		pg_hdr = ((struct mode_page *)((int)pg_buf +
4190			(uchar_t)sizeof (struct mode_header_10_struct) +
4191			(uchar_t *)(uintptr_t)(mode_header_ptr->bdesc_length)));
4192		offset = sizeof (struct mode_header_10_struct) +
4193			mode_header_ptr->bdesc_length;
4194		while (offset < (mode_header_ptr->length +
4195			sizeof (mode_header_ptr->length)) &&
4196						!mode_data_avail) {
4197			if (pg_hdr->code == MODEPAGE_CACHING) {
4198				mode_data_avail++;
4199				break;
4200			}
4201			offset += pg_hdr->length + sizeof (struct mode_page);
4202			pg_hdr = ((struct mode_page *)((int)pg_buf +
4203				(uchar_t)offset));
4204		}
4205	}
4206
4207	switch ((inq_struct.inq_dtype & DTYPE_MASK)) {
4208	case DTYPE_DIRECT:
4209	    fprintf(stdout, MSGSTR(121, "DEVICE PROPERTIES for disk: %s\n"),
4210		path_struct->argv);
4211	    break;
4212	case DTYPE_SEQUENTIAL: /* Tape */
4213	    fprintf(stdout, MSGSTR(2249, "DEVICE PROPERTIES for tape: %s\n"),
4214		path_struct->argv);
4215	    break;
4216	default:
4217	    fprintf(stdout, MSGSTR(2250, "DEVICE PROPERTIES for: %s\n"),
4218		path_struct->argv);
4219	    break;
4220	}
4221	while ((mlist != NULL) && (!(path_a_found && path_b_found))) {
4222		(void) strcpy(phys_path, mlist->dev_path);
4223		if (err = g_get_inquiry(phys_path, &local_inq)) {
4224			(void) fprintf(stderr,
4225				MSGSTR(2114,
4226				"non_encl_fc_disk_display: Inquiry failed\n"));
4227			(void) print_errString(err, phys_path);
4228			(void) g_free_multipath(
4229				l_disk_state.g_disk_state.multipath_list);
4230			(void) g_free_wwn_list(&wwn_list);
4231			return (-1);
4232		}
4233		if ((err = g_get_wwn(mlist->dev_path, port_wwn, node_wwn,
4234					&al_pa, verbose)) != 0) {
4235			(void) print_errString(err, mlist->dev_path);
4236			(void) g_free_multipath(
4237				l_disk_state.g_disk_state.multipath_list);
4238			(void) g_free_wwn_list(&wwn_list);
4239			return (-1);
4240		}
4241		if (strlen(l_disk_state.g_disk_state.node_wwn_s) == 0) {
4242			(void) sprintf(l_disk_state.g_disk_state.node_wwn_s,
4243			"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
4244			node_wwn[0], node_wwn[1], node_wwn[2], node_wwn[3],
4245			node_wwn[4], node_wwn[5], node_wwn[6], node_wwn[7]);
4246		}
4247		if ((err = l_get_disk_port_status(phys_path, &l_disk_state,
4248				(local_inq.inq_port) ? FC_PORT_B : FC_PORT_A,
4249				verbose)) != 0) {
4250			(void) print_errString(err, phys_path);
4251			(void) g_free_multipath(
4252				l_disk_state.g_disk_state.multipath_list);
4253			exit(-1);
4254		}
4255
4256		if ((!local_inq.inq_port) && (!path_a_found)) {
4257			(void) sprintf(l_disk_state.g_disk_state.port_a_wwn_s,
4258				"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
4259			port_wwn[0], port_wwn[1], port_wwn[2], port_wwn[3],
4260			port_wwn[4], port_wwn[5], port_wwn[6], port_wwn[7]);
4261		path_a_found = l_disk_state.g_disk_state.port_a_valid = 1;
4262		}
4263		if ((local_inq.inq_port) && (!path_b_found)) {
4264		path_b_found = l_disk_state.g_disk_state.port_b_valid = 1;
4265			(void) sprintf(l_disk_state.g_disk_state.port_b_wwn_s,
4266				"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
4267			port_wwn[0], port_wwn[1], port_wwn[2], port_wwn[3],
4268			port_wwn[4], port_wwn[5], port_wwn[6], port_wwn[7]);
4269		}
4270
4271		if ((strstr(mlist->dev_path, SCSI_VHCI) != NULL) &&
4272			(!l_get_disk_port_status(phys_path, &l_disk_state,
4273			(!local_inq.inq_port) ? FC_PORT_B : FC_PORT_A,
4274			verbose))) {
4275			(void) strcpy(temppath, mlist->dev_path);
4276			if (err = g_get_pathlist(temppath, &pathlist)) {
4277				(void) print_errString(err, NULL);
4278				exit(-1);
4279			}
4280			pathcnt = pathlist.path_count;
4281			if (pathcnt > 1) {
4282				for (i = 0; i < pathcnt; i++) {
4283					if ((!path_a_found) &&
4284						(path_b_found) &&
4285						(strstr(pathlist.path_info[i].
4286						path_addr,
4287						l_disk_state.g_disk_state.
4288						port_b_wwn_s) == NULL)) {
4289
4290						(void) strncpy(l_disk_state.
4291						g_disk_state.port_a_wwn_s,
4292						pathlist.path_info[i].
4293						path_addr, 16);
4294						path_a_found = l_disk_state.
4295						g_disk_state.port_a_valid = 1;
4296					}
4297					if ((path_a_found) &&
4298						(!path_b_found) &&
4299						(strstr(pathlist.path_info[i].
4300						path_addr,
4301						l_disk_state.g_disk_state.
4302						port_a_wwn_s) == NULL)) {
4303
4304						(void) strncpy(l_disk_state.
4305						g_disk_state.port_b_wwn_s,
4306						pathlist.path_info[i].
4307						path_addr, 16);
4308						path_b_found = l_disk_state.
4309						g_disk_state.port_b_valid = 1;
4310					}
4311					if ((path_a_found) && (path_b_found)) {
4312						break;
4313					}
4314				}
4315			}
4316			free(pathlist.path_info);
4317		}
4318
4319		mlist = mlist->next;
4320	}
4321
4322	if (l_disk_state.g_disk_state.port_a_valid) {
4323		(void) fprintf(stdout, "  ");
4324		(void) fprintf(stdout, MSGSTR(141, "Status(Port A):"));
4325		(void) fprintf(stdout, "\t");
4326	display_port_status(l_disk_state.g_disk_state.d_state_flags[FC_PORT_A]);
4327	}
4328
4329	if (l_disk_state.g_disk_state.port_b_valid) {
4330		(void) fprintf(stdout, "  ");
4331		(void) fprintf(stdout, MSGSTR(142, "Status(Port B):"));
4332		(void) fprintf(stdout, "\t");
4333	display_port_status(l_disk_state.g_disk_state.d_state_flags[FC_PORT_B]);
4334	}
4335
4336	(void) display_disk_info(local_inq, l_disk_state, path_struct,
4337				pg_hdr, mode_data_avail, NULL, verbose);
4338	(void) g_free_multipath(l_disk_state.g_disk_state.multipath_list);
4339
4340	if (!(argpwwn || argnwwn)) {
4341		break;
4342	}
4343
4344	}
4345	(void) g_free_wwn_list(&wwn_list);
4346	return (0);
4347}
4348
4349
4350
4351/*
4352 * display_disk_info() Prints the device specific information
4353 * for any FC_AL disk device.
4354 *
4355 * RETURNS:
4356 *	none.
4357 */
4358void
4359display_disk_info(L_inquiry inq, L_disk_state l_disk_state,
4360		Path_struct *path_struct, struct mode_page *pg_hdr,
4361		int mode_data_avail, char *name_buf, int options)
4362{
4363float		num_blks;
4364struct dlist	*mlist;
4365int		port_a, port_b;
4366struct	my_mode_caching	*pg8_buf;
4367L_inquiry	enc_inq;
4368char		*enc_phys_path;
4369Path_struct	*enc_path_struct;
4370int		enc_type = 0;
4371L_inquiry80	inq80;
4372size_t		serial_len;
4373int		err;
4374
4375	serial_len = sizeof (inq80.inq_serial);
4376	err = g_get_serial_number(path_struct->p_physical_path,
4377	    inq80.inq_serial, &serial_len);
4378	if (err) {
4379		fprintf(stderr, "\n");
4380		print_errString(err, path_struct->p_physical_path);
4381		fprintf(stderr, "\n");
4382		exit(1);
4383	}
4384	(void) fprintf(stdout, "  ");
4385	(void) fprintf(stdout, MSGSTR(3, "Vendor:"));
4386	(void) fprintf(stdout, "\t\t");
4387	print_chars(inq.inq_vid, sizeof (inq.inq_vid), 0);
4388
4389	(void) fprintf(stdout, MSGSTR(2115, "\n  Product ID:\t\t"));
4390	print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0);
4391
4392	(void) fprintf(stdout, MSGSTR(2116, "\n  WWN(Node):\t\t%s"),
4393				l_disk_state.g_disk_state.node_wwn_s);
4394
4395	if (l_disk_state.g_disk_state.port_a_valid) {
4396		(void) fprintf(stdout, MSGSTR(2117, "\n  WWN(Port A):\t\t%s"),
4397				l_disk_state.g_disk_state.port_a_wwn_s);
4398	}
4399	if (l_disk_state.g_disk_state.port_b_valid) {
4400		(void) fprintf(stdout, MSGSTR(2118, "\n  WWN(Port B):\t\t%s"),
4401				l_disk_state.g_disk_state.port_b_wwn_s);
4402	}
4403	(void) fprintf(stdout, "\n  ");
4404	(void) fprintf(stdout, MSGSTR(2119, "Revision:"));
4405	(void) fprintf(stdout, "\t\t");
4406	print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0);
4407
4408	(void) fprintf(stdout, "\n  ");
4409	(void) fprintf(stdout, MSGSTR(17, "Serial Num:"));
4410	(void) fprintf(stdout, "\t\t");
4411	print_chars(inq80.inq_serial, serial_len, 0);
4412	num_blks = l_disk_state.g_disk_state.num_blocks;
4413	if (num_blks) {
4414		num_blks /= 2048;	/* get Mbytes */
4415		(void) fprintf(stdout, "\n  ");
4416		(void) fprintf(stdout,
4417			MSGSTR(60,
4418		"Unformatted capacity:\t%6.3f MBytes"), num_blks);
4419	}
4420	(void) fprintf(stdout, "\n");
4421
4422	if (l_disk_state.g_disk_state.persistent_reserv_flag) {
4423		(void) fprintf(stdout,
4424			MSGSTR(2120, "  Persistent Reserve:\t"));
4425		if (l_disk_state.g_disk_state.persistent_active) {
4426			(void) fprintf(stdout,
4427				MSGSTR(39, "Active"));
4428				(void) fprintf(stdout, "\n");
4429		}
4430		if (l_disk_state.g_disk_state.persistent_registered) {
4431			(void) fprintf(stdout,
4432				MSGSTR(2121, "Found Registered Keys"));
4433		} else {
4434			(void) fprintf(stdout,
4435				MSGSTR(87, "Not being used"));
4436		}
4437		(void) fprintf(stdout, "\n");
4438	}
4439
4440	if ((mode_data_avail) && (pg_hdr->code == MODEPAGE_CACHING)) {
4441		pg8_buf = (struct my_mode_caching *)(int)pg_hdr;
4442		if (pg8_buf->wce) {
4443			(void) fprintf(stdout,
4444				MSGSTR(2122,
4445				"  Write Cache:\t\t"
4446				"Enabled\n"));
4447		}
4448		if (pg8_buf->rcd == 0) {
4449			(void) fprintf(stdout,
4450				MSGSTR(2123,
4451				"  Read Cache:\t\t"
4452				"Enabled\n"));
4453			(void) fprintf(stdout,
4454				MSGSTR(2320,
4455				"    Minimum prefetch:"
4456				"\t0x%x\n"
4457				"    Maximum prefetch:"
4458				"\t0x%x\n"),
4459				pg8_buf->min_prefetch,
4460				pg8_buf->max_prefetch);
4461		}
4462	}
4463
4464	/*
4465	 * When /dev/rdsk/cxtxdxsx form of input is specified
4466	 * for display command the initial library version didn't
4467	 * display Location information.  The change is made
4468	 * to display the same Location info as the non-library version.
4469	 */
4470
4471	if (name_buf != NULL) {
4472	    fprintf(stdout, MSGSTR(2125, "  Location:\t\t"));
4473	    if (path_struct->slot_valid) {
4474		/*
4475		 * We have to do another inquiry on the enclosure (name_buf)
4476		 * to determine if this device is within a daktari, or
4477		 * a two sided device.
4478		 */
4479		if (!l_convert_name(name_buf, &enc_phys_path,
4480			&enc_path_struct, 0)) {
4481		    if (!g_get_inquiry(enc_phys_path, &enc_inq)) {
4482			enc_type = l_get_enc_type(enc_inq);
4483		    }
4484		}
4485		/* If either of the above fail, we just assume the default */
4486		free(enc_phys_path);
4487		free(enc_path_struct);
4488		if (enc_type == DAK_ENC_TYPE) {
4489			if (path_struct->f_flag) {
4490				(void) fprintf(stdout, MSGSTR(2239,
4491				    "In slot %d in the enclosure named: %s\n"),
4492				    path_struct->slot, name_buf);
4493			} else {
4494				(void) fprintf(stdout, MSGSTR(2239,
4495				    "In slot %d in the enclosure named: %s\n"),
4496				    path_struct->slot + (MAX_DRIVES_DAK/2),
4497								name_buf);
4498			}
4499		} else	{  /* Default enclosure type */
4500		    (void) fprintf(stdout, path_struct->f_flag ?
4501				MSGSTR(2126,
4502			"In slot %d in the Front of the enclosure named: %s\n")
4503				: MSGSTR(2127,
4504			"In slot %d in the Rear of the enclosure named: %s\n"),
4505				path_struct->slot, name_buf);
4506		}
4507	    } else {
4508		(void) fprintf(stdout, MSGSTR(2228,
4509			"In the enclosure named: %s\n"),
4510			name_buf);
4511	    }
4512	}
4513
4514	(void) fprintf(stdout, "  %s\t\t%s\n",
4515			MSGSTR(35, "Device Type:"),
4516			dtype[inq.inq_dtype & DTYPE_MASK]);
4517
4518	mlist = l_disk_state.g_disk_state.multipath_list;
4519	(void) fprintf(stdout, MSGSTR(2128, "  Path(s):\n"));
4520	if (strstr(mlist->dev_path, SCSI_VHCI) != NULL) {
4521		(void) fprintf(stdout, "  %s\n  %s\n",
4522			mlist->logical_path, mlist->dev_path);
4523		(void) adm_print_pathlist(mlist->dev_path);
4524	} else {
4525		while (mlist) {
4526			(void) fprintf(stdout, "  %s\n  %s\n",
4527				mlist->logical_path, mlist->dev_path);
4528			mlist = mlist->next;
4529		}
4530	}
4531
4532	if (Options & OPTION_V) {
4533		if (path_struct->slot_valid) {
4534			port_a = PORT_A;
4535			port_b = PORT_B;
4536		} else {
4537			port_a = FC_PORT_A;
4538			port_b = FC_PORT_B;
4539		}
4540		/* Only bother if the state is O.K. */
4541		if ((l_disk_state.g_disk_state.port_a_valid) &&
4542			(l_disk_state.g_disk_state.d_state_flags[port_a] == 0))
4543		adm_display_verbose_disk(path_struct->p_physical_path, options);
4544		else if ((l_disk_state.g_disk_state.port_b_valid) &&
4545			(l_disk_state.g_disk_state.d_state_flags[port_b] == 0))
4546		adm_display_verbose_disk(path_struct->p_physical_path, options);
4547	}
4548	(void) fprintf(stdout, "\n");
4549
4550}
4551
4552
4553
4554/*
4555 * temp_decode() Display temperature bytes 1-3 state.
4556 *
4557 * RETURNS:
4558 *	none.
4559 */
4560void
4561temp_decode(Temp_elem_st *temp)
4562{
4563	if (temp->ot_fail) {
4564		(void) fprintf(stdout, MSGSTR(2129,
4565			": FAILURE - Over Temperature"));
4566	}
4567	if (temp->ut_fail) {
4568		(void) fprintf(stdout, MSGSTR(2130,
4569			": FAILURE - Under Temperature"));
4570	}
4571	if (temp->ot_warn) {
4572		(void) fprintf(stdout, MSGSTR(2131,
4573			": WARNING - Over Temperature"));
4574	}
4575	if (temp->ut_warn) {
4576		(void) fprintf(stdout, MSGSTR(2132,
4577			": WARNING - Under Temperature"));
4578	}
4579}
4580
4581
4582
4583/*
4584 * disp_degree() Display temperature in Degrees Celsius.
4585 *
4586 * RETURNS:
4587 *	none.
4588 */
4589void
4590disp_degree(Temp_elem_st *temp)
4591{
4592int	t;
4593
4594	t = temp->degrees;
4595	t -= 20;	/* re-adjust */
4596	/*
4597	 * NL_Comment
4598	 * The %c is the degree symbol.
4599	 */
4600	(void) fprintf(stdout, ":%1.2d%cC ", t, 186);
4601}
4602
4603
4604
4605/*
4606 * trans_decode() Display tranceivers state.
4607 *
4608 * RETURNS:
4609 *	none.
4610 */
4611void
4612trans_decode(Trans_elem_st *trans)
4613{
4614	if (trans->disabled) {
4615		(void) fprintf(stdout, ": ");
4616		(void) fprintf(stdout, MSGSTR(34,
4617			"Disabled"));
4618	}
4619	if (trans->lol) {
4620		(void) fprintf(stdout, MSGSTR(2133,
4621			": Not receiving a signal"));
4622	}
4623	if (trans->lsr_fail) {
4624		(void) fprintf(stdout, MSGSTR(2134,
4625			": Laser failed"));
4626	}
4627}
4628
4629
4630
4631/*
4632 * trans_messages() Display tranceiver status.
4633 *
4634 * NOTE: The decoding of the status assumes that the elements
4635 * are in order with the first two elements are for the
4636 * "A" IB. It also assumes the tranceivers are numbered
4637 * 0 and 1.
4638 *
4639 * RETURNS:
4640 *	none.
4641 */
4642void
4643trans_messages(struct l_state_struct *l_state, int ib_a_flag)
4644{
4645Trans_elem_st	trans;
4646int	i, j, k;
4647int	count = 0;
4648int	elem_index = 0;
4649
4650	/* Get and print messages */
4651	for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) {
4652	    elem_index++;
4653	    if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_FL) {
4654
4655		if (l_state->ib_tbl.config.type_hdr[i].text_len != 0) {
4656			(void) fprintf(stdout, "\n\t\t%s\n",
4657			l_state->ib_tbl.config.text[i]);
4658		}
4659		count = k = 0;
4660
4661		for (j = 0; j <
4662			(int)l_state->ib_tbl.config.type_hdr[i].num; j++) {
4663			/*
4664			 * Only display the status for the selected IB.
4665			 */
4666		    if ((count < 2 && ib_a_flag) ||
4667				(count >= 2 && !ib_a_flag)) {
4668			(void) bcopy((const void *)
4669				&l_state->ib_tbl.p2_s.element[elem_index + j],
4670				(void *)&trans, sizeof (trans));
4671
4672			if (k == 0) {
4673				(void) fprintf(stdout, "\t\t%d ", k);
4674			} else {
4675				(void) fprintf(stdout, "\n\t\t%d ", k);
4676			}
4677			if (trans.code == S_OK) {
4678				(void) fprintf(stdout,
4679				MSGSTR(29, "O.K."));
4680				revision_msg(l_state, elem_index + j);
4681			} else if ((trans.code == S_CRITICAL) ||
4682				(trans.code == S_NONCRITICAL)) {
4683				(void) fprintf(stdout,
4684				MSGSTR(2135, "Failed"));
4685				revision_msg(l_state, elem_index + j);
4686				trans_decode(&trans);
4687			} else if (trans.code == S_NOT_INSTALLED) {
4688				(void) fprintf(stdout,
4689				MSGSTR(30, "Not Installed"));
4690			} else if (trans.code == S_NOT_AVAILABLE) {
4691				(void) fprintf(stdout,
4692				MSGSTR(34, "Disabled"));
4693				revision_msg(l_state, elem_index + j);
4694			} else {
4695				(void) fprintf(stdout,
4696				MSGSTR(4, "Unknown status"));
4697			}
4698			k++;
4699		    }
4700		    count++;
4701		}
4702	    }
4703		/*
4704		 * Calculate the index to each element.
4705		 */
4706		elem_index += l_state->ib_tbl.config.type_hdr[i].num;
4707	}
4708	(void) fprintf(stdout, "\n");
4709}
4710
4711
4712
4713/*
4714 * temperature_messages() Display temperature status.
4715 *
4716 * RETURNS:
4717 *	none.
4718 */
4719void
4720temperature_messages(struct l_state_struct *l_state, int rear_flag)
4721{
4722Temp_elem_st	temp;
4723int	i, j, last_ok = 0;
4724int	all_ok = 1;
4725int	elem_index = 0;
4726
4727	/* Get and print messages */
4728	for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) {
4729	    elem_index++;	/* skip global */
4730	    if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_TS) {
4731		if (!rear_flag) {
4732		rear_flag = 1;		/* only do front or rear backplane */
4733		if (l_state->ib_tbl.config.type_hdr[i].text_len != 0) {
4734			(void) fprintf(stdout, "\t  %s",
4735			l_state->ib_tbl.config.text[i]);
4736		}
4737
4738		/*
4739		 * Check global status and if not all O.K.
4740		 * then print individually.
4741		 */
4742		(void) bcopy((const void *)&l_state->ib_tbl.p2_s.element[i],
4743			(void *)&temp, sizeof (temp));
4744		for (j = 0; j <
4745			(int)l_state->ib_tbl.config.type_hdr[i].num; j++) {
4746			(void) bcopy((const void *)
4747			&l_state->ib_tbl.p2_s.element[elem_index + j],
4748				(void *)&temp, sizeof (temp));
4749
4750			if ((j == 0) && (temp.code == S_OK) &&
4751				(!(temp.ot_fail || temp.ot_warn ||
4752					temp.ut_fail || temp.ut_warn))) {
4753				(void) fprintf(stdout, "\n\t  %d", j);
4754			} else if ((j == 6) && (temp.code == S_OK) &&
4755				all_ok) {
4756				(void) fprintf(stdout, "\n\t  %d", j);
4757			} else if (last_ok && (temp.code == S_OK)) {
4758				(void) fprintf(stdout, "%d", j);
4759			} else {
4760				(void) fprintf(stdout, "\n\t\t%d", j);
4761			}
4762			if (temp.code == S_OK) {
4763				disp_degree(&temp);
4764				if (temp.ot_fail || temp.ot_warn ||
4765					temp.ut_fail || temp.ut_warn) {
4766					temp_decode(&temp);
4767					all_ok = 0;
4768					last_ok = 0;
4769				} else {
4770					last_ok++;
4771				}
4772			} else if (temp.code == S_CRITICAL) {
4773				(void) fprintf(stdout,
4774				MSGSTR(122, "Critical failure"));
4775				last_ok = 0;
4776				all_ok = 0;
4777			} else if (temp.code == S_NONCRITICAL) {
4778				(void) fprintf(stdout,
4779				MSGSTR(89, "Non-Critical Failure"));
4780				last_ok = 0;
4781				all_ok = 0;
4782			} else if (temp.code == S_NOT_INSTALLED) {
4783				(void) fprintf(stdout,
4784				MSGSTR(30, "Not Installed"));
4785				last_ok = 0;
4786				all_ok = 0;
4787			} else if (temp.code == S_NOT_AVAILABLE) {
4788				(void) fprintf(stdout,
4789				MSGSTR(34, "Disabled"));
4790				last_ok = 0;
4791				all_ok = 0;
4792			} else {
4793				(void) fprintf(stdout,
4794				MSGSTR(4, "Unknown status"));
4795				last_ok = 0;
4796				all_ok = 0;
4797			}
4798		}
4799		if (all_ok) {
4800			(void) fprintf(stdout,
4801			MSGSTR(2136, " (All temperatures are "
4802			"NORMAL.)"));
4803		}
4804		all_ok = 1;
4805		(void) fprintf(stdout, "\n");
4806	    } else {
4807		rear_flag = 0;
4808	    }
4809	    }
4810	    elem_index += l_state->ib_tbl.config.type_hdr[i].num;
4811	}
4812}
4813
4814
4815
4816/*
4817 * ib_decode() Display IB byte 3 state.
4818 *
4819 * RETURNS:
4820 *	none.
4821 */
4822void
4823ib_decode(Ctlr_elem_st *ctlr)
4824{
4825	if (ctlr->overtemp_alart) {
4826		(void) fprintf(stdout, MSGSTR(2137,
4827			" - IB Over Temperature Alert "));
4828	}
4829	if (ctlr->ib_loop_1_fail) {
4830		(void) fprintf(stdout, MSGSTR(2138,
4831			" - IB Loop 1 has failed "));
4832	}
4833	if (ctlr->ib_loop_0_fail) {
4834		(void) fprintf(stdout, MSGSTR(2139,
4835			" - IB Loop 0 has failed "));
4836	}
4837}
4838
4839
4840
4841/*
4842 * mb_messages() Display motherboard
4843 * (interconnect assembly) messages.
4844 *
4845 * RETURNS:
4846 *	none.
4847 */
4848void
4849mb_messages(struct l_state_struct *l_state, int index, int elem_index)
4850{
4851int		j;
4852Interconnect_st	interconnect;
4853
4854	if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) {
4855		(void) fprintf(stdout, "%s\n",
4856		l_state->ib_tbl.config.text[index]);
4857	}
4858	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num;
4859			j++) {
4860		(void) bcopy((const void *)
4861			&l_state->ib_tbl.p2_s.element[elem_index + j],
4862			(void *)&interconnect, sizeof (interconnect));
4863		(void) fprintf(stdout, "\t");
4864
4865		if (interconnect.code == S_OK) {
4866			(void) fprintf(stdout,
4867			MSGSTR(29, "O.K."));
4868			revision_msg(l_state, elem_index + j);
4869		} else if (interconnect.code == S_NOT_INSTALLED) {
4870			(void) fprintf(stdout,
4871			MSGSTR(30, "Not Installed"));
4872		} else if (interconnect.code == S_CRITICAL) {
4873			if (interconnect.eprom_fail != 0) {
4874				(void) fprintf(stdout, MSGSTR(2140,
4875					"Critical Failure: EEPROM failure"));
4876			} else {
4877				(void) fprintf(stdout, MSGSTR(2141,
4878					"Critical Failure: Unknown failure"));
4879			}
4880			revision_msg(l_state, elem_index + j);
4881		} else if (interconnect.code == S_NONCRITICAL) {
4882			if (interconnect.eprom_fail != 0) {
4883				(void) fprintf(stdout, MSGSTR(2142,
4884				"Non-Critical Failure: EEPROM failure"));
4885			} else {
4886				(void) fprintf(stdout, MSGSTR(2143,
4887				"Non-Critical Failure: Unknown failure"));
4888			}
4889			revision_msg(l_state, elem_index + j);
4890		} else if (interconnect.code == S_NOT_AVAILABLE) {
4891			(void) fprintf(stdout,
4892			MSGSTR(34, "Disabled"));
4893			revision_msg(l_state, elem_index + j);
4894		} else {
4895			(void) fprintf(stdout,
4896			MSGSTR(4, "Unknown status"));
4897		}
4898		(void) fprintf(stdout, "\n");
4899	}
4900
4901
4902}
4903
4904
4905
4906/*
4907 * back_plane_messages() Display back_plane messages
4908 * including the temperature's.
4909 *
4910 * RETURNS:
4911 *	none.
4912 */
4913void
4914back_plane_messages(struct l_state_struct *l_state, int index, int elem_index)
4915{
4916Bp_elem_st	bp;
4917int		j;
4918char		status_string[MAXPATHLEN];
4919
4920	if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) {
4921		(void) fprintf(stdout, "%s\n",
4922		l_state->ib_tbl.config.text[index]);
4923	}
4924	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num;
4925			j++) {
4926		(void) bcopy((const void *)
4927			&l_state->ib_tbl.p2_s.element[elem_index + j],
4928			(void *)&bp, sizeof (bp));
4929		if (j == 0) {
4930			(void) fprintf(stdout,
4931				MSGSTR(2144, "\tFront Backplane: "));
4932		} else {
4933			(void) fprintf(stdout,
4934				MSGSTR(2145, "\tRear Backplane:  "));
4935		}
4936
4937		(void) l_element_msg_string(bp.code, status_string);
4938		(void) fprintf(stdout, "%s", status_string);
4939
4940		if (bp.code != S_NOT_INSTALLED) {
4941			revision_msg(l_state, elem_index + j);
4942			if ((bp.byp_a_enabled || bp.en_bypass_a) &&
4943				!(bp.byp_b_enabled || bp.en_bypass_b)) {
4944				(void) fprintf(stdout, " (");
4945				(void) fprintf(stdout,
4946				MSGSTR(130, "Bypass A enabled"));
4947				(void) fprintf(stdout, ")");
4948			} else if ((bp.byp_b_enabled || bp.en_bypass_b) &&
4949				!(bp.byp_a_enabled || bp.en_bypass_a)) {
4950				(void) fprintf(stdout, " (");
4951				(void) fprintf(stdout,
4952				MSGSTR(129, "Bypass B enabled"));
4953				(void) fprintf(stdout, ")");
4954			/* This case covers where a and b are bypassed */
4955			} else if (bp.byp_b_enabled || bp.en_bypass_b) {
4956				(void) fprintf(stdout,
4957				MSGSTR(2146, " (Bypass's A & B enabled)"));
4958			}
4959			(void) fprintf(stdout, "\n");
4960			temperature_messages(l_state, j);
4961		} else {
4962			(void) fprintf(stdout, "\n");
4963		}
4964	}
4965}
4966
4967
4968/*
4969 * dpm_SSC100_messages() Display SSC100 messages
4970 * including the temperature's.
4971 *
4972 * RETURNS:
4973 *	none.
4974 */
4975void
4976dpm_SSC100_messages(struct l_state_struct *l_state, int index, int elem_index)
4977{
4978Bp_elem_st	bp;
4979int		j;
4980char		status_string[MAXPATHLEN];
4981
4982	if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) {
4983		(void) fprintf(stdout, "%s\n",
4984		l_state->ib_tbl.config.text[index]);
4985	}
4986	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num;
4987			j++) {
4988		(void) bcopy((const void *)
4989			&l_state->ib_tbl.p2_s.element[elem_index + j],
4990			(void *)&bp, sizeof (bp));
4991		(void) fprintf(stdout, MSGSTR(2246, "    SSC100 #%d:    "), j);
4992
4993		(void) l_element_msg_string(bp.code, status_string);
4994		(void) fprintf(stdout, "%s", status_string);
4995
4996		if (bp.code != S_NOT_INSTALLED) {
4997			revision_msg(l_state, elem_index + j);
4998			if ((bp.byp_a_enabled || bp.en_bypass_a) &&
4999				!(bp.byp_b_enabled || bp.en_bypass_b)) {
5000				(void) fprintf(stdout, " (");
5001				(void) fprintf(stdout,
5002				MSGSTR(130, "Bypass A enabled"));
5003				(void) fprintf(stdout, ")");
5004			} else if ((bp.byp_b_enabled || bp.en_bypass_b) &&
5005				!(bp.byp_a_enabled || bp.en_bypass_a)) {
5006				(void) fprintf(stdout, " (");
5007				(void) fprintf(stdout,
5008				MSGSTR(129, "Bypass B enabled"));
5009				(void) fprintf(stdout, ")");
5010			/* This case covers where a and b are bypassed */
5011			} else if (bp.byp_b_enabled || bp.en_bypass_b) {
5012				(void) fprintf(stdout,
5013				MSGSTR(2146, " (Bypass's A & B enabled)"));
5014			}
5015			(void) fprintf(stdout, "\n");
5016		} else {
5017			(void) fprintf(stdout, "\n");
5018		}
5019	}
5020	temperature_messages(l_state, 0);
5021}
5022
5023
5024
5025
5026/*
5027 * loop_messages() Display loop messages.
5028 *
5029 * RETURNS:
5030 *	none.
5031 */
5032void
5033loop_messages(struct l_state_struct *l_state, int index, int elem_index)
5034{
5035Loop_elem_st	loop;
5036int		j;
5037
5038	if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) {
5039		(void) fprintf(stdout, "%s\n",
5040		l_state->ib_tbl.config.text[index]);
5041	}
5042	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num;
5043			j++) {
5044		(void) bcopy((const void *)
5045			&l_state->ib_tbl.p2_s.element[elem_index + j],
5046			(void *)&loop, sizeof (loop));
5047
5048		(void) fprintf(stdout, "\t");
5049		if (j == 0) {
5050			if (loop.code == S_NOT_INSTALLED) {
5051				(void) fprintf(stdout,
5052				MSGSTR(2147, "Loop A is not installed"));
5053			} else {
5054				if (loop.split) {
5055					(void) fprintf(stdout, MSGSTR(2148,
5056				"Loop A is configured as two separate loops."));
5057				} else {
5058					(void) fprintf(stdout, MSGSTR(2149,
5059				"Loop A is configured as a single loop."));
5060				}
5061			}
5062		} else {
5063			if (loop.code == S_NOT_INSTALLED) {
5064				(void) fprintf(stdout,
5065				MSGSTR(2150, "Loop B is not installed"));
5066			} else {
5067				if (loop.split) {
5068					(void) fprintf(stdout, MSGSTR(2151,
5069				"Loop B is configured as two separate loops."));
5070				} else {
5071					(void) fprintf(stdout, MSGSTR(2152,
5072				"Loop B is configured as a single loop."));
5073				}
5074			}
5075		}
5076		(void) fprintf(stdout, "\n");
5077	}
5078}
5079
5080
5081
5082/*
5083 * ctlr_messages() Display ESI Controller status.
5084 *
5085 * RETURNS:
5086 *	none.
5087 */
5088void
5089ctlr_messages(struct l_state_struct *l_state, int index, int elem_index)
5090{
5091Ctlr_elem_st	ctlr;
5092int		j;
5093int		ib_a_flag = 1;
5094
5095	if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) {
5096		(void) fprintf(stdout, "%s\n",
5097		l_state->ib_tbl.config.text[index]);
5098	}
5099	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num;
5100			j++) {
5101		(void) bcopy((const void *)
5102			&l_state->ib_tbl.p2_s.element[elem_index + j],
5103			(void *)&ctlr, sizeof (ctlr));
5104		if (j == 0) {
5105			(void) fprintf(stdout, MSGSTR(2153, "\tA: "));
5106		} else {
5107			(void) fprintf(stdout, MSGSTR(2154, "\tB: "));
5108			ib_a_flag = 0;
5109		}
5110		if (ctlr.code == S_OK) {
5111			(void) fprintf(stdout, MSGSTR(29, "O.K."));
5112			/* If any byte 3 bits set display */
5113			ib_decode(&ctlr);
5114			/* Display Version message */
5115			revision_msg(l_state, elem_index + j);
5116			/*
5117			 * Display the tranciver module state for this
5118			 * IB.
5119			 */
5120			trans_messages(l_state, ib_a_flag);
5121		} else if (ctlr.code == S_CRITICAL) {
5122			(void) fprintf(stdout,
5123			MSGSTR(122, "Critical failure"));
5124			ib_decode(&ctlr);
5125			(void) fprintf(stdout, "\n");
5126		} else if (ctlr.code == S_NONCRITICAL) {
5127			(void) fprintf(stdout,
5128			MSGSTR(89, "Non-Critical Failure"));
5129			ib_decode(&ctlr);
5130			(void) fprintf(stdout, "\n");
5131		} else if (ctlr.code == S_NOT_INSTALLED) {
5132			(void) fprintf(stdout,
5133			MSGSTR(30, "Not Installed"));
5134			(void) fprintf(stdout, "\n");
5135		} else if (ctlr.code == S_NOT_AVAILABLE) {
5136			(void) fprintf(stdout,
5137			MSGSTR(34, "Disabled"));
5138			(void) fprintf(stdout, "\n");
5139		} else {
5140			(void) fprintf(stdout,
5141			MSGSTR(4, "Unknown status"));
5142			(void) fprintf(stdout, "\n");
5143		}
5144	}
5145}
5146
5147
5148
5149/*
5150 * fan_decode() Display Fans bytes 1-3 state.
5151 *
5152 * RETURNS:
5153 *	none.
5154 */
5155void
5156fan_decode(Fan_elem_st *fan)
5157{
5158	if (fan->fail) {
5159		(void) fprintf(stdout, MSGSTR(2155,
5160			":Yellow LED is on"));
5161	}
5162	if (fan->speed == 0) {
5163		(void) fprintf(stdout, MSGSTR(2156,
5164			":Fan stopped"));
5165	} else if (fan->speed < S_HI_SPEED) {
5166		(void) fprintf(stdout, MSGSTR(2157,
5167			":Fan speed Low"));
5168	} else {
5169		(void) fprintf(stdout, MSGSTR(2158,
5170			":Fan speed Hi"));
5171	}
5172}
5173
5174/*
5175 * fan_messages() Display Fan status.
5176 *
5177 * RETURNS:
5178 *	none.
5179 */
5180void
5181fan_messages(struct l_state_struct *l_state, int hdr_index, int elem_index)
5182{
5183Fan_elem_st	fan;
5184int	j;
5185
5186	/* Get and print messages */
5187	if (l_state->ib_tbl.config.type_hdr[hdr_index].text_len != 0) {
5188		(void) fprintf(stdout, "%s\n",
5189		l_state->ib_tbl.config.text[hdr_index]);
5190	}
5191	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[hdr_index].num;
5192			j++) {
5193		(void) bcopy((const void *)
5194			&l_state->ib_tbl.p2_s.element[elem_index + j],
5195			(void *)&fan, sizeof (fan));
5196		(void) fprintf(stdout, "\t%d ", j);
5197		if (fan.code == S_OK) {
5198			(void) fprintf(stdout, MSGSTR(29, "O.K."));
5199			revision_msg(l_state, elem_index + j);
5200		} else if (fan.code == S_CRITICAL) {
5201			(void) fprintf(stdout,
5202			MSGSTR(122, "Critical failure"));
5203			fan_decode(&fan);
5204			revision_msg(l_state, elem_index + j);
5205		} else if (fan.code == S_NONCRITICAL) {
5206			(void) fprintf(stdout,
5207			MSGSTR(89, "Non-Critical Failure"));
5208			fan_decode(&fan);
5209			revision_msg(l_state, elem_index + j);
5210		} else if (fan.code == S_NOT_INSTALLED) {
5211			(void) fprintf(stdout,
5212			MSGSTR(30, "Not Installed"));
5213		} else if (fan.code == S_NOT_AVAILABLE) {
5214			(void) fprintf(stdout,
5215			MSGSTR(34, "Disabled"));
5216			revision_msg(l_state, elem_index + j);
5217		} else {
5218			(void) fprintf(stdout,
5219			MSGSTR(4, "Unknown status"));
5220		}
5221	}
5222	(void) fprintf(stdout, "\n");
5223}
5224
5225
5226
5227/*
5228 * ps_decode() Display Power Supply bytes 1-3 state.
5229 *
5230 * RETURNS:
5231 *	none.
5232 */
5233void
5234ps_decode(Ps_elem_st *ps)
5235{
5236	if (ps->dc_over) {
5237		(void) fprintf(stdout, MSGSTR(2159,
5238			": DC Voltage too high"));
5239	}
5240	if (ps->dc_under) {
5241		(void) fprintf(stdout, MSGSTR(2160,
5242			": DC Voltage too low"));
5243	}
5244	if (ps->dc_over_i) {
5245		(void) fprintf(stdout, MSGSTR(2161,
5246			": DC Current too high"));
5247	}
5248	if (ps->ovrtmp_fail || ps->temp_warn) {
5249		(void) fprintf(stdout, MSGSTR(2162,
5250			": Temperature too high"));
5251	}
5252	if (ps->ac_fail) {
5253		(void) fprintf(stdout, MSGSTR(2163,
5254			": AC Failed"));
5255	}
5256	if (ps->dc_fail) {
5257		(void) fprintf(stdout, MSGSTR(2164,
5258			": DC Failed"));
5259	}
5260}
5261
5262
5263
5264/*
5265 * revision_msg() Print the revision message from page 7.
5266 *
5267 * RETURNS:
5268 *	none.
5269 */
5270void
5271revision_msg(struct l_state_struct *l_state, int index)
5272{
5273	if (strlen((const char *)
5274		l_state->ib_tbl.p7_s.element_desc[index].desc_string)) {
5275		(void) fprintf(stdout, "(%s)",
5276		l_state->ib_tbl.p7_s.element_desc[index].desc_string);
5277	}
5278}
5279
5280
5281
5282/*
5283 * ps_messages() Display Power Supply status.
5284 *
5285 * RETURNS:
5286 *	none.
5287 */
5288void
5289ps_messages(struct l_state_struct *l_state, int	index, int elem_index)
5290{
5291Ps_elem_st	ps;
5292int	j;
5293
5294	/* Get and print Power Supply messages */
5295
5296	if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) {
5297		(void) fprintf(stdout, "%s\n",
5298		l_state->ib_tbl.config.text[index]);
5299	}
5300
5301	for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num;
5302		j++) {
5303		(void) bcopy((const void *)
5304			&l_state->ib_tbl.p2_s.element[elem_index + j],
5305			(void *)&ps, sizeof (ps));
5306		(void) fprintf(stdout, "\t%d ", j);
5307		if (ps.code == S_OK) {
5308			(void) fprintf(stdout, MSGSTR(29, "O.K."));
5309			revision_msg(l_state, elem_index + j);
5310		} else if (ps.code == S_CRITICAL) {
5311			(void) fprintf(stdout,
5312			MSGSTR(122, "Critical failure"));
5313			ps_decode(&ps);
5314			revision_msg(l_state, elem_index + j);
5315		} else if (ps.code == S_NONCRITICAL) {
5316			(void) fprintf(stdout,
5317			MSGSTR(89, "Non-Critical Failure"));
5318			ps_decode(&ps);
5319			revision_msg(l_state, elem_index + j);
5320		} else if (ps.code == S_NOT_INSTALLED) {
5321			(void) fprintf(stdout,
5322			MSGSTR(30, "Not Installed"));
5323		} else if (ps.code == S_NOT_AVAILABLE) {
5324			(void) fprintf(stdout,
5325			MSGSTR(34, "Disabled"));
5326			revision_msg(l_state, elem_index + j);
5327		} else {
5328			(void) fprintf(stdout,
5329			MSGSTR(4, "Unknown status"));
5330		}
5331
5332	}
5333	(void) fprintf(stdout, "\n");
5334}
5335
5336
5337
5338/*
5339 * abnormal_condition() Display any abnormal condition messages.
5340 *
5341 * RETURNS:
5342 *	none.
5343 */
5344void
5345abnormal_condition_display(struct l_state_struct *l_state)
5346{
5347
5348	(void) fprintf(stdout, "\n");
5349	if (l_state->ib_tbl.p2_s.ui.crit) {
5350		(void) fprintf(stdout,
5351			MSGSTR(2165, "                         "
5352			"CRITICAL CONDITION DETECTED\n"));
5353	}
5354	if (l_state->ib_tbl.p2_s.ui.non_crit) {
5355		(void) fprintf(stdout,
5356			MSGSTR(2166, "                   "
5357			"WARNING: NON-CRITICAL CONDITION DETECTED\n"));
5358	}
5359	if (l_state->ib_tbl.p2_s.ui.invop) {
5360		(void) fprintf(stdout,
5361			MSGSTR(2167, "                      "
5362			"WARNING: Invalid Operation bit set.\n"
5363			"\tThis means an Enclosure Control page"
5364			" or an Array Control page with an invalid\n"
5365			"\tformat has previously been transmitted to the"
5366			" Enclosure Services card by a\n\tSend Diagnostic"
5367			" SCSI command.\n"));
5368	}
5369	(void) fprintf(stdout, "\n");
5370}
5371
5372
5373
5374
5375
5376/*
5377 * adm_start() Spin up the given list
5378 * of SENA devices.
5379 *
5380 * RETURNS:
5381 *	none.
5382 */
5383int
5384adm_start(char **argv)
5385{
5386char		*path_phys = NULL;
5387Path_struct	*path_struct;
5388int		err = 0, retval = 0;
5389
5390	while (*argv != NULL) {
5391		if ((err = l_convert_name(*argv, &path_phys,
5392			&path_struct, Options & PVERBOSE)) != 0) {
5393			(void) fprintf(stderr, MSGSTR(33,
5394				" Error: converting"
5395				" %s to physical path.\n"
5396				" Invalid pathname.\n"),
5397				*argv);
5398		if (err != -1) {
5399			(void) print_errString(err, *argv);
5400		}
5401		(argv)++;
5402		retval++;
5403		continue;
5404	    }
5405	    VERBPRINT(MSGSTR(101, "Issuing start to:\n %s\n"), *argv);
5406	    if (err = g_start(path_phys))  {
5407		(void) print_errString(err, *argv);
5408		(argv)++;
5409		retval++;
5410		continue;
5411	    }
5412	    (argv)++;
5413	}
5414	return (retval);
5415}
5416
5417
5418
5419/*
5420 * adm_stop() Spin down a
5421 * given list of SENA devices.
5422 *
5423 * RETURNS:
5424 *	none.
5425 */
5426int
5427adm_stop(char **argv)
5428{
5429char		*path_phys = NULL;
5430Path_struct	*path_struct;
5431int		err = 0, retval = 0;
5432
5433	while (*argv != NULL) {
5434		if ((err = l_convert_name(*argv, &path_phys,
5435		    &path_struct, Options & PVERBOSE)) != 0) {
5436			(void) fprintf(stderr,
5437			    MSGSTR(33,
5438			    " Error: converting"
5439			    " %s to physical path.\n"
5440			    " Invalid pathname.\n"),
5441			    *argv);
5442			if (err != -1) {
5443				(void) print_errString(err, *argv);
5444			}
5445			(argv)++;
5446			retval++;
5447			continue;
5448		}
5449
5450		/*
5451		 * scsi stop is not supported for tape drives.
5452		 * The scsi unload op code for tape is the same as a
5453		 * scsi stop for disk so this command will eject the tape.
5454		 * If an eject is the desired behavior then remove the
5455		 * following if block. ('mt offline' will give you
5456		 * the same eject functionality).
5457		 */
5458		if (strstr(path_phys, SLSH_DRV_NAME_ST)) {
5459			errno = ENOTSUP;
5460			(void) print_errString(0, path_phys);
5461			(argv)++;
5462			continue;
5463		}
5464
5465		VERBPRINT(MSGSTR(100, "Issuing stop to:\n %s\n"), *argv);
5466			if (err = g_stop(path_phys, 1))  {
5467			(void) print_errString(err, *argv);
5468			(argv)++;
5469			retval++;
5470			continue;
5471		}
5472		(argv)++;
5473	}
5474	return (retval);
5475}
5476
5477
5478/*
5479 * On a SOC+ chip, the port is either put into (offline) or pulled out
5480 * of (online) a loopback mode since the laser cannot be turned on or off.
5481 * As of this writing, this feature is yet to be supported by the ifp
5482 * driver on a QLogic card.
5483 *
5484 * INPUT :
5485 *	Command line args and flag - LUX_P_ONLINE or LUX_P_OFFLINE
5486 *	The path that is passed has to be the physical path to the port.
5487 *	For example :
5488 *	/devices/sbus@2,0/SUNW,socal@2,0:0
5489 *	/devices/io-unit@f,e0200000/sbi@0,0/SUNW,socal@2,0:0
5490 *	/devices/pci@1f,4000/SUNW,ifp@2:devctl
5491 * RETURNS :
5492 *	Nothing
5493 */
5494int
5495adm_port_offline_online(char *argv[], int flag)
5496{
5497	int		err, retval = 0;
5498	char		*path_phys = NULL;
5499	char		*nexus_path_ptr = NULL;
5500	Path_struct	*path_struct = NULL;
5501
5502	while (*argv != NULL) {
5503		if ((err = l_convert_name(*argv, &path_phys,
5504			&path_struct, Options & PVERBOSE)) != 0) {
5505			(void) fprintf(stderr,
5506				MSGSTR(33,
5507					" Error: converting"
5508					" %s to physical path.\n"
5509					" Invalid pathname.\n"),
5510				*argv);
5511			if (err != -1) {
5512				(void) print_errString(err, *argv);
5513			}
5514			argv++;
5515			retval++;
5516			continue;
5517		}
5518
5519		/* Get the nexus path - need this to print messages */
5520		if ((err = g_get_nexus_path(path_phys, &nexus_path_ptr)) != 0) {
5521			(void) print_errString(err, *argv);
5522			retval++;
5523			goto cleanup_and_go;
5524		}
5525
5526		if (flag == LUX_P_OFFLINE) {
5527			if ((err = g_port_offline(nexus_path_ptr))) {
5528				(void) print_errString(err, nexus_path_ptr);
5529				retval++;
5530				goto cleanup_and_go;
5531			}
5532			fprintf(stdout,
5533				MSGSTR(2223, "Port %s has been disabled\n"),
5534					nexus_path_ptr);
5535		} else if (flag == LUX_P_ONLINE) {
5536			if ((err = g_port_online(nexus_path_ptr))) {
5537				(void) print_errString(err, nexus_path_ptr);
5538				retval++;
5539				goto cleanup_and_go;
5540			}
5541			fprintf(stdout,
5542				MSGSTR(2224, "Port %s has been enabled\n"),
5543					nexus_path_ptr);
5544		} else {
5545			(void) fprintf(stderr,
5546					MSGSTR(2225,
5547					"Unknown action requested "
5548					"on port - %d\nIgnoring."),
5549					flag);
5550			retval++;
5551		}
5552cleanup_and_go:
5553		free(path_phys);
5554		free(path_struct);
5555		free(nexus_path_ptr);
5556		argv++;
5557	}
5558	return (retval);
5559}
5560
5561/*
5562 * Expert level subcommand 'luxadm -e port'
5563 * which displays all FC ports on a host and state information for
5564 * connectivity (CONNECTED or NOT CONNECTED) indicating whether there
5565 * are devices attached to the port.
5566 *
5567 * Sample output for ifp:
5568 *
5569 * /devices/pci@1f,4000/SUNW,ifp@2:devctl		CONNECTED
5570 * /devices/pci@1f,2000/SUNW,ifp@1:devctl		NOT CONNECTED
5571 *
5572 * Sample output for socal:
5573 *
5574 * /devices/sbus@2,0/SUNW,socal@d,10000:0               CONNECTED
5575 * /devices/sbus@2,0/SUNW,socal@d,10000:1               NOT CONNECTED
5576 * /devices/sbus@2,0/SUNW,socal@2,0:0                   NOT CONNECTED
5577 * /devices/sbus@2,0/SUNW,socal@2,0:1                   CONNECTED
5578 *
5579 * Note: for socal the path returned is not a devctl path as there is no
5580 * devctl path for socal.
5581 *
5582 * Sample output for fp:
5583 *
5584 * /devices/sbus@2,0/SUNW,qlc@5/fp@0,0:devctl        CONNECTED
5585 * /devices/sbus@2,0/SUNW,qlc@4/fp@1,0:devctl        CONNECTED
5586 */
5587int
5588adm_display_port(int verbose)
5589{
5590	/*
5591	 * If another port driver needs to be searched, add it here
5592	 */
5593	static char *portdrvr_list[] = {"socal",
5594					"fp",
5595					"ifp",
5596					NULL};
5597	portlist_t portlist;
5598	int x = 0, err = 0, retval = 0;
5599	int port_state;
5600
5601	portlist.hbacnt = 0;
5602
5603	/*
5604	 * Look for all HBA ports as listed in portdrvr_list[]
5605	 */
5606	while (portdrvr_list[x]) {
5607		if (err = g_get_port_path(portdrvr_list[x], &portlist)) {
5608			if (err != L_PORT_DRIVER_NOT_FOUND &&
5609			    err != L_PHYS_PATH_NOT_FOUND) {
5610				(void) print_errString(err, portdrvr_list[x]);
5611				retval++;
5612			}
5613		}
5614		x++;
5615	}
5616
5617
5618	/*
5619	 * For each port path found get the connection state.
5620	 * If there are devices attached the state is considered connected.
5621	 */
5622	for (x = 0; x < portlist.hbacnt; x++) {
5623		if (err = g_get_port_state(portlist.physpath[x],
5624			    &port_state, verbose)) {
5625			(void) print_errString(err, portlist.physpath[x]);
5626			retval++;
5627		} else {
5628			fprintf(stdout, "%-65s  ", portlist.physpath[x]);
5629			if (port_state == PORT_CONNECTED) {
5630				(void) fprintf(stdout,
5631						MSGSTR(2233,
5632						"CONNECTED\n"));
5633			} else {
5634				(void) fprintf(stdout,
5635						MSGSTR(2234,
5636						"NOT CONNECTED\n"));
5637			}
5638		}
5639	}
5640	g_free_portlist(&portlist);
5641	return (retval);
5642}
5643
5644/*
5645 * Expert level subcommand 'luxadm -e external_loopback <portpath>
5646 *				      internal_loopback
5647 *				      no_loopback
5648 * Does just what you would think. Sets port in designated loopback
5649 * mode.
5650 * INPUT:  portpath - path to device on which to set loopback mode
5651 *	   flag     - loopback mode to set. Values are:
5652 *			EXT_LOOPBACK
5653 *			INT_LOOPBACK
5654 *			NO_LOOPBACK
5655 *
5656 * RETURN: 0 on success
5657 *         non-zero on failure
5658 */
5659int
5660adm_port_loopback(char *portpath, int flag)
5661{
5662	int		err;
5663	char		*path_phys = NULL;
5664	Path_struct	*path_struct = NULL;
5665	int		cmd;
5666
5667	if ((err = l_convert_name(portpath, &path_phys,
5668		&path_struct, Options & PVERBOSE)) != 0) {
5669		(void) fprintf(stderr,
5670			MSGSTR(33,
5671				" Error: converting"
5672				" %s to physical path.\n"
5673				" Invalid pathname.\n"),
5674			portpath);
5675		if (err != -1) {
5676			(void) print_errString(err, portpath);
5677		}
5678		return (-1);
5679	}
5680
5681	switch (flag) {
5682		case EXT_LOOPBACK:
5683			cmd = EXT_LPBACK;
5684			break;
5685		case INT_LOOPBACK:
5686			cmd = INT_LPBACK;
5687			break;
5688		case NO_LOOPBACK:
5689			cmd = NO_LPBACK;
5690			break;
5691		default:
5692			(void) fprintf(stderr,
5693					MSGSTR(2225,
5694					"Unknown action requested "
5695					"on port - %d\nIgnoring."),
5696					flag);
5697			free(path_phys);
5698			free(path_struct);
5699			return (-1);
5700	}
5701
5702
5703	if ((err = g_loopback_mode(path_phys, cmd)) != 0) {
5704		(void) print_errString(err, portpath);
5705		free(path_phys);
5706		free(path_struct);
5707		return (-1);
5708	} else {
5709		switch (flag) {
5710			case EXT_LOOPBACK:
5711				(void) fprintf(stdout,
5712						MSGSTR(2230,
5713						"External loopback mode set "
5714						"on:\n%s\n"),
5715						portpath);
5716				break;
5717			case INT_LOOPBACK:
5718				(void) fprintf(stdout,
5719						MSGSTR(2231,
5720						"Internal loopback mode set "
5721						"on:\n%s\n"),
5722						portpath);
5723				break;
5724			case NO_LOOPBACK:
5725				(void) fprintf(stdout,
5726						MSGSTR(2232,
5727						"Loopback mode unset "
5728						"on:\n%s\n"),
5729						portpath);
5730				break;
5731			default:
5732				fprintf(stderr,
5733					MSGSTR(2248, "Undefined command\n"));
5734				break;
5735		}
5736	}
5737	free(path_phys);
5738	free(path_struct);
5739	return (0);
5740}
5741
5742
5743
5744/*
5745 * To print the pathlist and mpxio path attributes
5746 */
5747void
5748adm_print_pathlist(char *dev_path)
5749{
5750	int		i, pathcnt = 1;
5751	mp_pathlist_t	pathlist;
5752	int		retval = 0;
5753	char		temppath[MAXPATHLEN];
5754	char		wwns[(WWN_SIZE *2) +1];
5755	uchar_t		wwn_data[WWN_SIZE];
5756	int		err;
5757	int		state, ext_state = 0;
5758	char	*path_state[5];
5759
5760	path_state[0] = MSGSTR(2400, "INIT");
5761	path_state[1] = MSGSTR(2401, "ONLINE");
5762	path_state[2] = MSGSTR(2402, "STANDBY");
5763	path_state[3] = MSGSTR(2403, "FAULT");
5764	path_state[4] = MSGSTR(2404, "OFFLINE");
5765
5766	(void) strcpy(temppath, dev_path);
5767	retval = g_get_pathlist(temppath, &pathlist);
5768	if (retval != 0) {
5769		(void) print_errString(retval, NULL);
5770		exit(-1);
5771	}
5772	pathcnt = pathlist.path_count;
5773	for (i = 0; i < pathcnt; i++) {
5774		(void) fprintf(stdout,
5775		MSGSTR(2303, "   Controller      \t%s\n"),
5776			pathlist.path_info[i].path_hba);
5777
5778		(void) fprintf(stdout,
5779		MSGSTR(2304, "    Device Address\t\t%s\n"),
5780			pathlist.path_info[i].path_addr);
5781
5782		if ((err = get_host_controller_pwwn(
5783				pathlist.path_info[i].path_hba,
5784				(uchar_t *)&wwn_data)) != 0) {
5785			if (err != ENOTSUP) {
5786				(void) print_errString(err,
5787					pathlist.path_info[i].path_hba);
5788				exit(1);
5789			}
5790		}
5791
5792		if (!err) {
5793			copy_wwn_data_to_str(wwns, wwn_data);
5794			(void) fprintf(stdout,
5795			    MSGSTR(2326, "    Host controller port WWN\t%s\n"),
5796				wwns);
5797		}
5798
5799		(void) fprintf(stdout,
5800		MSGSTR(2305, "    Class\t\t\t%s\n"),
5801			pathlist.path_info[i].path_class);
5802		if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
5803			(void) fprintf(stdout,
5804			MSGSTR(2306, "    State\t\t\t%s\n"),
5805			path_state[pathlist.path_info[i].path_state]);
5806		}
5807		if ((err = g_stms_get_path_state(dev_path,
5808				pathlist.path_info[i].path_hba, &state,
5809				&ext_state)) != 0) {
5810			(void) print_errString(err,
5811				pathlist.path_info[i].path_hba);
5812			exit(1);
5813		} else {
5814			if ((ext_state & MDI_PATHINFO_STATE_USER_DISABLE)
5815				== MDI_PATHINFO_STATE_USER_DISABLE) {
5816				ext_state = 0;
5817				fprintf(stdout,
5818				MSGSTR(2327,
5819				"    I/Os disabled on this %s path\n\n"),
5820				path_state[pathlist.path_info[i].path_state]);
5821			}
5822		}
5823	}
5824	/* Free memory for per path info properties */
5825	free(pathlist.path_info);
5826}
5827
5828/*
5829 * compare_multipath
5830 * compares path with all paths in pathlist
5831 * If there is a match, 0 is returned, otherwise 1 is returned
5832 */
5833int
5834compare_multipath(char *path, struct mplist_struct *pathlist)
5835{
5836
5837	while (pathlist != NULL) {
5838		if (strncmp(path, pathlist->devpath, MAXPATHLEN) == 0) {
5839			return (0);
5840		}
5841		pathlist = pathlist->next;
5842	}
5843	return (1);
5844}
5845
5846/*
5847 * lun_display() Prints the
5848 * information for an individual lun.
5849 *
5850 * RETURNS:
5851 *	none.
5852 */
5853static int
5854lun_display(Path_struct *path_struct, L_inquiry inq_struct, int verbose)
5855{
5856
5857char			phys_path[MAXPATHLEN], last_logical_path[MAXPATHLEN];
5858uchar_t			*pg_buf = NULL;
5859L_disk_state		l_disk_state;
5860struct dlist		*mlist;
5861int			offset, mode_data_avail, err = 0;
5862Mode_header_10		*mode_header_ptr;
5863struct mode_page	*pg_hdr;
5864WWN_list		*wwn_list, *list_start, *wwn_list_ptr;
5865WWN_list		*wwn_list_find;
5866int			found = 0;
5867int			argpwwn = 0, argnwwn = 0;
5868struct mplist_struct	*mplistp, *mpl, *mpln;
5869struct dlist		*dlist;
5870
5871
5872
5873	strcpy(phys_path, path_struct->p_physical_path);
5874	strcpy(last_logical_path, phys_path);
5875
5876	mplistp = mpl = mpln = (struct mplist_struct *)NULL;
5877	/*
5878	 * Get path to all the FC disk and tape devices.
5879	 * If there is no slash in the argument in this routine, we assume
5880	 * it is a wwn argument.
5881	 */
5882	if (strstr(path_struct->argv, "/") != NULL) {
5883		if ((err = g_devices_get_all(&wwn_list)) != 0) {
5884			return (err);
5885		}
5886	} else {
5887		if ((err = g_get_wwn_list(&wwn_list, verbose)) != 0) {
5888			return (err);
5889		}
5890	}
5891
5892	g_sort_wwn_list(&wwn_list);
5893
5894	list_start = wwn_list;
5895
5896	for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
5897		wwn_list_ptr = wwn_list_ptr->wwn_next) {
5898		if (strcasecmp(wwn_list_ptr->port_wwn_s,
5899			path_struct->argv) == 0) {
5900			list_start = wwn_list_ptr;
5901			argpwwn = 1;
5902			break;
5903		} else if (strcasecmp(wwn_list_ptr->node_wwn_s,
5904			path_struct->argv) == 0) {
5905			list_start = wwn_list_ptr;
5906			argnwwn = 1;
5907			break;
5908		}
5909	}
5910
5911	for (wwn_list_ptr = list_start; wwn_list_ptr != NULL;
5912		wwn_list_ptr = wwn_list_ptr->wwn_next) {
5913
5914
5915	if (argpwwn) {
5916		if (strcasecmp(wwn_list_ptr->port_wwn_s,
5917			path_struct->argv) != 0) {
5918			continue;
5919		}
5920		(void) strcpy(phys_path, wwn_list_ptr->physical_path);
5921	} else if (argnwwn) {
5922		if (strstr(wwn_list_ptr->logical_path,
5923			last_logical_path) != NULL) {
5924			continue;
5925		}
5926		if (strcasecmp(wwn_list_ptr->node_wwn_s,
5927			path_struct->argv) != 0) {
5928			continue;
5929		}
5930		(void) strcpy(phys_path, wwn_list_ptr->physical_path);
5931		(void) strcpy(last_logical_path,
5932			wwn_list_ptr->logical_path);
5933	}
5934
5935	if (argnwwn || argpwwn) {
5936		if (compare_multipath(wwn_list_ptr->logical_path,
5937			mplistp) == 0) {
5938			continue;
5939		}
5940	}
5941
5942	mode_data_avail = 0;
5943
5944	(void) memset(&l_disk_state, 0, sizeof (struct l_disk_state_struct));
5945
5946	/*
5947	 * Don't call g_get_multipath if this is a SCSI_VHCI device
5948	 * dlist gets alloc'ed here to retain the free at the end
5949	 */
5950	if (strstr(phys_path, SCSI_VHCI) == NULL) {
5951		if ((err = g_get_multipath(phys_path,
5952				    &(l_disk_state.g_disk_state.multipath_list),
5953				    wwn_list, verbose)) != 0) {
5954			return (err);
5955		}
5956
5957		mlist = l_disk_state.g_disk_state.multipath_list;
5958		if (mlist == NULL) {
5959			l_disk_state.l_state_flag = L_NO_PATH_FOUND;
5960			N_DPRINTF(" lun_display: Error finding"
5961			    " multiple paths to the disk.\n");
5962			(void) g_free_wwn_list(&wwn_list);
5963			return (L_NO_VALID_PATH);
5964		}
5965	} else {
5966		/* Search for match on physical path name */
5967		for (wwn_list_find = list_start; wwn_list_find != NULL;
5968		    wwn_list_find = wwn_list_find->wwn_next) {
5969			if (strncmp(wwn_list_find->physical_path, phys_path,
5970				    strlen(wwn_list_find->physical_path))
5971				    == 0) {
5972				found++;
5973				break;
5974			}
5975		}
5976
5977		if (!found) {
5978			return (L_NO_VALID_PATH);
5979		} else {
5980			found = 0;
5981		}
5982
5983		if ((dlist = (struct dlist *)
5984			    calloc(1, sizeof (struct dlist))) == NULL) {
5985			    return (L_MALLOC_FAILED);
5986		}
5987		if ((dlist->logical_path = (char *)calloc(1,
5988			    strlen(wwn_list_find->logical_path) + 1)) == NULL) {
5989			return (L_MALLOC_FAILED);
5990		}
5991		if ((dlist->dev_path = (char *)calloc(1,
5992			    strlen(phys_path) + 1)) == NULL) {
5993			return (L_MALLOC_FAILED);
5994		}
5995		strncpy(dlist->logical_path, wwn_list_find->logical_path,
5996		    strlen(wwn_list_find->logical_path));
5997		strncpy(dlist->dev_path, phys_path, strlen(phys_path));
5998		l_disk_state.g_disk_state.multipath_list = dlist;
5999	}
6000
6001	if (argnwwn || argpwwn) {
6002		for (mlist = l_disk_state.g_disk_state.multipath_list;
6003		    mlist != NULL; mlist = mlist->next) {
6004			/* add the path to the list for compare */
6005			if ((mpl = (struct mplist_struct *)
6006				    calloc(1, sizeof (struct mplist_struct)))
6007			    == NULL) {
6008				adm_mplist_free(mplistp);
6009				return (L_MALLOC_FAILED);
6010			}
6011
6012			mpl->devpath = (char *)calloc(1, MAXPATHLEN+1);
6013			if (mpl->devpath == NULL) {
6014				adm_mplist_free(mplistp);
6015				return (L_MALLOC_FAILED);
6016			}
6017			strncpy(mpl->devpath, mlist->logical_path,
6018			    strlen(mlist->logical_path));
6019			if (mplistp == NULL) {
6020				mplistp = mpln = mpl;
6021			} else {
6022				mpln->next = mpl;
6023				mpln = mpl;
6024			}
6025		}
6026	}
6027
6028	/* get mode page information for FC device */
6029	if (l_get_mode_pg(phys_path, &pg_buf, verbose) == 0) {
6030		mode_header_ptr = (struct mode_header_10_struct *)
6031					(void *)pg_buf;
6032		offset = sizeof (struct mode_header_10_struct) +
6033			mode_header_ptr->bdesc_length;
6034		pg_hdr = (struct mode_page *)&pg_buf[offset];
6035
6036		while (offset < (mode_header_ptr->length +
6037			sizeof (mode_header_ptr->length)) &&
6038						!mode_data_avail) {
6039			if (pg_hdr->code == MODEPAGE_CACHING) {
6040				mode_data_avail++;
6041				break;
6042			}
6043			offset += pg_hdr->length + sizeof (struct mode_page);
6044			pg_hdr = (struct mode_page *)&pg_buf[offset];
6045		}
6046	}
6047
6048	switch ((inq_struct.inq_dtype & DTYPE_MASK)) {
6049	case DTYPE_DIRECT:
6050	    fprintf(stdout, MSGSTR(121, "DEVICE PROPERTIES for disk: %s\n"),
6051		path_struct->argv);
6052	    break;
6053	case DTYPE_SEQUENTIAL: /* Tape */
6054	    fprintf(stdout, MSGSTR(2249, "DEVICE PROPERTIES for tape: %s\n"),
6055		path_struct->argv);
6056	    break;
6057	default:
6058	    fprintf(stdout, MSGSTR(2250, "DEVICE PROPERTIES for: %s\n"),
6059		path_struct->argv);
6060	    break;
6061	}
6062
6063	(void) display_lun_info(l_disk_state, path_struct, pg_hdr,
6064			mode_data_avail, wwn_list, phys_path);
6065
6066	(void) g_free_multipath(l_disk_state.g_disk_state.multipath_list);
6067
6068	if (!(argpwwn || argnwwn)) {
6069		break;
6070	}
6071
6072	} /* End for wwn_list_ptr = list_start... */
6073
6074	(void) g_free_wwn_list(&wwn_list);
6075	adm_mplist_free(mplistp);
6076	return (0);
6077}
6078
6079/*
6080 * display_lun_info() Prints the device specific information
6081 * for a lun.
6082 *
6083 * RETURNS:
6084 *	none.
6085 */
6086void
6087display_lun_info(L_disk_state l_disk_state, Path_struct *path_struct,
6088		struct mode_page *pg_hdr, int mode_data_avail, WWN_list
6089		*wwn_list, char *phys_path)
6090{
6091float		lunMbytes;
6092struct scsi_capacity_16 cap_data;
6093struct dlist	*mlist;
6094struct	my_mode_caching	*pg8_buf;
6095int		err;
6096L_inquiry	inq;
6097hrtime_t	start_time, end_time;
6098char		*envdb = NULL;
6099int		peripheral_qual;
6100L_inquiry80	inq80;
6101size_t		serial_len = sizeof (inq80.inq_serial);
6102
6103	if ((envdb = getenv("_LUX_T_DEBUG")) != NULL) {
6104		start_time = gethrtime();
6105	}
6106
6107	memset(&cap_data, 0, sizeof (cap_data));
6108
6109	if (err = g_get_inquiry(phys_path, &inq)) {
6110	    fprintf(stderr, "\n");
6111	    print_errString(err, phys_path);
6112	    fprintf(stderr, "\n");
6113	    exit(1);
6114	}
6115
6116	if (err = g_get_serial_number(phys_path, inq80.inq_serial,
6117	    &serial_len)) {
6118		fprintf(stderr, "\n");
6119		print_errString(err, phys_path);
6120		fprintf(stderr, "\n");
6121		exit(1);
6122	}
6123	/*
6124	 * check to see if the peripheral qualifier is zero
6125	 * if it is non-zero, we will return with an error.
6126	 */
6127	peripheral_qual = inq.inq_dtype & ~DTYPE_MASK;
6128	if (peripheral_qual != DPQ_POSSIBLE) {
6129		fprintf(stderr, MSGSTR(2254, "\n Error: Logical Unit "
6130			    "(%s) is not available.\n"), phys_path);
6131		exit(1);
6132	}
6133
6134	fprintf(stdout, "  ");
6135	fprintf(stdout, MSGSTR(3, "Vendor:"));
6136	fprintf(stdout, "\t\t");
6137	print_chars(inq.inq_vid, sizeof (inq.inq_vid), 0);
6138	fprintf(stdout, MSGSTR(2115, "\n  Product ID:\t\t"));
6139	print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0);
6140
6141	fprintf(stdout, "\n  ");
6142	fprintf(stdout, MSGSTR(2119, "Revision:"));
6143	fprintf(stdout, "\t\t");
6144	print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0);
6145
6146	fprintf(stdout, "\n  ");
6147	fprintf(stdout, MSGSTR(17, "Serial Num:"));
6148	fprintf(stdout, "\t\t");
6149	print_chars(inq80.inq_serial, serial_len, 0);
6150
6151	if ((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) {
6152		if ((err = get_lun_capacity(phys_path, &cap_data)) != 0) {
6153			print_errString(err, phys_path);
6154			exit(1);
6155		}
6156
6157		if (cap_data.sc_capacity > 0 && cap_data.sc_lbasize > 0) {
6158			lunMbytes = cap_data.sc_capacity + 1;
6159			lunMbytes *= cap_data.sc_lbasize;
6160			lunMbytes /= (float)(1024*1024);
6161			fprintf(stdout, "\n  ");
6162			fprintf(stdout, MSGSTR(60,
6163			"Unformatted capacity:\t%6.3f MBytes"), lunMbytes);
6164		}
6165	}
6166
6167	fprintf(stdout, "\n");
6168
6169	if ((mode_data_avail) && (pg_hdr->code == MODEPAGE_CACHING)) {
6170		pg8_buf = (struct my_mode_caching *)(void *)pg_hdr;
6171		if (pg8_buf->wce) {
6172			fprintf(stdout, MSGSTR(2122, "  Write Cache:\t\t"
6173				"Enabled\n"));
6174		}
6175		if (pg8_buf->rcd == 0) {
6176			fprintf(stdout, MSGSTR(2123, "  Read Cache:\t\t"
6177				"Enabled\n"));
6178			fprintf(stdout, MSGSTR(2124, "    Minimum prefetch:"
6179				"\t0x%x\n    Maximum prefetch:\t0x%x\n"),
6180				pg8_buf->min_prefetch,
6181				pg8_buf->max_prefetch);
6182		}
6183	}
6184
6185	fprintf(stdout, "  %s\t\t%s\n", MSGSTR(35, "Device Type:"),
6186			dtype[inq.inq_dtype & DTYPE_MASK]);
6187
6188
6189	fprintf(stdout, MSGSTR(2128, "  Path(s):\n"));
6190	fprintf(stdout, "\n");
6191
6192	if ((mlist = l_disk_state.g_disk_state.multipath_list) == NULL) {
6193		fprintf(stderr, MSGSTR(2323, "Error: No paths found (%s)"),
6194			path_struct->argv);
6195		exit(1);
6196	}
6197
6198
6199	if (strstr(mlist->dev_path, SCSI_VHCI) != NULL) {
6200		fprintf(stdout, "  %s\n  %s\n",
6201			mlist->logical_path, mlist->dev_path);
6202		adm_print_pathlist(mlist->dev_path);
6203	} else {
6204		/*
6205		 * first display user's requested path
6206		 * This will avoid duplicate inquiries as well
6207		 */
6208		for (mlist = l_disk_state.g_disk_state.multipath_list;
6209			mlist != NULL; mlist = mlist->next) {
6210		    if ((strcmp(mlist->dev_path, path_struct->p_physical_path))
6211				== 0) {
6212			display_path_info(mlist->dev_path, mlist->logical_path,
6213				wwn_list);
6214			break;
6215		    }
6216		}
6217
6218		/*
6219		 * Now display rest of paths
6220		 * skipping one already displayed
6221		 */
6222		for (mlist = l_disk_state.g_disk_state.multipath_list;
6223			mlist != NULL; mlist = mlist->next) {
6224		    if ((strcmp(mlist->dev_path, path_struct->p_physical_path))
6225				== 0) {
6226			continue;
6227		    }
6228		    if (err = g_get_inquiry(mlist->dev_path, &inq)) {
6229			fprintf(stderr, "\n");
6230			print_errString(err, mlist->dev_path);
6231			fprintf(stderr, "\n");
6232			exit(1);
6233		    }
6234		    display_path_info(mlist->dev_path, mlist->logical_path,
6235				wwn_list);
6236		}
6237	}
6238	fprintf(stdout, "\n");
6239
6240	if (envdb != NULL) {
6241		end_time = gethrtime();
6242		fprintf(stdout, "      display_lun_info: "
6243		"\t\tTime = %lld millisec\n",
6244		(end_time - start_time)/1000000);
6245	}
6246}
6247
6248/*
6249 * display_path_info() Prints the path specific information
6250 * for a lun.
6251 * Note: Only applies to ssd nodes currently
6252 *
6253 * RETURNS:
6254 *	none.
6255 */
6256static void
6257display_path_info(char *devpath, char *logicalpath, WWN_list *wwn_list)
6258{
6259WWN_list	*wwn_list_walk;
6260int		err;
6261uchar_t		wwn_data[WWN_SIZE];
6262char		wwns[(WWN_SIZE *2) +1];
6263char		drvr_path[MAXPATHLEN];
6264char		*cptr;
6265int		status;
6266
6267	fprintf(stdout, "  %s\n", logicalpath);
6268	fprintf(stdout, "  %s\n", devpath);
6269	fprintf(stdout, "    %s\t\t", MSGSTR(2321, "LUN path port WWN:"));
6270
6271	/*
6272	 * Walk the wwn list passed in and print the
6273	 * port wwn matching the device path
6274	 */
6275	for (wwn_list_walk = wwn_list; wwn_list_walk != NULL;
6276		wwn_list_walk = wwn_list_walk->wwn_next) {
6277		if (strcmp(wwn_list_walk->physical_path, devpath) == 0) {
6278			fprintf(stdout, "%s", wwn_list_walk->port_wwn_s);
6279			break;
6280		}
6281	}
6282	/*
6283	 * newline here in case port wwn not found
6284	 */
6285	fprintf(stdout, "\n");
6286
6287	drvr_path[0] = '\0';
6288	(void) strcat(drvr_path, devpath);
6289	if (((cptr = strstr(drvr_path, SLSH_DRV_NAME_SSD)) != NULL) ||
6290		((cptr = strstr(drvr_path, SLSH_DRV_NAME_ST)) != NULL)) {;
6291		*cptr = '\0';
6292	} else {
6293		fprintf(stderr, MSGSTR(2324, "Error: Incorrect path (%s)\n"),
6294				drvr_path);
6295		exit(1);
6296	}
6297	*cptr = '\0';
6298
6299	if ((err =