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