xref: /titanic_44/usr/src/lib/storage/liba5k/common/mon.c (revision 49b225e1cfa7bbf7738d4df0a03f18e3283426eb)
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 /*LINTLIBRARY*/
28 
29 /*
30  * I18N message number ranges
31  *  This file: 9000 - 9499
32  *  Shared common messages: 1 - 1999
33  */
34 
35 /*
36  *	This module is part of the photon library
37  */
38 /*	Includes	*/
39 #include	<stdlib.h>
40 #include	<stdio.h>
41 #include	<sys/file.h>
42 #include	<sys/types.h>
43 #include	<sys/stat.h>
44 #include	<sys/param.h>
45 #include	<fcntl.h>
46 #include	<unistd.h>
47 #include	<errno.h>
48 #include	<string.h>
49 #include	<assert.h>
50 #include	<sys/scsi/scsi.h>
51 #include	<dirent.h>		/* for DIR */
52 #include	<sys/vtoc.h>
53 #include	<sys/dkio.h>
54 #include	<nl_types.h>
55 #include	<strings.h>
56 #include	<sys/ddi.h>		/* for max */
57 #include	<l_common.h>
58 #include	<stgcom.h>
59 #include	<l_error.h>
60 #include	<rom.h>
61 #include	<exec.h>
62 #include	<a_state.h>
63 #include	<a5k.h>
64 
65 
66 /*	Defines 	*/
67 #define	PLNDEF		"SUNW,pln"	/* check if box name starts with 'c' */
68 #define	DOWNLOAD_RETRIES	60*5	/* 5 minutes */
69 #define	IBFIRMWARE_FILE		"/usr/lib/locale/C/LC_MESSAGES/ibfirmware"
70 
71 /*	Global variables	*/
72 extern	uchar_t		g_switch_to_alpa[];
73 extern	uchar_t		g_sf_alpa_to_switch[];
74 
75 /*	Forward declarations	*/
76 static	int pwr_up_down(char *, L_state *, int, int, int, int);
77 static	int load_flds_if_enc_disk(char *, struct path_struct **);
78 static	int copy_config_page(struct l_state_struct *, uchar_t *);
79 static	void copy_page_7(struct l_state_struct *, uchar_t *);
80 static	int l_get_node_status(char *, struct l_disk_state_struct *,
81 	int *, WWN_list *, int);
82 static	int check_file(int, int, uchar_t **, int);
83 static	int check_dpm_file(int);
84 static	int ib_download_code_cmd(int, int, int, uchar_t *, int, int);
85 static	int dak_download_code_cmd(int, uchar_t *, int);
86 static	void free_mp_dev_map(struct gfc_map_mp **);
87 static	int get_mp_dev_map(char *, struct gfc_map_mp **, int);
88 
89 /*
90  * l_get_mode_pg() - Read all mode pages.
91  *
92  * RETURNS:
93  *	0        O.K.
94  *	non-zero otherwise
95  *
96  * INPUTS:
97  *	path     pointer to device path
98  *	pg_buf   ptr to mode pages
99  *
100  */
101 /*ARGSUSED*/
102 int
103 l_get_mode_pg(char *path, uchar_t **pg_buf, int verbose)
104 {
105 Mode_header_10	*mode_header_ptr;
106 int		status, size, fd;
107 
108 	P_DPRINTF("  l_get_mode_pg: Reading Mode Sense pages.\n");
109 
110 	/* do not do mode sense if this is a tape device */
111 	/* mode sense will rewind the tape */
112 	if (strstr(path, SLSH_DRV_NAME_ST)) {
113 		return (-1);
114 	}
115 
116 	/* open controller */
117 	if ((fd = g_object_open(path, O_NDELAY | O_RDWR)) == -1)
118 		return (L_OPEN_PATH_FAIL);
119 
120 	/*
121 	 * Read the first part of the page to get the page size
122 	 */
123 	size = 20;
124 	if ((*pg_buf = (uchar_t *)g_zalloc(size)) == NULL) {
125 	    (void) close(fd);
126 	    return (L_MALLOC_FAILED);
127 	}
128 	/* read page */
129 	if (status = g_scsi_mode_sense_cmd(fd, *pg_buf, size,
130 	    0, MODEPAGE_ALLPAGES)) {
131 	    (void) close(fd);
132 	    (void) g_destroy_data((char *)*pg_buf);
133 	    return (status);
134 	}
135 	/* Now get the size for all pages */
136 	mode_header_ptr = (struct mode_header_10_struct *)(void *)*pg_buf;
137 	size = mode_header_ptr->length + sizeof (mode_header_ptr->length);
138 	(void) g_destroy_data((char *)*pg_buf);
139 	if ((*pg_buf = (uchar_t *)g_zalloc(size)) == NULL) {
140 	    (void) close(fd);
141 	    return (L_MALLOC_FAILED);
142 	}
143 	/* read all pages */
144 	if (status = g_scsi_mode_sense_cmd(fd, *pg_buf, size,
145 					0, MODEPAGE_ALLPAGES)) {
146 	    (void) close(fd);
147 	    (void) g_destroy_data((char *)*pg_buf);
148 	    return (status);
149 	}
150 	(void) close(fd);
151 	return (0);
152 }
153 
154 
155 
156 /*
157  * Format QLA21xx status
158  *
159  * INPUTS: message buffer
160  *         Count
161  *         status
162  *
163  * OUTPUT: Message of this format in message buffer
164  *         "status type:            0xstatus        count"
165  */
166 int
167 l_format_ifp_status_msg(char *status_msg_buf, int count, int status)
168 {
169 	if (status_msg_buf == NULL) {
170 		return (0);
171 	}
172 
173 	switch (status) {
174 	case IFP_CMD_CMPLT:
175 		(void) sprintf(status_msg_buf,
176 			MSGSTR(9000, "O.K.                          0x%-2x"
177 			"            %d"), status, count);
178 		break;
179 	case IFP_CMD_INCOMPLETE:
180 		(void) sprintf(status_msg_buf,
181 			MSGSTR(9001, "Cmd incomplete                0x%-2x"
182 			"            %d"), status, count);
183 		break;
184 	case IFP_CMD_DMA_DERR:
185 		(void) sprintf(status_msg_buf,
186 			MSGSTR(9002, "DMA direction error           0x%-2x"
187 			"            %d"), status, count);
188 		break;
189 	case IFP_CMD_TRAN_ERR:
190 		(void) sprintf(status_msg_buf,
191 			MSGSTR(9003, "Unspecified transport error   0x%-2x"
192 			"            %d"), status, count);
193 		break;
194 	case IFP_CMD_RESET:
195 		(void) sprintf(status_msg_buf,
196 			MSGSTR(9004, "Reset aborted transport       0x%-2x"
197 			"            %d"), status, count);
198 		break;
199 	case IFP_CMD_ABORTED:
200 		(void) sprintf(status_msg_buf,
201 			MSGSTR(9005, "Cmd aborted                   0x%-2x"
202 			"            %d"), status, count);
203 		break;
204 	case IFP_CMD_TIMEOUT:
205 		(void) sprintf(status_msg_buf,
206 			MSGSTR(9006, "Cmd Timeout                   0x%-2x"
207 			"            %d"), status, count);
208 		break;
209 	case IFP_CMD_DATA_OVR:
210 		(void) sprintf(status_msg_buf,
211 			MSGSTR(9007, "Data Overrun                  0x%-2x"
212 			"            %d"), status, count);
213 		break;
214 	case IFP_CMD_ABORT_REJECTED:
215 		(void) sprintf(status_msg_buf,
216 			MSGSTR(9008, "Target rejected abort msg     0x%-2x"
217 			"            %d"), status, count);
218 		break;
219 	case IFP_CMD_RESET_REJECTED:
220 		(void) sprintf(status_msg_buf,
221 			MSGSTR(9009, "Target rejected reset msg     0x%-2x"
222 			"            %d"), status, count);
223 		break;
224 	case IFP_CMD_DATA_UNDER:
225 		(void) sprintf(status_msg_buf,
226 			MSGSTR(9010, "Data underrun                 0x%-2x"
227 			"            %d"), status, count);
228 		break;
229 	case IFP_CMD_QUEUE_FULL:
230 		(void) sprintf(status_msg_buf,
231 			MSGSTR(9011, "Queue full SCSI status        0x%-2x"
232 			"            %d"), status, count);
233 		break;
234 	case IFP_CMD_PORT_UNAVAIL:
235 		(void) sprintf(status_msg_buf,
236 			MSGSTR(9012, "Port unavailable              0x%-2x"
237 			"            %d"), status, count);
238 		break;
239 	case IFP_CMD_PORT_LOGGED_OUT:
240 		(void) sprintf(status_msg_buf,
241 			MSGSTR(9013, "Port loged out                0x%-2x"
242 			"            %d"), status, count);
243 		break;
244 	case IFP_CMD_PORT_CONFIG_CHANGED:
245 		/* Not enough packets for given request */
246 		(void) sprintf(status_msg_buf,
247 			MSGSTR(9014, "Port name changed             0x%-2x"
248 			"            %d"), status, count);
249 		break;
250 	default:
251 		(void) sprintf(status_msg_buf,
252 			"%s                0x%-2x"
253 			"            %d", MSGSTR(4, "Unknown status"),
254 			status, count);
255 
256 	} /* End of switch() */
257 
258 	return (0);
259 
260 }
261 
262 
263 
264 /*
265  * Format Fibre Channel status
266  *
267  * INPUTS: message buffer
268  *         Count
269  *         status
270  *
271  * OUTPUT: Message of this format in message buffer
272  *         "status type:            0xstatus        count"
273  */
274 int
275 l_format_fc_status_msg(char *status_msg_buf, int count, int status)
276 {
277 	if (status_msg_buf == NULL) {
278 		return (0);
279 	}
280 
281 	switch (status) {
282 	case FCAL_STATUS_OK:
283 		(void) sprintf(status_msg_buf,
284 			MSGSTR(9015, "O.K.                          0x%-2x"
285 			"            %d"), status, count);
286 		break;
287 	case FCAL_STATUS_P_RJT:
288 		(void) sprintf(status_msg_buf,
289 			MSGSTR(9016, "P_RJT (Frame Rejected)        0x%-2x"
290 			"            %d"), status, count);
291 		break;
292 	case FCAL_STATUS_F_RJT:
293 		(void) sprintf(status_msg_buf,
294 			MSGSTR(9017, "F_RJT (Frame Rejected)        0x%-2x"
295 			"            %d"), status, count);
296 		break;
297 	case FCAL_STATUS_P_BSY:
298 		(void) sprintf(status_msg_buf,
299 			MSGSTR(9018, "P_BSY (Port Busy)             0x%-2x"
300 			"            %d"), status, count);
301 		break;
302 	case FCAL_STATUS_F_BSY:
303 		(void) sprintf(status_msg_buf,
304 			MSGSTR(9019, "F_BSY (Port Busy)             0x%-2x"
305 			"            %d"), status, count);
306 		break;
307 	case FCAL_STATUS_OLDPORT_ONLINE:
308 		/* Should not happen. */
309 		(void) sprintf(status_msg_buf,
310 			MSGSTR(9020, "Old port Online               0x%-2x"
311 			"            %d"), status, count);
312 		break;
313 	case FCAL_STATUS_ERR_OFFLINE:
314 		(void) sprintf(status_msg_buf,
315 			MSGSTR(9021, "Link Offline                  0x%-2x"
316 			"            %d"), status, count);
317 		break;
318 	case FCAL_STATUS_TIMEOUT:
319 		/* Should not happen. */
320 		(void) sprintf(status_msg_buf,
321 			MSGSTR(9022, "Sequence Timeout              0x%-2x"
322 			"            %d"), status, count);
323 		break;
324 	case FCAL_STATUS_ERR_OVERRUN:
325 		(void) sprintf(status_msg_buf,
326 			MSGSTR(9023, "Sequence Payload Overrun      0x%-2x"
327 			"            %d"), status, count);
328 		break;
329 	case FCAL_STATUS_LOOP_ONLINE:
330 		(void) sprintf(status_msg_buf,
331 			MSGSTR(9060, "Loop Online                   0x%-2x"
332 			"            %d"), status, count);
333 		break;
334 	case FCAL_STATUS_OLD_PORT:
335 		(void) sprintf(status_msg_buf,
336 			MSGSTR(9061, "Old port                      0x%-2x"
337 			"            %d"), status, count);
338 		break;
339 	case FCAL_STATUS_AL_PORT:
340 		(void) sprintf(status_msg_buf,
341 			MSGSTR(9062, "AL port                       0x%-2x"
342 			"            %d"), status, count);
343 		break;
344 	case FCAL_STATUS_UNKNOWN_CQ_TYPE:
345 		(void) sprintf(status_msg_buf,
346 			MSGSTR(9024, "Unknown request type          0x%-2x"
347 			"            %d"), status, count);
348 		break;
349 	case FCAL_STATUS_BAD_SEG_CNT:
350 		(void) sprintf(status_msg_buf,
351 			MSGSTR(9025, "Bad segment count             0x%-2x"
352 			"            %d"), status, count);
353 		break;
354 	case FCAL_STATUS_MAX_XCHG_EXCEEDED:
355 		(void) sprintf(status_msg_buf,
356 			MSGSTR(9026, "Maximum exchanges exceeded    0x%-2x"
357 			"            %d"), status, count);
358 		break;
359 	case FCAL_STATUS_BAD_XID:
360 		(void) sprintf(status_msg_buf,
361 			MSGSTR(9027, "Bad exchange identifier       0x%-2x"
362 			"            %d"), status, count);
363 		break;
364 	case FCAL_STATUS_XCHG_BUSY:
365 		(void) sprintf(status_msg_buf,
366 			MSGSTR(9028, "Duplicate exchange request    0x%-2x"
367 			"            %d"), status, count);
368 		break;
369 	case FCAL_STATUS_BAD_POOL_ID:
370 		(void) sprintf(status_msg_buf,
371 			MSGSTR(9029, "Bad memory pool ID            0x%-2x"
372 			"            %d"), status, count);
373 		break;
374 	case FCAL_STATUS_INSUFFICIENT_CQES:
375 		/* Not enough packets for given request */
376 		(void) sprintf(status_msg_buf,
377 			MSGSTR(9030, "Invalid # of segments for req 0x%-2x"
378 			"            %d"), status, count);
379 		break;
380 	case FCAL_STATUS_ALLOC_FAIL:
381 		(void) sprintf(status_msg_buf,
382 			MSGSTR(9031, "Resource allocation failure   0x%-2x"
383 			"            %d"), status, count);
384 		break;
385 	case FCAL_STATUS_BAD_SID:
386 		(void) sprintf(status_msg_buf,
387 			MSGSTR(9032, "Bad Source Identifier(S_ID)   0x%-2x"
388 			"            %d"), status, count);
389 		break;
390 	case FCAL_STATUS_NO_SEQ_INIT:
391 		(void) sprintf(status_msg_buf,
392 			MSGSTR(9033, "No sequence initiative        0x%-2x"
393 			"            %d"), status, count);
394 		break;
395 	case FCAL_STATUS_BAD_DID:
396 		(void) sprintf(status_msg_buf,
397 			MSGSTR(9034, "Bad Destination ID(D_ID)      0x%-2x"
398 			"            %d"), status, count);
399 		break;
400 	case FCAL_STATUS_ABORTED:
401 		(void) sprintf(status_msg_buf,
402 			MSGSTR(9035, "Received BA_ACC from abort    0x%-2x"
403 			"            %d"), status, count);
404 		break;
405 	case FCAL_STATUS_ABORT_FAILED:
406 		(void) sprintf(status_msg_buf,
407 			MSGSTR(9036, "Received BA_RJT from abort    0x%-2x"
408 			"            %d"), status, count);
409 		break;
410 	case FCAL_STATUS_DIAG_BUSY:
411 		(void) sprintf(status_msg_buf,
412 			MSGSTR(9037, "Diagnostics currently busy    0x%-2x"
413 			"            %d"), status, count);
414 		break;
415 	case FCAL_STATUS_DIAG_INVALID:
416 		(void) sprintf(status_msg_buf,
417 			MSGSTR(9038, "Diagnostics illegal request   0x%-2x"
418 			"            %d"), status, count);
419 		break;
420 	case FCAL_STATUS_INCOMPLETE_DMA_ERR:
421 		(void) sprintf(status_msg_buf,
422 			MSGSTR(9039, "SBus DMA did not complete     0x%-2x"
423 			"            %d"), status, count);
424 		break;
425 	case FCAL_STATUS_CRC_ERR:
426 		(void) sprintf(status_msg_buf,
427 			MSGSTR(9040, "CRC error detected            0x%-2x"
428 			"            %d"), status, count);
429 		break;
430 	case FCAL_STATUS_OPEN_FAIL:
431 		(void) sprintf(status_msg_buf,
432 			MSGSTR(9063, "Open failure                  0x%-2x"
433 			"            %d"), status, count);
434 		break;
435 	case FCAL_STATUS_ERROR:
436 		(void) sprintf(status_msg_buf,
437 			MSGSTR(9041, "Invalid status error          0x%-2x"
438 			"            %d"), status, count);
439 		break;
440 	case FCAL_STATUS_ONLINE_TIMEOUT:
441 		(void) sprintf(status_msg_buf,
442 			MSGSTR(9042, "Timed out before ONLINE       0x%-2x"
443 			"            %d"), status, count);
444 		break;
445 	default:
446 		(void) sprintf(status_msg_buf,
447 			"%s                0x%-2x"
448 			"            %d", MSGSTR(4, "Unknown status"),
449 			status, count);
450 
451 	} /* End of switch() */
452 
453 	return (0);
454 
455 }
456 
457 
458 
459 /*
460  * Get the indexes to the disk device elements in page 2,
461  * based on the locations found in page 1.
462  *
463  * RETURNS:
464  *	0	 O.K.
465  *	non-zero otherwise
466  */
467 int
468 l_get_disk_element_index(struct l_state_struct *l_state, int *front_index,
469 						int *rear_index)
470 {
471 int	index = 0, front_flag = 0, local_front = 0, local_rear = 0;
472 int	i, rear_flag = 0;
473 
474 	if ((l_state == NULL) || (front_index == NULL) ||
475 	    (rear_index == NULL)) {
476 		return (L_INVALID_PATH_FORMAT);
477 	}
478 
479 	*front_index = *rear_index = 0;
480 	/* Get the indexes to the disk device elements */
481 	for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) {
482 		if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_DD) {
483 			if (front_flag) {
484 				local_rear = index;
485 				rear_flag = 1;
486 				break;
487 			} else {
488 				local_front = index;
489 				front_flag = 1;
490 			}
491 		}
492 		index += l_state->ib_tbl.config.type_hdr[i].num;
493 		index++;		/* for global element */
494 	}
495 
496 	D_DPRINTF("  l_get_disk_element_index:"
497 		" Index to front disk elements 0x%x\n"
498 		"  l_get_disk_element_index:"
499 		" Index to rear disk elements 0x%x\n",
500 		local_front, local_rear);
501 
502 	if (!front_flag && !rear_flag) {    /* neither is found */
503 		return (L_RD_NO_DISK_ELEM);
504 	}
505 	*front_index = local_front;
506 	*rear_index = local_rear;
507 	return (0);
508 }
509 
510 
511 
512 /*
513  * l_led() manage the device led's
514  *
515  * RETURNS:
516  *	0	 O.K.
517  *	non-zero otherwise
518  */
519 int
520 l_led(struct path_struct *path_struct, int led_action,
521 	struct device_element *status,
522 	int verbose)
523 {
524 gfc_map_t		map;
525 char			ses_path[MAXPATHLEN];
526 uchar_t			*page_buf;
527 int 			err, write, fd, front_index, rear_index, offset;
528 unsigned short		page_len;
529 struct	device_element 	*elem;
530 L_state			*l_state;
531 int			enc_type;
532 
533 	if ((path_struct == NULL) || (status == NULL)) {
534 		return (L_INVALID_PATH_FORMAT);
535 	}
536 
537 	/*
538 	 * Need to get a valid location, front/rear & slot.
539 	 *
540 	 * The path_struct will return a valid slot
541 	 * and the IB path or a disk path.
542 	 */
543 
544 	map.dev_addr = (gfc_port_dev_info_t *)NULL;
545 	if (!path_struct->ib_path_flag) {
546 		if ((err = g_get_dev_map(path_struct->p_physical_path,
547 							&map, verbose)) != 0)
548 			return (err);
549 		if ((err = l_get_ses_path(path_struct->p_physical_path,
550 					ses_path, &map, verbose)) != 0) {
551 			free((void *)map.dev_addr);
552 			return (err);
553 		}
554 	} else {
555 		(void) strcpy(ses_path, path_struct->p_physical_path);
556 	}
557 
558 	if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
559 		free((void *)map.dev_addr);
560 		return (L_MALLOC_FAILED);
561 	}
562 
563 	if (!path_struct->slot_valid) {
564 		if ((map.dev_addr != NULL) &&
565 			(err = g_get_dev_map(path_struct->p_physical_path,
566 							&map, verbose)) != 0) {
567 			(void) l_free_lstate(&l_state);
568 			return (err);
569 		}
570 		if ((err = l_get_ses_path(path_struct->p_physical_path,
571 			ses_path, &map, verbose)) != 0) {
572 			(void) l_free_lstate(&l_state);
573 			free((void *)map.dev_addr);
574 			return (err);
575 		}
576 		if ((err = l_get_status(ses_path, l_state, verbose)) != 0) {
577 			(void) l_free_lstate(&l_state);
578 			free((void *)map.dev_addr);
579 			return (err);
580 		}
581 
582 		/* We are passing the disks path */
583 		if (err = l_get_slot(path_struct, l_state, verbose)) {
584 			(void) l_free_lstate(&l_state);
585 			free((void *)map.dev_addr);
586 			return (err);
587 		}
588 	}
589 	if (map.dev_addr != NULL)
590 		free((void *)map.dev_addr);	/* Not used anymore */
591 
592 	if ((page_buf = (uchar_t *)calloc(1,
593 				MAX_REC_DIAG_LENGTH)) == NULL) {
594 		(void) l_free_lstate(&l_state);
595 		return (L_MALLOC_FAILED);
596 	}
597 
598 	if ((fd = g_object_open(ses_path, O_NDELAY | O_RDWR)) == -1) {
599 		(void) l_free_lstate(&l_state);
600 		(void) g_destroy_data(page_buf);
601 		return (L_OPEN_PATH_FAIL);
602 	}
603 
604 	if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH,
605 						L_PAGE_2, verbose)) {
606 		(void) l_free_lstate(&l_state);
607 		(void) close(fd);
608 		(void) g_destroy_data(page_buf);
609 		return (err);
610 	}
611 
612 	page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN;
613 
614 	/* Get index to the disk we are interested in */
615 	if (err = l_get_status(ses_path, l_state, verbose)) {
616 		(void) l_free_lstate(&l_state);
617 		(void) close(fd);
618 		(void) g_destroy_data(page_buf);
619 		return (err);
620 	}
621 
622 	/* find enclosure type */
623 	if ((strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_OFF_NAME,
624 						strlen(DAK_OFF_NAME)) == 0) ||
625 		(strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_PROD_STR,
626 						strlen(DAK_PROD_STR)) == 0)) {
627 		enc_type = DAK_ENC_TYPE;
628 	} else {
629 		enc_type = SENA_ENC_TYPE;
630 	}
631 
632 	/* Double check slot. */
633 	if (path_struct->slot >= l_state->total_num_drv/2) {
634 		(void) l_free_lstate(&l_state);
635 		return (L_INVALID_SLOT);
636 	}
637 
638 	if (err = l_get_disk_element_index(l_state, &front_index,
639 	    &rear_index)) {
640 		(void) l_free_lstate(&l_state);
641 		return (err);
642 	}
643 
644 	/* Skip global element */
645 	front_index++;
646 	if (enc_type == DAK_ENC_TYPE) {
647 		rear_index += l_state->total_num_drv/2 + 1;
648 	} else {
649 		rear_index++;
650 	}
651 
652 	if (path_struct->f_flag) {
653 		offset = (8 + (front_index + path_struct->slot)*4);
654 	} else {
655 		offset = (8 + (rear_index + path_struct->slot)*4);
656 	}
657 
658 	elem = (struct device_element *)(page_buf + offset);
659 	/*
660 	 * now do requested action.
661 	 */
662 	bcopy((const void *)elem, (void *)status,
663 		sizeof (struct device_element));	/* save status */
664 	bzero(elem, sizeof (struct device_element));
665 	elem->select = 1;
666 	elem->dev_off = status->dev_off;
667 	elem->en_bypass_a = status->en_bypass_a;
668 	elem->en_bypass_b = status->en_bypass_b;
669 	write = 1;
670 
671 	switch (led_action) {
672 	case	L_LED_STATUS:
673 		write = 0;
674 		break;
675 	case	L_LED_RQST_IDENTIFY:
676 		elem->ident = 1;
677 		if (verbose) {
678 		    if (enc_type == DAK_ENC_TYPE) {
679 			(void) fprintf(stdout,
680 			MSGSTR(9043, "  Blinking LED for slot %d in enclosure"
681 			" %s\n"), path_struct->f_flag ? path_struct->slot :
682 			path_struct->slot + (MAX_DRIVES_DAK/2),
683 			l_state->ib_tbl.enclosure_name);
684 		    } else {
685 			(void) fprintf(stdout,
686 			MSGSTR(9043, "  Blinking LED for slot %d in enclosure"
687 			" %s\n"), path_struct->slot,
688 			l_state->ib_tbl.enclosure_name);
689 		    }
690 		}
691 		break;
692 	case	L_LED_OFF:
693 		if (verbose) {
694 		    if (enc_type == DAK_ENC_TYPE) {
695 			(void) fprintf(stdout,
696 			MSGSTR(9044,
697 			"  Turning off LED for slot %d in enclosure"
698 			" %s\n"), path_struct->f_flag ? path_struct->slot
699 			: path_struct->slot + (MAX_DRIVES_DAK/2),
700 			l_state->ib_tbl.enclosure_name);
701 		    } else {
702 			(void) fprintf(stdout,
703 			MSGSTR(9044,
704 			"  Turning off LED for slot %d in enclosure"
705 			" %s\n"), path_struct->slot,
706 			l_state->ib_tbl.enclosure_name);
707 		    }
708 		}
709 		break;
710 	default:
711 		(void) l_free_lstate(&l_state);
712 		return (L_INVALID_LED_RQST);
713 	} /* End of switch */
714 
715 	if (write) {
716 		if (getenv("_LUX_D_DEBUG") != NULL) {
717 			g_dump("  l_led: Updating led state: "
718 			"Device Status Element ",
719 			(uchar_t *)elem, sizeof (struct device_element),
720 			HEX_ONLY);
721 		}
722 		if (err = g_scsi_send_diag_cmd(fd,
723 			(uchar_t *)page_buf, page_len)) {
724 			(void) close(fd);
725 			(void) g_destroy_data(page_buf);
726 			(void) l_free_lstate(&l_state);
727 			return (err);
728 		}
729 
730 		bzero(page_buf, MAX_REC_DIAG_LENGTH);
731 		if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH,
732 					L_PAGE_2, verbose)) {
733 			(void) g_destroy_data(page_buf);
734 			(void) close(fd);
735 			(void) l_free_lstate(&l_state);
736 			return (err);
737 		}
738 		elem = (struct device_element *)(page_buf + offset);
739 		bcopy((const void *)elem, (void *)status,
740 			sizeof (struct device_element));
741 	}
742 	if (getenv("_LUX_D_DEBUG") != NULL) {
743 		g_dump("  l_led: Device Status Element ",
744 		(uchar_t *)status, sizeof (struct device_element),
745 		HEX_ONLY);
746 	}
747 
748 	(void) l_free_lstate(&l_state);
749 	(void) close(fd);
750 	(void) g_destroy_data(page_buf);
751 	return (0);
752 }
753 
754 
755 /*
756  * frees the previously alloced l_state
757  * structure.
758  *
759  * RETURNS:
760  *	0	O.K.
761  *	non-zero otherwise
762  */
763 int
764 l_free_lstate(L_state **l_state)
765 {
766 int	i;
767 
768 	if ((l_state == NULL) || (*l_state == NULL))
769 		return (0);
770 
771 	for (i = 0; i < (int)(*l_state)->total_num_drv/2; i++) {
772 	if ((*l_state)->drv_front[i].g_disk_state.multipath_list != NULL)
773 		(void) g_free_multipath(
774 		(*l_state)->drv_front[i].g_disk_state.multipath_list);
775 	if ((*l_state)->drv_rear[i].g_disk_state.multipath_list != NULL)
776 		(void) g_free_multipath(
777 		(*l_state)->drv_rear[i].g_disk_state.multipath_list);
778 	}
779 	(void) g_destroy_data (*l_state);
780 	l_state = NULL;
781 
782 	return (0);
783 }
784 
785 
786 
787 /*
788  * Set the state of an individual disk
789  * in the Photon enclosure the powered
790  * up/down mode. The path must point to
791  * a disk or the ib_path_flag must be set.
792  *
793  * RETURNS:
794  *	0	 O.K.
795  *	non-zero otherwise
796  */
797 int
798 l_dev_pwr_up_down(char *path_phys, struct path_struct *path_struct,
799 		int power_off_flag, int verbose, int force_flag)
800 /*ARGSUSED*/
801 {
802 gfc_map_t		map;
803 char			ses_path[MAXPATHLEN], dev_path[MAXPATHLEN];
804 int			slot, err = 0;
805 L_state			*l_state = NULL;
806 struct l_disk_state_struct	*drive;
807 struct dlist		*dl, *dl1;
808 devctl_hdl_t		devhdl;
809 WWN_list		*wwn_list = NULL;
810 L_inquiry		inq;
811 
812 	if (path_struct == NULL) {
813 		return (L_INVALID_PATH_FORMAT);
814 	}
815 
816 	dl = (struct dlist *)NULL;
817 	map.dev_addr = (gfc_port_dev_info_t *)NULL;
818 
819 	if (err = g_get_dev_map(path_struct->p_physical_path,
820 					&map, verbose))
821 		return (err);
822 
823 	if (err = l_get_ses_path(path_struct->p_physical_path,
824 				ses_path, &map, verbose)) {
825 		free((void *)map.dev_addr);
826 		return (err);
827 	}
828 	free((void *)map.dev_addr);	/* Not used anymore */
829 
830 	/*
831 	 * Check to see if we have a photon, and if not, don't allow
832 	 * this operation
833 	 */
834 	if (err = g_get_inquiry(ses_path, &inq)) {
835 	    return (err);
836 	}
837 	if (l_get_enc_type(inq) != SENA_ENC_TYPE) {
838 	    return (L_ENCL_INVALID_PATH);
839 	}
840 	/*
841 	 * OK, so we have a photon... we can continue
842 	 */
843 
844 
845 	if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
846 		return (L_MALLOC_FAILED);
847 	}
848 
849 	if (err = l_get_status(ses_path, l_state, verbose)) {
850 		(void) l_free_lstate(&l_state);
851 		return (err);
852 	}
853 
854 	if (!path_struct->slot_valid) {
855 		/* We are passing the disks path */
856 		if (err = l_get_slot(path_struct, l_state, verbose)) {
857 			(void) l_free_lstate(&l_state);
858 			return (err);
859 		}
860 	}
861 
862 	slot = path_struct->slot;
863 	(void) strcpy(dev_path, path_struct->p_physical_path);
864 
865 	/*
866 	 * Either front or rear drive
867 	 */
868 	if (path_struct->f_flag) {
869 		drive = &l_state->drv_front[slot];
870 	} else {
871 		drive = &l_state->drv_rear[slot];
872 	}
873 
874 	/*
875 	 * Check for drive presence always
876 	 */
877 	if (drive->ib_status.code == S_NOT_INSTALLED) {
878 		(void) l_free_lstate(&l_state);
879 		return (L_SLOT_EMPTY);
880 	}
881 
882 	/*
883 	 * Check disk state
884 	 * before the power off.
885 	 *
886 	 */
887 	if (power_off_flag && !force_flag) {
888 		goto pre_pwr_dwn;
889 	} else {
890 		goto pwr_up_dwn;
891 	}
892 
893 pre_pwr_dwn:
894 
895 	/*
896 	 * Check whether disk
897 	 * is reserved by another
898 	 * host
899 	 */
900 	if ((drive->g_disk_state.d_state_flags[PORT_A] & L_RESERVED) ||
901 		(drive->g_disk_state.d_state_flags[PORT_B] &
902 		L_RESERVED)) {
903 		(void) l_free_lstate(&l_state);
904 		return (L_DEVICE_RESERVED);
905 	}
906 
907 
908 	if ((dl = (struct dlist *)g_zalloc(sizeof (struct dlist))) == NULL) {
909 		(void) l_free_lstate(&l_state);
910 		return (L_MALLOC_FAILED);
911 	}
912 
913 	/*
914 	 * NOTE: It is not necessary to get the multipath list here as ------
915 	 * we alread have it after getting the status earlier.
916 	 * - REWRITE -
917 	 */
918 
919 	/*
920 	 * Get path to all the FC disk and tape devices.
921 	 *
922 	 * I get this now and pass down for performance
923 	 * reasons.
924 	 * If for some reason the list can become invalid,
925 	 * i.e. device being offlined, then the list
926 	 * must be re-gotten.
927 	 */
928 	if (err = g_get_wwn_list(&wwn_list, verbose)) {
929 		(void) g_destroy_data(dl);
930 		(void) l_free_lstate(&l_state);
931 		return (err);   /* Failure */
932 	}
933 
934 	dl->dev_path = dev_path;
935 	if ((err = g_get_multipath(dev_path,
936 			&(dl->multipath), wwn_list, verbose)) != 0) {
937 		(void) g_destroy_data(dl);
938 		(void) g_free_wwn_list(&wwn_list);
939 		(void) l_free_lstate(&l_state);
940 		return (err);
941 	}
942 
943 	for (dl1 = dl->multipath; dl1 != NULL; dl1 = dl1->next) {
944 		if ((devhdl = devctl_device_acquire(dl1->dev_path,
945 						DC_EXCL)) == NULL) {
946 			if (errno != EBUSY) {
947 				ER_DPRINTF("%s could not acquire"
948 				" the device: %s\n\n",
949 				strerror(errno), dl1->dev_path);
950 				continue;
951 			}
952 		}
953 		if (devctl_device_offline(devhdl) != 0) {
954 			(void) devctl_release(devhdl);
955 			(void) g_free_multipath(dl->multipath);
956 			(void) g_destroy_data(dl);
957 			(void) g_free_wwn_list(&wwn_list);
958 			(void) l_free_lstate(&l_state);
959 			return (L_POWER_OFF_FAIL_BUSY);
960 		}
961 		(void) devctl_release(devhdl);
962 	}
963 
964 pwr_up_dwn:
965 	err = pwr_up_down(ses_path, l_state, path_struct->f_flag,
966 			path_struct->slot, power_off_flag, verbose);
967 
968 	if (dl != NULL) {
969 		(void) g_free_multipath(dl->multipath);
970 		(void) g_destroy_data(dl);
971 	}
972 	(void) g_free_wwn_list(&wwn_list);
973 	(void) l_free_lstate(&l_state);
974 	if (err) {
975 		return (err);
976 	}
977 	return (0);
978 }
979 
980 
981 
982 /*
983  * l_pho_pwr_up_down() Set the state of the Photon enclosure
984  * the powered up/down mode.
985  * The path must point to an IB.
986  *
987  * RETURNS:
988  *	0	 O.K.
989  *	non-zero otherwise
990  */
991 int
992 l_pho_pwr_up_down(char *dev_name, char *path_phys, int power_off_flag,
993 	int verbose, int force_flag)
994 {
995 L_state		*l_state = NULL;
996 int		i, err = 0;
997 struct dlist	*dl, *dl1;
998 char		dev_path[MAXPATHLEN];
999 devctl_hdl_t	devhdl;
1000 WWN_list	*wwn_list = NULL;
1001 
1002 	if (path_phys == NULL) {
1003 		return (L_INVALID_PATH_FORMAT);
1004 	}
1005 
1006 	dl = (struct dlist *)NULL;
1007 	if ((l_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
1008 		return (L_MALLOC_FAILED);
1009 	}
1010 	if (err = l_get_status(path_phys, l_state, verbose)) {
1011 		(void) l_free_lstate(&l_state);
1012 		return (err);
1013 	}
1014 	if (power_off_flag && !force_flag) {
1015 		goto pre_pwr_dwn;
1016 	} else {
1017 		goto pwr_up_dwn;
1018 	}
1019 
1020 pre_pwr_dwn:
1021 
1022 	/*
1023 	 * Check if any disk in this enclosure
1024 	 * is reserved by another host before
1025 	 * the power off.
1026 	 */
1027 	for (i = 0; i < l_state->total_num_drv/2; i++) {
1028 		if ((l_state->drv_front[i].g_disk_state.d_state_flags[PORT_A] &
1029 						L_RESERVED) ||
1030 		(l_state->drv_front[i].g_disk_state.d_state_flags[PORT_B] &
1031 						L_RESERVED) ||
1032 		(l_state->drv_rear[i].g_disk_state.d_state_flags[PORT_A] &
1033 						L_RESERVED) ||
1034 		(l_state->drv_rear[i].g_disk_state.d_state_flags[PORT_B] &
1035 						L_RESERVED)) {
1036 				return (L_DISKS_RESERVED);
1037 		}
1038 	}
1039 
1040 	/*
1041 	 * Check if any disk in this enclosure
1042 	 * Get path to all the FC disk and tape devices.
1043 	 *
1044 	 * I get this now and pass down for performance
1045 	 * reasons.
1046 	 * If for some reason the list can become invalid,
1047 	 * i.e. device being offlined, then the list
1048 	 * must be re-gotten.
1049 	 */
1050 	if (err = g_get_wwn_list(&wwn_list, verbose)) {
1051 		(void) l_free_lstate(&l_state);
1052 		return (err);   /* Failure */
1053 	}
1054 	for (i = 0; i < l_state->total_num_drv/2; i++) {
1055 		if (*l_state->drv_front[i].g_disk_state.physical_path) {
1056 			(void) memset(dev_path, 0, MAXPATHLEN);
1057 			(void) strcpy(dev_path,
1058 		(char *)&l_state->drv_front[i].g_disk_state.physical_path);
1059 
1060 			if ((dl = (struct dlist *)
1061 				g_zalloc(sizeof (struct dlist))) == NULL) {
1062 				(void) g_free_wwn_list(&wwn_list);
1063 				(void) l_free_lstate(&l_state);
1064 				return (L_MALLOC_FAILED);
1065 			}
1066 			dl->dev_path = dev_path;
1067 			if (g_get_multipath(dev_path, &(dl->multipath),
1068 				wwn_list, verbose) != 0) {
1069 				(void) g_destroy_data(dl);
1070 				continue;
1071 			}
1072 
1073 			for (dl1 = dl->multipath;
1074 			    dl1 != NULL;
1075 			    dl1 = dl1->next) {
1076 
1077 				/* attempt to acquire the device */
1078 				if ((devhdl = devctl_device_acquire(
1079 					dl1->dev_path, DC_EXCL)) == NULL) {
1080 					if (errno != EBUSY) {
1081 						ER_DPRINTF("%s: Could not "
1082 						"acquire the device: %s\n\n",
1083 						strerror(errno),
1084 						dl1->dev_path);
1085 						continue;
1086 					}
1087 				}
1088 
1089 				/* attempt to offline the device */
1090 				if (devctl_device_offline(devhdl) != 0) {
1091 					(void) devctl_release(devhdl);
1092 					(void) g_free_multipath(
1093 						dl->multipath);
1094 					(void) g_destroy_data(dl);
1095 					(void) g_free_wwn_list(&wwn_list);
1096 					(void) l_free_lstate(&l_state);
1097 					return (L_POWER_OFF_FAIL_BUSY);
1098 				}
1099 
1100 				/* release handle acquired above */
1101 				(void) devctl_release(devhdl);
1102 			}
1103 			(void) g_free_multipath(dl->multipath);
1104 			(void) g_destroy_data(dl);
1105 
1106 		}
1107 		if (*l_state->drv_rear[i].g_disk_state.physical_path) {
1108 			(void) memset(dev_path, 0, MAXPATHLEN);
1109 			(void) strcpy(dev_path,
1110 		(char *)&l_state->drv_rear[i].g_disk_state.physical_path);
1111 
1112 			if ((dl = (struct dlist *)
1113 				g_zalloc(sizeof (struct dlist))) == NULL) {
1114 				(void) g_free_wwn_list(&wwn_list);
1115 				(void) l_free_lstate(&l_state);
1116 				return (L_MALLOC_FAILED);
1117 			}
1118 			dl->dev_path = dev_path;
1119 			if (g_get_multipath(dev_path, &(dl->multipath),
1120 				wwn_list, verbose) != 0) {
1121 				(void) g_destroy_data(dl);
1122 				continue;
1123 			}
1124 
1125 
1126 			for (dl1 = dl->multipath;
1127 			    dl1 != NULL;
1128 			    dl1 = dl1->next) {
1129 
1130 				/* attempt to acquire the device */
1131 				if ((devhdl = devctl_device_acquire(
1132 					dl1->dev_path, DC_EXCL)) == NULL) {
1133 					if (errno != EBUSY) {
1134 						ER_DPRINTF("%s: Could not "
1135 						"acquire the device: %s\n\n",
1136 						strerror(errno),
1137 						dl1->dev_path);
1138 						continue;
1139 					}
1140 				}
1141 				/* attempt to offline the device */
1142 				if (devctl_device_offline(devhdl) != 0) {
1143 					(void) devctl_release(devhdl);
1144 					(void) g_free_multipath(
1145 							dl->multipath);
1146 					(void) g_destroy_data(dl);
1147 					(void) g_free_wwn_list(&wwn_list);
1148 					(void) l_free_lstate(&l_state);
1149 					return (L_POWER_OFF_FAIL_BUSY);
1150 				}
1151 
1152 				/* release handle acquired above */
1153 				(void) devctl_release(devhdl);
1154 			}
1155 			(void) g_free_multipath(dl->multipath);
1156 			(void) g_destroy_data(dl);
1157 
1158 		}
1159 	}
1160 
1161 pwr_up_dwn:
1162 
1163 	(void) g_free_wwn_list(&wwn_list);
1164 	if ((err = pwr_up_down(path_phys, l_state, 0, -1,
1165 		power_off_flag, verbose)) != 0) {
1166 		(void) l_free_lstate(&l_state);
1167 		return (err);
1168 	}
1169 	(void) l_free_lstate(&l_state);
1170 	return (0);
1171 }
1172 
1173 
1174 /*
1175  * Set the state of the Photon enclosure or disk
1176  * powered up/down mode.
1177  * The path must point to an IB.
1178  * slot == -1 implies entire enclosure.
1179  *
1180  * RETURNS:
1181  *	0	 O.K.
1182  *	non-zero otherwise
1183  */
1184 static int
1185 pwr_up_down(char *path_phys, L_state *l_state, int front, int slot,
1186 		int power_off_flag, int verbose)
1187 {
1188 L_inquiry		inq;
1189 int			fd, status, err;
1190 uchar_t			*page_buf;
1191 int 			front_index, rear_index, front_offset, rear_offset;
1192 unsigned short		page_len;
1193 struct	device_element	*front_elem, *rear_elem;
1194 
1195 	(void) memset(&inq, 0, sizeof (inq));
1196 	if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) {
1197 		return (L_OPEN_PATH_FAIL);
1198 	}
1199 	/* Verify it is a Photon */
1200 	if (status = g_scsi_inquiry_cmd(fd,
1201 		(uchar_t *)&inq, sizeof (struct l_inquiry_struct))) {
1202 		(void) close(fd);
1203 		return (status);
1204 	}
1205 	if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
1206 		(!(strncmp((char *)inq.inq_vid, "SUN     ",
1207 		sizeof (inq.inq_vid)) &&
1208 		((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
1209 		(void) close(fd);
1210 		return (L_ENCL_INVALID_PATH);
1211 	}
1212 
1213 	/*
1214 	 * To power up/down a Photon we use the Driver Off
1215 	 * bit in the global device control element.
1216 	 */
1217 	if ((page_buf = (uchar_t *)malloc(MAX_REC_DIAG_LENGTH)) == NULL) {
1218 		return (L_MALLOC_FAILED);
1219 	}
1220 	if (err = l_get_envsen_page(fd, page_buf, MAX_REC_DIAG_LENGTH,
1221 				L_PAGE_2, verbose)) {
1222 		(void) close(fd);
1223 		(void) g_destroy_data(page_buf);
1224 		return (err);
1225 	}
1226 
1227 	page_len = (page_buf[2] << 8 | page_buf[3]) + HEADER_LEN;
1228 
1229 	/* Double check slot as convert_name only does gross check */
1230 	if (slot >= l_state->total_num_drv/2) {
1231 		(void) close(fd);
1232 		(void) g_destroy_data(page_buf);
1233 		return (L_INVALID_SLOT);
1234 	}
1235 
1236 	if (err = l_get_disk_element_index(l_state, &front_index,
1237 		&rear_index)) {
1238 		(void) close(fd);
1239 		(void) g_destroy_data(page_buf);
1240 		return (err);
1241 	}
1242 	/* Skip global element */
1243 	front_index++;
1244 	rear_index++;
1245 
1246 	front_offset = (8 + (front_index + slot)*4);
1247 	rear_offset = (8 + (rear_index + slot)*4);
1248 
1249 	front_elem = (struct device_element *)(page_buf + front_offset);
1250 	rear_elem = (struct device_element *)(page_buf + rear_offset);
1251 
1252 	if (front || slot == -1) {
1253 		/*
1254 		 * now do requested action.
1255 		 */
1256 		bzero(front_elem, sizeof (struct device_element));
1257 		/* Set/reset power off bit */
1258 		front_elem->dev_off = power_off_flag;
1259 		front_elem->select = 1;
1260 	}
1261 	if (!front || slot == -1) {
1262 		/* Now do rear */
1263 		bzero(rear_elem, sizeof (struct device_element));
1264 		/* Set/reset power off bit */
1265 		rear_elem->dev_off = power_off_flag;
1266 		rear_elem->select = 1;
1267 	}
1268 
1269 	if (getenv("_LUX_D_DEBUG") != NULL) {
1270 		if (front || slot == -1) {
1271 			g_dump("  pwr_up_down: "
1272 				"Front Device Status Element ",
1273 				(uchar_t *)front_elem,
1274 				sizeof (struct device_element),
1275 				HEX_ONLY);
1276 		}
1277 		if (!front || slot == -1) {
1278 			g_dump("  pwr_up_down: "
1279 				"Rear Device Status Element ",
1280 				(uchar_t *)rear_elem,
1281 				sizeof (struct device_element),
1282 				HEX_ONLY);
1283 		}
1284 	}
1285 	if (err = g_scsi_send_diag_cmd(fd,
1286 		(uchar_t *)page_buf, page_len)) {
1287 		(void) close(fd);
1288 		(void) g_destroy_data(page_buf);
1289 		return (err);
1290 	}
1291 	(void) close(fd);
1292 	(void) g_destroy_data(page_buf);
1293 	return (0);
1294 }
1295 
1296 /*
1297  * Set the password of the FPM by sending the password
1298  * in page 4 of the Send Diagnostic command.
1299  *
1300  * The path must point to an IB.
1301  *
1302  * The size of the password string must be <= 8 bytes.
1303  * The string can also be NULL. This is the way the user
1304  * chooses to not have a password.
1305  *
1306  * I then tell the photon by giving him 4 NULL bytes.
1307  *
1308  * RETURNS:
1309  *	0	 O.K.
1310  *	non-zero otherwise
1311  */
1312 int
1313 l_new_password(char *path_phys, char *password)
1314 {
1315 Page4_name	page4;
1316 L_inquiry	inq;
1317 int		fd, status;
1318 
1319 	(void) memset(&inq, 0, sizeof (inq));
1320 	(void) memset(&page4, 0, sizeof (page4));
1321 
1322 	if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) {
1323 		return (L_OPEN_PATH_FAIL);
1324 	}
1325 	/* Verify it is a Photon */
1326 	if (status = g_scsi_inquiry_cmd(fd,
1327 		(uchar_t *)&inq, sizeof (struct l_inquiry_struct))) {
1328 		(void) close(fd);
1329 		return (status);
1330 	}
1331 	if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
1332 		(!(strncmp((char *)inq.inq_vid, "SUN     ",
1333 		sizeof (inq.inq_vid)) &&
1334 		((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
1335 		(void) close(fd);
1336 		return (L_ENCL_INVALID_PATH);
1337 	}
1338 
1339 	page4.page_code = L_PAGE_4;
1340 	page4.page_len = (ushort_t)max((strlen(password) + 4), 8);
1341 	/* Double check */
1342 	if (strlen(password) > 8) {
1343 		return (L_INVALID_PASSWORD_LEN);
1344 	}
1345 	page4.string_code = L_PASSWORD;
1346 	page4.enable = 1;
1347 	(void) strcpy((char *)page4.name, password);
1348 
1349 	if (status = g_scsi_send_diag_cmd(fd, (uchar_t *)&page4,
1350 		page4.page_len + HEADER_LEN)) {
1351 		(void) close(fd);
1352 		return (status);
1353 	}
1354 
1355 	(void) close(fd);
1356 	return (0);
1357 }
1358 
1359 
1360 
1361 /*
1362  * Set the name of the enclosure by sending the name
1363  * in page 4 of the Send Diagnostic command.
1364  *
1365  * The path must point to an IB.
1366  *
1367  * RETURNS:
1368  *	0	 O.K.
1369  *	non-zero otherwise
1370  */
1371 int
1372 l_new_name(char *path_phys, char *name)
1373 {
1374 Page4_name	page4;
1375 L_inquiry	inq;
1376 int		fd, status;
1377 
1378 	if ((path_phys == NULL) || (name == NULL)) {
1379 		return (L_INVALID_PATH_FORMAT);
1380 	}
1381 
1382 	(void) memset(&inq, 0, sizeof (inq));
1383 	(void) memset(&page4, 0, sizeof (page4));
1384 
1385 	if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) {
1386 		return (L_OPEN_PATH_FAIL);
1387 	}
1388 	/* Verify it is a Photon */
1389 	if (status = g_scsi_inquiry_cmd(fd,
1390 		(uchar_t *)&inq, sizeof (struct l_inquiry_struct))) {
1391 		(void) close(fd);
1392 		return (status);
1393 	}
1394 	if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
1395 		(!(strncmp((char *)inq.inq_vid, "SUN     ",
1396 		sizeof (inq.inq_vid)) &&
1397 		((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
1398 		(void) close(fd);
1399 		return (L_ENCL_INVALID_PATH);
1400 	}
1401 
1402 	page4.page_code = L_PAGE_4;
1403 	page4.page_len = (ushort_t)((sizeof (struct page4_name) - 4));
1404 	page4.string_code = L_ENCL_NAME;
1405 	page4.enable = 1;
1406 	strncpy((char *)page4.name, name, sizeof (page4.name));
1407 
1408 	if (status = g_scsi_send_diag_cmd(fd, (uchar_t *)&page4,
1409 		sizeof (page4))) {
1410 		(void) close(fd);
1411 		return (status);
1412 	}
1413 
1414 	/*
1415 	 * Check the name really changed.
1416 	 */
1417 	if (status = g_scsi_inquiry_cmd(fd,
1418 		(uchar_t *)&inq, sizeof (struct l_inquiry_struct))) {
1419 		(void) close(fd);
1420 		return (status);
1421 	}
1422 	if (strncmp((char *)inq.inq_box_name, name, sizeof (page4.name)) != 0) {
1423 		char	name_buf[MAXNAMELEN];
1424 		(void) close(fd);
1425 		strncpy((char *)name_buf, (char *)inq.inq_box_name,
1426 			sizeof (inq.inq_box_name));
1427 		return (L_ENCL_NAME_CHANGE_FAIL);
1428 	}
1429 
1430 	(void) close(fd);
1431 	return (0);
1432 }
1433 
1434 
1435 
1436 /*
1437  * Issue a Loop Port enable Primitive sequence
1438  * to the device specified by the pathname.
1439  */
1440 int
1441 l_enable(char *path, int verbose)
1442 /*ARGSUSED*/
1443 {
1444 
1445 	return (0);
1446 }
1447 
1448 /*
1449  * Issue a Loop Port Bypass Primitive sequence
1450  * to the device specified by the pathname. This requests the
1451  * device to set its L_Port into the bypass mode.
1452  */
1453 int
1454 l_bypass(char *path, int verbose)
1455 /*ARGSUSED*/
1456 {
1457 
1458 	return (0);
1459 }
1460 
1461 
1462 
1463 /*
1464  * Create a linked list of all the Photon enclosures that
1465  * are attached to this host.
1466  *
1467  * RETURN VALUES: 0 O.K.
1468  *
1469  * box_list pointer:
1470  *			NULL: No enclosures found.
1471  *			!NULL: Enclosures found
1472  *                      box_list points to a linked list of boxes.
1473  */
1474 int
1475 l_get_box_list(struct box_list_struct **box_list_ptr, int verbose)
1476 {
1477 char		*dev_name;
1478 DIR		*dirp;
1479 struct dirent	*entp;
1480 char		namebuf[MAXPATHLEN];
1481 struct stat	sb;
1482 char		*result = NULL;
1483 int		fd, status;
1484 L_inquiry	inq;
1485 Box_list	*box_list, *l1, *l2;
1486 IB_page_config	page1;
1487 uchar_t		node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
1488 int		al_pa;
1489 
1490 	if (box_list_ptr == NULL) {
1491 		return (L_INVALID_PATH_FORMAT);
1492 	}
1493 
1494 	box_list = *box_list_ptr = NULL;
1495 	if ((dev_name = (char *)g_zalloc(sizeof ("/dev/es"))) == NULL) {
1496 		return (L_MALLOC_FAILED);
1497 	}
1498 	(void) sprintf((char *)dev_name, "/dev/es");
1499 
1500 	if (verbose) {
1501 		(void) fprintf(stdout,
1502 		MSGSTR(9045,
1503 			"  Searching directory %s for links to enclosures\n"),
1504 			dev_name);
1505 	}
1506 
1507 	if ((dirp = opendir(dev_name)) == NULL) {
1508 		(void) g_destroy_data(dev_name);
1509 		/* No Photons found */
1510 		B_DPRINTF("  l_get_box_list: No Photons found\n");
1511 		return (0);
1512 	}
1513 
1514 
1515 	while ((entp = readdir(dirp)) != NULL) {
1516 		if (strcmp(entp->d_name, ".") == 0 ||
1517 			strcmp(entp->d_name, "..") == 0)
1518 			continue;
1519 
1520 		(void) sprintf(namebuf, "%s/%s", dev_name, entp->d_name);
1521 
1522 		if ((lstat(namebuf, &sb)) < 0) {
1523 			ER_DPRINTF("Warning: Cannot stat %s\n",
1524 							namebuf);
1525 			continue;
1526 		}
1527 
1528 		if (!S_ISLNK(sb.st_mode)) {
1529 			ER_DPRINTF("Warning: %s is not a symbolic link\n",
1530 								namebuf);
1531 			continue;
1532 		}
1533 		if ((result = g_get_physical_name_from_link(namebuf)) == NULL) {
1534 			ER_DPRINTF("  Warning: Get physical name from"
1535 			" link failed. Link=%s\n", namebuf);
1536 			continue;
1537 		}
1538 
1539 		/* Found a SES card. */
1540 		B_DPRINTF("  l_get_box_list: Link to SES Card found: %s/%s\n",
1541 			dev_name, entp->d_name);
1542 		if ((fd = g_object_open(result, O_NDELAY | O_RDONLY)) == -1) {
1543 			g_destroy_data(result);
1544 			continue;	/* Ignore errors */
1545 		}
1546 		/* Get the box name */
1547 		if (status = g_scsi_inquiry_cmd(fd,
1548 			(uchar_t *)&inq, sizeof (struct l_inquiry_struct))) {
1549 			(void) close(fd);
1550 			g_destroy_data(result);
1551 			continue;	/* Ignore errors */
1552 		}
1553 
1554 		if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != NULL) ||
1555 			(((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI) &&
1556 				(l_get_enc_type(inq) == DAK_ENC_TYPE))) {
1557 			/*
1558 			 * Found Photon/Daktari
1559 			 */
1560 
1561 			/* Get the port WWN from the IB, page 1 */
1562 			if ((status = l_get_envsen_page(fd, (uchar_t *)&page1,
1563 				sizeof (page1), 1, 0)) != NULL) {
1564 				(void) close(fd);
1565 				g_destroy_data(result);
1566 				(void) g_destroy_data(dev_name);
1567 				closedir(dirp);
1568 				return (status);
1569 			}
1570 
1571 			/*
1572 			 * Build list of names.
1573 			 */
1574 			if ((l2 = (struct  box_list_struct *)
1575 				g_zalloc(sizeof (struct  box_list_struct)))
1576 				== NULL) {
1577 				(void) close(fd);
1578 				g_destroy_data(result);
1579 				g_destroy_data(dev_name);
1580 				closedir(dirp);
1581 				return (L_MALLOC_FAILED);
1582 			}
1583 
1584 			/* Fill in structure */
1585 			(void) strcpy((char *)l2->b_physical_path,
1586 				(char *)result);
1587 			(void) strcpy((char *)l2->logical_path,
1588 				(char *)namebuf);
1589 			bcopy((void *)page1.enc_node_wwn,
1590 				(void *)l2->b_node_wwn, WWN_SIZE);
1591 			(void) sprintf(l2->b_node_wwn_s,
1592 			"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
1593 				page1.enc_node_wwn[0],
1594 				page1.enc_node_wwn[1],
1595 				page1.enc_node_wwn[2],
1596 				page1.enc_node_wwn[3],
1597 				page1.enc_node_wwn[4],
1598 				page1.enc_node_wwn[5],
1599 				page1.enc_node_wwn[6],
1600 				page1.enc_node_wwn[7]);
1601 			strncpy((char *)l2->prod_id_s,
1602 				(char *)inq.inq_pid,
1603 				sizeof (inq.inq_pid));
1604 			strncpy((char *)l2->b_name,
1605 				(char *)inq.inq_box_name,
1606 				sizeof (inq.inq_box_name));
1607 			/* make sure null terminated */
1608 			l2->b_name[sizeof (l2->b_name) - 1] = NULL;
1609 
1610 			/*
1611 			 * Now get the port WWN for the port
1612 			 * we are connected to.
1613 			 */
1614 			status = g_get_wwn(result, port_wwn, node_wwn,
1615 					&al_pa, verbose);
1616 			if (status == 0) {
1617 				(void) sprintf(l2->b_port_wwn_s,
1618 				"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
1619 				port_wwn[0], port_wwn[1], port_wwn[2],
1620 				port_wwn[3], port_wwn[4], port_wwn[5],
1621 				port_wwn[6], port_wwn[7]);
1622 				bcopy((void *)port_wwn,
1623 					(void *)l2->b_port_wwn, WWN_SIZE);
1624 
1625 				B_DPRINTF("  l_get_box_list:"
1626 				" Found enclosure named:%s\n", l2->b_name);
1627 
1628 				if (box_list == NULL) {
1629 					l1 = box_list = l2;
1630 				} else {
1631 					l2->box_prev = l1;
1632 					l1 = l1->box_next = l2;
1633 				}
1634 			} else {
1635 				(void) close(fd);
1636 				g_destroy_data(result);
1637 				(void) g_destroy_data(dev_name);
1638 				(void) g_destroy_data(l2);
1639 				closedir(dirp);
1640 				return (status);
1641 			}
1642 
1643 		}
1644 		g_destroy_data(result);
1645 		(void) close(fd);
1646 		*box_list_ptr = box_list; /* pass back ptr to list */
1647 	}
1648 	(void) g_destroy_data(dev_name);
1649 	closedir(dirp);
1650 	return (0);
1651 }
1652 
1653 void
1654 l_free_box_list(struct box_list_struct **box_list)
1655 {
1656 Box_list	*next = NULL;
1657 
1658 	if (box_list == NULL) {
1659 		return;
1660 	}
1661 
1662 	for (; *box_list != NULL; *box_list = next) {
1663 		next = (*box_list)->box_next;
1664 		(void) g_destroy_data(*box_list);
1665 	}
1666 
1667 	*box_list = NULL;
1668 }
1669 
1670 
1671 
1672 /*
1673  * Finds out if there are any other boxes
1674  * with the same name as "name".
1675  *
1676  * RETURNS:
1677  *	0   There are no other boxes with the same name.
1678  *	>0  if duplicate names found
1679  */
1680 /*ARGSUSED*/
1681 int
1682 l_duplicate_names(Box_list *b_list, char wwn[], char *name, int verbose)
1683 {
1684 int		dup_flag = 0;
1685 Box_list	*box_list_ptr = NULL;
1686 
1687 	if ((name == NULL) || (wwn == NULL))
1688 		return (0);
1689 
1690 	box_list_ptr = b_list;
1691 	while (box_list_ptr != NULL) {
1692 		if ((strcmp(name, (const char *)box_list_ptr->b_name) == 0) &&
1693 			(strcmp(box_list_ptr->b_node_wwn_s, wwn) != 0)) {
1694 			dup_flag++;
1695 			break;
1696 		}
1697 		box_list_ptr = box_list_ptr->box_next;
1698 	}
1699 	return (dup_flag);
1700 }
1701 
1702 
1703 
1704 /*
1705  * Checks for a name conflict with an SSA cN type name.
1706  */
1707 int
1708 l_get_conflict(char *name, char **result, int verbose)
1709 {
1710 char		s[MAXPATHLEN];
1711 char		*p = NULL;
1712 char		*pp = NULL;
1713 Box_list	*box_list = NULL;
1714 int		found_box = 0, err = 0;
1715 
1716 	(void) strcpy(s, name);
1717 	if ((*result = g_get_physical_name(s)) == NULL) {
1718 		return (0);
1719 	}
1720 	if ((strstr((const char *)*result, PLNDEF)) == NULL) {
1721 		(void) g_destroy_data(*result);
1722 		*result = NULL;
1723 		return (0);
1724 	}
1725 	P_DPRINTF("  l_get_conflict: Found "
1726 		"SSA path using %s\n", s);
1727 	/* Find path to IB */
1728 	if ((err = l_get_box_list(&box_list, verbose)) != 0) {
1729 		return (err);	/* Failure */
1730 	}
1731 	/*
1732 	 * Valid cN type name found.
1733 	 */
1734 	while (box_list != NULL) {
1735 		if ((strcmp((char *)s,
1736 			(char *)box_list->b_name)) == 0) {
1737 			found_box = 1;
1738 			if (p == NULL) {
1739 				if ((p = g_zalloc(strlen(
1740 				box_list->b_physical_path)
1741 				+ 2)) == NULL) {
1742 				(void) l_free_box_list(&box_list);
1743 				return (errno);
1744 				}
1745 			} else {
1746 				if ((pp = g_zalloc(strlen(
1747 				box_list->b_physical_path)
1748 				+ strlen(p)
1749 				+ 2)) == NULL) {
1750 				(void) l_free_box_list(&box_list);
1751 				return (errno);
1752 				}
1753 				(void) strcpy(pp, p);
1754 				(void) g_destroy_data(p);
1755 				p = pp;
1756 			}
1757 			(void) strcat(p, box_list->b_physical_path);
1758 			(void) strcat(p, "\n");
1759 		}
1760 		box_list = box_list->box_next;
1761 	}
1762 	if (found_box) {
1763 		D_DPRINTF("There is a conflict between the "
1764 			"enclosure\nwith this name, %s, "
1765 			"and a SSA name of the same form.\n"
1766 			"Please use one of the following physical "
1767 			"pathnames:\n%s\n%s\n",
1768 			s, *result, p);
1769 
1770 		(void) l_free_box_list(&box_list);
1771 		(void) g_destroy_data(p);
1772 		return (L_SSA_CONFLICT);	/* failure */
1773 	}
1774 	(void) l_free_box_list(&box_list);
1775 	return (0);
1776 }
1777 
1778 /*
1779  * This function sets the "slot", "slot_valid" and "f_flag" fields of the
1780  * path_struct that is passed in IFF the device path passed in ("phys_path")
1781  * is a disk in an A5K or a Daktari. This is achieved by calling l_get_slot().
1782  *
1783  * INPUT  :
1784  *	phys_path - physical path to a device
1785  *	path_sturct - Pointer to pointer to a path_struct data structure
1786  *
1787  * OUTPUT :
1788  *	if phys_path is that of an A5K/Daktari disk
1789  *		path_struct->slot is set to the slot position in enclosure
1790  *		path_struct->slot_valid is set to 1
1791  *		path_struct->f_flag is set to 1 if in the front of an A5k
1792  *			    or if among the first 6 disks on a Daktari
1793  *	else
1794  *		they are left as they were
1795  * RETURNS:
1796  *	0 on SUCCESS
1797  *	non-zero otherwise
1798  */
1799 static int
1800 load_flds_if_enc_disk(char *phys_path, struct path_struct **path_struct)
1801 {
1802 	int		err = 0, verbose = 0;
1803 	char		ses_path[MAXPATHLEN];
1804 	gfc_map_t	map;
1805 	L_inquiry	inq;
1806 	L_state		*l_state = NULL;
1807 
1808 	if ((path_struct == NULL) || (*path_struct == NULL) ||
1809 				(phys_path == NULL) || (*phys_path == NULL)) {
1810 		return (L_INVALID_PATH_FORMAT);
1811 	}
1812 
1813 	if ((strstr(phys_path, SLSH_DRV_NAME_SSD) == NULL) ||
1814 	    (g_get_path_type(phys_path) == 0)) {
1815 		/*
1816 		 * Don't proceed when not a disk device or if it is not a
1817 		 * valid FC device on which g_get_dev_map() can be done
1818 		 * (for example, g_get_dev_map() will fail on SSAs).
1819 		 *
1820 		 * Just return success
1821 		 */
1822 		return (0);
1823 	}
1824 
1825 	if ((*path_struct)->ib_path_flag) {
1826 		/*
1827 		 * If this flag is set, l_get_slot() should not be called
1828 		 * So, no point in proceeding. Just return success.
1829 		 */
1830 		return (0);
1831 	}
1832 
1833 	if ((err = g_get_dev_map(phys_path, &map, verbose)) != 0) {
1834 		return (err);
1835 	}
1836 
1837 	if ((err = l_get_ses_path(phys_path, ses_path, &map, verbose)) != 0) {
1838 		(void) free(map.dev_addr);
1839 		if (err == L_NO_SES_PATH) {
1840 			/*
1841 			 * This is not an error since this could be a device
1842 			 * which does not have SES nodes
1843 			 */
1844 			return (0);
1845 		}
1846 		return (err);
1847 	}
1848 
1849 	/*
1850 	 * There is a SES path on the same FCA as the given disk. But if the
1851 	 * SES node is not of a photon/Daktari, we dont proceed
1852 	 */
1853 	if ((err = g_get_inquiry(ses_path, &inq)) != 0) {
1854 		(void) free(map.dev_addr);
1855 		return (err);
1856 	}
1857 
1858 	/*
1859 	 * only want to continue if this is a photon or a Daktari
1860 	 *
1861 	 * if product ID is not SENA or VID is not "SUN" (checks for photon)
1862 	 * and if enclosure type is not a Daktari, then I return
1863 	 */
1864 	if (((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) ||
1865 		    (strncmp((char *)inq.inq_vid, "SUN     ",
1866 			sizeof (inq.inq_vid)) != 0)) &&
1867 	    ((l_get_enc_type(inq) != DAK_ENC_TYPE))) {
1868 		/* Not a photon/Daktari */
1869 		(void) free(map.dev_addr);
1870 		return (0);
1871 	}
1872 
1873 	/* Now, set some fields that l_get_slot() uses and then call it */
1874 	if ((l_state = (L_state *)g_zalloc(sizeof (L_state))) == NULL) {
1875 		(void) free(map.dev_addr);
1876 		return (L_MALLOC_FAILED);
1877 	}
1878 
1879 	if ((err = l_get_ib_status(ses_path, l_state, verbose)) != 0) {
1880 		(void) free(map.dev_addr);
1881 		(void) l_free_lstate(&l_state);
1882 		return (err);
1883 	}
1884 
1885 	if ((err = l_get_slot(*path_struct, l_state, verbose)) != 0) {
1886 		(void) free(map.dev_addr);
1887 		(void) l_free_lstate(&l_state);
1888 		return (err);
1889 	}
1890 
1891 	(void) free(map.dev_addr);
1892 	(void) l_free_lstate(&l_state);
1893 	return (0);
1894 }
1895 
1896 /*
1897  * convert box name or WWN or logical path to physical path.
1898  *
1899  *	OUTPUT:
1900  *		path_struct:
1901  *		- This structure is used to return more detailed
1902  *		  information about the path.
1903  *		- *p_physical_path
1904  *		  Normally this is the requested physical path.
1905  *		  If the requested path is not found then iff the
1906  *		  ib_path_flag is set this is the IB path.
1907  *		- *argv
1908  *		This is the argument variable input. e.g. Bob,f1
1909  *              - slot_valid
1910  *              - slot
1911  *		This is the slot number that was entered when using
1912  *		  the box,[fr]slot format. It is only valid if the
1913  *		  slot_valid flag is set.
1914  *		- f_flag
1915  *		  Front flag - If set, the requested device is located in the
1916  *		  front of the enclosure.
1917  *		- ib_path_flag
1918  *		  If this flag is set it means a devices path was requested
1919  *		  but could not be found but an IB's path was found and
1920  *		  the p_physical_path points to that path.
1921  *		- **phys_path
1922  *		  physical path to the device.
1923  *	RETURNS:
1924  *		- 0  if O.K.
1925  *		- error otherwise.
1926  */
1927 int
1928 l_convert_name(char *name, char **phys_path,
1929 		struct path_struct **path_struct, int verbose)
1930 {
1931 char		tmp_name[MAXPATHLEN], ses_path[MAXPATHLEN];
1932 char		*char_ptr, *ptr = NULL;
1933 char		*result = NULL;
1934 char		*env = NULL;
1935 char		save_frd;	    /* which designator was it? */
1936 int		slot = 0, slot_flag = 0, found_box = 0, found_comma = 0;
1937 int		err = 0, enc_type = 0;
1938 hrtime_t	start_time, end_time;
1939 Box_list	*box_list = NULL, *box_list_ptr = NULL;
1940 L_inquiry	inq;
1941 L_state		*l_state = NULL;
1942 Path_struct	*path_ptr = NULL;
1943 WWN_list	*wwn_list, *wwn_list_ptr;
1944 
1945 	if ((name == NULL) || (phys_path == NULL) ||
1946 	    (path_struct == NULL)) {
1947 		return (L_INVALID_PATH_FORMAT);
1948 	}
1949 
1950 	if ((env = getenv("_LUX_T_DEBUG")) != NULL) {
1951 		start_time = gethrtime();
1952 	}
1953 
1954 	if ((*path_struct = path_ptr = (struct path_struct *)
1955 		g_zalloc(sizeof (struct path_struct))) == NULL) {
1956 		return (L_MALLOC_FAILED);
1957 	}
1958 
1959 	*phys_path = NULL;
1960 	/*
1961 	 * If the path contains a "/" then assume
1962 	 * it is a logical or physical path as the
1963 	 * box name or wwn can not contain "/"s.
1964 	 */
1965 	if (strchr(name, '/') != NULL) {
1966 		if ((result = g_get_physical_name(name)) == NULL) {
1967 			return (L_NO_PHYS_PATH);
1968 		}
1969 
1970 		path_ptr->p_physical_path = result;
1971 		/*
1972 		 * Make sure it's a disk or tape path
1973 		 */
1974 		if (strstr(name, DEV_RDIR) || strstr(name, SLSH_DRV_NAME_SSD) ||
1975 			strstr(name, DEV_TAPE_DIR) ||
1976 			strstr(name, SLSH_DRV_NAME_ST)) {
1977 			if ((err = g_get_inquiry(result, &inq)) != 0) {
1978 				(void) free(result);
1979 				return (L_SCSI_ERROR);
1980 			}
1981 			/*
1982 			 * Check to see if it is not a
1983 			 * A5K/v880/v890 disk
1984 			 *
1985 			 */
1986 			if (!g_enclDiskChk((char *)inq.inq_vid,
1987 				    (char *)inq.inq_pid)) {
1988 				path_ptr->argv = name;
1989 				*phys_path = result;
1990 				return (0);
1991 			}
1992 		}
1993 
1994 		if (err = load_flds_if_enc_disk(result, path_struct)) {
1995 			(void) free(result);
1996 			return (err);
1997 		}
1998 		goto done;
1999 	}
2000 
2001 	(void) strcpy(tmp_name, name);
2002 	if ((tmp_name[0] == 'c') &&
2003 		((int)strlen(tmp_name) > 1) && ((int)strlen(tmp_name) < 5)) {
2004 		if ((err = l_get_conflict(tmp_name, &result, verbose)) != 0) {
2005 			if (result != NULL) {
2006 				(void) g_destroy_data(result);
2007 			}
2008 			return (err);
2009 		}
2010 		if (result != NULL) {
2011 			path_ptr->p_physical_path = result;
2012 			if ((err = g_get_inquiry(result, &inq)) != 0) {
2013 				(void) free(result);
2014 				return (L_SCSI_ERROR);
2015 			}
2016 			/*
2017 			 * Check to see if it is a supported
2018 			 * A5K/v880/v890 storage subsystem disk
2019 			 */
2020 			if (g_enclDiskChk((char *)inq.inq_vid,
2021 				    (char *)inq.inq_pid)) {
2022 				if (err = load_flds_if_enc_disk(
2023 					    result, path_struct)) {
2024 					(void) free(result);
2025 					return (err);
2026 				}
2027 			}
2028 			goto done;
2029 		}
2030 	}
2031 
2032 	/*
2033 	 * Check to see if we have a box or WWN name.
2034 	 *
2035 	 * If it contains a , then the format must be
2036 	 *    box_name,f1 where f is front and 1 is the slot number
2037 	 * or it is a format like
2038 	 * ssd@w2200002037049adf,0:h,raw
2039 	 * or
2040 	 * SUNW,pln@a0000000,77791d:ctlr
2041 	 */
2042 	if (((char_ptr = strstr(tmp_name, ",")) != NULL) &&
2043 		((*(char_ptr + 1) == 'f') || (*(char_ptr + 1) == 'r') ||
2044 		    (*(char_ptr + 1) == 's'))) {
2045 		char_ptr++;	/* point to f/r */
2046 		if ((*char_ptr == 'f') || (*char_ptr == 's')) {
2047 			path_ptr->f_flag = 1;
2048 		} else if (*char_ptr != 'r') {
2049 			return (L_INVALID_PATH_FORMAT);
2050 		}
2051 		save_frd = (char)*char_ptr;	/* save it */
2052 		char_ptr++;
2053 		slot = strtol(char_ptr, &ptr, 10);
2054 		/*
2055 		 * NOTE: Need to double check the slot when we get
2056 		 * the number of the devices actually in the box.
2057 		 */
2058 		if ((slot < 0) || (ptr == char_ptr) ||
2059 		    ((save_frd == 's' && slot >= MAX_DRIVES_DAK) ||
2060 		    ((save_frd != 's' && slot >= (MAX_DRIVES_PER_BOX/2))))) {
2061 			return (L_INVALID_SLOT);
2062 		}
2063 		/* Say slot valid. */
2064 		slot_flag = path_ptr->slot_valid = 1;
2065 		if (save_frd == 's' && slot >= (MAX_DRIVES_DAK/2)) {
2066 			path_ptr->slot = slot = slot % (MAX_DRIVES_DAK/2);
2067 			path_ptr->f_flag = 0;
2068 		} else
2069 			path_ptr->slot = slot;
2070 	}
2071 
2072 	if (((char_ptr = strstr(tmp_name, ",")) != NULL) &&
2073 		((*(char_ptr + 1) == 'f') || (*(char_ptr + 1) == 'r') ||
2074 		    (*(char_ptr + 1) == 's'))) {
2075 		*char_ptr = NULL; /* make just box name */
2076 		found_comma = 1;
2077 	}
2078 	/* Find path to IB */
2079 	if ((err = l_get_box_list(&box_list, verbose)) != 0) {
2080 		(void) l_free_box_list(&box_list);
2081 		return (err);
2082 	}
2083 	box_list_ptr = box_list;
2084 	/* Look for box name. */
2085 	while (box_list != NULL) {
2086 	    if ((strcmp((char *)tmp_name, (char *)box_list->b_name)) == 0) {
2087 			result =
2088 				g_alloc_string(box_list->b_physical_path);
2089 			L_DPRINTF("  l_convert_name:"
2090 			" Found subsystem: name %s  WWN %s\n",
2091 			box_list->b_name, box_list->b_node_wwn_s);
2092 			/*
2093 			 * Check for another box with this name.
2094 			 */
2095 			if (l_duplicate_names(box_list_ptr,
2096 				box_list->b_node_wwn_s,
2097 				(char *)box_list->b_name,
2098 				verbose)) {
2099 				(void) l_free_box_list(&box_list_ptr);
2100 				(void) g_destroy_data(result);
2101 				return (L_DUPLICATE_ENCLOSURES);
2102 			}
2103 			found_box = 1;
2104 			break;
2105 		}
2106 		box_list = box_list->box_next;
2107 	}
2108 	/*
2109 	 * Check to see if we must get individual disks path.
2110 	 */
2111 
2112 	if (found_box && slot_flag) {
2113 		if ((l_state = (L_state *)g_zalloc(sizeof (L_state))) == NULL) {
2114 			(void) g_destroy_data(result);
2115 			(void) l_free_box_list(&box_list_ptr);
2116 			return (L_MALLOC_FAILED);
2117 		}
2118 		(void) strcpy(ses_path, result);
2119 		if ((err = l_get_status(ses_path, l_state,
2120 			verbose)) != 0) {
2121 			(void) g_destroy_data(result);
2122 			(void) g_destroy_data(l_state);
2123 			(void) l_free_box_list(&box_list_ptr);
2124 			return (err);
2125 		}
2126 		/*
2127 		 * Now double check the slot number.
2128 		 */
2129 		if (slot >= l_state->total_num_drv/2) {
2130 			path_ptr->slot_valid = 0;
2131 			(void) g_destroy_data(result);
2132 			(void) l_free_box_list(&box_list_ptr);
2133 			(void) l_free_lstate(&l_state);
2134 			return (L_INVALID_SLOT);
2135 		}
2136 
2137 		/* Only allow the single slot version for Daktari */
2138 		if (g_get_inquiry(ses_path, &inq)) {
2139 		    return (L_SCSI_ERROR);
2140 		}
2141 		enc_type = l_get_enc_type(inq);
2142 		if (((enc_type == DAK_ENC_TYPE) && (save_frd != 's')) ||
2143 			((enc_type != DAK_ENC_TYPE) && (save_frd == 's'))) {
2144 			path_ptr->slot_valid = 0;
2145 			(void) g_destroy_data(result);
2146 			(void) l_free_box_list(&box_list_ptr);
2147 			(void) l_free_lstate(&l_state);
2148 			return (L_INVALID_SLOT);
2149 		}
2150 
2151 		if (path_ptr->f_flag) {
2152 		if (*l_state->drv_front[slot].g_disk_state.physical_path) {
2153 				result =
2154 	g_alloc_string(l_state->drv_front[slot].g_disk_state.physical_path);
2155 			} else {
2156 				/* Result is the IB path */
2157 				path_ptr->ib_path_flag = 1;
2158 				path_ptr->p_physical_path =
2159 					g_alloc_string(result);
2160 				(void) g_destroy_data(result);
2161 				result = NULL;
2162 			}
2163 		} else {
2164 		if (*l_state->drv_rear[slot].g_disk_state.physical_path) {
2165 				result =
2166 	g_alloc_string(l_state->drv_rear[slot].g_disk_state.physical_path);
2167 			} else {
2168 				/* Result is the IB path */
2169 				path_ptr->ib_path_flag = 1;
2170 				path_ptr->p_physical_path =
2171 					g_alloc_string(result);
2172 				(void) g_destroy_data(result);
2173 				result = NULL;
2174 			}
2175 		}
2176 		(void) l_free_lstate(&l_state);
2177 		goto done;
2178 	}
2179 	if (found_box || found_comma) {
2180 		goto done;
2181 	}
2182 	/*
2183 	 * No luck with the box name.
2184 	 *
2185 	 * Try WWN's
2186 	 */
2187 	/* Look for the SES's WWN */
2188 	box_list = box_list_ptr;
2189 	while (box_list != NULL) {
2190 		if (((strcasecmp((char *)tmp_name,
2191 			(char *)box_list->b_port_wwn_s)) == 0) ||
2192 			((strcasecmp((char *)tmp_name,
2193 			(char *)box_list->b_node_wwn_s)) == 0)) {
2194 				result =
2195 				g_alloc_string(box_list->b_physical_path);
2196 				L_DPRINTF("  l_convert_name:"
2197 				" Found subsystem using the WWN"
2198 				": name %s  WWN %s\n",
2199 				box_list->b_name, box_list->b_node_wwn_s);
2200 				goto done;
2201 		}
2202 		box_list = box_list->box_next;
2203 	}
2204 	/* Look for a device's WWN */
2205 	if (strlen(tmp_name) <= L_WWN_LENGTH) {
2206 		if ((err = g_get_wwn_list(&wwn_list, verbose)) != 0) {
2207 			(void) l_free_box_list(&box_list_ptr);
2208 			return (err);
2209 		}
2210 		for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL;
2211 				wwn_list_ptr = wwn_list_ptr->wwn_next) {
2212 			if (((strcasecmp((char *)tmp_name,
2213 				(char *)wwn_list_ptr->node_wwn_s)) == 0) ||
2214 				((strcasecmp((char *)tmp_name,
2215 				(char *)wwn_list_ptr->port_wwn_s)) == 0)) {
2216 			/*
2217 			 * Found the device's WWN in the global WWN list.
2218 			 * It MAY be in a photon/Daktari. If it is, we'll set
2219 			 * additional fields in path_struct.
2220 			 */
2221 			result = g_alloc_string(wwn_list_ptr->physical_path);
2222 			L_DPRINTF("  l_convert_name:"
2223 					"  Found device: WWN %s Path %s\n",
2224 					tmp_name, wwn_list_ptr->logical_path);
2225 
2226 			(void) g_free_wwn_list(&wwn_list);
2227 
2228 			/*
2229 			 * Now check if it is a disk in an A5K and set
2230 			 * path_struct fields
2231 			 */
2232 			path_ptr->p_physical_path = result;
2233 			if ((err = g_get_inquiry(result, &inq)) != 0) {
2234 				(void) free(result);
2235 				return (L_SCSI_ERROR);
2236 			}
2237 			/*
2238 			 * Check to see if it is a supported
2239 			 * A5K/v880/v890 storage subsystem disk
2240 			 */
2241 			if (g_enclDiskChk((char *)inq.inq_vid,
2242 				    (char *)inq.inq_pid)) {
2243 				if (err = load_flds_if_enc_disk(
2244 					    result, path_struct)) {
2245 					(void) free(result);
2246 					return (err);
2247 				}
2248 			}
2249 			goto done;
2250 		    }
2251 		}
2252 	}
2253 
2254 	/*
2255 	 * Try again in case we were in the /dev
2256 	 * or /devices directory.
2257 	 */
2258 	result = g_get_physical_name(name);
2259 
2260 done:
2261 	(void) l_free_box_list(&box_list_ptr);
2262 	path_ptr->argv = name;
2263 	if (result == NULL) {
2264 		if (!path_ptr->ib_path_flag)
2265 			return (-1);
2266 	} else {
2267 		path_ptr->p_physical_path = result;
2268 	}
2269 
2270 	L_DPRINTF("  l_convert_name: path_struct:\n\tphysical_path:\n\t %s\n"
2271 		"\targv:\t\t%s"
2272 		"\n\tslot_valid\t%d"
2273 		"\n\tslot\t\t%d"
2274 		"\n\tf_flag\t\t%d"
2275 		"\n\tib_path_flag\t%d\n",
2276 		path_ptr->p_physical_path,
2277 		path_ptr->argv,
2278 		path_ptr->slot_valid,
2279 		path_ptr->slot,
2280 		path_ptr->f_flag,
2281 		path_ptr->ib_path_flag);
2282 	if (env != NULL) {
2283 		end_time = gethrtime();
2284 		(void) fprintf(stdout, "  l_convert_name: "
2285 		"Time = %lld millisec\n",
2286 		(end_time - start_time)/1000000);
2287 	}
2288 
2289 	if (path_ptr->ib_path_flag)
2290 		return (-1);
2291 	*phys_path = result;
2292 	return (0);
2293 }
2294 
2295 
2296 /*
2297  * Gets envsen information of an enclosure from IB
2298  *
2299  * RETURNS:
2300  *	0	 O.K.
2301  *	non-zero otherwise
2302  */
2303 int
2304 l_get_envsen_page(int fd, uchar_t *buf, int buf_size, uchar_t page_code,
2305 	int verbose)
2306 {
2307 Rec_diag_hdr	hdr;
2308 uchar_t	*pg;
2309 int	size, new_size, status;
2310 
2311 	if (buf == NULL) {
2312 		return (L_INVALID_BUF_LEN);
2313 	}
2314 
2315 	if (verbose) {
2316 		(void) fprintf(stdout,
2317 		MSGSTR(9046, "  Reading SES page %x\n"), page_code);
2318 	}
2319 
2320 	(void) memset(&hdr, 0, sizeof (struct rec_diag_hdr));
2321 	if (status = g_scsi_rec_diag_cmd(fd, (uchar_t *)&hdr,
2322 		sizeof (struct rec_diag_hdr), page_code)) {
2323 		return (status);
2324 	}
2325 
2326 	/* Check */
2327 	if ((hdr.page_code != page_code) || (hdr.page_len == 0)) {
2328 		return (L_RD_PG_INVLD_CODE);
2329 	}
2330 	size = HEADER_LEN + hdr.page_len;
2331 	/*
2332 	 * Because of a hardware restriction in the soc+ chip
2333 	 * the transfers must be word aligned.
2334 	 */
2335 	while (size & 0x03) {
2336 		size++;
2337 		if (size > buf_size) {
2338 			return (L_RD_PG_MIN_BUFF);
2339 		}
2340 		P_DPRINTF("  l_get_envsen_page: Adjusting size of the "
2341 			"g_scsi_rec_diag_cmd buffer.\n");
2342 	}
2343 
2344 	if ((pg = (uchar_t *)g_zalloc(size)) == NULL) {
2345 		return (L_MALLOC_FAILED);
2346 	}
2347 
2348 	P_DPRINTF("  l_get_envsen_page: Reading page %x of size 0x%x\n",
2349 		page_code, size);
2350 	if (status = g_scsi_rec_diag_cmd(fd, pg, size, page_code)) {
2351 		(void) g_destroy_data((char *)pg);
2352 		return (status);
2353 	}
2354 
2355 	new_size = MIN(size, buf_size);
2356 	bcopy((const void *)pg, (void *)buf, (size_t)new_size);
2357 
2358 	(void) g_destroy_data(pg);
2359 	return (0);
2360 }
2361 
2362 
2363 
2364 /*
2365  * Get consolidated copy of all environmental information
2366  * into buf structure.
2367  *
2368  * RETURNS:
2369  *	0	 O.K.
2370  *	non-zero otherwise
2371  */
2372 
2373 int
2374 l_get_envsen(char *path_phys, uchar_t *buf, int size, int verbose)
2375 {
2376 int		fd, rval;
2377 uchar_t		*page_list_ptr, page_code, *local_buf_ptr = buf;
2378 Rec_diag_hdr	*hdr = (struct rec_diag_hdr *)(void *)buf;
2379 ushort_t	num_pages;
2380 
2381 	if ((path_phys == NULL) || (buf == NULL)) {
2382 		return (L_INVALID_PATH_FORMAT);
2383 	}
2384 
2385 	page_code = L_PAGE_PAGE_LIST;
2386 
2387 	/* open IB */
2388 	if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1)
2389 		return (L_OPEN_PATH_FAIL);
2390 
2391 	P_DPRINTF("  l_get_envsen: Getting list of supported"
2392 		" pages from IB\n");
2393 	if (verbose) {
2394 		(void) fprintf(stdout,
2395 		MSGSTR(9047, "  Getting list of supported pages from IB\n"));
2396 	}
2397 
2398 	/* Get page 0 */
2399 	if ((rval = l_get_envsen_page(fd, local_buf_ptr,
2400 		size, page_code, verbose)) != NULL) {
2401 		(void) close(fd);
2402 		return (rval);
2403 	}
2404 
2405 	page_list_ptr = buf + HEADER_LEN + 1; /* +1 to skip page 0 */
2406 
2407 	num_pages = hdr->page_len - 1;
2408 
2409 	/*
2410 	 * check whether the number of pages received
2411 	 * from IB are valid. SENA enclosure
2412 	 * supports only 8 pages of sense information.
2413 	 * According to SES specification dpANS X3.xxx-1997
2414 	 * X3T10/Project 1212-D/Rev 8a, the enclosure supported
2415 	 * pages can go upto L_MAX_POSSIBLE_PAGES (0xFF).
2416 	 * Return an error if no. of pages exceeds L_MAX_POSSIBLE_PAGES.
2417 	 * See if (num_pages >= L_MAX_POSSIBLE_PAGES) since 1 page (page 0)
2418 	 * was already subtracted from the total number of pages before.
2419 	 */
2420 	if (num_pages < 1 || num_pages >= L_MAX_POSSIBLE_PAGES) {
2421 		return (L_INVALID_NO_OF_ENVSEN_PAGES);
2422 	}
2423 	/*
2424 	 * Buffer size of MAX_REC_DIAG_LENGTH can be small if the
2425 	 * number of pages exceed more than L_MAX_SENAIB_PAGES
2426 	 * but less than L_MAX_POSSIBLE_PAGES.
2427 	 */
2428 	if (size == MAX_REC_DIAG_LENGTH &&
2429 			num_pages >= L_MAX_SENAIB_PAGES) {
2430 		return (L_INVALID_BUF_LEN);
2431 	}
2432 	/* Align buffer */
2433 	while (hdr->page_len & 0x03) {
2434 		hdr->page_len++;
2435 	}
2436 	local_buf_ptr += HEADER_LEN + hdr->page_len;
2437 
2438 	/*
2439 	 * Getting all pages and appending to buf
2440 	 */
2441 	for (; num_pages--; page_list_ptr++) {
2442 		/*
2443 		 * The fifth byte of page 0 is the start
2444 		 * of the list of pages not including page 0.
2445 		 */
2446 		page_code = *page_list_ptr;
2447 
2448 		if ((rval = l_get_envsen_page(fd, local_buf_ptr,
2449 			size, page_code, verbose)) != NULL) {
2450 			(void) close(fd);
2451 			return (rval);
2452 		}
2453 		hdr = (struct rec_diag_hdr *)(void *)local_buf_ptr;
2454 		local_buf_ptr += HEADER_LEN + hdr->page_len;
2455 	}
2456 
2457 	(void) close(fd);
2458 	return (0);
2459 }
2460 
2461 
2462 
2463 /*
2464  * Get the individual disk status.
2465  * Path must be physical and point to a disk.
2466  *
2467  * This function updates the d_state_flags, port WWN's
2468  * and num_blocks for all accessiable ports
2469  * in l_disk_state->g_disk_state structure.
2470  *
2471  * RETURNS:
2472  *	0	 O.K.
2473  *	non-zero otherwise
2474  */
2475 int
2476 l_get_disk_status(char *path, struct l_disk_state_struct *l_disk_state,
2477 	WWN_list *wwn_list, int verbose)
2478 {
2479 struct dlist	*ml;
2480 char		path_a[MAXPATHLEN], path_b[MAXPATHLEN], ses_path[MAXPATHLEN];
2481 gfc_map_t	map;
2482 int		path_a_found = 0, path_b_found = 0, local_port_a_flag;
2483 uchar_t		node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
2484 int		al_pa, err, pathcnt = 1;
2485 int		i = 0;
2486 char		temppath[MAXPATHLEN];
2487 mp_pathlist_t	pathlist;
2488 char		pwwn[WWN_S_LEN];
2489 struct		stat sbuf;
2490 
2491 	if ((path == NULL) || (l_disk_state == NULL)) {
2492 		return (L_INVALID_PATH_FORMAT);
2493 	}
2494 
2495 	/* Check device name */
2496 	if (stat(path, &sbuf) || (sbuf.st_rdev == NODEV)) {
2497 		G_DPRINTF("  l_get_disk_status: invalid device %s\n", path);
2498 		return (L_INVALID_PATH);
2499 	}
2500 
2501 	/* Initialize */
2502 	*path_a = *path_b = NULL;
2503 	l_disk_state->g_disk_state.num_blocks = 0;
2504 
2505 	/* Get paths. */
2506 	g_get_multipath(path,
2507 		&(l_disk_state->g_disk_state.multipath_list),
2508 		wwn_list, verbose);
2509 	ml = l_disk_state->g_disk_state.multipath_list;
2510 	if (ml == NULL) {
2511 		l_disk_state->l_state_flag = L_NO_PATH_FOUND;
2512 		G_DPRINTF("  l_get_disk_status: Error finding a "
2513 			"multipath to the disk.\n");
2514 		return (0);
2515 	}
2516 
2517 	if (strstr(path, SCSI_VHCI) != NULL) {
2518 		/*
2519 		 * It is an MPXIO Path
2520 		 */
2521 		(void) strcpy(temppath, path);
2522 		if (g_get_pathlist(temppath, &pathlist)) {
2523 			return (0);
2524 		}
2525 		pathcnt = pathlist.path_count;
2526 		for (i = 0; i < pathcnt; i++) {
2527 			/*
2528 			 * Skip inactive paths.
2529 			 * A path that is not in either
2530 			 * MDI_PATHINFO_STATE_ONLINE or
2531 			 * MDI_PATHINFO_STATE_STANDBY state is not
2532 			 * an active path.
2533 			 *
2534 			 * When a disk port is bypassed and mpxio is
2535 			 * enabled, the path_state for that path goes to the
2536 			 * offline state
2537 			 */
2538 			if (pathlist.path_info[i].path_state !=
2539 			    MDI_PATHINFO_STATE_ONLINE &&
2540 			    pathlist.path_info[i].path_state !=
2541 			    MDI_PATHINFO_STATE_STANDBY) {
2542 				continue;
2543 			}
2544 			(void) strncpy(pwwn, pathlist.path_info[i].path_addr,
2545 								L_WWN_LENGTH);
2546 			pwwn[L_WWN_LENGTH] = '\0';
2547 			if (!(path_a_found || path_b_found)) {
2548 				if (pwwn[1] == '1') {
2549 					local_port_a_flag = 1;
2550 				} else {
2551 					local_port_a_flag = 0;
2552 				}
2553 			} else if (path_a_found &&
2554 				(strstr(l_disk_state->g_disk_state.port_a_wwn_s,
2555 							pwwn) == NULL)) {
2556 				/* do port b */
2557 				local_port_a_flag = 0;
2558 			} else if (path_b_found &&
2559 				(strstr(l_disk_state->g_disk_state.port_b_wwn_s,
2560 							pwwn) == NULL)) {
2561 				/* do port a */
2562 				local_port_a_flag = 1;
2563 			}
2564 
2565 			if (err = l_get_disk_port_status(path,
2566 				l_disk_state, local_port_a_flag, verbose)) {
2567 				return (err);
2568 			}
2569 
2570 			if (local_port_a_flag && (!path_a_found)) {
2571 				(void) strcpy(l_disk_state->
2572 					g_disk_state.port_a_wwn_s, pwwn);
2573 				l_disk_state->g_disk_state.port_a_valid++;
2574 				path_a_found++;
2575 			}
2576 
2577 			if ((!local_port_a_flag) && (!path_b_found)) {
2578 				(void) strcpy(l_disk_state->
2579 					g_disk_state.port_b_wwn_s, pwwn);
2580 				l_disk_state->g_disk_state.port_b_valid++;
2581 				path_b_found++;
2582 			}
2583 		}
2584 		free(pathlist.path_info);
2585 		return (0);
2586 	}
2587 
2588 	while (ml && (!(path_a_found && path_b_found))) {
2589 		if (err = g_get_dev_map(ml->dev_path, &map, verbose)) {
2590 			(void) g_free_multipath(ml);
2591 			return (err);
2592 		}
2593 		if ((err = l_get_ses_path(ml->dev_path, ses_path,
2594 			&map, verbose)) != 0) {
2595 			(void) g_free_multipath(ml);
2596 			free((void *)map.dev_addr);
2597 			return (err);
2598 		}
2599 		free((void *)map.dev_addr);	/* Not used anymore */
2600 
2601 		/*
2602 		 * Get the port, A or B, of the disk,
2603 		 * by passing the IB path.
2604 		 */
2605 		if (err = l_get_port(ses_path, &local_port_a_flag, verbose)) {
2606 			(void) g_free_multipath(ml);
2607 			return (err);
2608 		}
2609 		if (local_port_a_flag && (!path_a_found)) {
2610 			G_DPRINTF("  l_get_disk_status: Path to Port A "
2611 				"found: %s\n", ml->dev_path);
2612 			if (err = l_get_disk_port_status(ml->dev_path,
2613 				l_disk_state, local_port_a_flag, verbose)) {
2614 				(void) g_free_multipath(ml);
2615 				return (err);
2616 			}
2617 			if (err = g_get_wwn(ml->dev_path,
2618 				port_wwn, node_wwn,
2619 				&al_pa, verbose)) {
2620 				(void) g_free_multipath(ml);
2621 				return (err);
2622 			}
2623 			(void) sprintf(l_disk_state->g_disk_state.port_a_wwn_s,
2624 			"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
2625 			port_wwn[0], port_wwn[1], port_wwn[2], port_wwn[3],
2626 			port_wwn[4], port_wwn[5], port_wwn[6], port_wwn[7]);
2627 
2628 			l_disk_state->g_disk_state.port_a_valid++;
2629 			path_a_found++;
2630 		}
2631 		if ((!local_port_a_flag) && (!path_b_found)) {
2632 			G_DPRINTF("  l_get_disk_status: Path to Port B "
2633 				"found: %s\n", ml->dev_path);
2634 			if (err = l_get_disk_port_status(ml->dev_path,
2635 				l_disk_state, local_port_a_flag, verbose)) {
2636 				return (err);
2637 			}
2638 			if (err = g_get_wwn(ml->dev_path,
2639 				port_wwn, node_wwn,
2640 				&al_pa, verbose)) {
2641 				(void) g_free_multipath(ml);
2642 				return (err);
2643 			}
2644 			(void) sprintf(l_disk_state->g_disk_state.port_b_wwn_s,
2645 			"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
2646 			port_wwn[0], port_wwn[1], port_wwn[2], port_wwn[3],
2647 			port_wwn[4], port_wwn[5], port_wwn[6], port_wwn[7]);
2648 
2649 			l_disk_state->g_disk_state.port_b_valid++;
2650 			path_b_found++;
2651 		}
2652 		ml = ml->next;
2653 	}
2654 	return (0);
2655 
2656 
2657 }
2658 
2659 
2660 
2661 /*
2662  * Check for Persistent Reservations.
2663  */
2664 int
2665 l_persistent_check(int fd, struct l_disk_state_struct *l_disk_state,
2666 	int verbose)
2667 {
2668 int	status;
2669 Read_keys	read_key_buf;
2670 Read_reserv	read_reserv_buf;
2671 
2672 	(void) memset(&read_key_buf, 0, sizeof (struct  read_keys_struct));
2673 	if ((status = g_scsi_persistent_reserve_in_cmd(fd,
2674 		(uchar_t *)&read_key_buf, sizeof (struct  read_keys_struct),
2675 		ACTION_READ_KEYS))) {
2676 		return (status);
2677 	}
2678 	/* This means persistent reservations are supported by the disk. */
2679 	l_disk_state->g_disk_state.persistent_reserv_flag = 1;
2680 
2681 	if (read_key_buf.rk_length) {
2682 		l_disk_state->g_disk_state.persistent_registered = 1;
2683 	}
2684 
2685 	(void) memset(&read_reserv_buf, 0,
2686 			sizeof (struct  read_reserv_struct));
2687 	if ((status = g_scsi_persistent_reserve_in_cmd(fd,
2688 		(uchar_t *)&read_reserv_buf,
2689 		sizeof (struct  read_reserv_struct),
2690 		ACTION_READ_RESERV))) {
2691 		return (status);
2692 	}
2693 	if (read_reserv_buf.rr_length) {
2694 		l_disk_state->g_disk_state.persistent_active = 1;
2695 	}
2696 	if (verbose) {
2697 		(void) fprintf(stdout,
2698 		MSGSTR(9048, "  Checking for Persistent "
2699 			"Reservations:"));
2700 		if (l_disk_state->g_disk_state.persistent_reserv_flag) {
2701 		    if (l_disk_state->g_disk_state.persistent_active != NULL) {
2702 			(void) fprintf(stdout, MSGSTR(39, "Active"));
2703 		    } else {
2704 			(void) fprintf(stdout, MSGSTR(9049, "Registered"));
2705 		    }
2706 		} else {
2707 			(void) fprintf(stdout,
2708 			MSGSTR(87,
2709 			"Not being used"));
2710 		}
2711 		(void) fprintf(stdout, "\n");
2712 	}
2713 	return (0);
2714 }
2715 
2716 
2717 
2718 /*
2719  * Gets the disk status and
2720  * updates the l_disk_state_struct structure.
2721  * Checks for open fail, Reservation Conflicts,
2722  * Not Ready and so on.
2723  *
2724  * RETURNS:
2725  *	0	 O.K.
2726  *	non-zero otherwise
2727  */
2728 int
2729 l_get_disk_port_status(char *path, struct l_disk_state_struct *l_disk_state,
2730 	int port_a_flag, int verbose)
2731 {
2732 int		fd, status = 0, local_state = 0;
2733 Read_capacity_data	capacity;	/* local read capacity buffer */
2734 struct vtoc	vtoc;
2735 
2736 	if ((path == NULL) || (l_disk_state == NULL)) {
2737 		return (L_INVALID_PATH_FORMAT);
2738 	}
2739 
2740 	/*
2741 	 * Try to open drive.
2742 	 */
2743 	if ((fd = g_object_open(path, O_RDONLY)) == -1) {
2744 	    if ((fd = g_object_open(path,
2745 		O_RDONLY | O_NDELAY)) == -1) {
2746 		G_DPRINTF("  l_get_disk_port_status: Error "
2747 			"opening drive %s\n", path);
2748 		local_state = L_OPEN_FAIL;
2749 	    } else {
2750 		/* See if drive ready */
2751 		if (status = g_scsi_tur(fd)) {
2752 			if ((status & L_SCSI_ERROR) &&
2753 				((status & ~L_SCSI_ERROR) == STATUS_CHECK)) {
2754 				/*
2755 				 * TBD
2756 				 * This is where I should figure out
2757 				 * if the device is Not Ready or whatever.
2758 				 */
2759 				local_state = L_NOT_READY;
2760 			} else if ((status & L_SCSI_ERROR) &&
2761 			    ((status & ~L_SCSI_ERROR) ==
2762 			    STATUS_RESERVATION_CONFLICT)) {
2763 			    /* mark reserved */
2764 			    local_state = L_RESERVED;
2765 			} else {
2766 				local_state = L_SCSI_ERR;
2767 			}
2768 
2769 		/*
2770 		 * There may not be a label on the drive - check
2771 		 */
2772 		} else if (ioctl(fd, DKIOCGVTOC, &vtoc) == 0) {
2773 			/*
2774 			 * Sanity-check the vtoc
2775 			 */
2776 		    if (vtoc.v_sanity != VTOC_SANE ||
2777 			vtoc.v_sectorsz != DEV_BSIZE) {
2778 			local_state = L_NO_LABEL;
2779 			G_DPRINTF("  l_get_disk_port_status: "
2780 				"Checking vtoc - No Label found.\n");
2781 		    }
2782 		} else if (errno != ENOTSUP) {
2783 		    I_DPRINTF("\t- DKIOCGVTOC ioctl failed: "
2784 		    " invalid geometry\n");
2785 		    local_state = L_NO_LABEL;
2786 		}
2787 	    }
2788 	}
2789 	/*
2790 	 * Need an extra check for tape devices
2791 	 * read capacity should not be run on tape devices.
2792 	 * It will always return Not Readable
2793 	 */
2794 	if (((local_state == 0) || (local_state == L_NO_LABEL)) &&
2795 		! (strstr(path, SLSH_DRV_NAME_ST))) {
2796 
2797 	    if (status = g_scsi_read_capacity_cmd(fd, (uchar_t *)&capacity,
2798 		sizeof (capacity))) {
2799 			G_DPRINTF("  l_get_disk_port_status: "
2800 				"Read Capacity failed.\n");
2801 		if (status & L_SCSI_ERROR) {
2802 		    if ((status & ~L_SCSI_ERROR) ==
2803 			STATUS_RESERVATION_CONFLICT) {
2804 			/* mark reserved */
2805 			local_state |= L_RESERVED;
2806 		    } else
2807 			/* mark bad */
2808 			local_state |= L_NOT_READABLE;
2809 		} else {
2810 			/*
2811 			 * TBD
2812 			 * Need a more complete state definition here.
2813 			 */
2814 			l_disk_state->g_disk_state.d_state_flags[port_a_flag] =
2815 								L_SCSI_ERR;
2816 			(void) close(fd);
2817 			return (0);
2818 		}
2819 	    } else {
2820 		/* save capacity */
2821 		l_disk_state->g_disk_state.num_blocks =
2822 					capacity.last_block_addr + 1;
2823 	    }
2824 
2825 	}
2826 	(void) close(fd);
2827 
2828 	l_disk_state->g_disk_state.d_state_flags[port_a_flag] = local_state;
2829 	G_DPRINTF("  l_get_disk_port_status: Individual Disk"
2830 		" Status: 0x%x for"
2831 		" port %s for path:"
2832 		" %s\n", local_state,
2833 		port_a_flag ? "A" : "B", path);
2834 
2835 	return (0);
2836 }
2837 
2838 
2839 
2840 /*
2841  * Copy and format page 1 from big buffer to state structure.
2842  *
2843  * RETURNS:
2844  *	0	 O.K.
2845  *	non-zero otherwise
2846  */
2847 
2848 static int
2849 copy_config_page(struct l_state_struct *l_state, uchar_t *from_ptr)
2850 {
2851 IB_page_config	*encl_ptr;
2852 int		size, i;
2853 
2854 
2855 	encl_ptr = (struct ib_page_config *)(void *)from_ptr;
2856 
2857 	/* Sanity check. */
2858 	if ((encl_ptr->enc_len > MAX_VEND_SPECIFIC_ENC) ||
2859 		(encl_ptr->enc_len == 0)) {
2860 		return (L_REC_DIAG_PG1);
2861 	}
2862 	if ((encl_ptr->enc_num_elem > MAX_IB_ELEMENTS) ||
2863 		(encl_ptr->enc_num_elem == 0)) {
2864 		return (L_REC_DIAG_PG1);
2865 	}
2866 
2867 	size = HEADER_LEN + 4 + HEADER_LEN + encl_ptr->enc_len;
2868 	bcopy((void *)(from_ptr),
2869 		(void *)&l_state->ib_tbl.config, (size_t)size);
2870 	/*
2871 	 * Copy Type Descriptors seperately to get aligned.
2872 	 */
2873 	from_ptr += size;
2874 	size = (sizeof (struct	type_desc_hdr))*encl_ptr->enc_num_elem;
2875 	bcopy((void *)(from_ptr),
2876 		(void *)&l_state->ib_tbl.config.type_hdr, (size_t)size);
2877 
2878 	/*
2879 	 * Copy Text Descriptors seperately to get aligned.
2880 	 *
2881 	 * Must use the text size from the Type Descriptors.
2882 	 */
2883 	from_ptr += size;
2884 	for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) {
2885 		size = l_state->ib_tbl.config.type_hdr[i].text_len;
2886 		bcopy((void *)(from_ptr),
2887 			(void *)&l_state->ib_tbl.config.text[i], (size_t)size);
2888 		from_ptr += size;
2889 	}
2890 	return (0);
2891 }
2892 
2893 
2894 
2895 /*
2896  * Copy page 7 (Element Descriptor page) to state structure.
2897  * Copy header then copy each element descriptor
2898  * seperately.
2899  *
2900  * RETURNS:
2901  *	0	 O.K.
2902  *	non-zero otherwise
2903  */
2904 static void
2905 copy_page_7(struct l_state_struct *l_state, uchar_t *from_ptr)
2906 {
2907 uchar_t	*my_from_ptr;
2908 int	size, j, k, p7_index;
2909 
2910 	size = HEADER_LEN +
2911 		sizeof (l_state->ib_tbl.p7_s.gen_code);
2912 	bcopy((void *)(from_ptr),
2913 		(void *)&l_state->ib_tbl.p7_s, (size_t)size);
2914 	my_from_ptr = from_ptr + size;
2915 	if (getenv("_LUX_D_DEBUG") != NULL) {
2916 		g_dump("  copy_page_7: Page 7 header:  ",
2917 		(uchar_t *)&l_state->ib_tbl.p7_s, size,
2918 		HEX_ASCII);
2919 		(void) fprintf(stdout,
2920 			"  copy_page_7: Elements being stored "
2921 			"in state table\n"
2922 			"              ");
2923 	}
2924 	/* I am assuming page 1 has been read. */
2925 	for (j = 0, p7_index = 0;
2926 		j < (int)l_state->ib_tbl.config.enc_num_elem; j++) {
2927 		/* Copy global element */
2928 		size = HEADER_LEN +
2929 			((*(my_from_ptr + 2) << 8) | *(my_from_ptr + 3));
2930 		bcopy((void *)(my_from_ptr),
2931 		(void *)&l_state->ib_tbl.p7_s.element_desc[p7_index++],
2932 			(size_t)size);
2933 		my_from_ptr += size;
2934 		for (k = 0; k < (int)l_state->ib_tbl.config.type_hdr[j].num;
2935 			k++) {
2936 			/* Copy individual elements */
2937 			size = HEADER_LEN +
2938 				((*(my_from_ptr + 2) << 8) |
2939 					*(my_from_ptr + 3));
2940 			bcopy((void *)(my_from_ptr),
2941 			(void *)&l_state->ib_tbl.p7_s.element_desc[p7_index++],
2942 				(size_t)size);
2943 			my_from_ptr += size;
2944 			D_DPRINTF(".");
2945 		}
2946 	}
2947 	D_DPRINTF("\n");
2948 }
2949 
2950 
2951 /*
2952  * Gets IB diagnostic pages on a given pathname from l_get_envsen().
2953  * It also fills up the individual device element of l_state_struct using
2954  * diagnostics pages.
2955  * Gets IB diagnostic pages on a given pathname from l_get_envsen().
2956  * It also fills up the individual device element of l_state_struct using
2957  * diagnostics pages.
2958  *
2959  * The path must be of the ses driver.
2960  * e.g.
2961  * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
2962  * or
2963  * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@WWN,0:0
2964  *
2965  *
2966  * RETURNS:
2967  *	0	 O.K.
2968  *	non-zero otherwise
2969  */
2970 int
2971 l_get_ib_status(char *path, struct l_state_struct *l_state,
2972 	int verbose)
2973 {
2974 L_inquiry	inq;
2975 uchar_t		*ib_buf, *from_ptr;
2976 int		num_pages, i, size, err;
2977 IB_page_2	*encl_ptr;
2978 int		front_index, rear_index;
2979 int		enc_type = 0;
2980 
2981 	if ((path == NULL) || (l_state == NULL)) {
2982 		return (L_INVALID_PATH_FORMAT);
2983 	}
2984 
2985 	/*
2986 	 * get big buffer
2987 	 */
2988 	if ((ib_buf = (uchar_t *)calloc(1,
2989 				MAX_REC_DIAG_LENGTH)) == NULL) {
2990 		return (L_MALLOC_FAILED);
2991 	}
2992 
2993 	/*
2994 	 * Get IB information
2995 	 * Even if there are 2 IB's in this box on this loop don't bother
2996 	 * talking to the other one as both IB's in a box
2997 	 * are supposed to report the same information.
2998 	 */
2999 	if (err = l_get_envsen(path, ib_buf, MAX_REC_DIAG_LENGTH,
3000 		verbose)) {
3001 		(void) g_destroy_data(ib_buf);
3002 		return (err);
3003 	}
3004 
3005 	/*
3006 	 * Set up state structure
3007 	 */
3008 	bcopy((void *)ib_buf, (void *)&l_state->ib_tbl.p0,
3009 		(size_t)sizeof (struct  ib_page_0));
3010 
3011 	num_pages = l_state->ib_tbl.p0.page_len;
3012 	from_ptr = ib_buf + HEADER_LEN + l_state->ib_tbl.p0.page_len;
3013 
3014 	for (i = 1; i < num_pages; i++) {
3015 		if (l_state->ib_tbl.p0.sup_page_codes[i] == L_PAGE_1) {
3016 			if (err = copy_config_page(l_state, from_ptr)) {
3017 				return (err);
3018 			}
3019 		} else if (l_state->ib_tbl.p0.sup_page_codes[i] ==
3020 								L_PAGE_2) {
3021 			encl_ptr = (struct ib_page_2 *)(void *)from_ptr;
3022 			size = HEADER_LEN + encl_ptr->page_len;
3023 			bcopy((void *)(from_ptr),
3024 				(void *)&l_state->ib_tbl.p2_s, (size_t)size);
3025 			if (getenv("_LUX_D_DEBUG") != NULL) {
3026 				g_dump("  l_get_ib_status: Page 2:  ",
3027 				(uchar_t *)&l_state->ib_tbl.p2_s, size,
3028 				HEX_ONLY);
3029 			}
3030 
3031 		} else if (l_state->ib_tbl.p0.sup_page_codes[i] ==
3032 								L_PAGE_7) {
3033 			(void) copy_page_7(l_state, from_ptr);
3034 		}
3035 		from_ptr += ((*(from_ptr + 2) << 8) | *(from_ptr + 3));
3036 		from_ptr += HEADER_LEN;
3037 	}
3038 	(void) g_destroy_data(ib_buf);
3039 	G_DPRINTF("  l_get_ib_status: Read %d Receive Diagnostic pages "
3040 		"from the IB.\n", num_pages);
3041 
3042 	if (err = g_get_inquiry(path, &inq)) {
3043 		return (err);
3044 	}
3045 	enc_type = l_get_enc_type(inq);
3046 	/*
3047 	 * Get the total number of drives per box.
3048 	 * This assumes front & rear are the same.
3049 	 */
3050 	l_state->total_num_drv = 0; /* default to use as a flag */
3051 	for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) {
3052 		if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_DD) {
3053 			if (l_state->total_num_drv) {
3054 				if (l_state->total_num_drv !=
3055 				(l_state->ib_tbl.config.type_hdr[i].num * 2)) {
3056 					return (L_INVALID_NUM_DISKS_ENCL);
3057 				}
3058 			} else {
3059 				if (enc_type == DAK_ENC_TYPE) {
3060 				    l_state->total_num_drv =
3061 				    l_state->ib_tbl.config.type_hdr[i].num;
3062 				} else {
3063 				    l_state->total_num_drv =
3064 				    l_state->ib_tbl.config.type_hdr[i].num * 2;
3065 				}
3066 			}
3067 		}
3068 	}
3069 
3070 	/*
3071 	 * transfer the individual drive Device Element information
3072 	 * from IB state to drive state.
3073 	 */
3074 	if (err = l_get_disk_element_index(l_state, &front_index,
3075 		&rear_index)) {
3076 		return (err);
3077 	}
3078 	/* Skip global element */
3079 	front_index++;
3080 	if (enc_type == DAK_ENC_TYPE) {
3081 		rear_index += l_state->total_num_drv/2 + 1;
3082 	} else {
3083 		rear_index++;
3084 	}
3085 
3086 	for (i = 0; i < l_state->total_num_drv/2; i++) {
3087 		bcopy((void *)&l_state->ib_tbl.p2_s.element[front_index + i],
3088 			(void *)&l_state->drv_front[i].ib_status,
3089 			(size_t)sizeof (struct device_element));
3090 		bcopy((void *)&l_state->ib_tbl.p2_s.element[rear_index + i],
3091 			(void *)&l_state->drv_rear[i].ib_status,
3092 			(size_t)sizeof (struct device_element));
3093 	}
3094 	if (getenv("_LUX_G_DEBUG") != NULL) {
3095 		g_dump("  l_get_ib_status: disk elements:  ",
3096 		(uchar_t *)&l_state->ib_tbl.p2_s.element[front_index],
3097 		((sizeof (struct device_element)) * (l_state->total_num_drv)),
3098 		HEX_ONLY);
3099 	}
3100 
3101 	return (0);
3102 }
3103 
3104 
3105 
3106 /*
3107  * Given an IB path get the port, A or B.
3108  *
3109  * OUTPUT:
3110  *	port_a:	sets to 1 for port A
3111  *		and 0 for port B.
3112  * RETURNS:
3113  *	err:	0 O.k.
3114  *		non-zero otherwise
3115  */
3116 int
3117 l_get_port(char *ses_path, int *port_a, int verbose)
3118 {
3119 L_state	*ib_state = NULL;
3120 Ctlr_elem_st	ctlr;
3121 int	i, err, elem_index = 0;
3122 
3123 	if ((ses_path == NULL) || (port_a == NULL)) {
3124 		return (L_NO_SES_PATH);
3125 	}
3126 
3127 	if ((ib_state = (L_state *)calloc(1, sizeof (L_state))) == NULL) {
3128 		return (L_MALLOC_FAILED);
3129 	}
3130 
3131 	bzero(&ctlr, sizeof (ctlr));
3132 	if (err = l_get_ib_status(ses_path, ib_state, verbose)) {
3133 		(void) l_free_lstate(&ib_state);
3134 		return (err);
3135 	}
3136 
3137 	for (i = 0; i < (int)ib_state->ib_tbl.config.enc_num_elem; i++) {
3138 	    elem_index++;		/* skip global */
3139 	    if (ib_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_IB) {
3140 		bcopy((const void *)
3141 			&ib_state->ib_tbl.p2_s.element[elem_index],
3142 			(void *)&ctlr, sizeof (ctlr));
3143 		break;
3144 	    }
3145 	    elem_index += ib_state->ib_tbl.config.type_hdr[i].num;
3146 	}
3147 	*port_a = ctlr.report;
3148 	G_DPRINTF("  l_get_port: Found ses is the %s card.\n",
3149 		ctlr.report ? "A" : "B");
3150 	(void) l_free_lstate(&ib_state);
3151 	return (0);
3152 }
3153 
3154 /*
3155  * This function expects a pointer to a device path ending in the form
3156  * .../ses@w<NODEWWN>,<something> or .../ssd@w<NODEWWN>,<something>
3157  *
3158  * No validity checking of the path is done by the function.
3159  *
3160  * It gets the wwn (node wwn) out of the passed string, searches the passed
3161  * map for a match, gets the corresponding phys addr (port id) for that entry
3162  * and stores in the pointer the caller has passed as an argument (pid)
3163  *
3164  * This function is to be called only for public/fabric topologies
3165  *
3166  * If this interface is going to get exported, one point to be
3167  * considered is if a call to g_get_path_type() has to be made.
3168  *
3169  * INPUT:
3170  * path - pointer to the enclosure/disk device path
3171  * map - pointer to the map
3172  *
3173  * OUTPUT:
3174  * pid - the physical address associated for the node WWN that was found
3175  *       in the map
3176  *
3177  * RETURNS:
3178  * 0 - on success
3179  * non-zero - otherwise
3180  */
3181 int
3182 l_get_pid_from_path(const char *path, const gfc_map_t *map, int *pid)
3183 {
3184 int			i;
3185 unsigned long long	ll_wwn;
3186 char			*char_ptr, wwn_str[WWN_SIZE * 2 + 1];
3187 char			*byte_ptr, *temp_ptr;
3188 gfc_port_dev_info_t	*dev_addr_ptr;
3189 mp_pathlist_t		pathlist;
3190 char			path0[MAXPATHLEN], pwwn0[WWN_S_LEN];
3191 
3192 	/* if mpxio device */
3193 	if (strstr(path, SCSI_VHCI) != NULL) {
3194 		(void) strcpy(path0, path);
3195 		if (g_get_pathlist(path0, &pathlist)) {
3196 			return (L_INVALID_PATH);
3197 		} else {
3198 			(void) strncpy(pwwn0, pathlist.path_info[0].
3199 				path_addr, L_WWN_LENGTH);
3200 			pwwn0[L_WWN_LENGTH] = '\0';
3201 			free(pathlist.path_info);
3202 			char_ptr = pwwn0;
3203 		}
3204 	} else {
3205 		/* First a quick check on the path */
3206 		if (((char_ptr = strrchr(path, '@')) == NULL) ||
3207 					(*++char_ptr != 'w')) {
3208 			return (L_INVALID_PATH);
3209 		} else {
3210 			char_ptr++;
3211 		}
3212 	}
3213 
3214 	if (strlen(char_ptr) < (WWN_SIZE * 2)) {
3215 		return (L_INVALID_PATH);
3216 	}
3217 	(void) strncpy(wwn_str, char_ptr, WWN_SIZE * 2);
3218 	wwn_str[WWN_SIZE * 2] = '\0';
3219 	errno = 0;	/* For error checking */
3220 	ll_wwn = strtoull(wwn_str, &temp_ptr, L_WWN_LENGTH);
3221 
3222 	if (errno || (temp_ptr != (wwn_str + (WWN_SIZE * 2)))) {
3223 		return (L_INVALID_PATH);
3224 	}
3225 
3226 	byte_ptr = (char *)&ll_wwn;
3227 
3228 	/*
3229 	 * Search for the ses's node wwn in map to get the area and
3230 	 * domain ids from the corresponding port id (phys address).
3231 	 */
3232 	for (dev_addr_ptr = map->dev_addr, i = 0; i < map->count;
3233 						dev_addr_ptr++, i++) {
3234 		if (bcmp((char *)dev_addr_ptr->gfc_port_dev.
3235 			pub_port.dev_nwwn.raw_wwn, byte_ptr, WWN_SIZE) == 0)
3236 			break;
3237 	}
3238 	if (i >= map->count)
3239 		return (L_INVALID_PATH);
3240 	*pid = dev_addr_ptr->gfc_port_dev.pub_port.dev_did.port_id;
3241 	return (0);
3242 }
3243 
3244 
3245 /*
3246  * Finds the disk's node wwn string, and
3247  * port A and B's WWNs and their port status.
3248  *
3249  * INPUT:
3250  * path		- pointer to a ses path
3251  * wwn_list	- pointer to the wwn_list
3252  *
3253  * OUTPUT:
3254  * state	- node_wwn and wwn of ports A & B of disk, etc are inited
3255  *		- by l_get_disk_status()
3256  * found_flag	- incremented after each examined element in the map
3257  *
3258  * RETURNS:
3259  *	0	 O.K.
3260  *	non-zero otherwise.
3261  */
3262 static int
3263 l_get_node_status(char *path, struct l_disk_state_struct *state,
3264 	int *found_flag, WWN_list *wwn_list, int verbose)
3265 {
3266 int		j, select_id, err;
3267 int		path_pid;
3268 char		temp_path[MAXPATHLEN];
3269 char		sbuf[MAXPATHLEN], *char_ptr;
3270 gfc_map_mp_t	*map_mp, *map_ptr;
3271 struct stat	stat_buf;
3272 WWN_list	*wwnlp;
3273 char		wwnp[WWN_S_LEN];
3274 
3275 	/*
3276 	 * Get a new map.
3277 	 */
3278 	map_mp = NULL;
3279 	if (err = get_mp_dev_map(path, &map_mp, verbose))
3280 		return (err);
3281 
3282 	for (map_ptr = map_mp; map_ptr != NULL; map_ptr = map_ptr->map_next) {
3283 	    switch (map_ptr->map.hba_addr.port_topology) {
3284 		case FC_TOP_PRIVATE_LOOP:
3285 		    for (j = 0; j < map_ptr->map.count; j++) {
3286 			/*
3287 			 * Get a generic path to a device
3288 			 *
3289 			 * This assumes the path looks something like this
3290 			 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/...
3291 			 *					...ses@x,0:0
3292 			 * then creates a path that looks like
3293 			 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ssd@
3294 			 */
3295 			(void) strcpy(temp_path, path);
3296 			if ((char_ptr = strrchr(temp_path, '/')) == NULL) {
3297 				free_mp_dev_map(&map_mp);
3298 				return (L_INVALID_PATH);
3299 			}
3300 			*char_ptr = '\0';   /* Terminate sting  */
3301 			(void) strcat(temp_path, SLSH_DRV_NAME_SSD);
3302 			/*
3303 			 * Create complete path.
3304 			 *
3305 			 * Build entry ssd@xx,0:c,raw
3306 			 * where xx is the WWN.
3307 			 */
3308 			select_id = g_sf_alpa_to_switch[map_ptr->map.
3309 			    dev_addr[j].gfc_port_dev.priv_port.sf_al_pa];
3310 			G_DPRINTF("  l_get_node_status: Searching loop map "
3311 				"to find disk: ID:0x%x"
3312 				" AL_PA:0x%x\n", select_id,
3313 				state->ib_status.sel_id);
3314 
3315 		if (strstr(path, SCSI_VHCI) == NULL) {
3316 
3317 			(void) sprintf(sbuf,
3318 			"w%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x,0:c,raw",
3319 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3320 								sf_port_wwn[0],
3321 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3322 								sf_port_wwn[1],
3323 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3324 								sf_port_wwn[2],
3325 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3326 								sf_port_wwn[3],
3327 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3328 								sf_port_wwn[4],
3329 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3330 								sf_port_wwn[5],
3331 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3332 								sf_port_wwn[6],
3333 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3334 								sf_port_wwn[7]);
3335 			(void) strcat(temp_path, sbuf);
3336 
3337 		}
3338 			/*
3339 			 * If we find a device on this loop in this box
3340 			 * update its status.
3341 			 */
3342 			if (state->ib_status.sel_id == select_id) {
3343 				/*
3344 				 * Found a device on this loop in this box.
3345 				 *
3346 				 * Update state.
3347 				 */
3348 				(void) sprintf(state->g_disk_state.node_wwn_s,
3349 				"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
3350 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3351 								sf_node_wwn[0],
3352 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3353 								sf_node_wwn[1],
3354 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3355 								sf_node_wwn[2],
3356 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3357 								sf_node_wwn[3],
3358 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3359 								sf_node_wwn[4],
3360 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3361 								sf_node_wwn[5],
3362 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3363 								sf_node_wwn[6],
3364 				map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3365 								sf_node_wwn[7]);
3366 
3367 	if (strstr(path, SCSI_VHCI) != NULL) {
3368 		(void) g_ll_to_str(map_ptr->map.dev_addr[j].gfc_port_dev.
3369 			priv_port.sf_node_wwn, wwnp);
3370 		for (wwnlp = wwn_list; wwnlp != NULL;
3371 			wwnlp = wwnlp->wwn_next) {
3372 			if (strcmp(wwnlp->node_wwn_s, wwnp) == 0) {
3373 			(void) strcpy(temp_path, wwnlp->physical_path);
3374 				break;
3375 			}
3376 		}
3377 		if (wwnlp == NULL) {
3378 			(void) sprintf(sbuf,
3379 		"g%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x:c,raw",
3380 			map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3381 							sf_node_wwn[0],
3382 			map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3383 							sf_node_wwn[1],
3384 			map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3385 							sf_node_wwn[2],
3386 			map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3387 							sf_node_wwn[3],
3388 			map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3389 							sf_node_wwn[4],
3390 			map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3391 							sf_node_wwn[5],
3392 			map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3393 							sf_node_wwn[6],
3394 			map_ptr->map.dev_addr[j].gfc_port_dev.priv_port.
3395 							sf_node_wwn[7]);
3396 			(void) strcat(temp_path, sbuf);
3397 			/*
3398 			 * check to make sure this is a valid path.
3399 			 * Paths may not always be created on the
3400 			 * host. So, we make a quick check.
3401 			 */
3402 			if (stat(temp_path, &stat_buf) == -1) {
3403 				free_mp_dev_map(&map_mp);
3404 				return (errno);
3405 			}
3406 
3407 		}
3408 	}
3409 		(void) strcpy(state->g_disk_state.physical_path,
3410 			temp_path);
3411 
3412 
3413 				/* Bad if WWN is all zeros. */
3414 				if (is_null_wwn(map_ptr->map.dev_addr[j].
3415 					    gfc_port_dev.priv_port.
3416 					    sf_node_wwn)) {
3417 					state->l_state_flag = L_INVALID_WWN;
3418 					G_DPRINTF("  l_get_node_status: "
3419 						"Disk state was "
3420 						" Invalid WWN.\n");
3421 					(*found_flag)++;
3422 					free_mp_dev_map(&map_mp);
3423 					return (0);
3424 				}
3425 
3426 				/* get device status */
3427 				if (err = l_get_disk_status(temp_path, state,
3428 							wwn_list, verbose)) {
3429 					free_mp_dev_map(&map_mp);
3430 					return (err);
3431 				}
3432 				/*
3433 				 * found device in map.  Don't need to look
3434 				 * any further
3435 				 */
3436 				(*found_flag)++;
3437 				free_mp_dev_map(&map_mp);
3438 				return (0);
3439 			}
3440 		    }	/* for loop */
3441 		break;
3442 	case FC_TOP_PUBLIC_LOOP:
3443 	case FC_TOP_FABRIC:
3444 		/*
3445 		 * Get a generic path to a device
3446 		 * This assumes the path looks something like this
3447 		 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@wWWN,0:0
3448 		 * then creates a path that looks like
3449 		 * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ssd@
3450 		 */
3451 		(void) strcpy(temp_path, path);
3452 		if ((char_ptr = strrchr(temp_path, '/')) == NULL) {
3453 			free_mp_dev_map(&map_mp);
3454 			return (L_INVALID_PATH);
3455 		}
3456 		*char_ptr = '\0';   /* Terminate sting  */
3457 
3458 		if (err = l_get_pid_from_path(path, &map_ptr->map, &path_pid)) {
3459 			free_mp_dev_map(&map_mp);
3460 			return (err);
3461 		}
3462 
3463 		/* Now append the ssd string */
3464 		(void) strcat(temp_path, SLSH_DRV_NAME_SSD);
3465 
3466 		/*
3467 		 * Create complete path.
3468 		 *
3469 		 * Build entry ssd@WWN,0:c,raw
3470 		 *
3471 		 * First, search the map for a device with the area code and
3472 		 * domain as in 'path_pid'.
3473 		 */
3474 		for (j = 0; j < map_ptr->map.count; j++) {
3475 			if (map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3476 			    dev_dtype != DTYPE_ESI) {
3477 				select_id = g_sf_alpa_to_switch[map_ptr->map.
3478 				    dev_addr[j].gfc_port_dev.pub_port.dev_did.
3479 				    port_id & 0xFF];
3480 
3481 				if (((map_ptr->map.dev_addr[j].gfc_port_dev.
3482 						    pub_port.dev_did.port_id &
3483 						    AREA_DOMAIN_ID) ==
3484 					    (path_pid & AREA_DOMAIN_ID)) &&
3485 				    (state->ib_status.sel_id == select_id)) {
3486 					/*
3487 					 * Found the device. Update state.
3488 					 */
3489 		if (strstr(temp_path, SCSI_VHCI) == NULL) {
3490 					(void) sprintf(sbuf,
3491 			"w%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x,0:c,raw",
3492 					map_ptr->map.dev_addr[j].gfc_port_dev.
3493 					pub_port.dev_pwwn.raw_wwn[0],
3494 					map_ptr->map.dev_addr[j].gfc_port_dev.
3495 					pub_port.dev_pwwn.raw_wwn[1],
3496 					map_ptr->map.dev_addr[j].gfc_port_dev.
3497 					pub_port.dev_pwwn.raw_wwn[2],
3498 					map_ptr->map.dev_addr[j].gfc_port_dev.
3499 					pub_port.dev_pwwn.raw_wwn[3],
3500 					map_ptr->map.dev_addr[j].gfc_port_dev.
3501 					pub_port.dev_pwwn.raw_wwn[4],
3502 					map_ptr->map.dev_addr[j].gfc_port_dev.
3503 					pub_port.dev_pwwn.raw_wwn[5],
3504 					map_ptr->map.dev_addr[j].gfc_port_dev.
3505 					pub_port.dev_pwwn.raw_wwn[6],
3506 					map_ptr->map.dev_addr[j].gfc_port_dev.
3507 					pub_port.dev_pwwn.raw_wwn[7]);
3508 					(void) strcat(temp_path, sbuf);
3509 
3510 					/*
3511 					 * Paths for fabric cases may not always
3512 					 * be created on the host. So, we make a
3513 					 * quick check.
3514 					 */
3515 					if (stat(temp_path, &stat_buf) == -1) {
3516 						free_mp_dev_map(&map_mp);
3517 						return (errno);
3518 					}
3519 
3520 					(void) sprintf(state->
3521 							g_disk_state.node_wwn_s,
3522 				"%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
3523 					map_ptr->map.dev_addr[j].gfc_port_dev.
3524 					pub_port.dev_nwwn.raw_wwn[0],
3525 					map_ptr->map.dev_addr[j].gfc_port_dev.
3526 					pub_port.dev_nwwn.raw_wwn[1],
3527 					map_ptr->map.dev_addr[j].gfc_port_dev.
3528 					pub_port.dev_nwwn.raw_wwn[2],
3529 					map_ptr->map.dev_addr[j].gfc_port_dev.
3530 					pub_port.dev_nwwn.raw_wwn[3],
3531 					map_ptr->map.dev_addr[j].gfc_port_dev.
3532 					pub_port.dev_nwwn.raw_wwn[4],
3533 					map_ptr->map.dev_addr[j].gfc_port_dev.
3534 					pub_port.dev_nwwn.raw_wwn[5],
3535 					map_ptr->map.dev_addr[j].gfc_port_dev.
3536 					pub_port.dev_nwwn.raw_wwn[6],
3537 					map_ptr->map.dev_addr[j].gfc_port_dev.
3538 					pub_port.dev_nwwn.raw_wwn[7]);
3539 
3540 		} else {
3541 		(void) g_ll_to_str(map_ptr->map.dev_addr[j].gfc_port_dev.
3542 			priv_port.sf_node_wwn, wwnp);
3543 		for (wwnlp = wwn_list; wwnlp != NULL;
3544 		wwnlp = wwnlp->wwn_next) {
3545 			if (strcmp(wwnlp->node_wwn_s, wwnp) == 0) {
3546 			(void) strcpy(temp_path, wwnlp->physical_path);
3547 			break;
3548 			}
3549 		}
3550 		if (wwnlp == NULL) {
3551 			(void) sprintf(sbuf,
3552 		"w%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x,0:c,raw",
3553 			map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3554 						dev_nwwn.raw_wwn[0],
3555 			map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3556 						dev_nwwn.raw_wwn[1],
3557 			map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3558 						dev_nwwn.raw_wwn[2],
3559 			map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3560 						dev_nwwn.raw_wwn[3],
3561 			map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3562 						dev_nwwn.raw_wwn[4],
3563 			map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3564 						dev_nwwn.raw_wwn[5],
3565 			map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3566 						dev_nwwn.raw_wwn[6],
3567 			map_ptr->map.dev_addr[j].gfc_port_dev.pub_port.
3568 						dev_nwwn.raw_wwn[7]);
3569 				(void) strcat(temp_path, sbuf);
3570 		}
3571 		}
3572 		(void) strcpy(state->g_disk_state.physical_path,
3573 		temp_path);
3574 
3575 					/* Bad if WWN is all zeros. */
3576 					if (is_null_wwn(map_ptr->map.
3577 						    dev_addr[j].gfc_port_dev.
3578 						    pub_port.dev_nwwn.
3579 						    raw_wwn)) {
3580 						state->l_state_flag =
3581 								L_INVALID_WWN;
3582 						G_DPRINTF(
3583 						"  l_get_node_status: "
3584 						"Disk state was "
3585 						" Invalid WWN.\n");
3586 						(*found_flag)++;
3587 						free_mp_dev_map(&map_mp);
3588 						return (0);
3589 					}
3590 
3591 					/* get device status */
3592 					if (err = l_get_disk_status(temp_path,
3593 						state, wwn_list, verbose)) {
3594 						free_mp_dev_map(&map_mp);
3595 						return (err);
3596 					}
3597 
3598 					(*found_flag)++;
3599 					free_mp_dev_map(&map_mp);
3600 					return (0);
3601 				}	/* if select_id match */
3602 			}	/* if !DTYPE_ESI */
3603 		}		/* for loop */
3604 		break;
3605 	case FC_TOP_PT_PT:
3606 		free_mp_dev_map(&map_mp);
3607 		return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
3608 	default:
3609 		free_mp_dev_map(&map_mp);
3610 		return (L_UNEXPECTED_FC_TOPOLOGY);
3611 	    }	/* End of switch on port_topology */
3612 
3613 	}
3614 	free_mp_dev_map(&map_mp);
3615 	return (0);
3616 }
3617 
3618 
3619 /*
3620  * Get the individual drives status for the device specified by the index.
3621  * device at the path where the path is of the IB and updates the
3622  * g_disk_state_struct structure.
3623  *
3624  * If the disk's port is bypassed,  it gets the
3625  * drive status such as node WWN from the second port.
3626  *
3627  * RETURNS:
3628  *	0	 O.K.
3629  *	non-zero otherwise
3630  */
3631 int
3632 l_get_individual_state(char *path,
3633 	struct l_disk_state_struct *state, Ib_state *ib_state,
3634 	int front_flag, struct box_list_struct *box_list,
3635 	struct wwn_list_struct *wwn_list, int verbose)
3636 {
3637 int		found_flag = 0, elem_index = 0;
3638 int		port_a_flag, err, j;
3639 struct dlist	*seslist = NULL;
3640 Bp_elem_st	bpf, bpr;
3641 hrtime_t	start_time, end_time;
3642 
3643 	if ((path == NULL) || (state == NULL) ||
3644 	    (ib_state == NULL) || (box_list == NULL)) {
3645 		return (L_INVALID_PATH_FORMAT);
3646 	}
3647 
3648 	start_time = gethrtime();
3649 
3650 
3651 	if ((state->ib_status.code != S_NOT_INSTALLED) &&
3652 		(state->ib_status.code != S_NOT_AVAILABLE)) {
3653 
3654 		/*
3655 		 * Disk could have been bypassed on this loop.
3656 		 * Check the port state before l_state_flag
3657 		 * is set to L_INVALID_MAP.
3658 		 */
3659 		for (j = 0;
3660 		j < (int)ib_state->config.enc_num_elem;
3661 		j++) {
3662 			elem_index++;
3663 			if (ib_state->config.type_hdr[j].type ==
3664 							ELM_TYP_BP)
3665 				break;
3666 			elem_index +=
3667 				ib_state->config.type_hdr[j].num;
3668 		}
3669 
3670 		/*
3671 		 * check if port A & B of backplane are bypassed.
3672 		 * If so, do not bother.
3673 		 */
3674 		if (front_flag) {
3675 			bcopy((const void *)
3676 			&(ib_state->p2_s.element[elem_index]),
3677 			(void *)&bpf, sizeof (bpf));
3678 
3679 			if ((bpf.byp_a_enabled || bpf.en_bypass_a) &&
3680 				(bpf.byp_b_enabled || bpf.en_bypass_b))
3681 				return (0);
3682 		} else {
3683 			/* if disk is in rear slot */
3684 			bcopy((const void *)
3685 			&(ib_state->p2_s.element[elem_index+1]),
3686 			(void *)&bpr, sizeof (bpr));
3687 
3688 			if ((bpr.byp_b_enabled || bpr.en_bypass_b) &&
3689 				(bpr.byp_a_enabled || bpr.en_bypass_a))
3690 				return (0);
3691 		}
3692 
3693 		if ((err = l_get_node_status(path, state,
3694 				&found_flag, wwn_list, verbose)) != 0)
3695 			return (err);
3696 
3697 		if (!found_flag) {
3698 			if ((err = l_get_allses(path, box_list,
3699 						&seslist, 0)) != 0) {
3700 				return (err);
3701 			}
3702 
3703 			if (err = l_get_port(path, &port_a_flag, verbose))
3704 				goto done;
3705 
3706 			if (port_a_flag) {
3707 				if ((state->ib_status.bypass_a_en &&
3708 					!(state->ib_status.bypass_b_en)) ||
3709 					!(state->ib_status.bypass_b_en)) {
3710 					while (seslist != NULL && !found_flag) {
3711 						if (err = l_get_port(
3712 							seslist->dev_path,
3713 						&port_a_flag, verbose)) {
3714 							goto done;
3715 						}
3716 						if ((strcmp(seslist->dev_path,
3717 							path) != 0) &&
3718 							!port_a_flag) {
3719 							*path = NULL;
3720 							(void) strcpy(path,
3721 							seslist->dev_path);
3722 							if (err =
3723 							l_get_node_status(path,
3724 							state, &found_flag,
3725 							wwn_list, verbose)) {
3726 								goto done;
3727 							}
3728 						}
3729 						seslist = seslist->next;
3730 					}
3731 				}
3732 			} else {
3733 				if ((state->ib_status.bypass_b_en &&
3734 					!(state->ib_status.bypass_a_en)) ||
3735 					!(state->ib_status.bypass_a_en)) {
3736 					while (seslist != NULL && !found_flag) {
3737 						if (err = l_get_port(
3738 							seslist->dev_path,
3739 						&port_a_flag, verbose)) {
3740 							goto done;
3741 						}
3742 						if ((strcmp(seslist->dev_path,
3743 						path) != 0) && port_a_flag) {
3744 							*path = NULL;
3745 							(void) strcpy(path,
3746 							seslist->dev_path);
3747 							if (err =
3748 							l_get_node_status(path,
3749 							state, &found_flag,
3750 							wwn_list, verbose)) {
3751 								goto done;
3752 							}
3753 						}
3754 						seslist = seslist->next;
3755 					}
3756 				}
3757 			}
3758 			if (!found_flag) {
3759 				state->l_state_flag = L_INVALID_MAP;
3760 				G_DPRINTF("  l_get_individual_state: "
3761 					"Disk state was "
3762 					"Not in map.\n");
3763 			} else {
3764 				G_DPRINTF("  l_get_individual_state: "
3765 					"Disk was found in the map.\n");
3766 			}
3767 
3768 			if (seslist != NULL)
3769 				(void) g_free_multipath(seslist);
3770 
3771 		}
3772 
3773 	} else {
3774 		G_DPRINTF("  l_get_individual_state: Disk state was %s.\n",
3775 			(state->ib_status.code == S_NOT_INSTALLED) ?
3776 			"Not Installed" : "Not Available");
3777 	}
3778 
3779 	if (getenv("_LUX_T_DEBUG") != NULL) {
3780 		end_time = gethrtime();
3781 		(void) fprintf(stdout, "    l_get_individual_state:"
3782 		"\tTime = %lld millisec\n",
3783 		(end_time - start_time)/1000000);
3784 	}
3785 
3786 	return (0);
3787 done:
3788 	(void) g_free_multipath(seslist);
3789 	return (err);
3790 }
3791 
3792 
3793 
3794 /*
3795  * Get the global state of the photon.
3796  *
3797  * INPUT:
3798  * path and verbose flag
3799  *
3800  * "path" must be of the ses driver.
3801  * e.g.
3802  * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@e,0:0
3803  * or
3804  * /devices/sbus@1f,0/SUNW,socal@1,0/SUNW,sf@0,0/ses@WWN,0:0
3805  *
3806  * OUTPUT:
3807  * The struct l_state (which was passed in) has the status info
3808  *
3809  * RETURNS:
3810  *	0	 O.K.
3811  *	non-zero otherwise
3812  */
3813 int
3814 l_get_status(char *path, struct l_state_struct *l_state, int verbose)
3815 {
3816 int		err = 0, i, count;
3817 L_inquiry	inq;
3818 uchar_t		node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
3819 int		al_pa, found_front, found_rear, front_flag, enc_type;
3820 char		ses_path_front[MAXPATHLEN];
3821 char		ses_path_rear[MAXPATHLEN];
3822 Box_list	*b_list = NULL;
3823 Box_list	*o_list = NULL;
3824 char		node_wwn_s[(WWN_SIZE*2)+1];
3825 uint_t		select_id;
3826 hrtime_t	start_time, end_time;
3827 WWN_list		*wwn_list = NULL;
3828 
3829 	if ((path == NULL) || (l_state == NULL)) {
3830 		return (L_INVALID_PATH_FORMAT);
3831 	}
3832 
3833 	start_time = gethrtime();
3834 
3835 	G_DPRINTF("  l_get_status: Get Status for enclosure at: "
3836 		" %s\n", path);
3837 
3838 	/* initialization */
3839 	(void) memset(l_state, 0, sizeof (struct l_state_struct));
3840 
3841 	if (err = g_get_inquiry(path, &inq)) {
3842 		return (err);
3843 	}
3844 	if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
3845 		(!(strncmp((char *)inq.inq_vid, "SUN     ",
3846 		sizeof (inq.inq_vid)) &&
3847 		((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
3848 		return (L_ENCL_INVALID_PATH);
3849 	}
3850 
3851 	(void) strncpy((char *)l_state->ib_tbl.enclosure_name,
3852 		(char *)inq.inq_box_name, sizeof (inq.inq_box_name));
3853 
3854 	/*
3855 	 * Get all of the IB Receive Diagnostic pages.
3856 	 */
3857 	if (err = l_get_ib_status(path, l_state, verbose)) {
3858 		return (err);
3859 	}
3860 
3861 	/*
3862 	 * Now get the individual devices information from
3863 	 * the device itself.
3864 	 *
3865 	 * May need to use multiple paths to get to the
3866 	 * front and rear drives in the box.
3867 	 * If the loop is split some drives may not even be available
3868 	 * from this host.
3869 	 *
3870 	 * The way this works is in the select ID the front disks
3871 	 * are accessed via the IB with the bit 4 = 0
3872 	 * and the rear disks by the IB with bit 4 = 1.
3873 	 *
3874 	 * First get device map from fc nexus driver for this loop.
3875 	 */
3876 	/*
3877 	 * Get the boxes node WWN & al_pa for this path.
3878 	 */
3879 	if (err = g_get_wwn(path, port_wwn, node_wwn, &al_pa, verbose)) {
3880 		return (err);
3881 	}
3882 	if (err = l_get_box_list(&o_list, verbose)) {
3883 		(void) l_free_box_list(&o_list);
3884 		return (err);	/* Failure */
3885 	}
3886 
3887 	found_front = found_rear = 0;
3888 	for (i = 0; i < WWN_SIZE; i++) {
3889 		(void) sprintf(&node_wwn_s[i << 1], "%02x", node_wwn[i]);
3890 	}
3891 
3892 	/*
3893 	 * The al_pa (or pa) can be 24 bits in size for fabric loops.
3894 	 * But we will take only the low order byte to get the select_id.
3895 	 * Private loops have al_pa which is only a byte in size.
3896 	 */
3897 	select_id = g_sf_alpa_to_switch[al_pa & 0xFF];
3898 	l_state->ib_tbl.box_id = (select_id & BOX_ID_MASK) >> 5;
3899 
3900 	G_DPRINTF("  l_get_status: Using this select_id 0x%x "
3901 		"and node WWN %s\n",
3902 		select_id, node_wwn_s);
3903 
3904 	if (strstr(path, SCSI_VHCI) != NULL) {
3905 		/* there is no way to obtain all the al_pa with */
3906 		/*  current implementation. assume both front   */
3907 		/*  and rear. need changes later on. */
3908 		found_rear = 1;
3909 		found_front = 1;
3910 		(void) strcpy(ses_path_rear, path);
3911 		(void) strcpy(ses_path_front, path);
3912 	} else {
3913 
3914 	if (select_id & ALT_BOX_ID) {
3915 		found_rear = 1;
3916 		(void) strcpy(ses_path_rear, path);
3917 		b_list = o_list;
3918 		while (b_list) {
3919 			if (strcmp(b_list->b_node_wwn_s, node_wwn_s) == 0) {
3920 				if (err = g_get_wwn(b_list->b_physical_path,
3921 					port_wwn, node_wwn,
3922 					&al_pa, verbose)) {
3923 					(void) l_free_box_list(&o_list);
3924 					return (err);
3925 				}
3926 
3927 				/* Take the low order byte of al_pa */
3928 				select_id = g_sf_alpa_to_switch[al_pa & 0xFF];
3929 				if (!(select_id & ALT_BOX_ID)) {
3930 					(void) strcpy(ses_path_front,
3931 					b_list->b_physical_path);
3932 					found_front = 1;
3933 					break;
3934 				}
3935 			}
3936 			b_list = b_list->box_next;
3937 		}
3938 	} else {
3939 		(void) strcpy(ses_path_front, path);
3940 		found_front = 1;
3941 		b_list = o_list;
3942 		while (b_list) {
3943 			if (strcmp(b_list->b_node_wwn_s, node_wwn_s) == 0) {
3944 				if (err = g_get_wwn(b_list->b_physical_path,
3945 					port_wwn, node_wwn,
3946 					&al_pa, verbose)) {
3947 					(void) l_free_box_list(&o_list);
3948 					return (err);
3949 				}
3950 				select_id = g_sf_alpa_to_switch[al_pa & 0xFF];
3951 				if (select_id & ALT_BOX_ID) {
3952 					(void) strcpy(ses_path_rear,
3953 					b_list->b_physical_path);
3954 					found_rear = 1;
3955 					break;
3956 				}
3957 			}
3958 			b_list = b_list->box_next;
3959 		}
3960 	}
3961 	}
3962 
3963 	if (getenv("_LUX_G_DEBUG") != NULL) {
3964 		if (!found_front) {
3965 		(void) printf("l_get_status: Loop to front disks not found.\n");
3966 		}
3967 		if (!found_rear) {
3968 		(void) printf("l_get_status: Loop to rear disks not found.\n");
3969 		}
3970 	}
3971 
3972 	/*
3973 	 * Get path to all the FC disk and tape devices.
3974 	 *
3975 	 * I get this now and pass down for performance
3976 	 * reasons.
3977 	 * If for some reason the list can become invalid,
3978 	 * i.e. device being offlined, then the list
3979 	 * must be re-gotten.
3980 	 */
3981 	if (err = g_get_wwn_list(&wwn_list, verbose)) {
3982 		return (err);   /* Failure */
3983 	}
3984 
3985 	enc_type = l_get_enc_type(inq);
3986 	if (found_front) {
3987 		front_flag = 1;
3988 		for (i = 0, count = 0; i < l_state->total_num_drv/2;
3989 							count++, i++) {
3990 			if (enc_type == DAK_ENC_TYPE) {
3991 				G_DPRINTF("  l_get_status: Getting individual"
3992 				    " State for disk in slot %d\n", count);
3993 			} else {
3994 				G_DPRINTF("  l_get_status: Getting individual"
3995 				    " State for front disk in slot %d\n", i);
3996 			}
3997 			if (err = l_get_individual_state(ses_path_front,
3998 			(struct l_disk_state_struct *)&l_state->drv_front[i],
3999 					&l_state->ib_tbl, front_flag, o_list,
4000 					wwn_list, verbose)) {
4001 				(void) l_free_box_list(&o_list);
4002 				(void) g_free_wwn_list(&wwn_list);
4003 				return (err);
4004 			}
4005 		}
4006 	} else {
4007 		/* Set to loop not accessable. */
4008 		for (i = 0; i < l_state->total_num_drv/2; i++) {
4009 			l_state->drv_front[i].l_state_flag = L_NO_LOOP;
4010 		}
4011 	}
4012 	/*
4013 	 * For Daktari's, disk 0-5 information are located in the
4014 	 * l_state->drv_front array
4015 	 * For Daktari's, disk 6-11 information are located in the
4016 	 * l_state->drv_rear array
4017 	 *
4018 	 * For this reason, on daktari's, I ignore the found_front and
4019 	 * found_rear flags and check both the drv_front and drv_rear
4020 	 */
4021 
4022 	if (enc_type == DAK_ENC_TYPE && found_front) {
4023 		front_flag = 1;
4024 		for (i = 0; i < l_state->total_num_drv/2; i++, count++) {
4025 			G_DPRINTF("  l_get_status: Getting individual"
4026 				    " State for disk in slot %d\n", count);
4027 			if (err = l_get_individual_state(ses_path_front,
4028 			(struct l_disk_state_struct *)&l_state->drv_rear[i],
4029 					&l_state->ib_tbl, front_flag, o_list,
4030 					wwn_list, verbose)) {
4031 				(void) l_free_box_list(&o_list);
4032 				(void) g_free_wwn_list(&wwn_list);
4033 				return (err);
4034 			}
4035 		}
4036 	} else if (enc_type != DAK_ENC_TYPE && found_rear) {
4037 		for (i = 0; i < l_state->total_num_drv/2; i++, count++) {
4038 				G_DPRINTF("  l_get_status: Getting individual"
4039 					" State for rear disk in slot %d\n", i);
4040 			if (err = l_get_individual_state(ses_path_rear,
4041 			    (struct l_disk_state_struct *)&l_state->drv_rear[i],
4042 			    &l_state->ib_tbl, front_flag, o_list,
4043 			    wwn_list, verbose)) {
4044 				(void) l_free_box_list(&o_list);
4045 				(void) g_free_wwn_list(&wwn_list);
4046 				return (err);
4047 			}
4048 		}
4049 	} else if (enc_type != DAK_ENC_TYPE) {
4050 		/* Set to loop not accessable. */
4051 		for (i = 0; i < l_state->total_num_drv/2; i++) {
4052 			l_state->drv_rear[i].l_state_flag = L_NO_LOOP;
4053 		}
4054 	}
4055 
4056 	(void) l_free_box_list(&o_list);
4057 	(void) g_free_wwn_list(&wwn_list);
4058 	if (getenv("_LUX_T_DEBUG") != NULL) {
4059 		end_time = gethrtime();
4060 		(void) fprintf(stdout, "  l_get_status:   "
4061 		"Time = %lld millisec\n",
4062 		(end_time - start_time)/1000000);
4063 	}
4064 
4065 	return (0);
4066 }
4067 
4068 
4069 
4070 /*
4071  * Check the SENA file for validity:
4072  *	- verify the size is that of 3 proms worth of text.
4073  *	- verify PROM_MAGIC.
4074  *	- verify (and print) the date.
4075  *	- verify the checksum.
4076  *	- verify the WWN == 0.
4077  * Since this requires reading the entire file, do it now and pass a pointer
4078  * to the allocated buffer back to the calling routine (which is responsible
4079  * for freeing it).  If the buffer is not allocated it will be NULL.
4080  *
4081  * RETURNS:
4082  *	0	 O.K.
4083  *	non-zero otherwise
4084  */
4085 
4086 static int
4087 check_file(int fd, int verbose, uchar_t **buf_ptr, int dl_info_offset)
4088 {
4089 struct	exec	the_exec;
4090 int		temp, i, j, *p, size, *start;
4091 uchar_t		*buf;
4092 char		*date_str;
4093 struct	dl_info	*dl_info;
4094 
4095 	*buf_ptr = NULL;
4096 
4097 	/* read exec header */
4098 	if (lseek(fd, 0, SEEK_SET) == -1)
4099 		return (errno);
4100 	if ((temp = read(fd, (char *)&the_exec, sizeof (the_exec))) == -1) {
4101 	    return (L_DWNLD_READ_HEADER_FAIL);
4102 	}
4103 	if (temp != sizeof (the_exec)) {
4104 	    return (L_DWNLD_READ_INCORRECT_BYTES);
4105 	}
4106 
4107 	if (the_exec.a_text != PROMSIZE) {
4108 	    return (L_DWNLD_INVALID_TEXT_SIZE);
4109 	}
4110 
4111 	if (!(buf = (uchar_t *)g_zalloc(PROMSIZE)))
4112 	    return (L_MALLOC_FAILED);
4113 
4114 	if ((temp = read(fd, buf, PROMSIZE)) == -1) {
4115 	    return (L_DWNLD_READ_ERROR);
4116 	}
4117 
4118 	if (temp != PROMSIZE) {
4119 	    return (L_DWNLD_READ_INCORRECT_BYTES);
4120 	}
4121 
4122 
4123 
4124 	/* check the IB firmware MAGIC */
4125 	dl_info = (struct dl_info *)(unsigned long)(buf + dl_info_offset);
4126 	if (dl_info->magic != PROM_MAGIC) {
4127 		return (L_DWNLD_BAD_FRMWARE);
4128 	}
4129 
4130 	/*
4131 	 * Get the date
4132 	 */
4133 
4134 	date_str = ctime(&dl_info->datecode);
4135 
4136 	if (verbose) {
4137 		(void) fprintf(stdout,
4138 		MSGSTR(9050, "  IB Prom Date: %s"),
4139 		date_str);
4140 	}
4141 
4142 	/*
4143 	 * verify checksum
4144 	 */
4145 
4146 	if (dl_info_offset == FPM_DL_INFO) {
4147 		start = (int *)(long)(buf + FPM_OFFSET);
4148 		size = FPM_SZ;
4149 	} else {
4150 		start = (int *)(long)buf;
4151 		size = TEXT_SZ + IDATA_SZ;
4152 	}
4153 
4154 	for (j = 0, p = start, i = 0; i < (size/ 4); i++, j ^= *p++);
4155 
4156 	if (j != 0) {
4157 		return (L_DWNLD_CHKSUM_FAILED);
4158 	}
4159 
4160 	/* file verified */
4161 	*buf_ptr = buf;
4162 
4163 	return (0);
4164 }
4165 
4166 /*
4167  * Check the DPM file for validity:
4168  *
4169  * RETURNS:
4170  *	0	 O.K.
4171  *	non-zero otherwise
4172  */
4173 #define	dakstring	"64616B74617269"
4174 #define	dakoffs		"BFC00000"
4175 
4176 static int
4177 check_dpm_file(int fd)
4178 {
4179 	struct s3hdr {
4180 	    char	rtype[2];
4181 	    char	rlen[2];
4182 	    char	data[255];
4183 	} theRec;
4184 	int nread;
4185 	int reclen;
4186 
4187 	if (fd < 0) {
4188 	    return (L_DWNLD_READ_ERROR);
4189 	}
4190 	lseek(fd, 0, SEEK_SET);
4191 
4192 	/* First record */
4193 	memset((void*)&theRec, 0, sizeof (struct s3hdr));
4194 	nread = read(fd, (void *)&theRec, 4);
4195 	if (nread != 4) {
4196 	    /* error reading first record/length */
4197 	    return (L_DWNLD_READ_ERROR);
4198 	}
4199 	if (strncmp((char *)&theRec.rtype[0], "S0", 2) != 0) {
4200 	    /* error in first record type */
4201 	    return (L_DWNLD_READ_HEADER_FAIL);
4202 	}
4203 	reclen = strtol(&theRec.rlen[0], (char **)NULL, 16);
4204 	if (reclen == 0) {
4205 	    /* error in length == 0 */
4206 	    return (L_DWNLD_READ_HEADER_FAIL);
4207 	}
4208 	nread = read(fd, (void *)&theRec.data[0], ((reclen*2) +1));
4209 	if (nread != ((reclen*2) +1)) {
4210 	    /* error in trying to read data */
4211 	    return (L_DWNLD_READ_HEADER_FAIL);
4212 	}
4213 	if (strncmp(&theRec.data[4], dakstring, 14) != 0) {
4214 	    /* error in compiled file name */
4215 	    return (L_DWNLD_READ_HEADER_FAIL);
4216 	}
4217 
4218 	/* Second record */
4219 	memset((void*)&theRec, 0, sizeof (struct s3hdr));
4220 	nread = read(fd, (void *)&theRec, 4);
4221 	if (nread != 4) {
4222 	    /* error reading second record/length */
4223 	    return (L_DWNLD_READ_ERROR);
4224 	}
4225 	if (strncmp((char *)&theRec.rtype[0], "S3", 2) != 0) {
4226 	    /* error in second record type */
4227 	    return (L_DWNLD_READ_HEADER_FAIL);
4228 	}
4229 	reclen = strtol(&theRec.rlen[0], (char **)NULL, 16);
4230 	if (reclen == 0) {
4231 	    /* error in length == 0 */
4232 	    return (L_DWNLD_READ_HEADER_FAIL);
4233 	}
4234 	nread = read(fd, (void *)&theRec.data[0], ((reclen*2) +1));
4235 	if (nread != ((reclen*2) +1)) {
4236 	    /* error in trying to read data */
4237 	    return (L_DWNLD_READ_HEADER_FAIL);
4238 	}
4239 	if (strncmp(&theRec.data[0], dakoffs, 8) != 0) {
4240 	    /* error in SSC100 offset pointer */
4241 	    return (L_DWNLD_READ_HEADER_FAIL);
4242 	}
4243 	lseek(fd, 0, SEEK_SET);
4244 	return (0);
4245 }
4246 
4247 
4248 
4249 int
4250 l_check_file(char *file, int verbose)
4251 {
4252 int	file_fd;
4253 int	err;
4254 uchar_t	*buf;
4255 
4256 	if ((file_fd = g_object_open(file, O_RDONLY)) == -1) {
4257 	    return (L_OPEN_PATH_FAIL);
4258 	}
4259 	err = check_file(file_fd, verbose, &buf, FW_DL_INFO);
4260 	if (buf)
4261 		(void) g_destroy_data((char *)buf);
4262 	return (err);
4263 }
4264 
4265 
4266 
4267 /*
4268  * Write buffer command set up to download
4269  * firmware to the Photon IB.
4270  *
4271  * RETURNS:
4272  *	status
4273  */
4274 static int
4275 ib_download_code_cmd(int fd, int promid, int off, uchar_t *buf_ptr,
4276 						int buf_len, int sp)
4277 {
4278 int	status, sz;
4279 
4280 	while (buf_len) {
4281 		sz = MIN(256, buf_len);
4282 		buf_len -= sz;
4283 		status = g_scsi_writebuffer_cmd(fd, off, buf_ptr, sz,
4284 						(sp) ? 3 : 2, promid);
4285 		if (status)
4286 			return (status);
4287 		buf_ptr += sz;
4288 		off += sz;
4289 	}
4290 
4291 	return (status);
4292 }
4293 
4294 /*
4295  *
4296  * Downloads the code to the DAKTARI/DPM with the hdr set correctly
4297  *
4298  *
4299  * Inputs:
4300  *	fd - int for the file descriptor
4301  *	buf_ptr - uchar_t pointer to the firmware itself
4302  *	buf_len - int for the length of the data
4303  *
4304  * Returns:
4305  *	status:  0 indicates success, != 0 failure, returned from writebuffer
4306  *
4307  */
4308 
4309 static int
4310 dak_download_code_cmd(int fd, uchar_t *buf_ptr, int buf_len)
4311 {
4312 	int 	status = 0;
4313 	int	sz = 0;
4314 	int	offs = 0;
4315 
4316 	while (buf_len > 0) {
4317 		sz = MIN(256, buf_len);
4318 		buf_len -= sz;
4319 		status = g_scsi_writebuffer_cmd(fd, offs, buf_ptr, sz, 0x07, 0);
4320 		if (status != 0) {
4321 		    return (status);
4322 		}
4323 		buf_ptr += sz;
4324 		offs += sz;
4325 	}
4326 	return (status);
4327 }
4328 
4329 
4330 
4331 
4332 /*
4333  * Downloads the new prom image to IB.
4334  *
4335  * INPUTS:
4336  * 	path		- physical path of Photon SES card
4337  * 	file		- input file for new code (may be NULL)
4338  * 	ps		- whether the "save" bit should be set
4339  * 	verbose		- to be verbose or not
4340  *
4341  * RETURNS:
4342  *	0	 O.K.
4343  *	non-zero otherwise
4344  */
4345 int
4346 l_download(char *path_phys, char *file, int ps, int verbose)
4347 {
4348 int		file_fd, controller_fd;
4349 int		err, status;
4350 uchar_t		*buf_ptr;
4351 char		printbuf[MAXPATHLEN];
4352 int		retry;
4353 char		file_path[MAXPATHLEN];
4354 struct stat	statbuf;
4355 int		enc_type;
4356 L_inquiry	inq;
4357 
4358 	if (path_phys == NULL) {
4359 		return (L_INVALID_PATH_FORMAT);
4360 	}
4361 
4362 	if (!file) {
4363 		(void) strcpy(file_path, IBFIRMWARE_FILE);
4364 	} else {
4365 		(void) strncpy(file_path, file, sizeof (file_path));
4366 	}
4367 	if (verbose)
4368 		(void) fprintf(stdout, "%s\n",
4369 			MSGSTR(9051, "  Opening the IB for I/O."));
4370 
4371 	if ((controller_fd = g_object_open(path_phys, O_NDELAY | O_RDWR)) == -1)
4372 		return (L_OPEN_PATH_FAIL);
4373 
4374 	(void) sprintf(printbuf, MSGSTR(9052, "  Doing download to:"
4375 			"\n\t%s.\n  From file: %s."), path_phys, file_path);
4376 
4377 	if (verbose)
4378 		(void) fprintf(stdout, "%s\n", printbuf);
4379 	P_DPRINTF("  Doing download to:"
4380 			"\n\t%s\n  From file: %s\n", path_phys, file_path);
4381 
4382 	if ((file_fd = g_object_open(file_path, O_NDELAY | O_RDONLY)) == -1) {
4383 		/*
4384 		 * Return a different error code here to differentiate between
4385 		 * this failure in g_object_open() and the one above.
4386 		 */
4387 		return (L_INVALID_PATH);
4388 	}
4389 
4390 	if (g_scsi_inquiry_cmd(controller_fd, (uchar_t *)&inq, sizeof (inq))) {
4391 	    return (L_SCSI_ERROR);
4392 	}
4393 	enc_type = l_get_enc_type(inq);
4394 	switch (enc_type) {
4395 	case DAK_ENC_TYPE:
4396 	/*
4397 	 * We don't have a default daktari file location, so
4398 	 * the user must specify the firmware file on the command line
4399 	 */
4400 	    if (!file) {
4401 		return (L_REQUIRE_FILE);
4402 	    }
4403 	    /* Validate the file */
4404 	    if ((err = check_dpm_file(file_fd))) {
4405 		return (err);
4406 	    }
4407 	    /* Now go ahead and load up the data */
4408 	    if (fstat(file_fd, &statbuf) == -1) {
4409 		err = errno;
4410 		(void) fprintf(stdout, "%s  %s\n",
4411 		    MSGSTR(9101, "  Stat'ing the F/W file:"), strerror(err));
4412 		return (L_OPEN_PATH_FAIL);
4413 	    }
4414 	    buf_ptr = (uchar_t *)g_zalloc(statbuf.st_size);
4415 	    if (buf_ptr == NULL) {
4416 		err = errno;
4417 		(void) fprintf(stdout, "%s  %s\n",
4418 		    MSGSTR(9102, "  Cannot alloc mem to read F/W file:"),
4419 		    strerror(err));
4420 		return (L_MALLOC_FAILED);
4421 	    }
4422 	    if (read(file_fd, buf_ptr, statbuf.st_size) == -1) {
4423 		err = errno;
4424 		(void) fprintf(stdout, "%s  %s\n",
4425 		    MSGSTR(9103, "  Reading F/W file:"), strerror(err));
4426 		g_destroy_data((char *)buf_ptr);
4427 		return (L_DWNLD_READ_ERROR);
4428 	    }
4429 	    break;
4430 	default:
4431 	    if (err = check_file(file_fd, verbose, &buf_ptr, FW_DL_INFO)) {
4432 		if (buf_ptr) {
4433 		    (void) g_destroy_data((char *)buf_ptr);
4434 		    return (err);
4435 		}
4436 	    }
4437 	    break;
4438 	}
4439 
4440 	if (verbose) {
4441 		(void) fprintf(stdout, "  ");
4442 		(void) fprintf(stdout, MSGSTR(127, "Checkfile O.K."));
4443 		(void) fprintf(stdout, "\n");
4444 	}
4445 	P_DPRINTF("  Checkfile OK.\n");
4446 	(void) close(file_fd);
4447 
4448 	if (verbose) {
4449 		(void) fprintf(stdout, MSGSTR(9053,
4450 			"  Verifying the IB is available.\n"));
4451 	}
4452 
4453 	retry = DOWNLOAD_RETRIES;
4454 	while (retry) {
4455 		if ((status = g_scsi_tur(controller_fd)) == 0) {
4456 			break;
4457 		} else {
4458 			if ((retry % 30) == 0) {
4459 				ER_DPRINTF(" Waiting for the IB to be"
4460 						" available.\n");
4461 			}
4462 			(void) sleep(1);
4463 		}
4464 	}
4465 	if (!retry) {
4466 		if (buf_ptr)
4467 			(void) g_destroy_data((char *)buf_ptr);
4468 		(void) close(controller_fd);
4469 		return (status);
4470 	}
4471 
4472 	if (verbose)
4473 		(void) fprintf(stdout, "%s\n",
4474 			MSGSTR(9054, "  Writing new text image to IB."));
4475 	P_DPRINTF("  Writing new image to IB\n");
4476 	switch (enc_type) {
4477 	case DAK_ENC_TYPE:
4478 	    status = dak_download_code_cmd(controller_fd, buf_ptr,
4479 		statbuf.st_size);
4480 	    if (status != 0) {
4481 		if (buf_ptr != NULL) {
4482 		    g_destroy_data((char *)buf_ptr);
4483 		}
4484 		(void) close(controller_fd);
4485 		return (status);
4486 	    }
4487 	    break;
4488 	default:
4489 	    status = ib_download_code_cmd(controller_fd, IBEEPROM, TEXT_OFFSET,
4490 		(uchar_t *)(buf_ptr + TEXT_OFFSET), TEXT_SZ, ps);
4491 	    if (status) {
4492 		(void) close(controller_fd);
4493 		(void) g_destroy_data((char *)buf_ptr);
4494 		return (status);
4495 	    }
4496 	    if (verbose) {
4497 		(void) fprintf(stdout, "%s\n",
4498 		    MSGSTR(9055, "  Writing new data image to IB."));
4499 	    }
4500 	    status = ib_download_code_cmd(controller_fd, IBEEPROM, IDATA_OFFSET,
4501 		(uchar_t *)(buf_ptr + IDATA_OFFSET), IDATA_SZ, ps);
4502 	    if (status) {
4503 		(void) close(controller_fd);
4504 		(void) g_destroy_data((char *)buf_ptr);
4505 		return (status);
4506 	    }
4507 	    break;
4508 	}
4509 
4510 
4511 	if (verbose) {
4512 		(void) fprintf(stdout, MSGSTR(9056,
4513 			"  Re-verifying the IB is available.\n"));
4514 	}
4515 
4516 	retry = DOWNLOAD_RETRIES;
4517 	while (retry) {
4518 		if ((status = g_scsi_tur(controller_fd)) == 0) {
4519 			break;
4520 		} else {
4521 			if ((retry % 30) == 0) {
4522 				ER_DPRINTF("  Waiting for the IB to be"
4523 					" available.\n");
4524 			}
4525 			(void) sleep(1);
4526 		}
4527 		retry--;
4528 	}
4529 	if (!retry) {
4530 		(void) close(controller_fd);
4531 		(void) g_destroy_data((char *)buf_ptr);
4532 		return (L_DWNLD_TIMED_OUT);
4533 	}
4534 
4535 	switch (enc_type) {
4536 	case DAK_ENC_TYPE:
4537 	    break;
4538 	default:
4539 	    if (verbose) {
4540 		(void) fprintf(stdout, "%s\n",
4541 		    MSGSTR(9057, "  Writing new image to FPM."));
4542 	    }
4543 	    status = ib_download_code_cmd(controller_fd, MBEEPROM, FPM_OFFSET,
4544 	    (uchar_t *)(buf_ptr + FPM_OFFSET), FPM_SZ, ps);
4545 	    break;
4546 	}
4547 
4548 	if ((!status) && ps) {
4549 		/*
4550 		 * Reset the IB
4551 		 */
4552 		status = g_scsi_reset(controller_fd);
4553 	}
4554 
4555 	(void) close(controller_fd);
4556 	return (status);
4557 }
4558 
4559 /*
4560  * Set the World Wide Name
4561  * in page 4 of the Send Diagnostic command.
4562  *
4563  * Is it allowed to change the wwn ???
4564  * The path must point to an IB.
4565  *
4566  */
4567 int
4568 l_set_wwn(char *path_phys, char *wwn)
4569 {
4570 Page4_name	page4;
4571 L_inquiry	inq;
4572 int		fd, status;
4573 char		wwnp[WWN_SIZE];
4574 
4575 	(void) memset(&inq, 0, sizeof (inq));
4576 	(void) memset(&page4, 0, sizeof (page4));
4577 
4578 	if ((fd = g_object_open(path_phys, O_NDELAY | O_RDONLY)) == -1) {
4579 		return (L_OPEN_PATH_FAIL);
4580 	}
4581 	/* Verify it is a Photon */
4582 	if (status = g_scsi_inquiry_cmd(fd,
4583 		(uchar_t *)&inq, sizeof (struct l_inquiry_struct))) {
4584 		(void) close(fd);
4585 		return (status);
4586 	}
4587 	if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) &&
4588 		(!(strncmp((char *)inq.inq_vid, "SUN     ",
4589 		sizeof (inq.inq_vid)) &&
4590 		((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) {
4591 		(void) close(fd);
4592 		return (L_ENCL_INVALID_PATH);
4593 	}
4594 
4595 	page4.page_code = L_PAGE_4;
4596 	page4.page_len = (ushort_t)((sizeof (struct page4_name) - 4));
4597 	page4.string_code = L_WWN;
4598 	page4.enable = 1;
4599 	if (g_string_to_wwn((uchar_t *)wwn, (uchar_t *)&page4.name)) {
4600 		close(fd);
4601 		return (EINVAL);
4602 	}
4603 	bcopy((void *)wwnp, (void *)page4.name, (size_t)WWN_SIZE);
4604 
4605 	if (status = g_scsi_send_diag_cmd(fd, (uchar_t *)&page4,
4606 		sizeof (page4))) {
4607 		(void) close(fd);
4608 		return (status);
4609 	}
4610 
4611 	/*
4612 	 * Check the wwn really changed.
4613 	 */
4614 	bzero((char *)page4.name, 32);
4615 	if (status = g_scsi_rec_diag_cmd(fd, (uchar_t *)&page4,
4616 				sizeof (page4), L_PAGE_4)) {
4617 		(void) close(fd);
4618 		return (status);
4619 	}
4620 	if (bcmp((char *)page4.name, wwnp, WWN_SIZE)) {
4621 		(void) close(fd);
4622 		return (L_WARNING);
4623 	}
4624 
4625 	(void) close(fd);
4626 	return (0);
4627 }
4628 
4629 
4630 
4631 /*
4632  * Use a physical path to a disk in a Photon box
4633  * as the base to genererate a path to a SES
4634  * card in this box.
4635  *
4636  * path_phys: Physical path to a Photon disk.
4637  * ses_path:  This must be a pointer to an already allocated path string.
4638  *
4639  * RETURNS:
4640  *	0	 O.K.
4641  *	non-zero otherwise
4642  */
4643 int
4644 l_get_ses_path(char *path_phys, char *ses_path, gfc_map_t *map,
4645 	int verbose)
4646 {
4647 char	*char_ptr, id_buf[MAXPATHLEN], wwn[20];
4648 uchar_t	t_wwn[20], *ses_wwn, *ses_wwn1, *ses_nwwn;
4649 int	j, al_pa, al_pa1, box_id, fd, disk_flag = 0;
4650 int	err, found = 0;
4651 gfc_port_dev_info_t	*dev_addr_ptr;
4652 
4653 	if ((path_phys == NULL) || (ses_path == NULL) || (map == NULL)) {
4654 		return (L_NO_SES_PATH);
4655 	}
4656 
4657 	(void) strcpy(ses_path, path_phys);
4658 	if ((char_ptr = strrchr(ses_path, '/')) == NULL) {
4659 			return (L_INVLD_PATH_NO_SLASH_FND);
4660 	}
4661 	disk_flag++;
4662 	*char_ptr = '\0';   /* Terminate sting  */
4663 	(void) strcat(ses_path, SLSH_SES_NAME);
4664 
4665 	/*
4666 	 * Figure out and create the boxes pathname.
4667 	 *
4668 	 * NOTE: This uses the fact that the disks's
4669 	 * AL_PA and the boxes AL_PA must match
4670 	 * the assigned hard address in the current
4671 	 * implementations. This may not be true in the
4672 	 * future.
4673 	 */
4674 	if ((char_ptr = strrchr(path_phys, '@')) == NULL) {
4675 		return (L_INVLD_PATH_NO_ATSIGN_FND);
4676 	}
4677 	char_ptr++;	/* point to the loop identifier */
4678 
4679 	if ((err = g_get_wwn(path_phys, t_wwn, t_wwn,
4680 		&al_pa, verbose)) != 0) {
4681 		return (err);
4682 	}
4683 	box_id = g_sf_alpa_to_switch[al_pa & 0xFF] & BOX_ID_MASK;
4684 
4685 	switch (map->hba_addr.port_topology) {
4686 	case FC_TOP_PRIVATE_LOOP:
4687 		for (j = 0, dev_addr_ptr = map->dev_addr;
4688 			j < map->count; j++, dev_addr_ptr++) {
4689 		    if (dev_addr_ptr->gfc_port_dev.priv_port.
4690 			sf_inq_dtype == DTYPE_ESI) {
4691 			al_pa1 = dev_addr_ptr->gfc_port_dev.
4692 				priv_port.sf_al_pa;
4693 			if (box_id == (g_sf_alpa_to_switch[al_pa1] &
4694 				BOX_ID_MASK)) {
4695 			    if (!found) {
4696 				ses_wwn = dev_addr_ptr->
4697 					gfc_port_dev.priv_port.sf_port_wwn;
4698 				ses_nwwn = dev_addr_ptr->
4699 					gfc_port_dev.priv_port.sf_node_wwn;
4700 				if (getenv("_LUX_P_DEBUG")) {
4701 					(void) g_ll_to_str(ses_wwn,
4702 						(char *)t_wwn);
4703 					(void) printf(
4704 					"  l_get_ses_path: "
4705 					"Found ses wwn = %s "
4706 					"al_pa 0x%x\n", t_wwn, al_pa1);
4707 				}
4708 			} else {
4709 				ses_wwn1 = dev_addr_ptr->
4710 				    gfc_port_dev.priv_port.sf_port_wwn;
4711 				if (getenv("_LUX_P_DEBUG")) {
4712 					(void) g_ll_to_str(ses_wwn1,
4713 							(char *)t_wwn);
4714 					(void) printf(
4715 						"  l_get_ses_path: "
4716 						"Found second ses " "wwn = %s "
4717 						"al_pa 0x%x\n", t_wwn, al_pa1);
4718 				}
4719 			    }
4720 			    found++;
4721 			}
4722 		    }
4723 		}
4724 		break;
4725 	case FC_TOP_FABRIC:
4726 	case FC_TOP_PUBLIC_LOOP:
4727 		for (j = 0, dev_addr_ptr = map->dev_addr;
4728 			j < map->count; j++, dev_addr_ptr++) {
4729 		    if (dev_addr_ptr->gfc_port_dev.pub_port.dev_dtype ==
4730 				DTYPE_ESI) {
4731 			/*
4732 			 * We found an enclosure, lets match the
4733 			 * area and domain codes for this enclosure with
4734 			 * that of the ses path since there may be
4735 			 * multiple enclosures with same box id on a
4736 			 * fabric
4737 			 */
4738 			al_pa1 = dev_addr_ptr->gfc_port_dev.
4739 				pub_port.dev_did.port_id;
4740 			if ((al_pa & AREA_DOMAIN_ID) ==
4741 				(al_pa1 & AREA_DOMAIN_ID)) {
4742 				/*
4743 				 * The area and domain matched. Now, we
4744 				 * match the box id of the disk with
4745 				 * this enclosure
4746 				 */
4747 				if (box_id ==
4748 				    (g_sf_alpa_to_switch[al_pa1 &
4749 					0xFF] & BOX_ID_MASK)) {
4750 				    if (!found) {
4751 					ses_wwn = dev_addr_ptr->
4752 						gfc_port_dev.pub_port.
4753 						    dev_pwwn.raw_wwn;
4754 					ses_nwwn = dev_addr_ptr->
4755 						gfc_port_dev.pub_port.
4756 						dev_nwwn.raw_wwn;
4757 					if (getenv("_LUX_P_DEBUG")) {
4758 					    (void) g_ll_to_str(ses_wwn,
4759 							(char *)t_wwn);
4760 					    (void) printf(
4761 						    "  l_get_ses_path: "
4762 						    "Found ses wwn = %s "
4763 						    "al_pa 0x%x\n", t_wwn,
4764 						    al_pa1);
4765 					}
4766 				    } else {
4767 					ses_wwn1 = dev_addr_ptr->
4768 						gfc_port_dev.pub_port.
4769 						    dev_pwwn.raw_wwn;
4770 					if (getenv("_LUX_P_DEBUG")) {
4771 					    (void) g_ll_to_str(ses_wwn1,
4772 						(char *)t_wwn);
4773 					    (void) printf(
4774 						"  l_get_ses_path: "
4775 						"Found second ses "
4776 						"wwn = %s "
4777 						"al_pa 0x%x\n", t_wwn,
4778 						al_pa1);
4779 					}
4780 				    }
4781 				    found++;
4782 				}
4783 			    }
4784 			}
4785 		    }
4786 		    break;
4787 	case FC_TOP_PT_PT:
4788 		return (L_PT_PT_FC_TOP_NOT_SUPPORTED);
4789 	default:
4790 		return (L_UNEXPECTED_FC_TOPOLOGY);
4791 	}	/* End of switch on port_topology */
4792 
4793 	if (!found) {
4794 		return (L_NO_SES_PATH);
4795 	}
4796 
4797 	if (strstr(path_phys, SCSI_VHCI) != NULL) {
4798 		(void) g_ll_to_str(ses_nwwn, wwn);
4799 		(void) sprintf(id_buf, "g%s:0", wwn);
4800 	} else {
4801 		(void) g_ll_to_str(ses_wwn, wwn);
4802 		(void) sprintf(id_buf, "w%s,0:0", wwn);
4803 	}
4804 	(void) strcat(ses_path, id_buf);
4805 	if (verbose) {
4806 		(void) fprintf(stdout,
4807 			MSGSTR(9058, "  Creating enclosure path:\n    %s\n"),
4808 			ses_path);
4809 	}
4810 
4811 	/*
4812 	 * see if these paths exist.
4813 	 */
4814 	if ((fd = g_object_open(ses_path, O_NDELAY | O_RDONLY)) == -1) {
4815 
4816 		if (strstr(path_phys, SCSI_VHCI) != NULL) {
4817 			return (L_INVALID_PATH);
4818 		}
4819 
4820 		char_ptr = strrchr(ses_path, '/');
4821 		*char_ptr = '\0';
4822 		(void) strcat(ses_path, SLSH_SES_NAME);
4823 		if (found > 1) {
4824 			(void) g_ll_to_str(ses_wwn1, wwn);
4825 			P_DPRINTF("  l_get_ses_path: "
4826 				"Using second path, ses wwn1 = %s\n",
4827 				wwn);
4828 			(void) sprintf(id_buf, "w%s,0:0", wwn);
4829 			strcat(ses_path, id_buf);
4830 			return (0);
4831 		} else {
4832 			return (L_NO_SES_PATH);
4833 		}
4834 	}
4835 	close(fd);
4836 	return (0);
4837 }
4838 
4839 
4840 
4841 /*
4842  * Get a valid location, front/rear & slot.
4843  *
4844  * path_struct->p_physical_path must be of a disk.
4845  *
4846  * OUTPUT: path_struct->slot_valid
4847  *	path_struct->slot
4848  *	path_struct->f_flag
4849  *
4850  * RETURN:
4851  *	0	 O.K.
4852  *	non-zero otherwise
4853  */
4854 int
4855 l_get_slot(struct path_struct *path_struct, L_state *l_state, int verbose)
4856 {
4857 int		err, al_pa, slot, found = 0;
4858 uchar_t		node_wwn[WWN_SIZE], port_wwn[WWN_SIZE];
4859 uint_t		select_id;
4860 
4861 	if ((path_struct == NULL) || (l_state == NULL)) {
4862 		return (L_INVALID_PATH_FORMAT);
4863 	}
4864 
4865 	/* Double check to see if we need to calculate. */
4866 	if (path_struct->slot_valid)
4867 		return (0);
4868 
4869 	/* Programming error if this occures */
4870 	assert(path_struct->ib_path_flag == 0);
4871 
4872 	if (strstr(path_struct->p_physical_path, "ssd") == NULL) {
4873 		return (L_INVLD_PHYS_PATH_TO_DISK);
4874 	}
4875 	if (err = g_get_wwn(path_struct->p_physical_path, port_wwn, node_wwn,
4876 		&al_pa, verbose)) {
4877 		return (err);
4878 	}
4879 
4880 	/*
4881 	 * Find the slot by searching for the matching hard address.
4882 	 * Take only the low order byte ignoring area and domain code in
4883 	 * fabric devices' 24 bit al_pa
4884 	 */
4885 	select_id = g_sf_alpa_to_switch[al_pa & 0xFF];
4886 	P_DPRINTF("  l_get_slot: Searching Receive Diagnostic page 2, "
4887 		"to find the slot number with this ID:0x%x\n",
4888 		select_id);
4889 
4890 	for (slot = 0; slot < l_state->total_num_drv/2; slot++) {
4891 		if (l_state->drv_front[slot].ib_status.sel_id ==
4892 			select_id) {
4893 			path_struct->f_flag = 1;
4894 			found = 1;
4895 			break;
4896 		} else if (l_state->drv_rear[slot].ib_status.sel_id ==
4897 			select_id) {
4898 			path_struct->f_flag = 0;
4899 			found = 1;
4900 			break;
4901 		}
4902 	}
4903 	if (!found) {
4904 		return (L_INVALID_SLOT);	/* Failure */
4905 	}
4906 	if ((strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_OFF_NAME,
4907 						strlen(DAK_OFF_NAME)) == 0) ||
4908 		(strncmp((char *)l_state->ib_tbl.config.prod_id, DAK_PROD_STR,
4909 						strlen(DAK_OFF_NAME)) == 0)) {
4910 		P_DPRINTF("  l_get_slot: Found slot %d.\n",
4911 			path_struct->f_flag ? slot : slot + (MAX_DRIVES_DAK/2));
4912 	} else {
4913 		P_DPRINTF("  l_get_slot: Found slot %d %s.\n", slot,
4914 			path_struct->f_flag ? "Front" : "Rear");
4915 	}
4916 	path_struct->slot = slot;
4917 	path_struct->slot_valid = 1;
4918 	return (0);
4919 }
4920 
4921 
4922 void
4923 l_element_msg_string(uchar_t code, char *es)
4924 {
4925 	if (code == S_OK) {
4926 		(void) sprintf(es, MSGSTR(29, "O.K."));
4927 	} else if (code == S_NOT_AVAILABLE) {
4928 		(void) sprintf(es, MSGSTR(34, "Disabled"));
4929 	} else if (code == S_NOT_INSTALLED) {
4930 		(void) sprintf(es, MSGSTR(30, "Not Installed"));
4931 	} else if (code == S_NONCRITICAL) {
4932 		(void) sprintf(es, MSGSTR(9059, "Noncritical failure"));
4933 	} else if (code == S_CRITICAL) {
4934 		(void) sprintf(es, MSGSTR(122, "Critical failure"));
4935 	} else {
4936 		(void) sprintf(es, MSGSTR(4, "Unknown status"));
4937 	}
4938 }
4939 
4940 
4941 /*
4942  * Get all ses paths paths to a given box.
4943  * The arg should be the physical path to one of the box's IB.
4944  * NOTE: The caller must free the allocated lists.
4945  *
4946  * OUTPUT:
4947  *	a pointer to a list of ses paths if found
4948  *	NULL on error.
4949  *
4950  * RETURNS:
4951  *	0	 if O.K.
4952  *	non-zero otherwise
4953  */
4954 int
4955 l_get_allses(char *path, struct box_list_struct *box_list,
4956 			struct dlist **ses_list, int verbose)
4957 {
4958 struct box_list_struct 	*box_list_ptr;
4959 char			node_wwn_s[WWN_S_LEN];
4960 struct dlist		*dlt, *dl;
4961 
4962 	if ((path == NULL) || (box_list == NULL) || (ses_list == NULL)) {
4963 		return (L_INVALID_PATH_FORMAT);
4964 	}
4965 
4966 	/* Initialize lists/arrays */
4967 	*ses_list = dlt = dl = (struct dlist *)NULL;
4968 	node_wwn_s[0] = '\0';
4969 
4970 	H_DPRINTF("  l_get_allses: Looking for all ses paths for"
4971 		" box at path: %s\n", path);
4972 
4973 	for (box_list_ptr = box_list; box_list_ptr != NULL;
4974 				box_list_ptr = box_list_ptr->box_next) {
4975 		H_DPRINTF("  l_get_allses: physical_path= %s\n",
4976 				box_list_ptr->b_physical_path);
4977 		if (strcmp(path, box_list_ptr->b_physical_path) == 0) {
4978 			(void) strcpy(node_wwn_s, box_list_ptr->b_node_wwn_s);
4979 			break;
4980 		}
4981 	}
4982 	if (node_wwn_s[0] == '\0') {
4983 		H_DPRINTF("node_wwn_s is NULL!\n");
4984 		return (L_NO_NODE_WWN_IN_BOXLIST);
4985 	}
4986 	H_DPRINTF("  l_get_allses: node_wwn=%s\n", node_wwn_s);
4987 	for (box_list_ptr = box_list; box_list_ptr != NULL;
4988 				box_list_ptr = box_list_ptr->box_next) {
4989 		if (strcmp(node_wwn_s, box_list_ptr->b_node_wwn_s) == 0) {
4990 			if ((dl = (struct dlist *)
4991 				g_zalloc(sizeof (struct dlist))) == NULL) {
4992 				while (*ses_list != NULL) {
4993 					dl = dlt->next;
4994 					(void) g_destroy_data(dlt);
4995 					dlt = dl;
4996 				}
4997 				return (L_MALLOC_FAILED);
4998 			}
4999 			H_DPRINTF("  l_get_allses: Found ses=%s\n",
5000 					box_list_ptr->b_physical_path);
5001 			dl->dev_path = strdup(box_list_ptr->b_physical_path);
5002 			dl->logical_path = strdup(box_list_ptr->logical_path);
5003 			if (*ses_list == NULL) {
5004 				*ses_list = dlt = dl;
5005 			} else {
5006 				dlt->next = dl;
5007 				dl->prev = dlt;
5008 				dlt = dl;
5009 			}
5010 		}
5011 	}
5012 
5013 	return (0);
5014 }
5015 
5016 /*
5017  *	Routine to return the enclosure type pointed to by the path.
5018  *	Inputs:	The inquiry data for the device in question
5019  *
5020  *	Return:  >= 0 is the type:
5021  *
5022  *	Types are defined in storage/libg_fc/common/hdrs/g_state.h:
5023  *
5024  *		0 -> default (SENA)
5025  *		1 -> Daktari
5026  *		2 -> Other Enclosures
5027  *
5028  */
5029 int
5030 l_get_enc_type(L_inquiry inq)
5031 {
5032 	if (strncmp((char *)&inq.inq_pid[0], ENCLOSURE_PROD_ID,
5033 		    strlen(ENCLOSURE_PROD_ID)) == 0) {
5034 		return (SENA_ENC_TYPE);
5035 	}
5036 	if (strncmp((char *)&inq.inq_pid[0], DAK_OFF_NAME,
5037 		strlen(DAK_OFF_NAME)) == 0) {
5038 	    return (DAK_ENC_TYPE);
5039 	}
5040 	if (strncmp((char *)&inq.inq_pid[0], DAK_PROD_STR,
5041 		strlen(DAK_PROD_STR)) == 0) {
5042 	    return (DAK_ENC_TYPE);
5043 	}
5044 	/*
5045 	 *  ADD OTHERS here if ever needed/wanted, and add to def's
5046 	 * 	as noted above
5047 	 */
5048 	return (UNDEF_ENC_TYPE);
5049 }
5050 
5051 void
5052 free_mp_dev_map(gfc_map_mp_t **map_mp_ptr) {
5053 	gfc_map_mp_t	    *next = NULL;
5054 
5055 	for (; *map_mp_ptr != NULL; *map_mp_ptr = next) {
5056 		next = (*map_mp_ptr)->map_next;
5057 		(void) g_destroy_data((*map_mp_ptr)->map.dev_addr);
5058 		(void) g_destroy_data(*map_mp_ptr);
5059 	}
5060 	*map_mp_ptr = NULL;
5061 }
5062 /*
5063  * This function will return a linked list of device maps
5064  * An example of when this will be used is when we want to return the device
5065  * map of a vhci path.
5066  */
5067 
5068 int
5069 get_mp_dev_map(char *path, gfc_map_mp_t **map_mp_ptr, int verbose) {
5070 
5071 	int		pathcnt, i, err;
5072 	mp_pathlist_t	pathlist;
5073 	gfc_map_mp_t	*new_map_mp_ptr;
5074 	char		drvr_path[MAXPATHLEN];
5075 	if (strstr(path, SCSI_VHCI)) {
5076 		if (g_get_pathlist(path, &pathlist)) {
5077 			return (L_INVALID_PATH);
5078 		}
5079 		pathcnt = pathlist.path_count;
5080 		for (i = 0; i < pathcnt; i++) {
5081 			if (pathlist.path_info[i].path_state < MAXPATHSTATE) {
5082 				/*
5083 				 * only pay attention to paths that are either
5084 				 * ONLINE or STANDBY
5085 				 */
5086 				if ((pathlist.path_info[i].path_state ==
5087 					MDI_PATHINFO_STATE_ONLINE) ||
5088 				    (pathlist.path_info[i].path_state ==
5089 					MDI_PATHINFO_STATE_STANDBY)) {
5090 					if ((new_map_mp_ptr = (gfc_map_mp_t *)
5091 					    g_zalloc(sizeof (gfc_map_mp_t)))
5092 								== NULL) {
5093 						free(pathlist.path_info);
5094 						free_mp_dev_map(map_mp_ptr);
5095 						return (L_MALLOC_FAILED);
5096 					}
5097 					(void) strcpy(drvr_path,
5098 						pathlist.path_info[i].path_hba);
5099 					(void) strcat(drvr_path, FC_CTLR);
5100 					if (err = g_get_dev_map(drvr_path,
5101 					    &(new_map_mp_ptr->map),
5102 					    verbose)) {
5103 						free(pathlist.path_info);
5104 						free_mp_dev_map(map_mp_ptr);
5105 						return (err);
5106 					}
5107 					/* add newly created map onto list */
5108 					if (*map_mp_ptr == NULL) {
5109 						new_map_mp_ptr->map_next = NULL;
5110 						*map_mp_ptr = new_map_mp_ptr;
5111 					} else {
5112 						new_map_mp_ptr->map_next =
5113 						    *map_mp_ptr;
5114 						*map_mp_ptr = new_map_mp_ptr;
5115 					}
5116 				}
5117 			}
5118 		}
5119 		free(pathlist.path_info);
5120 	} else {
5121 		if ((new_map_mp_ptr = (gfc_map_mp_t *)g_zalloc
5122 			    (sizeof (gfc_map_mp_t))) == NULL) {
5123 			return (L_MALLOC_FAILED);
5124 		}
5125 		g_get_dev_map(path, &(new_map_mp_ptr->map), verbose);
5126 		*map_mp_ptr = new_map_mp_ptr;
5127 	}
5128 	return (0);
5129 }
5130