xref: /titanic_52/usr/src/cmd/luxadm/g_adm.c (revision b9e93c10c0a2a4bb069d38bb311021a9478c4711)
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 
61 extern char		*dtype[];
62 extern char		*whoami;
63 extern	int	Options;
64 extern	const	int OPTION_A;
65 extern	const	int OPTION_B;
66 extern	const	int OPTION_C;
67 extern	const	int OPTION_D;
68 extern	const	int OPTION_E;
69 extern	const	int OPTION_F;
70 extern	const	int OPTION_L;
71 extern	const	int OPTION_P;
72 extern	const	int OPTION_R;
73 extern	const	int OPTION_T;
74 extern	const	int OPTION_V;
75 extern	const	int OPTION_Z;
76 extern	const	int OPTION_Y;
77 extern	const	int OPTION_CAPF;
78 extern	const	int PVERBOSE;
79 extern	const	int SAVE;
80 extern	const	int EXPERT;
81 
82 static		struct termios	termios;
83 static		int termio_fd;
84 static	void	pho_display_config(char *);
85 static	void	dpm_display_config(char *);
86 static	void	n_rem_list_entry(uchar_t,  struct gfc_map *,
87 		WWN_list **);
88 static	void	n_rem_list_entry_fabric(int, struct gfc_map *,
89 		WWN_list **);
90 static	void	n_rem_wwn_entry(uchar_t *, WWN_list **);
91 static	void	display_disk_info(L_inquiry, L_disk_state,
92 		Path_struct *, struct mode_page *, int, char *, int);
93 static	void	display_lun_info(L_disk_state, Path_struct *,
94 		struct mode_page *, int, WWN_list *, char *);
95 static	void	display_fc_disk(struct path_struct *, char *, gfc_map_t *,
96 		L_inquiry, int);
97 static 	void	adm_display_err(char *, int);
98 static	void	temperature_messages(struct l_state_struct *, int);
99 static	void	ctlr_messages(struct l_state_struct *, int, int);
100 static	void	fan_messages(struct l_state_struct *, int, int);
101 static	void	ps_messages(struct l_state_struct *, int, int);
102 static	void	abnormal_condition_display(struct l_state_struct *);
103 static	void	loop_messages(struct l_state_struct *, int, int);
104 static	void	revision_msg(struct l_state_struct *, int);
105 static	void	mb_messages(struct l_state_struct *, int, int);
106 static	void	back_plane_messages(struct l_state_struct *, int, int);
107 static	void	dpm_SSC100_messages(struct l_state_struct *, int, int);
108 static	void	mb_messages(struct l_state_struct *, int, int);
109 static	void	back_plane_messages(struct l_state_struct *, int, int);
110 static	void	dpm_SSC100_messages(struct l_state_struct *, int, int);
111 static	void	trans_decode(Trans_elem_st *trans);
112 static	void	trans_messages(struct l_state_struct *, int);
113 static	void	adm_print_pathlist(char *);
114 static	void	display_path_info(char *, char *, WWN_list *);
115 static void	copy_wwn_data_to_str(char *, const uchar_t *);
116 static void	adm_mplist_free(struct mplist_struct *);
117 static int	lun_display(Path_struct *path_struct, L_inquiry inq_struct,
118 		int verbose);
119 static int	non_encl_fc_disk_display(Path_struct *path_struct,
120 		L_inquiry inq_struct, int verbose);
121 static int	get_enclStatus(char *phys_path, char *encl_name, int off_flag);
122 static int	get_host_controller_pwwn(char *hba_path, uchar_t *pwwn);
123 static int	get_lun_capacity(char *devpath,
124 		struct scsi_capacity_16 *cap_data);
125 static int	get_path_status(char *devpath, int *status);
126 static 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  */
138 int
139 print_devState(char *devname, char *ppath, int fr_flag, int slot,
140 						int verbose_flag)
141 {
142 L_state		l_state;
143 int		err;
144 int		i, elem_index = 0;
145 uchar_t		device_off, ib_status_code, bypass_a_en, bypass_b_en;
146 Bp_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  */
233 void
234 print_errString(int errnum, char *devpath)
235 {
236 
237 char	*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  */
261 int
262 adm_inquiry(char **argv)
263 {
264 L_inquiry	inq;
265 L_inquiry80	inq80;
266 size_t		serial_len;
267 int		path_index = 0, retval = 0;
268 int		slot, f_r, err = 0, argpwwn, argnwwn;
269 char		inq_path[MAXNAMELEN];
270 char		*path_phys = NULL, *ptr;
271 Path_struct	*path_struct;
272 WWN_list	*wwn_list, *wwn_list_ptr, *list_start;
273 char		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 = NULL;
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  */
464 int
465 adm_forcelip(char **argv)
466 {
467 int		slot, f_r, path_index = 0, err = 0, retval = 0;
468 Path_struct	*path_struct = NULL;
469 char		*path_phys = NULL, *ptr;
470 char		 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 = NULL;
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  */
544 int
545 adm_display_config(char **argv)
546 {
547 L_inquiry	inq, ses_inq;
548 int		i, slot, f_r, path_index = 0, err = 0, opnerr = 0;
549 int		retval = 0;
550 gfc_map_t	map;
551 Path_struct	*path_struct;
552 char		*path_phys = NULL, *ptr;
553 char		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 = NULL;
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  */
792 int
793 adm_power_off(char **argv, int off_flag)
794 {
795 int		path_index = 0, err = 0, retval = 0;
796 L_inquiry	inq;
797 char		*path_phys = NULL;
798 Path_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 
894 void
895 adm_bypass_enable(char **argv, int bypass_flag)
896 {
897 int		path_index = 0, err = 0;
898 L_inquiry	inq;
899 char		*path_phys = NULL;
900 Path_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  */
992 void
993 adm_download(char **argv, char *file_name)
994 {
995 int		path_index = 0, err = 0;
996 char		*path_phys = NULL;
997 L_inquiry	inq;
998 Path_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  */
1048 void
1049 display_link_status(char **argv)
1050 {
1051 AL_rls		*rls = NULL, *n;
1052 int		path_index = 0, err = 0;
1053 char		*path_phys = NULL;
1054 Path_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  */
1132 int
1133 ib_present_chk(struct l_state_struct *l_state, int which_one)
1134 {
1135 Ctlr_elem_st	ctlr;
1136 int	i;
1137 int	elem_index = 0;
1138 int	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  */
1162 void
1163 print_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  */
1220 void
1221 display_disk_msg(struct l_disk_state_struct *dsk_ptr,
1222 	struct l_state_struct *l_state, Bp_elem_st *bp, int front_flag)
1223 {
1224 int	loop_flag = 0;
1225 int	a_and_b = 0;
1226 int	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  */
1392 void
1393 pho_display_config(char *path_phys)
1394 {
1395 L_state		l_state;
1396 Bp_elem_st	bpf, bpr;
1397 int		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  */
1524 void
1525 dpm_display_config(char *path_phys)
1526 {
1527 L_state		l_state;
1528 Bp_elem_st	bpf, bpr;
1529 int		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  */
1668 void
1669 intfix(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  */
1685 void
1686 up_password(char **argv)
1687 {
1688 int		path_index = 0, err = 0;
1689 char		password[1024];
1690 char		input[1024];
1691 int		i, j, matched, equal;
1692 L_inquiry	inq;
1693 void		(*sig)();
1694 char		*path_phys = NULL;
1695 Path_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  */
1814 void
1815 adm_failover(char **argv)
1816 {
1817 int		path_index = 0, err = 0;
1818 char		pathclass[20];
1819 char		*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  */
1854 void
1855 up_encl_name(char **argv, int argc)
1856 {
1857 int		i, rval, al_pa, path_index = 0, err = 0;
1858 L_inquiry	inq;
1859 Box_list	*b_list = NULL;
1860 uchar_t		node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
1861 char		wwn1[(WWN_SIZE*2)+1], name[1024], *path_phys = NULL;
1862 Path_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 
1973 static int
1974 get_enclStatus(char *phys_path, char *encl_name, int off_flag)
1975 {
1976 int	found_pwrOnDrv = 0, slot;
1977 int	found_pwrOffDrv = 0, err = 0;
1978 L_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  */
2047 void
2048 adm_led(char **argv, int led_action)
2049 {
2050 int		path_index = 0, err = 0;
2051 gfc_map_t	map;
2052 L_inquiry	inq;
2053 Dev_elem_st	status;
2054 char		*path_phys = NULL;
2055 Path_struct	*path_struct;
2056 int		enc_t = 0;		/* enclosure type */
2057 char		ses_path[MAXPATHLEN];
2058 L_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  */
2226 void
2227 dump(char **argv)
2228 {
2229 uchar_t		*buf;
2230 int		path_index = 0, err = 0;
2231 L_inquiry	inq;
2232 char		hdr_buf[MAXNAMELEN];
2233 Rec_diag_hdr	*hdr, *hdr_ptr;
2234 char		*path_phys = NULL;
2235 Path_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  */
2303 void
2304 display_socal_stats(int port, char *socal_path, struct socal_stats *fc_stats)
2305 {
2306 int		i;
2307 int		header_flag = 0;
2308 char		status_msg_buf[MAXNAMELEN];
2309 int		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 != NULL) &&
2321 			(*fc_stats->port_wwn[port] != NULL)) {
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 != NULL) {
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  */
2396 void
2397 display_sf_stats(char *path_phys, int dtype, struct sf_stats *sf_stats)
2398 {
2399 int		i, al_pa, err = 0;
2400 gfc_map_t	map;
2401 uchar_t		node_wwn[WWN_SIZE];
2402 uchar_t		port_wwn[WWN_SIZE];
2403 gfc_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  */
2499 static void
2500 adm_display_err(char *path_phys, int dtype)
2501 {
2502 int		i, drvr_inst, sf_inst, socal_inst, port, al_pa, err = 0;
2503 char		*char_ptr, socal_path[MAXPATHLEN], drvr_path[MAXPATHLEN];
2504 struct		stat sbuf;
2505 kstat_ctl_t	*kc;
2506 kstat_t		*ifp_ks, *sf_ks, *fc_ks;
2507 sf_stats_t	sf_stats;
2508 socal_stats_t	fc_stats;
2509 ifp_stats_t	ifp_stats;
2510 int		header_flag = 0, pathcnt = 1;
2511 char		status_msg_buf[MAXNAMELEN];
2512 gfc_map_t	map;
2513 uchar_t		node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
2514 uint_t		path_type;
2515 gfc_port_dev_info_t	*dev_addr_list;
2516 mp_pathlist_t	pathlist;
2517 int		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 != NULL) &&
2617 				(*ifp_stats.port_wwn != NULL)) {
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 != NULL) {
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  */
2793 void
2794 adm_display_verbose_disk(char *path, int verbose)
2795 {
2796 uchar_t		*pg_buf;
2797 Mode_header_10	*mode_header_ptr;
2798 Mp_01		*pg1_buf;
2799 Mp_04		*pg4_buf;
2800 struct mode_page *pg_hdr;
2801 int		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  */
2872 void
2873 print_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  */
2885 void
2886 print_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  */
2898 void
2899 print_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  */
2915 void
2916 dump_map(char **argv)
2917 {
2918 int		i = 0, path_index = 0, pathcnt = 1;
2919 int		limited_map_flag = 0, err = 0;
2920 char		*path_phys = NULL;
2921 Path_struct	*path_struct;
2922 struct lilpmap	limited_map;
2923 uint_t		dev_type;
2924 char		temp2path[MAXPATHLEN];
2925 mp_pathlist_t	pathlist;
2926 int		p_pw = 0, p_on = 0, p_st = 0;
2927 gfc_dev_t	map_root, map_dev;
2928 int 		*port_addr, *hard_addr, pos = 0, count;
2929 uchar_t		*hba_port_wwn, *port_wwn, *node_wwn, *dtype_prop;
2930 uint_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  */
3190 int
3191 n_get_non_encl_list(WWN_list **wwn_list_ptr, int verbose)
3192 {
3193 int		i, j, k, err, found_ib = 0, pathcnt = 1;
3194 WWN_list	*wwn_list;
3195 Box_list	*b_list = NULL;
3196 gfc_map_t	map;
3197 uchar_t		box_id;
3198 gfc_port_dev_info_t	*dev_addr_list;
3199 char		phci_path[MAXPATHLEN], oldphci_path[MAXPATHLEN];
3200 mp_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  */
3343 void
3344 n_rem_list_entry(uchar_t box_id,  struct gfc_map *map,
3345 	struct	wwn_list_struct **wwn_list)
3346 {
3347 int		k;
3348 gfc_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  */
3378 void
3379 n_rem_list_entry_fabric(int pa,  struct gfc_map *map,
3380 	struct	wwn_list_struct **wwn_list)
3381 {
3382 int		k;
3383 gfc_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  */
3412 void
3413 n_rem_wwn_entry(uchar_t node_wwn[], struct  wwn_list_struct **wwn_list)
3414 {
3415 int		l, found_dev;
3416 WWN_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  */
3477 void
3478 non_encl_probe()
3479 {
3480 WWN_list	*wwn_list, *wwn_listh, *inner, *l1;
3481 int		err = 0;
3482 char		lun_a[MAXPATHLEN], lun_b[MAXPATHLEN], temppath[MAXPATHLEN];
3483 char		*tempptra, *tempptrb, *tempptr;
3484 mp_pathlist_t	pathlist;
3485 int		compare_result, retr_outer = 0;
3486 ddi_devid_t	devid1 = NULL, devid2 = NULL;
3487 di_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 
3697 void
3698 pho_probe()
3699 {
3700 
3701 Box_list	*b_list, *o_list, *c_list;
3702 int		multi_path_flag, multi_print_flag;
3703 int		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  */
3818 void
3819 display_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  */
3852 void
3853 display_fc_disk(struct path_struct *path_struct, char *ses_path,
3854 	gfc_map_t *map, L_inquiry inq, int verbose)
3855 {
3856 static WWN_list		*wwn_list = NULL;
3857 static char		path_phys[MAXPATHLEN];
3858 static L_disk_state	l_disk_state;
3859 static L_inquiry	local_inq;
3860 static uchar_t		node_wwn[WWN_SIZE];
3861 char			same_path_phys = B_FALSE; /* To chk for repeat args */
3862 uchar_t			port_wwn[WWN_SIZE], *pg_buf;
3863 char			logical_path[MAXPATHLEN];
3864 int			al_pa, port_a_flag = 0;
3865 int			offset, mode_data_avail = 0;
3866 int			no_path_flag = 0, err = 0;
3867 L_state			l_state;
3868 Mode_header_10		*mode_header_ptr = NULL;
3869 struct 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 != NULL) {
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  */
4094 static int
4095 non_encl_fc_disk_display(Path_struct *path_struct,
4096 				L_inquiry inq_struct, int verbose)
4097 {
4098 
4099 char			phys_path[MAXPATHLEN];
4100 uchar_t			node_wwn[WWN_SIZE], port_wwn[WWN_SIZE], *pg_buf = NULL;
4101 L_disk_state		l_disk_state;
4102 struct dlist		*mlist;
4103 int			i = 0, al_pa, offset, mode_data_avail = 0, err = 0;
4104 int			path_a_found = 0, path_b_found = 0, argpwwn = 0,
4105 			argnwwn = 0, pathcnt = 1;
4106 L_inquiry		local_inq;
4107 Mode_header_10		*mode_header_ptr;
4108 struct mode_page	*pg_hdr;
4109 WWN_list		*wwn_list, *wwn_list_ptr, *list_start;
4110 char			temppath[MAXPATHLEN], last_logical_path[MAXPATHLEN];
4111 mp_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  */
4358 void
4359 display_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 {
4363 float		num_blks;
4364 struct dlist	*mlist;
4365 int		port_a, port_b;
4366 struct	my_mode_caching	*pg8_buf;
4367 L_inquiry	enc_inq;
4368 char		*enc_phys_path;
4369 Path_struct	*enc_path_struct;
4370 int		enc_type = 0;
4371 L_inquiry80	inq80;
4372 size_t		serial_len;
4373 int		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  */
4560 void
4561 temp_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  */
4589 void
4590 disp_degree(Temp_elem_st *temp)
4591 {
4592 int	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  */
4611 void
4612 trans_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  */
4642 void
4643 trans_messages(struct l_state_struct *l_state, int ib_a_flag)
4644 {
4645 Trans_elem_st	trans;
4646 int	i, j, k;
4647 int	count = 0;
4648 int	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  */
4719 void
4720 temperature_messages(struct l_state_struct *l_state, int rear_flag)
4721 {
4722 Temp_elem_st	temp;
4723 int	i, j, last_ok = 0;
4724 int	all_ok = 1;
4725 int	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  */
4822 void
4823 ib_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  */
4848 void
4849 mb_messages(struct l_state_struct *l_state, int index, int elem_index)
4850 {
4851 int		j;
4852 Interconnect_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 != NULL) {
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 != NULL) {
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  */
4913 void
4914 back_plane_messages(struct l_state_struct *l_state, int index, int elem_index)
4915 {
4916 Bp_elem_st	bp;
4917 int		j;
4918 char		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  */
4975 void
4976 dpm_SSC100_messages(struct l_state_struct *l_state, int index, int elem_index)
4977 {
4978 Bp_elem_st	bp;
4979 int		j;
4980 char		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  */
5032 void
5033 loop_messages(struct l_state_struct *l_state, int index, int elem_index)
5034 {
5035 Loop_elem_st	loop;
5036 int		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  */
5088 void
5089 ctlr_messages(struct l_state_struct *l_state, int index, int elem_index)
5090 {
5091 Ctlr_elem_st	ctlr;
5092 int		j;
5093 int		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  */
5155 void
5156 fan_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  */
5180 void
5181 fan_messages(struct l_state_struct *l_state, int hdr_index, int elem_index)
5182 {
5183 Fan_elem_st	fan;
5184 int	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  */
5233 void
5234 ps_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  */
5270 void
5271 revision_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  */
5288 void
5289 ps_messages(struct l_state_struct *l_state, int	index, int elem_index)
5290 {
5291 Ps_elem_st	ps;
5292 int	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  */
5344 void
5345 abnormal_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  */
5383 int
5384 adm_start(char **argv)
5385 {
5386 char		*path_phys = NULL;
5387 Path_struct	*path_struct;
5388 int		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  */
5426 int
5427 adm_stop(char **argv)
5428 {
5429 char		*path_phys = NULL;
5430 Path_struct	*path_struct;
5431 int		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  */
5494 int
5495 adm_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 		}
5552 cleanup_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  */
5587 int
5588 adm_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  */
5659 int
5660 adm_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  */
5747 void
5748 adm_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  */
5833 int
5834 compare_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  */
5853 static int
5854 lun_display(Path_struct *path_struct, L_inquiry inq_struct, int verbose)
5855 {
5856 
5857 char			phys_path[MAXPATHLEN], last_logical_path[MAXPATHLEN];
5858 uchar_t			*pg_buf = NULL;
5859 L_disk_state		l_disk_state;
5860 struct dlist		*mlist;
5861 int			offset, mode_data_avail, err = 0;
5862 Mode_header_10		*mode_header_ptr;
5863 struct mode_page	*pg_hdr;
5864 WWN_list		*wwn_list, *list_start, *wwn_list_ptr;
5865 WWN_list		*wwn_list_find;
5866 int			found = 0;
5867 int			argpwwn = 0, argnwwn = 0;
5868 struct mplist_struct	*mplistp, *mpl, *mpln;
5869 struct 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  */
6086 void
6087 display_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 {
6091 float		lunMbytes;
6092 struct scsi_capacity_16 cap_data;
6093 struct dlist	*mlist;
6094 struct	my_mode_caching	*pg8_buf;
6095 int		err;
6096 L_inquiry	inq;
6097 hrtime_t	start_time, end_time;
6098 char		*envdb = NULL;
6099 int		peripheral_qual;
6100 L_inquiry80	inq80;
6101 size_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  */
6256 static void
6257 display_path_info(char *devpath, char *logicalpath, WWN_list *wwn_list)
6258 {
6259 WWN_list	*wwn_list_walk;
6260 int		err;
6261 uchar_t		wwn_data[WWN_SIZE];
6262 char		wwns[(WWN_SIZE *2) +1];
6263 char		drvr_path[MAXPATHLEN];
6264 char		*cptr;
6265 int		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 = get_host_controller_pwwn(drvr_path,
6300 			(uchar_t *)&wwn_data)) != 0) {
6301 		print_errString(err, drvr_path);
6302 		exit(1);
6303 	}
6304 
6305 	copy_wwn_data_to_str(wwns, wwn_data);
6306 	fprintf(stdout, "    %s\t%s\n",
6307 		MSGSTR(2322, "Host controller port WWN:"), wwns);
6308 
6309 	/*
6310 	 * Determine path status
6311 	 */
6312 	if ((err = get_path_status(devpath, &status)) != 0) {
6313 		print_errString(err, devpath);
6314 		exit(1);
6315 	} else {
6316 		fprintf(stdout, "    %s\t\t", MSGSTR(2329, "Path status:"));
6317 		display_port_status(status);
6318 	}
6319 }
6320 
6321 /*
6322  * Retrieves the lun capacity
6323  */
6324 static int
6325 get_lun_capacity(char *devpath, struct scsi_capacity_16 *cap_data)
6326 {
6327 int	fd;
6328 
6329 	if (devpath == NULL || cap_data == NULL) {
6330 		return (L_INVALID_PATH);
6331 	}
6332 
6333 	if ((fd = g_object_open(devpath, O_RDONLY | O_NDELAY)) == -1) {
6334 		return (L_OPEN_PATH_FAIL);
6335 	} else {
6336 		(void) g_scsi_read_capacity_1016_cmd(fd, cap_data,
6337 			sizeof (struct scsi_capacity_16));
6338 		close(fd);
6339 	}
6340 	return (0);
6341 }
6342 
6343 /*
6344  * Retrieves the reservation status
6345  */
6346 static int
6347 get_path_status(char *devpath, int *status)
6348 {
6349 int	fd, mystatus = 0;
6350 
6351 
6352 	if (devpath == NULL || status == NULL) {
6353 		return (L_INVALID_PATH);
6354 	}
6355 
6356 	*status = 0;
6357 	if ((fd = g_object_open(devpath, O_RDONLY | O_NDELAY)) == -1) {
6358 		return (L_OPEN_PATH_FAIL);
6359 	} else {
6360 		if ((mystatus = g_scsi_tur(fd)) != 0) {
6361 			if ((mystatus & L_SCSI_ERROR) &&
6362 				((mystatus & ~L_SCSI_ERROR) == STATUS_CHECK)) {
6363 				*status = L_NOT_READY;
6364 			} else if ((mystatus & L_SCSI_ERROR) &&
6365 				((mystatus & ~L_SCSI_ERROR) ==
6366 					STATUS_RESERVATION_CONFLICT)) {
6367 				*status = L_RESERVED;
6368 			} else {
6369 				*status = L_SCSI_ERR;
6370 			}
6371 		}
6372 	}
6373 	close(fd);
6374 	return (0);
6375 }
6376 
6377 /*
6378  * Description:
6379  *	Retrieves the port wwn associated with the hba node
6380  *
6381  * hba_path: /devices/pci@8,600000/SUNW,qlc@4/fp@0,0
6382  * pwwn: ptr to a uchar_t array of size WWN_SIZE
6383  */
6384 static int
6385 get_host_controller_pwwn(char *hba_path, uchar_t *pwwn)
6386 {
6387 char *cptr, *portptr;
6388 int found = 0, err, devlen;
6389 char my_hba_path[MAXPATHLEN];
6390 di_node_t node;
6391 di_prom_prop_t promprop;
6392 uchar_t *port_wwn_data = NULL;
6393 int di_ret;
6394 di_prom_handle_t ph;
6395 char *promname;
6396 uchar_t *promdata;
6397 uint_t path_type;
6398 fc_port_dev_t hba_port;
6399 
6400 	if (hba_path == NULL || pwwn == NULL) {
6401 		return (L_INVALID_PATH);
6402 	}
6403 
6404 	if ((path_type = g_get_path_type(hba_path)) == 0) {
6405 		return (L_INVALID_PATH);
6406 	}
6407 
6408 	/*
6409 	 * ifp nodes do not have a port-wwn prom property
6410 	 * so handle them via FC4 device map
6411 	 */
6412 	if (path_type & FC4_XPORT_MASK) {
6413 		if ((err = get_FC4_host_controller_pwwn(hba_path, pwwn)) != 0) {
6414 			return (err);
6415 		} else {
6416 			return (0);
6417 		}
6418 	/* For Leadville path get the port wwn through g_get_host param. */
6419 	} else if ((path_type & FC_GEN_XPORT) &&
6420 		((path_type & FC_FCA_MASK) == FC_FCA_MASK)) {
6421 		/*
6422 		 * For Leadville path, get the port wwn through
6423 		 * g_get_host param. This is a general solution
6424 		 * to support 3rd party vendor Leadville FCA.
6425 		 */
6426 		my_hba_path[0] = '\0';
6427 		(void) strlcat(my_hba_path, hba_path, sizeof (my_hba_path));
6428 		(void) snprintf(my_hba_path, sizeof (my_hba_path), "%s%s",
6429 			hba_path, FC_CTLR);
6430 		if ((err = g_get_host_params(
6431 			my_hba_path, &hba_port, 0)) != 0) {
6432 			return (err);
6433 		} else {
6434 			(void) memcpy(pwwn, &hba_port.dev_pwwn.raw_wwn[0],
6435 			    WWN_SIZE);
6436 			return (0);
6437 		}
6438 	} else if ((path_type & FC_FCA_MASK) == FC_PCI_FCA) {
6439 		/*
6440 		 * Get port WWN through prom property
6441 		 */
6442 		my_hba_path[0] = '\0';
6443 		(void) strlcat(my_hba_path, hba_path, sizeof (my_hba_path));
6444 		/*
6445 		 * sanity check for /devices mount point
6446 		 */
6447 		if (strlen(my_hba_path) > (devlen = strlen("/devices"))) {
6448 			cptr = &my_hba_path[devlen];
6449 		} else {
6450 			return (L_INVALID_PATH);
6451 		}
6452 
6453 		/*
6454 		 * Now strip off the trailing "/fp@"
6455 		 */
6456 		if ((portptr = strstr(cptr, "/fp@")) != NULL) {
6457 			*portptr = '\0';
6458 		}
6459 
6460 		if ((node = di_init(cptr, DINFOCPYALL)) == DI_NODE_NIL) {
6461 			return (L_DEV_SNAPSHOT_FAILED);
6462 		}
6463 
6464 		if (di_nodeid(node) == DI_SID_NODEID) {
6465 			di_ret = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
6466 				"port-wwn", &port_wwn_data);
6467 			if (di_ret == -1 || port_wwn_data == NULL) {
6468 				di_fini(node);
6469 				return (L_NO_WWN_PROP_FOUND);
6470 			} else {
6471 				(void) memcpy(pwwn, port_wwn_data, WWN_SIZE);
6472 				found++;
6473 			}
6474 		} else if (di_nodeid(node) == DI_PROM_NODEID) {
6475 		    if ((ph = di_prom_init()) == DI_PROM_HANDLE_NIL) {
6476 			di_fini(node);
6477 			return (L_PROM_INIT_FAILED);
6478 		    }
6479 
6480 		    for (promprop = di_prom_prop_next(ph, node,
6481 			DI_PROM_PROP_NIL);
6482 			promprop != DI_PROM_PROP_NIL;
6483 			promprop = di_prom_prop_next(ph, node, promprop)) {
6484 			if (((promname = di_prom_prop_name(
6485 				promprop)) != NULL) &&
6486 				(strcmp(promname, "port-wwn") == 0) &&
6487 				(di_prom_prop_data(promprop,
6488 					&promdata) == WWN_SIZE)) {
6489 				/* Found port-wwn */
6490 				(void) memcpy(pwwn, promdata, WWN_SIZE);
6491 				found++;
6492 				break;
6493 			}
6494 		    }
6495 		    di_prom_fini(ph);
6496 		}
6497 
6498 		di_fini(node);
6499 		if (found) {
6500 			return (0);
6501 		} else {
6502 			return (L_INVALID_PATH);
6503 		}
6504 	} else {
6505 		return (L_INVALID_PATH_TYPE);
6506 	}
6507 }
6508 
6509 
6510 /*
6511  * Description:
6512  *    Retrieve pwwn via SFIOCGMAP
6513  */
6514 static int
6515 get_FC4_host_controller_pwwn(char *hba_path, uchar_t *pwwn)
6516 {
6517 sf_al_map_t sf_map;
6518 char my_hba_path[MAXPATHLEN];
6519 int fd;
6520 
6521 	if (hba_path == NULL || pwwn == NULL) {
6522 		return (L_INVALID_PATH);
6523 	}
6524 
6525 	(void) snprintf(my_hba_path, sizeof (my_hba_path), "%s%s",
6526 			hba_path, FC_CTLR);
6527 
6528 	if ((fd = g_object_open(my_hba_path, O_NDELAY | O_RDONLY)) == -1) {
6529 		return (errno);
6530 	}
6531 
6532 	memset(&sf_map, 0, sizeof (sf_al_map_t));
6533 
6534 	if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) {
6535 		close(fd);
6536 		return (L_SFIOCGMAP_IOCTL_FAIL);
6537 	}
6538 
6539 	close(fd);
6540 
6541 	if (sf_map.sf_count == 0) {
6542 		close(fd);
6543 		return (L_SFIOCGMAP_IOCTL_FAIL);
6544 	}
6545 
6546 	(void) memcpy(pwwn, &sf_map.sf_hba_addr.sf_port_wwn[0], WWN_SIZE);
6547 
6548 	return (0);
6549 }
6550 
6551 /*
6552  * from_ptr: ptr to uchar_t array of size WWN_SIZE
6553  * to_ptr: char ptr to string of size WWN_SIZE*2+1
6554  */
6555 void
6556 copy_wwn_data_to_str(char *to_ptr, const uchar_t *from_ptr)
6557 {
6558 	if ((to_ptr == NULL) || (from_ptr == NULL))
6559 		return;
6560 
6561 	sprintf(to_ptr, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
6562 	from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3],
6563 	from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]);
6564 }
6565 
6566 /*
6567  * Frees a previously allocated mplist_struct
6568  */
6569 void
6570 adm_mplist_free(struct mplist_struct *mplistp)
6571 {
6572 struct mplist_struct *mplistn;
6573 
6574 	while (mplistp != NULL) {
6575 		mplistn = mplistp->next;
6576 		if (mplistp->devpath != NULL) {
6577 			free(mplistp->devpath);
6578 			mplistp->devpath = NULL;
6579 		}
6580 		free(mplistp);
6581 		mplistp = mplistn;
6582 	}
6583 }
6584 
6585 int
6586 adm_reserve(char *path)
6587 {
6588 	char	*path_phys = NULL;
6589 	int	err;
6590 	if ((path_phys =
6591 		    g_get_physical_name(path)) == NULL) {
6592 
6593 		(void) fprintf(stderr, "%s: ", whoami);
6594 		(void) fprintf(stderr,
6595 			MSGSTR(112, "Error: Invalid pathname (%s)"),
6596 			path);
6597 		(void) fprintf(stderr, "\n");
6598 		return (1);
6599 	}
6600 
6601 	if ((err = g_reserve(path_phys)) != 0) {
6602 	    (void) print_errString(err, path);
6603 	    return (1);
6604 	}
6605 	return (0);
6606 }
6607 
6608 int
6609 adm_release(char *path)
6610 {
6611 	char	*path_phys = NULL;
6612 	int	err;
6613 	if ((path_phys =
6614 		    g_get_physical_name(path)) == NULL) {
6615 
6616 		(void) fprintf(stderr, "%s: ", whoami);
6617 		(void) fprintf(stderr,
6618 			MSGSTR(112, "Error: Invalid pathname (%s)"),
6619 			path);
6620 		(void) fprintf(stderr, "\n");
6621 		return (1);
6622 	}
6623 
6624 	if ((err = g_release(path_phys)) != 0) {
6625 	    (void) print_errString(err, path);
6626 	    return (1);
6627 	}
6628 	return (0);
6629 }
6630 
6631 void
6632 i18n_catopen() {
6633     (void) g_i18n_catopen();
6634 }
6635 
6636 int adm_check_file(char **path, int flag) {
6637 	int err;
6638 	if (err = l_check_file(*path, flag)) {
6639 	    (void) print_errString(err, *path);
6640 	    return (-1);
6641 	}
6642 
6643 	(void) fprintf(stdout, MSGSTR(2212, "Download file O.K. \n\n"));
6644 	return (0);
6645 }
6646 
6647 /*
6648  * Print out private loop dev dtype
6649  */
6650 void
6651 print_private_loop_dtype_prop(uchar_t *hba_port_wwn, uchar_t *port_wwn,
6652 	uchar_t dtype_prop)
6653 {
6654 	if ((dtype_prop & DTYPE_MASK) < 0x10) {
6655 		(void) fprintf(stdout, " 0x%-2x (%s",
6656 		(dtype_prop & DTYPE_MASK), dtype[(dtype_prop & DTYPE_MASK)]);
6657 	} else if ((dtype_prop & DTYPE_MASK) < 0x1f) {
6658 		(void) fprintf(stdout,
6659 		MSGSTR(2243, " 0x%-2x (Reserved"),
6660 		(dtype_prop & DTYPE_MASK));
6661 	} else {
6662 		(void) fprintf(stdout, MSGSTR(2245,
6663 		" 0x%-2x (Unknown Type"), (dtype_prop & DTYPE_MASK));
6664 	}
6665 	/* Check to see if this is the HBA */
6666 	if (wwnConversion(hba_port_wwn) == wwnConversion(port_wwn)) {
6667 		/* MATCH */
6668 		(void) fprintf(stdout, MSGSTR(2244,
6669 		",Host Bus Adapter)\n"));
6670 	} else {
6671 		(void) fprintf(stdout, ")\n");
6672 	}
6673 }
6674