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