1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte /*
22fcf3ce44SJohn Forte  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23fcf3ce44SJohn Forte  * Use is subject to license terms.
24fcf3ce44SJohn Forte  */
25fcf3ce44SJohn Forte 
26fcf3ce44SJohn Forte 
27fcf3ce44SJohn Forte #include "cfga_fp.h"
28fcf3ce44SJohn Forte #include <sys/fibre-channel/impl/fc_error.h>
29fcf3ce44SJohn Forte 
30fcf3ce44SJohn Forte /* Structure for walking the tree */
31fcf3ce44SJohn Forte typedef struct {
32fcf3ce44SJohn Forte 	apid_t		*apidp;
33fcf3ce44SJohn Forte 	char		*xport_logp;
34fcf3ce44SJohn Forte 	ldata_list_t	*listp;
35fcf3ce44SJohn Forte 	fpcfga_cmd_t	cmd;
36fcf3ce44SJohn Forte 	cfga_stat_t	chld_config;
37fcf3ce44SJohn Forte 	cfga_type_t	xport_type;
38fcf3ce44SJohn Forte 	cfga_stat_t	xport_rstate;
39fcf3ce44SJohn Forte 	fpcfga_ret_t	ret;
40fcf3ce44SJohn Forte 	int		l_errno;
41fcf3ce44SJohn Forte } fpcfga_list_t;
42fcf3ce44SJohn Forte 
43fcf3ce44SJohn Forte typedef struct {
44fcf3ce44SJohn Forte 	uint_t itype;
45fcf3ce44SJohn Forte 	const char *ntype;
46fcf3ce44SJohn Forte 	const char *name;
47fcf3ce44SJohn Forte } fpcfga_devtype_t;
48fcf3ce44SJohn Forte 
49fcf3ce44SJohn Forte #define	ERR_INQ_DTYPE	0xff
50fcf3ce44SJohn Forte 
51fcf3ce44SJohn Forte /* The TYPE field is parseable and should not contain spaces */
52fcf3ce44SJohn Forte #define	FP_FC_PORT_TYPE		"fc"
53fcf3ce44SJohn Forte #define	FP_FC_PORT_ERROR	"fc-error"
54fcf3ce44SJohn Forte #define	FP_FC_FABRIC_PORT_TYPE	"fc-fabric"
55fcf3ce44SJohn Forte #define	FP_FC_PUBLIC_PORT_TYPE	"fc-public"
56fcf3ce44SJohn Forte #define	FP_FC_PRIVATE_PORT_TYPE	"fc-private"
57fcf3ce44SJohn Forte #define	FP_FC_PT_TO_PT_PORT_TYPE	"fc-pt_to_pt"
58fcf3ce44SJohn Forte 
59fcf3ce44SJohn Forte /* Indicates no plag passing */
60fcf3ce44SJohn Forte #define	NO_FLAG			0
61fcf3ce44SJohn Forte 
62fcf3ce44SJohn Forte /* defines for retry algorithm */
63fcf3ce44SJohn Forte #define	OPEN_RETRY_COUNT	5
64fcf3ce44SJohn Forte #define	OPEN_RETRY_INTERVAL	10000 /* 1/100 of a sec. */
65fcf3ce44SJohn Forte #define	IOCTL_RETRY_COUNT	5
66fcf3ce44SJohn Forte #define	IOCTL_RETRY_INTERVAL	5000000 /* 5 sec */
67fcf3ce44SJohn Forte 
68fcf3ce44SJohn Forte /* define for fcp scsi passthru wait */
69fcf3ce44SJohn Forte #define	FCP_SCSI_CMD_TIMEOUT	10
70fcf3ce44SJohn Forte 
71fcf3ce44SJohn Forte /* define for fcp pseudo node */
72fcf3ce44SJohn Forte #define	FCP_PATH	"/devices/pseudo/fcp@0:fcp"
73fcf3ce44SJohn Forte 
74fcf3ce44SJohn Forte /* Function prototypes */
75fcf3ce44SJohn Forte static fpcfga_ret_t postprocess_list_data(const ldata_list_t *listp,
76fcf3ce44SJohn Forte     fpcfga_cmd_t cmd, cfga_stat_t chld_config, int *np, uint_t flags);
77fcf3ce44SJohn Forte static int stat_fc_dev(di_node_t node, void *arg);
78fcf3ce44SJohn Forte static int stat_FCP_dev(di_node_t node, void *arg);
79fcf3ce44SJohn Forte static fpcfga_ret_t do_stat_fca_xport(fpcfga_list_t *lap, int limited_stat,
80fcf3ce44SJohn Forte 	HBA_PORTATTRIBUTES portAttrs);
81fcf3ce44SJohn Forte static int get_xport_state(di_node_t node, void *arg);
82fcf3ce44SJohn Forte 
83fcf3ce44SJohn Forte static fpcfga_ret_t do_stat_fc_dev(const di_node_t node, const char *nodepath,
84fcf3ce44SJohn Forte     fpcfga_list_t *lap, int limited_stat);
85fcf3ce44SJohn Forte static fpcfga_ret_t do_stat_FCP_dev(const di_node_t node, const char *nodepath,
86fcf3ce44SJohn Forte     fpcfga_list_t *lap, int limited_stat);
87fcf3ce44SJohn Forte static cfga_stat_t xport_devinfo_to_recep_state(uint_t xport_di_state);
88fcf3ce44SJohn Forte static cfga_stat_t dev_devinfo_to_occupant_state(uint_t dev_di_state);
89fcf3ce44SJohn Forte static void get_hw_info(di_node_t node, cfga_list_data_t *clp);
90fcf3ce44SJohn Forte static const char *get_device_type(di_node_t);
91fcf3ce44SJohn Forte static fpcfga_ret_t init_ldata_for_accessible_dev(const char *dyncomp,
92fcf3ce44SJohn Forte 	uchar_t inq_type, fpcfga_list_t *lap);
93fcf3ce44SJohn Forte static fpcfga_ret_t init_ldata_for_accessible_FCP_dev(const char *port_wwn,
94fcf3ce44SJohn Forte 	int num_luns, struct report_lun_resp *resp_buf,
95fcf3ce44SJohn Forte 	fpcfga_list_t *larg, int *l_errnop);
96fcf3ce44SJohn Forte static fpcfga_ret_t is_dyn_ap_on_ldata_list(const char *port_wwn,
97fcf3ce44SJohn Forte 	const ldata_list_t *listp, ldata_list_t **matchldpp, int *l_errno);
98fcf3ce44SJohn Forte static fpcfga_ret_t is_FCP_dev_ap_on_ldata_list(const char *port_wwn,
99fcf3ce44SJohn Forte 	const int lun_num, ldata_list_t *ldatap, ldata_list_t **matchldpp);
100fcf3ce44SJohn Forte 
101fcf3ce44SJohn Forte static fpcfga_ret_t init_ldata_for_mpath_dev(di_path_t path, char *port_wwn,
102fcf3ce44SJohn Forte 	int *l_errnop, fpcfga_list_t *lap);
103fcf3ce44SJohn Forte static fpcfga_ret_t insert_ldata_to_ldatalist(const char *port_wwn,
104fcf3ce44SJohn Forte 	int *lun_nump, ldata_list_t *listp, ldata_list_t **ldatapp);
105fcf3ce44SJohn Forte static fpcfga_ret_t insert_fc_dev_ldata(const char *port_wwn,
106fcf3ce44SJohn Forte 	ldata_list_t *listp, ldata_list_t **ldatapp);
107fcf3ce44SJohn Forte static fpcfga_ret_t insert_FCP_dev_ldata(const char *port_wwn, int lun_num,
108fcf3ce44SJohn Forte 	ldata_list_t *listp, ldata_list_t **ldatapp);
109fcf3ce44SJohn Forte static int stat_path_info_fc_dev(di_node_t root, fpcfga_list_t	*lap,
110fcf3ce44SJohn Forte 	int *l_errnop);
111fcf3ce44SJohn Forte static int stat_path_info_FCP_dev(di_node_t root, fpcfga_list_t	*lap,
112fcf3ce44SJohn Forte 	int *l_errnop);
113fcf3ce44SJohn Forte static fpcfga_ret_t get_accessible_FCP_dev_ldata(const char *dyncomp,
114fcf3ce44SJohn Forte 	fpcfga_list_t *lap, int *l_errnop);
115fcf3ce44SJohn Forte static fpcfga_ret_t get_standard_inq_data(const char *xport_phys,
116fcf3ce44SJohn Forte 	const char *dyncomp, uchar_t *lun_num, struct scsi_inquiry **inq_buf,
117fcf3ce44SJohn Forte 	int *l_errnop);
118fcf3ce44SJohn Forte static void init_fcp_scsi_cmd(struct fcp_scsi_cmd *fscsi, uchar_t *lun_num,
119fcf3ce44SJohn Forte 	la_wwn_t *pwwn, void *scmdbuf, size_t scmdbuf_len, void *respbuf,
120fcf3ce44SJohn Forte 	size_t respbuf_len, void *sensebuf, size_t sensebuf_len);
121fcf3ce44SJohn Forte static fpcfga_ret_t issue_fcp_scsi_cmd(const char *xport_phys,
122fcf3ce44SJohn Forte 	struct fcp_scsi_cmd *fscsi, int *l_errnop);
123fcf3ce44SJohn Forte static uchar_t get_inq_dtype(char *xport_phys, char *dyncomp, HBA_HANDLE handle,
124fcf3ce44SJohn Forte     HBA_PORTATTRIBUTES *portAttrs, HBA_PORTATTRIBUTES *discPortAttrs);
125fcf3ce44SJohn Forte 
126fcf3ce44SJohn Forte static fpcfga_devtype_t device_list[] = {
127fcf3ce44SJohn Forte 	{ DTYPE_DIRECT,		DDI_NT_BLOCK_CHAN,	"disk"},
128fcf3ce44SJohn Forte 	{ DTYPE_DIRECT,		DDI_NT_BLOCK,		"disk"},
129fcf3ce44SJohn Forte 	{ DTYPE_DIRECT,		DDI_NT_BLOCK_WWN,	"disk"},
130fcf3ce44SJohn Forte 	{ DTYPE_DIRECT,		DDI_NT_BLOCK_FABRIC,	"disk"},
131fcf3ce44SJohn Forte 	{ DTYPE_SEQUENTIAL,	DDI_NT_TAPE,		"tape"},
132fcf3ce44SJohn Forte 	{ DTYPE_PRINTER,	NULL,			"printer"},
133fcf3ce44SJohn Forte 	{ DTYPE_PROCESSOR,	NULL,			"processor"},
134fcf3ce44SJohn Forte 	{ DTYPE_WORM,		NULL,			"WORM"},
135fcf3ce44SJohn Forte 	{ DTYPE_RODIRECT,	DDI_NT_CD_CHAN,		"CD-ROM"},
136fcf3ce44SJohn Forte 	{ DTYPE_RODIRECT,	DDI_NT_CD,		"CD-ROM"},
137fcf3ce44SJohn Forte 	{ DTYPE_SCANNER,	NULL,			"scanner"},
138fcf3ce44SJohn Forte 	{ DTYPE_OPTICAL,	NULL,			"optical"},
139fcf3ce44SJohn Forte 	{ DTYPE_CHANGER,	NULL,			"med-changer"},
140fcf3ce44SJohn Forte 	{ DTYPE_COMM,		NULL,			"comm-device"},
141fcf3ce44SJohn Forte 	{ DTYPE_ARRAY_CTRL,	NULL,			"array-ctrl"},
142fcf3ce44SJohn Forte 	{ DTYPE_ESI,		NULL,			"ESI"},
143fcf3ce44SJohn Forte 	/*
144fcf3ce44SJohn Forte 	 * This has to be the LAST entry for DTYPE_UNKNOWN_INDEX.
145fcf3ce44SJohn Forte 	 * Add entries before this.
146fcf3ce44SJohn Forte 	 */
147fcf3ce44SJohn Forte 	{ DTYPE_UNKNOWN,	NULL,			"unknown"}
148fcf3ce44SJohn Forte };
149fcf3ce44SJohn Forte 
150fcf3ce44SJohn Forte #define	N_DEVICE_TYPES	(sizeof (device_list) / sizeof (device_list[0]))
151fcf3ce44SJohn Forte 
152fcf3ce44SJohn Forte #define	DTYPE_UNKNOWN_INDEX	(N_DEVICE_TYPES - 1)
153fcf3ce44SJohn Forte 
154fcf3ce44SJohn Forte /*
155fcf3ce44SJohn Forte  * Main routine for list operation.
156fcf3ce44SJohn Forte  * It calls various routines to consturct ldata list and
157fcf3ce44SJohn Forte  * postprocess the list data.
158fcf3ce44SJohn Forte  *
159fcf3ce44SJohn Forte  * Overall algorithm:
160fcf3ce44SJohn Forte  * Get the device list on input hba port and construct ldata list for
161fcf3ce44SJohn Forte  * accesible devices.
162fcf3ce44SJohn Forte  * Stat hba port and devices through walking the device tree.
163fcf3ce44SJohn Forte  * Verify the validity of the list data.
164fcf3ce44SJohn Forte  */
165fcf3ce44SJohn Forte fpcfga_ret_t
do_list(apid_t * apidp,fpcfga_cmd_t cmd,ldata_list_t ** llpp,int * nelemp,char ** errstring)166fcf3ce44SJohn Forte do_list(
167fcf3ce44SJohn Forte 	apid_t *apidp,
168fcf3ce44SJohn Forte 	fpcfga_cmd_t cmd,
169fcf3ce44SJohn Forte 	ldata_list_t **llpp,
170fcf3ce44SJohn Forte 	int *nelemp,
171fcf3ce44SJohn Forte 	char **errstring)
172fcf3ce44SJohn Forte {
173fcf3ce44SJohn Forte 	int		n = -1, l_errno = 0, limited_stat;
174fcf3ce44SJohn Forte 	walkarg_t	walkarg;
175fcf3ce44SJohn Forte 	fpcfga_list_t	larg = {NULL};
176fcf3ce44SJohn Forte 	fpcfga_ret_t	ret;
177fcf3ce44SJohn Forte 	la_wwn_t	pwwn;
178fcf3ce44SJohn Forte 	char		*dyncomp = NULL;
179fcf3ce44SJohn Forte 	HBA_HANDLE	handle;
180fcf3ce44SJohn Forte 	HBA_PORTATTRIBUTES	portAttrs;
181fcf3ce44SJohn Forte 	HBA_PORTATTRIBUTES	discPortAttrs;
182fcf3ce44SJohn Forte 	HBA_STATUS		status;
183fcf3ce44SJohn Forte 	int			portIndex, discIndex;
184fcf3ce44SJohn Forte 	int			retry;
185fcf3ce44SJohn Forte 	uchar_t			inq_dtype;
186fcf3ce44SJohn Forte 
187fcf3ce44SJohn Forte 	if (*llpp != NULL || *nelemp != 0) {
188fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
189fcf3ce44SJohn Forte 	}
190fcf3ce44SJohn Forte 
191fcf3ce44SJohn Forte 	/* Create the hba logid (also base component of logical ap_id) */
192fcf3ce44SJohn Forte 	ret = make_xport_logid(apidp->xport_phys, &larg.xport_logp, &l_errno);
193fcf3ce44SJohn Forte 	if (ret != FPCFGA_OK) {
194fcf3ce44SJohn Forte 		cfga_err(errstring, l_errno, ERR_LIST, 0);
195fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
196fcf3ce44SJohn Forte 	}
197fcf3ce44SJohn Forte 
198fcf3ce44SJohn Forte 	assert(larg.xport_logp != NULL);
199fcf3ce44SJohn Forte 
200fcf3ce44SJohn Forte 	larg.cmd = cmd;
201fcf3ce44SJohn Forte 	larg.apidp = apidp;
202fcf3ce44SJohn Forte 	larg.xport_rstate = CFGA_STAT_NONE;
203fcf3ce44SJohn Forte 
204fcf3ce44SJohn Forte 	if ((ret = findMatchingAdapterPort(larg.apidp->xport_phys, &handle,
205fcf3ce44SJohn Forte 	    &portIndex, &portAttrs, errstring)) != FPCFGA_OK) {
206fcf3ce44SJohn Forte 	    S_FREE(larg.xport_logp);
207fcf3ce44SJohn Forte 	    return (ret);
208fcf3ce44SJohn Forte 	}
209fcf3ce44SJohn Forte 
210fcf3ce44SJohn Forte 	/*
211fcf3ce44SJohn Forte 	 * If stating a specific device, we will do limited stat on fca port.
212fcf3ce44SJohn Forte 	 * otherwise full stat on fca part is required.
213fcf3ce44SJohn Forte 	 * If stating a specific device we don't know if it exists or is
214fcf3ce44SJohn Forte 	 * configured yet.  larg.ret is set to apid noexist for do_stat_dev.
215fcf3ce44SJohn Forte 	 * otherwise larg.ret is set to ok initially.
216fcf3ce44SJohn Forte 	 */
217fcf3ce44SJohn Forte 	if (larg.cmd == FPCFGA_STAT_FC_DEV) {
218fcf3ce44SJohn Forte 		limited_stat = 1;		/* for do_stat_fca_xport */
219fcf3ce44SJohn Forte 		larg.ret = FPCFGA_APID_NOEXIST; /* for stat_fc_dev	*/
220fcf3ce44SJohn Forte 	} else {
221fcf3ce44SJohn Forte 		limited_stat = 0;		/* for do_stat_fca_xport */
222fcf3ce44SJohn Forte 		larg.ret = FPCFGA_OK;		/* for stat_fc_dev	*/
223fcf3ce44SJohn Forte 	}
224fcf3ce44SJohn Forte 
225fcf3ce44SJohn Forte 	/* For all list commands, the fca port needs to be stat'ed */
226fcf3ce44SJohn Forte 	if ((ret = do_stat_fca_xport(&larg, limited_stat,
227fcf3ce44SJohn Forte 		portAttrs)) != FPCFGA_OK) {
228fcf3ce44SJohn Forte 		cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
229fcf3ce44SJohn Forte 		list_free(&larg.listp);
230fcf3ce44SJohn Forte 		S_FREE(larg.xport_logp);
231fcf3ce44SJohn Forte 		HBA_CloseAdapter(handle);
232fcf3ce44SJohn Forte 		HBA_FreeLibrary();
233fcf3ce44SJohn Forte 		return (ret);
234fcf3ce44SJohn Forte 	}
235fcf3ce44SJohn Forte 
236fcf3ce44SJohn Forte #ifdef DEBUG
237fcf3ce44SJohn Forte 	if (limited_stat) {
238fcf3ce44SJohn Forte 		assert(larg.listp == NULL);
239fcf3ce44SJohn Forte 	} else {
240fcf3ce44SJohn Forte 		assert(larg.listp != NULL);
241fcf3ce44SJohn Forte 	}
242fcf3ce44SJohn Forte #endif
243fcf3ce44SJohn Forte 	/*
244fcf3ce44SJohn Forte 	 * If stat'ing a FCA port or ALL, we have the bus stat data at
245fcf3ce44SJohn Forte 	 * this point.
246fcf3ce44SJohn Forte 	 * Assume that the bus has no configured children.
247fcf3ce44SJohn Forte 	 */
248fcf3ce44SJohn Forte 	larg.chld_config = CFGA_STAT_UNCONFIGURED;
249fcf3ce44SJohn Forte 
250fcf3ce44SJohn Forte 	switch (larg.cmd) {
251fcf3ce44SJohn Forte 	case FPCFGA_STAT_FC_DEV:
252fcf3ce44SJohn Forte 		/* la_wwn_t has uchar_t raw_wwn[8] thus no need to free. */
253fcf3ce44SJohn Forte 		if (cvt_dyncomp_to_lawwn(apidp->dyncomp, &pwwn) != 0) {
254fcf3ce44SJohn Forte 			cfga_err(errstring, 0, ERR_LIST, 0);
255fcf3ce44SJohn Forte 			list_free(&larg.listp);
256fcf3ce44SJohn Forte 			S_FREE(larg.xport_logp);
257fcf3ce44SJohn Forte 			HBA_CloseAdapter(handle);
258fcf3ce44SJohn Forte 			HBA_FreeLibrary();
259fcf3ce44SJohn Forte 			return (FPCFGA_LIB_ERR);
260fcf3ce44SJohn Forte 		}
261fcf3ce44SJohn Forte 		/*
262fcf3ce44SJohn Forte 		 * if the dyncomp exists on disco ports construct list_data
263fcf3ce44SJohn Forte 		 * otherwise return FPCFGA_APID_NOEXIST.
264fcf3ce44SJohn Forte 		 */
265fcf3ce44SJohn Forte 		retry = 0;
266fcf3ce44SJohn Forte 		do {
267fcf3ce44SJohn Forte 		    status = getPortAttrsByWWN(handle,
268fcf3ce44SJohn Forte 			*((HBA_WWN *)(&pwwn)), &discPortAttrs);
269fcf3ce44SJohn Forte 		    if (status == HBA_STATUS_ERROR_STALE_DATA) {
270fcf3ce44SJohn Forte 			/* get Port Attributes again after refresh. */
271fcf3ce44SJohn Forte 			HBA_RefreshInformation(handle);
272fcf3ce44SJohn Forte 		    } else {
273fcf3ce44SJohn Forte 			break; /* either okay or some other error */
274fcf3ce44SJohn Forte 		    }
275fcf3ce44SJohn Forte 		} while (retry++ < HBA_MAX_RETRIES);
276fcf3ce44SJohn Forte 
277fcf3ce44SJohn Forte 		if (status == HBA_STATUS_OK) {
278fcf3ce44SJohn Forte 			/*
279fcf3ce44SJohn Forte 			 * if dyncomp found in disco ports
280fcf3ce44SJohn Forte 			 * construct  ldata_list and return.
281fcf3ce44SJohn Forte 			 * otherwise continue to stat on dev tree with
282fcf3ce44SJohn Forte 			 * larg.ret set to access_ok which informs stat_fc_dev
283fcf3ce44SJohn Forte 			 * the existence of device on disco ports.
284fcf3ce44SJohn Forte 			 *
285fcf3ce44SJohn Forte 			 * if path is null that guatantees the node is not
286fcf3ce44SJohn Forte 			 * configured.  if node is detached the path
287fcf3ce44SJohn Forte 			 * is incomplete and not usable for further
288fcf3ce44SJohn Forte 			 * operations like uscsi_inq so take care of it here.
289fcf3ce44SJohn Forte 			 */
290fcf3ce44SJohn Forte 			inq_dtype = get_inq_dtype(apidp->xport_phys,
291fcf3ce44SJohn Forte 			    apidp->dyncomp, handle, &portAttrs, &discPortAttrs);
292fcf3ce44SJohn Forte 
293fcf3ce44SJohn Forte 			if (init_ldata_for_accessible_dev(apidp->dyncomp,
294fcf3ce44SJohn Forte 				inq_dtype, &larg) != FPCFGA_OK) {
295fcf3ce44SJohn Forte 				cfga_err(errstring, larg.l_errno,
296fcf3ce44SJohn Forte 					ERR_LIST, 0);
297fcf3ce44SJohn Forte 				list_free(&larg.listp);
298fcf3ce44SJohn Forte 				S_FREE(larg.xport_logp);
299fcf3ce44SJohn Forte 				HBA_CloseAdapter(handle);
300fcf3ce44SJohn Forte 				HBA_FreeLibrary();
301fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
302fcf3ce44SJohn Forte 			}
303fcf3ce44SJohn Forte 			if (apidp->lunlist == NULL) {
304fcf3ce44SJohn Forte 				n = 0;
305fcf3ce44SJohn Forte 				if (postprocess_list_data(
306fcf3ce44SJohn Forte 					larg.listp, cmd,
307fcf3ce44SJohn Forte 					larg.chld_config, &n, NO_FLAG) !=
308fcf3ce44SJohn Forte 					FPCFGA_OK) {
309fcf3ce44SJohn Forte 					cfga_err(errstring,
310fcf3ce44SJohn Forte 					larg.l_errno, ERR_LIST, 0);
311fcf3ce44SJohn Forte 					list_free(&larg.listp);
312fcf3ce44SJohn Forte 					S_FREE(larg.xport_logp);
313fcf3ce44SJohn Forte 					HBA_CloseAdapter(handle);
314fcf3ce44SJohn Forte 					HBA_FreeLibrary();
315fcf3ce44SJohn Forte 					return (FPCFGA_LIB_ERR);
316fcf3ce44SJohn Forte 				}
317fcf3ce44SJohn Forte 				*nelemp = n;
318fcf3ce44SJohn Forte 				*llpp = larg.listp;
319fcf3ce44SJohn Forte 				S_FREE(larg.xport_logp);
320fcf3ce44SJohn Forte 				HBA_CloseAdapter(handle);
321fcf3ce44SJohn Forte 				HBA_FreeLibrary();
322fcf3ce44SJohn Forte 				return (FPCFGA_OK);
323fcf3ce44SJohn Forte 			}
324fcf3ce44SJohn Forte 			larg.ret = FPCFGA_ACCESS_OK;
325fcf3ce44SJohn Forte 		} else if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
326fcf3ce44SJohn Forte 			/*
327fcf3ce44SJohn Forte 			 * path indicates if the node exists in dev tree.
328fcf3ce44SJohn Forte 			 * if not found in dev tree return apid no exist.
329fcf3ce44SJohn Forte 			 * otherwise continue to stat with larg.ret set to
330fcf3ce44SJohn Forte 			 * apid_noexist.
331fcf3ce44SJohn Forte 			 */
332fcf3ce44SJohn Forte 			if (apidp->lunlist == NULL) {
333fcf3ce44SJohn Forte 				list_free(&larg.listp);
334fcf3ce44SJohn Forte 				S_FREE(larg.xport_logp);
335fcf3ce44SJohn Forte 				HBA_CloseAdapter(handle);
336fcf3ce44SJohn Forte 				HBA_FreeLibrary();
337fcf3ce44SJohn Forte 				return (FPCFGA_APID_NOEXIST);
338fcf3ce44SJohn Forte 			}
339fcf3ce44SJohn Forte 		} else { /* any error */
340fcf3ce44SJohn Forte 			/*
341fcf3ce44SJohn Forte 			 * path indicates if the node exists in dev tree.
342fcf3ce44SJohn Forte 			 * if not found in dev tree return lib error.
343fcf3ce44SJohn Forte 			 * otherwise continue to stat with larg.ret set to
344fcf3ce44SJohn Forte 			 * apid_noexist.
345fcf3ce44SJohn Forte 			 */
346fcf3ce44SJohn Forte 			if (apidp->lunlist == NULL) {
347fcf3ce44SJohn Forte 				cfga_err(errstring, 0, ERR_FC_GET_DEVLIST, 0);
348fcf3ce44SJohn Forte 				list_free(&larg.listp);
349fcf3ce44SJohn Forte 				S_FREE(larg.xport_logp);
350fcf3ce44SJohn Forte 				HBA_CloseAdapter(handle);
351fcf3ce44SJohn Forte 				HBA_FreeLibrary();
352fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
353fcf3ce44SJohn Forte 			}
354fcf3ce44SJohn Forte 		}
355fcf3ce44SJohn Forte 		break;
356fcf3ce44SJohn Forte 	case FPCFGA_STAT_ALL:
357fcf3ce44SJohn Forte 		/*
358fcf3ce44SJohn Forte 		 * for each dev in disco ports, create a ldata_list element.
359fcf3ce44SJohn Forte 		 * if if no disco ports found, continue to stat on devinfo tree
360fcf3ce44SJohn Forte 		 * to see if any node exist on the fca port.
361fcf3ce44SJohn Forte 		 */
362fcf3ce44SJohn Forte 		for (discIndex = 0;
363fcf3ce44SJohn Forte 			discIndex < portAttrs.NumberofDiscoveredPorts;
364fcf3ce44SJohn Forte 			discIndex++) {
365fcf3ce44SJohn Forte 		    if (getDiscPortAttrs(handle, portIndex,
366fcf3ce44SJohn Forte 			discIndex, &discPortAttrs)) {
367fcf3ce44SJohn Forte 			/* Move on to the next target */
368fcf3ce44SJohn Forte 			continue;
369fcf3ce44SJohn Forte 		    }
370fcf3ce44SJohn Forte 		    memcpy(&pwwn, &discPortAttrs.PortWWN, sizeof (la_wwn_t));
371fcf3ce44SJohn Forte 		    cvt_lawwn_to_dyncomp(&pwwn, &dyncomp, &l_errno);
372fcf3ce44SJohn Forte 		    if (dyncomp == NULL) {
373fcf3ce44SJohn Forte 			cfga_err(errstring, l_errno, ERR_LIST, 0);
374fcf3ce44SJohn Forte 			list_free(&larg.listp);
375fcf3ce44SJohn Forte 			S_FREE(larg.xport_logp);
376fcf3ce44SJohn Forte 			HBA_CloseAdapter(handle);
377fcf3ce44SJohn Forte 			HBA_FreeLibrary();
378fcf3ce44SJohn Forte 			return (FPCFGA_LIB_ERR);
379fcf3ce44SJohn Forte 		    }
380fcf3ce44SJohn Forte 		    inq_dtype = get_inq_dtype(apidp->xport_phys, dyncomp,
381fcf3ce44SJohn Forte 			handle, &portAttrs, &discPortAttrs);
382fcf3ce44SJohn Forte 
383fcf3ce44SJohn Forte 		    if ((ret = init_ldata_for_accessible_dev(
384fcf3ce44SJohn Forte 			    dyncomp, inq_dtype, &larg)) != FPCFGA_OK) {
385fcf3ce44SJohn Forte 			S_FREE(dyncomp);
386fcf3ce44SJohn Forte 			cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
387fcf3ce44SJohn Forte 				list_free(&larg.listp);
388fcf3ce44SJohn Forte 			S_FREE(larg.xport_logp);
389fcf3ce44SJohn Forte 			HBA_CloseAdapter(handle);
390fcf3ce44SJohn Forte 			HBA_FreeLibrary();
391fcf3ce44SJohn Forte 			return (FPCFGA_LIB_ERR);
392fcf3ce44SJohn Forte 		    }
393fcf3ce44SJohn Forte 		    S_FREE(dyncomp);
394fcf3ce44SJohn Forte 		}
395fcf3ce44SJohn Forte 		break;
396fcf3ce44SJohn Forte 	default:
397fcf3ce44SJohn Forte 		break;
398fcf3ce44SJohn Forte 	}
399fcf3ce44SJohn Forte 
400fcf3ce44SJohn Forte 	/* we need to stat at least 1 device for all commands */
401fcf3ce44SJohn Forte 	if (apidp->flags == FLAG_DEVINFO_FORCE) {
402fcf3ce44SJohn Forte 		walkarg.flags = FLAG_DEVINFO_FORCE;
403fcf3ce44SJohn Forte 	} else {
404fcf3ce44SJohn Forte 		walkarg.flags = 0;
405fcf3ce44SJohn Forte 	}
406fcf3ce44SJohn Forte 
407fcf3ce44SJohn Forte 	walkarg.flags |= FLAG_PATH_INFO_WALK;
408fcf3ce44SJohn Forte 	walkarg.walkmode.node_args.flags = DI_WALK_CLDFIRST;
409fcf3ce44SJohn Forte 	walkarg.walkmode.node_args.fcn = stat_fc_dev;
410fcf3ce44SJohn Forte 
411fcf3ce44SJohn Forte 	/*
412fcf3ce44SJohn Forte 	 * Subtree is ALWAYS rooted at the HBA (not at the device) as
413fcf3ce44SJohn Forte 	 * otherwise deadlock may occur if bus is disconnected.
414fcf3ce44SJohn Forte 	 *
415fcf3ce44SJohn Forte 	 * DINFOPROP was sufficient on apidp->xport_phys prior to the support
416fcf3ce44SJohn Forte 	 * on scsi_vhci child node.  In order to get the link between
417fcf3ce44SJohn Forte 	 * scsi_vhci node and path info node the snap shot of the
418fcf3ce44SJohn Forte 	 * the whole device tree is required with DINFOCPYALL | DINFOPATH flag.
419fcf3ce44SJohn Forte 	 */
420fcf3ce44SJohn Forte 	ret = walk_tree(apidp->xport_phys, &larg, DINFOCPYALL | DINFOPATH,
421fcf3ce44SJohn Forte 			&walkarg, FPCFGA_WALK_NODE, &larg.l_errno);
422fcf3ce44SJohn Forte 
423fcf3ce44SJohn Forte 	/*
424fcf3ce44SJohn Forte 	 * ret from walk_tree is either FPCFGA_OK or FPCFGA_ERR.
425fcf3ce44SJohn Forte 	 * larg.ret is used to detect other errors. Make sure larg.ret
426fcf3ce44SJohn Forte 	 * is set to a correct error.
427fcf3ce44SJohn Forte 	 */
428fcf3ce44SJohn Forte 	if (ret != FPCFGA_OK || (ret = larg.ret) != FPCFGA_OK) {
429fcf3ce44SJohn Forte 		if (ret != FPCFGA_APID_NOEXIST) {
430fcf3ce44SJohn Forte 			cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
431fcf3ce44SJohn Forte 		}
432fcf3ce44SJohn Forte 		/* if larg.ret = FPCFGA_APID_NOEXIST; */
433fcf3ce44SJohn Forte 		goto out;
434fcf3ce44SJohn Forte 	}
435fcf3ce44SJohn Forte 
436fcf3ce44SJohn Forte 	assert(larg.listp != NULL);
437fcf3ce44SJohn Forte 
438fcf3ce44SJohn Forte 	n = 0;
439fcf3ce44SJohn Forte 	ret = postprocess_list_data(larg.listp, cmd, larg.chld_config, &n,
440fcf3ce44SJohn Forte 		NO_FLAG);
441fcf3ce44SJohn Forte 	if (ret != FPCFGA_OK) {
442fcf3ce44SJohn Forte 		cfga_err(errstring, 0, ERR_LIST, 0);
443fcf3ce44SJohn Forte 		ret = FPCFGA_LIB_ERR;
444fcf3ce44SJohn Forte 		goto out;
445fcf3ce44SJohn Forte 	}
446fcf3ce44SJohn Forte 
447fcf3ce44SJohn Forte 	*nelemp = n;
448fcf3ce44SJohn Forte 	*llpp = larg.listp;
449fcf3ce44SJohn Forte 	ret = FPCFGA_OK;
450fcf3ce44SJohn Forte 	/* FALLTHROUGH */
451fcf3ce44SJohn Forte out:
452fcf3ce44SJohn Forte 	if (ret != FPCFGA_OK) list_free(&larg.listp);
453fcf3ce44SJohn Forte 	S_FREE(larg.xport_logp);
454fcf3ce44SJohn Forte 	HBA_CloseAdapter(handle);
455fcf3ce44SJohn Forte 	HBA_FreeLibrary();
456fcf3ce44SJohn Forte 	return (ret);
457fcf3ce44SJohn Forte }
458fcf3ce44SJohn Forte 
459fcf3ce44SJohn Forte /*
460fcf3ce44SJohn Forte  * Main routine for list operation when show_FCP_dev option is given.
461fcf3ce44SJohn Forte  * It calls various routines to consturct ldata list and
462fcf3ce44SJohn Forte  * postprocess the list data.
463fcf3ce44SJohn Forte  *
464fcf3ce44SJohn Forte  * The difference between do_list() and do_list_FCP_dev() is to
465fcf3ce44SJohn Forte  * process FCP SCSI LUN data list via uscsi report lun operation and
466fcf3ce44SJohn Forte  * stat lun level instead of port WWN based target level.
467fcf3ce44SJohn Forte  * The rest of logic is same.
468fcf3ce44SJohn Forte  *
469fcf3ce44SJohn Forte  * Overall algorithm:
470fcf3ce44SJohn Forte  * Get the device list on input hba port and construct ldata list for
471fcf3ce44SJohn Forte  * accesible devices.
472fcf3ce44SJohn Forte  * For each configured device, USCSI report lun is issued and ldata list
473fcf3ce44SJohn Forte  * with FCP device level(LUN) information is created.
474fcf3ce44SJohn Forte  * Stat hba port and LUN devices through walking the device tree.
475fcf3ce44SJohn Forte  * Verify the validity of the list data.
476fcf3ce44SJohn Forte  */
477fcf3ce44SJohn Forte fpcfga_ret_t
do_list_FCP_dev(const char * ap_id,uint_t flags,fpcfga_cmd_t cmd,ldata_list_t ** llpp,int * nelemp,char ** errstring)478fcf3ce44SJohn Forte do_list_FCP_dev(
479fcf3ce44SJohn Forte 	const char *ap_id,
480fcf3ce44SJohn Forte 	uint_t flags,
481fcf3ce44SJohn Forte 	fpcfga_cmd_t cmd,
482fcf3ce44SJohn Forte 	ldata_list_t **llpp,
483fcf3ce44SJohn Forte 	int *nelemp,
484fcf3ce44SJohn Forte 	char **errstring)
485fcf3ce44SJohn Forte {
486fcf3ce44SJohn Forte 	int		n = -1, l_errno = 0, limited_stat, len;
487fcf3ce44SJohn Forte 	walkarg_t	walkarg;
488fcf3ce44SJohn Forte 	fpcfga_list_t	larg = {NULL};
489fcf3ce44SJohn Forte 	fpcfga_ret_t	ret;
490fcf3ce44SJohn Forte 	la_wwn_t	pwwn;
491fcf3ce44SJohn Forte 	char		*xport_phys = NULL, *dyn = NULL, *dyncomp = NULL,
492fcf3ce44SJohn Forte 			*lun_dyn = NULL;
493fcf3ce44SJohn Forte 	apid_t		apid_con = {NULL};
494fcf3ce44SJohn Forte 	HBA_HANDLE	handle;
495fcf3ce44SJohn Forte 	HBA_PORTATTRIBUTES	portAttrs;
496fcf3ce44SJohn Forte 	HBA_PORTATTRIBUTES	discPortAttrs;
497fcf3ce44SJohn Forte 	HBA_STATUS		status;
498fcf3ce44SJohn Forte 	int			portIndex, discIndex;
499fcf3ce44SJohn Forte 	int			retry;
500fcf3ce44SJohn Forte 	uint64_t		lun = 0;
501fcf3ce44SJohn Forte 	struct scsi_inquiry inq;
502fcf3ce44SJohn Forte 	struct scsi_extended_sense sense;
503fcf3ce44SJohn Forte 	HBA_UINT8		scsiStatus;
504fcf3ce44SJohn Forte 	uint32_t		inquirySize = sizeof (inq),
505fcf3ce44SJohn Forte 				senseSize = sizeof (sense);
506fcf3ce44SJohn Forte 
507fcf3ce44SJohn Forte 	if (*llpp != NULL || *nelemp != 0) {
508fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
509fcf3ce44SJohn Forte 	}
510fcf3ce44SJohn Forte 
511fcf3ce44SJohn Forte 	if ((xport_phys = pathdup(ap_id, &l_errno)) == NULL) {
512fcf3ce44SJohn Forte 		cfga_err(errstring, l_errno, ERR_OP_FAILED, 0);
513fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
514fcf3ce44SJohn Forte 	}
515fcf3ce44SJohn Forte 
516fcf3ce44SJohn Forte 	/* Extract the base(hba) and dynamic(device) component if any */
517fcf3ce44SJohn Forte 	if ((dyn = GET_DYN(xport_phys)) != NULL) {
518fcf3ce44SJohn Forte 		len = strlen(DYN_TO_DYNCOMP(dyn)) + 1;
519fcf3ce44SJohn Forte 		dyncomp = calloc(1, len);
520fcf3ce44SJohn Forte 		if (dyncomp == NULL) {
521fcf3ce44SJohn Forte 			cfga_err(errstring, errno, ERR_OP_FAILED, 0);
522fcf3ce44SJohn Forte 			S_FREE(xport_phys);
523fcf3ce44SJohn Forte 			return (FPCFGA_LIB_ERR);
524fcf3ce44SJohn Forte 		}
525fcf3ce44SJohn Forte 
526fcf3ce44SJohn Forte 		(void) strcpy(dyncomp, DYN_TO_DYNCOMP(dyn));
527fcf3ce44SJohn Forte 		/* Remove the dynamic component from the base. */
528fcf3ce44SJohn Forte 		*dyn = '\0';
529fcf3ce44SJohn Forte 		/* if lun dyncomp exists delete it */
530fcf3ce44SJohn Forte 		if ((lun_dyn = GET_LUN_DYN(dyncomp)) != NULL) {
531fcf3ce44SJohn Forte 			*lun_dyn = '\0';
532fcf3ce44SJohn Forte 		}
533fcf3ce44SJohn Forte 	}
534fcf3ce44SJohn Forte 
535fcf3ce44SJohn Forte 	apid_con.xport_phys = xport_phys;
536fcf3ce44SJohn Forte 	apid_con.dyncomp = dyncomp;
537fcf3ce44SJohn Forte 	apid_con.flags = flags;
538fcf3ce44SJohn Forte 
539fcf3ce44SJohn Forte 	larg.apidp = &apid_con;
540fcf3ce44SJohn Forte 
541fcf3ce44SJohn Forte 	/* Create the hba logid (also base component of logical ap_id) */
542fcf3ce44SJohn Forte 	ret = make_xport_logid(larg.apidp->xport_phys, &larg.xport_logp,
543fcf3ce44SJohn Forte 		&l_errno);
544fcf3ce44SJohn Forte 	if (ret != FPCFGA_OK) {
545fcf3ce44SJohn Forte 		cfga_err(errstring, l_errno, ERR_LIST, 0);
546fcf3ce44SJohn Forte 		S_FREE(larg.apidp->xport_phys);
547fcf3ce44SJohn Forte 		S_FREE(larg.apidp->dyncomp);
548fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
549fcf3ce44SJohn Forte 	}
550fcf3ce44SJohn Forte 
551fcf3ce44SJohn Forte 	assert(larg.xport_logp != NULL);
552fcf3ce44SJohn Forte 
553fcf3ce44SJohn Forte 	larg.cmd = cmd;
554fcf3ce44SJohn Forte 	larg.xport_rstate = CFGA_STAT_NONE;
555fcf3ce44SJohn Forte 
556fcf3ce44SJohn Forte 	if ((ret = findMatchingAdapterPort(larg.apidp->xport_phys, &handle,
557fcf3ce44SJohn Forte 	    &portIndex, &portAttrs, errstring)) != FPCFGA_OK) {
558fcf3ce44SJohn Forte 	    S_FREE(larg.xport_logp);
559fcf3ce44SJohn Forte 	    S_FREE(larg.apidp->dyncomp);
560fcf3ce44SJohn Forte 	    return (ret);
561fcf3ce44SJohn Forte 	}
562fcf3ce44SJohn Forte 
563fcf3ce44SJohn Forte 	/*
564fcf3ce44SJohn Forte 	 * If stating a specific device, we will do limited stat on fca port.
565fcf3ce44SJohn Forte 	 * otherwise full stat on fca part is required.
566fcf3ce44SJohn Forte 	 * If stating a specific device we don't know if it exists or is
567fcf3ce44SJohn Forte 	 * configured yet.  larg.ret is set to apid noexist for do_stat_dev.
568fcf3ce44SJohn Forte 	 * otherwise larg.ret is set to ok initially.
569fcf3ce44SJohn Forte 	 */
570fcf3ce44SJohn Forte 	if (larg.cmd == FPCFGA_STAT_FC_DEV) {
571fcf3ce44SJohn Forte 		limited_stat = 1;		/* for do_stat_fca_xport */
572fcf3ce44SJohn Forte 		larg.ret = FPCFGA_APID_NOEXIST; /* for stat_fc_dev	*/
573fcf3ce44SJohn Forte 	} else {
574fcf3ce44SJohn Forte 		limited_stat = 0;		/* for do_stat_fca_xport */
575fcf3ce44SJohn Forte 		larg.ret = FPCFGA_OK;		/* for stat_fc_dev	*/
576fcf3ce44SJohn Forte 	}
577fcf3ce44SJohn Forte 
578fcf3ce44SJohn Forte 	/* For all list commands, the fca port needs to be stat'ed */
579fcf3ce44SJohn Forte 	if ((ret = do_stat_fca_xport(&larg, limited_stat,
580fcf3ce44SJohn Forte 		portAttrs)) != FPCFGA_OK) {
581fcf3ce44SJohn Forte 		cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
582fcf3ce44SJohn Forte 		list_free(&larg.listp);
583fcf3ce44SJohn Forte 		S_FREE(larg.xport_logp);
584fcf3ce44SJohn Forte 		S_FREE(larg.apidp->xport_phys);
585fcf3ce44SJohn Forte 		S_FREE(larg.apidp->dyncomp);
586fcf3ce44SJohn Forte 		HBA_CloseAdapter(handle);
587fcf3ce44SJohn Forte 		HBA_FreeLibrary();
588fcf3ce44SJohn Forte 		return (ret);
589fcf3ce44SJohn Forte 	}
590fcf3ce44SJohn Forte 
591fcf3ce44SJohn Forte 	/*
592fcf3ce44SJohn Forte 	 * If stat'ing a FCA port or ALL, we have the bus stat data at
593fcf3ce44SJohn Forte 	 * this point.
594fcf3ce44SJohn Forte 	 * Assume that the bus has no configured children.
595fcf3ce44SJohn Forte 	 */
596fcf3ce44SJohn Forte 	larg.chld_config = CFGA_STAT_UNCONFIGURED;
597fcf3ce44SJohn Forte 
598fcf3ce44SJohn Forte 	switch (larg.cmd) {
599fcf3ce44SJohn Forte 	case FPCFGA_STAT_FC_DEV:
600fcf3ce44SJohn Forte 		/* la_wwn_t has uchar_t raw_wwn[8] thus no need to free. */
601fcf3ce44SJohn Forte 		if (cvt_dyncomp_to_lawwn(larg.apidp->dyncomp, &pwwn) != 0) {
602fcf3ce44SJohn Forte 			cfga_err(errstring, 0, ERR_LIST, 0);
603fcf3ce44SJohn Forte 			list_free(&larg.listp);
604fcf3ce44SJohn Forte 			S_FREE(larg.xport_logp);
605fcf3ce44SJohn Forte 			S_FREE(larg.apidp->xport_phys);
606fcf3ce44SJohn Forte 			S_FREE(larg.apidp->dyncomp);
607fcf3ce44SJohn Forte 			HBA_CloseAdapter(handle);
608fcf3ce44SJohn Forte 			HBA_FreeLibrary();
609fcf3ce44SJohn Forte 			return (FPCFGA_LIB_ERR);
610fcf3ce44SJohn Forte 		}
611fcf3ce44SJohn Forte 		/*
612fcf3ce44SJohn Forte 		 * if the dyncomp exists on disco ports construct list_data
613fcf3ce44SJohn Forte 		 * otherwise return FPCFGA_APID_NOEXIST.
614fcf3ce44SJohn Forte 		 */
615fcf3ce44SJohn Forte 		retry = 0;
616fcf3ce44SJohn Forte 		do {
617fcf3ce44SJohn Forte 		    status = getPortAttrsByWWN(handle,
618fcf3ce44SJohn Forte 			*((HBA_WWN *)(&pwwn)), &discPortAttrs);
619fcf3ce44SJohn Forte 		    if (status == HBA_STATUS_ERROR_STALE_DATA) {
620fcf3ce44SJohn Forte 			/* get Port Attributes again after refresh. */
621fcf3ce44SJohn Forte 			HBA_RefreshInformation(handle);
622fcf3ce44SJohn Forte 		    } else {
623fcf3ce44SJohn Forte 			break; /* either okay or some other error */
624fcf3ce44SJohn Forte 		    }
625fcf3ce44SJohn Forte 		} while (retry++ < HBA_MAX_RETRIES);
626fcf3ce44SJohn Forte 
627fcf3ce44SJohn Forte 		if (status == HBA_STATUS_OK) {
628fcf3ce44SJohn Forte 			/*
629fcf3ce44SJohn Forte 			 * if dyncomp exists only in dev list
630fcf3ce44SJohn Forte 			 * construct  ldata_list and return.
631fcf3ce44SJohn Forte 			 * otherwise continue to stat on dev tree with
632fcf3ce44SJohn Forte 			 * larg.ret set to access_ok which informs stat_fc_dev
633fcf3ce44SJohn Forte 			 * the existence of device on dev_list.
634fcf3ce44SJohn Forte 			 *
635fcf3ce44SJohn Forte 			 * if path is null that guatantees the node is not
636fcf3ce44SJohn Forte 			 * configured.  if node is detached the path
637fcf3ce44SJohn Forte 			 * is incomplete and not usable for further
638fcf3ce44SJohn Forte 			 * operations like uscsi_inq so take care of it here.
639fcf3ce44SJohn Forte 			 */
640fcf3ce44SJohn Forte 			status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN,
641fcf3ce44SJohn Forte 				    discPortAttrs.PortWWN, lun, 0, 0,
642fcf3ce44SJohn Forte 				    &inq, &inquirySize, &scsiStatus,
643fcf3ce44SJohn Forte 				    &sense, &senseSize);
644fcf3ce44SJohn Forte 			if (status == HBA_STATUS_OK) {
645fcf3ce44SJohn Forte 				inq.inq_dtype = inq.inq_dtype & DTYPE_MASK;
646fcf3ce44SJohn Forte 			} else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
647fcf3ce44SJohn Forte 				inq.inq_dtype = DTYPE_UNKNOWN;
648fcf3ce44SJohn Forte 			} else {
649fcf3ce44SJohn Forte 			    inq.inq_dtype = ERR_INQ_DTYPE;
650fcf3ce44SJohn Forte 			}
651fcf3ce44SJohn Forte 
652fcf3ce44SJohn Forte 			if (init_ldata_for_accessible_dev(larg.apidp->dyncomp,
653fcf3ce44SJohn Forte 				inq.inq_dtype, &larg) != FPCFGA_OK) {
654fcf3ce44SJohn Forte 				cfga_err(errstring, larg.l_errno,
655fcf3ce44SJohn Forte 					ERR_LIST, 0);
656fcf3ce44SJohn Forte 				list_free(&larg.listp);
657fcf3ce44SJohn Forte 				S_FREE(larg.xport_logp);
658fcf3ce44SJohn Forte 				S_FREE(larg.apidp->xport_phys);
659fcf3ce44SJohn Forte 				S_FREE(larg.apidp->dyncomp);
660fcf3ce44SJohn Forte 				HBA_CloseAdapter(handle);
661fcf3ce44SJohn Forte 				HBA_FreeLibrary();
662fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
663fcf3ce44SJohn Forte 			}
664fcf3ce44SJohn Forte 			if ((ret = get_accessible_FCP_dev_ldata(
665fcf3ce44SJohn Forte 					larg.apidp->dyncomp, &larg, &l_errno))
666fcf3ce44SJohn Forte 					!= FPCFGA_OK) {
667fcf3ce44SJohn Forte 				cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
668fcf3ce44SJohn Forte 				list_free(&larg.listp);
669fcf3ce44SJohn Forte 				S_FREE(larg.xport_logp);
670fcf3ce44SJohn Forte 				S_FREE(larg.apidp->xport_phys);
671fcf3ce44SJohn Forte 				S_FREE(larg.apidp->dyncomp);
672fcf3ce44SJohn Forte 				HBA_CloseAdapter(handle);
673fcf3ce44SJohn Forte 				HBA_FreeLibrary();
674fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
675fcf3ce44SJohn Forte 			} else {
676fcf3ce44SJohn Forte 				/* continue to stat dev with access okay. */
677fcf3ce44SJohn Forte 				larg.ret = FPCFGA_ACCESS_OK;
678fcf3ce44SJohn Forte 			}
679fcf3ce44SJohn Forte 		} else if (status == HBA_STATUS_ERROR_ILLEGAL_WWN) {
680fcf3ce44SJohn Forte 			/*
681fcf3ce44SJohn Forte 			 * path indicates if the node exists in dev tree.
682fcf3ce44SJohn Forte 			 * if not found in dev tree return apid no exist.
683fcf3ce44SJohn Forte 			 * otherwise continue to stat with larg.ret set to
684fcf3ce44SJohn Forte 			 * apid_noexist.
685fcf3ce44SJohn Forte 			 */
686fcf3ce44SJohn Forte 			if (larg.apidp->lunlist == NULL) {
687fcf3ce44SJohn Forte 				list_free(&larg.listp);
688fcf3ce44SJohn Forte 				S_FREE(larg.xport_logp);
689fcf3ce44SJohn Forte 				HBA_CloseAdapter(handle);
690fcf3ce44SJohn Forte 				HBA_FreeLibrary();
691fcf3ce44SJohn Forte 				return (FPCFGA_APID_NOEXIST);
692fcf3ce44SJohn Forte 			}
693fcf3ce44SJohn Forte 		} else {	/* not found or any error */
694fcf3ce44SJohn Forte 			/*
695fcf3ce44SJohn Forte 			 * continue to stat dev with larg.ret set to
696fcf3ce44SJohn Forte 			 * apid_noexist.
697fcf3ce44SJohn Forte 			 */
698fcf3ce44SJohn Forte 			larg.ret = FPCFGA_APID_NOEXIST;
699fcf3ce44SJohn Forte 		}
700fcf3ce44SJohn Forte 		break;
701fcf3ce44SJohn Forte 	case FPCFGA_STAT_ALL:
702fcf3ce44SJohn Forte 		/*
703fcf3ce44SJohn Forte 		 * for each dev in disco ports, create a ldata_list element.
704fcf3ce44SJohn Forte 		 * if if no disco ports found, continue to stat on devinfo tree
705fcf3ce44SJohn Forte 		 * to see if any node exist on the fca port.
706fcf3ce44SJohn Forte 		 */
707fcf3ce44SJohn Forte 		for (discIndex = 0;
708fcf3ce44SJohn Forte 			discIndex < portAttrs.NumberofDiscoveredPorts;
709fcf3ce44SJohn Forte 			discIndex++) {
710fcf3ce44SJohn Forte 		    if (getDiscPortAttrs(handle, portIndex,
711fcf3ce44SJohn Forte 			discIndex, &discPortAttrs)) {
712fcf3ce44SJohn Forte 			/* Move on to the next target */
713fcf3ce44SJohn Forte 			continue;
714fcf3ce44SJohn Forte 		    }
715fcf3ce44SJohn Forte 		    memcpy(&pwwn, &discPortAttrs.PortWWN, sizeof (la_wwn_t));
716fcf3ce44SJohn Forte 		    cvt_lawwn_to_dyncomp(&pwwn, &dyncomp, &l_errno);
717fcf3ce44SJohn Forte 		    if (dyncomp == NULL) {
718fcf3ce44SJohn Forte 			cfga_err(errstring, l_errno, ERR_LIST, 0);
719fcf3ce44SJohn Forte 			list_free(&larg.listp);
720fcf3ce44SJohn Forte 			S_FREE(larg.xport_logp);
721fcf3ce44SJohn Forte 			S_FREE(larg.apidp->xport_phys);
722fcf3ce44SJohn Forte 			S_FREE(larg.apidp->dyncomp);
723fcf3ce44SJohn Forte 			HBA_CloseAdapter(handle);
724fcf3ce44SJohn Forte 			HBA_FreeLibrary();
725fcf3ce44SJohn Forte 			return (FPCFGA_LIB_ERR);
726fcf3ce44SJohn Forte 		    }
727fcf3ce44SJohn Forte 		    status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN,
728fcf3ce44SJohn Forte 			    discPortAttrs.PortWWN, lun, 0, 0,
729fcf3ce44SJohn Forte 			    &inq, &inquirySize, &scsiStatus,
730fcf3ce44SJohn Forte 			    &sense, &senseSize);
731fcf3ce44SJohn Forte 		    if (status == HBA_STATUS_OK) {
732fcf3ce44SJohn Forte 			    inq.inq_dtype = inq.inq_dtype & DTYPE_MASK;
733fcf3ce44SJohn Forte 		    } else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
734fcf3ce44SJohn Forte 			    inq.inq_dtype = DTYPE_UNKNOWN;
735fcf3ce44SJohn Forte 		    } else {
736fcf3ce44SJohn Forte 			    inq.inq_dtype = ERR_INQ_DTYPE;
737fcf3ce44SJohn Forte 		    }
738fcf3ce44SJohn Forte 		    if ((ret = init_ldata_for_accessible_dev(
739fcf3ce44SJohn Forte 			    dyncomp, inq.inq_dtype, &larg)) != FPCFGA_OK) {
740fcf3ce44SJohn Forte 			S_FREE(dyncomp);
741fcf3ce44SJohn Forte 			cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
742fcf3ce44SJohn Forte 			list_free(&larg.listp);
743fcf3ce44SJohn Forte 			S_FREE(larg.xport_logp);
744fcf3ce44SJohn Forte 			S_FREE(larg.apidp->xport_phys);
745fcf3ce44SJohn Forte 			S_FREE(larg.apidp->dyncomp);
746fcf3ce44SJohn Forte 			HBA_CloseAdapter(handle);
747fcf3ce44SJohn Forte 			HBA_FreeLibrary();
748fcf3ce44SJohn Forte 			return (FPCFGA_LIB_ERR);
749fcf3ce44SJohn Forte 		    }
750fcf3ce44SJohn Forte 		    if ((ret = get_accessible_FCP_dev_ldata(
751fcf3ce44SJohn Forte 			dyncomp, &larg, &l_errno)) != FPCFGA_OK) {
752fcf3ce44SJohn Forte 			S_FREE(dyncomp);
753fcf3ce44SJohn Forte 			cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
754fcf3ce44SJohn Forte 			list_free(&larg.listp);
755fcf3ce44SJohn Forte 			S_FREE(larg.xport_logp);
756fcf3ce44SJohn Forte 			S_FREE(larg.apidp->xport_phys);
757fcf3ce44SJohn Forte 			S_FREE(larg.apidp->dyncomp);
758fcf3ce44SJohn Forte 			HBA_CloseAdapter(handle);
759fcf3ce44SJohn Forte 			HBA_FreeLibrary();
760fcf3ce44SJohn Forte 			return (ret);
761fcf3ce44SJohn Forte 		    }
762fcf3ce44SJohn Forte 		    S_FREE(dyncomp);
763fcf3ce44SJohn Forte 		}
764fcf3ce44SJohn Forte 		break;
765fcf3ce44SJohn Forte 	/* default: continue */
766fcf3ce44SJohn Forte 	}
767fcf3ce44SJohn Forte 
768fcf3ce44SJohn Forte 	/* we need to stat at least 1 device for all commands */
769fcf3ce44SJohn Forte 	if ((larg.apidp->flags & FLAG_DEVINFO_FORCE) == FLAG_DEVINFO_FORCE) {
770fcf3ce44SJohn Forte 		walkarg.flags = FLAG_DEVINFO_FORCE;
771fcf3ce44SJohn Forte 	} else {
772fcf3ce44SJohn Forte 		walkarg.flags = 0;
773fcf3ce44SJohn Forte 	}
774fcf3ce44SJohn Forte 
775fcf3ce44SJohn Forte 	walkarg.flags |= FLAG_PATH_INFO_WALK;
776fcf3ce44SJohn Forte 	walkarg.walkmode.node_args.flags = DI_WALK_CLDFIRST;
777fcf3ce44SJohn Forte 	walkarg.walkmode.node_args.fcn = stat_FCP_dev;
778fcf3ce44SJohn Forte 
779fcf3ce44SJohn Forte 	/*
780fcf3ce44SJohn Forte 	 * Subtree is ALWAYS rooted at the HBA (not at the device) as
781fcf3ce44SJohn Forte 	 * otherwise deadlock may occur if bus is disconnected.
782fcf3ce44SJohn Forte 	 *
783fcf3ce44SJohn Forte 	 * DINFOPROP was sufficient on apidp->xport_phys prior to the support
784fcf3ce44SJohn Forte 	 * on scsi_vhci child node.  In order to get the link between
785fcf3ce44SJohn Forte 	 * scsi_vhci node and path info node the snap shot of the
786fcf3ce44SJohn Forte 	 * the whole device tree is required with DINFOCPYALL | DINFOPATH flag.
787fcf3ce44SJohn Forte 	 */
788fcf3ce44SJohn Forte 	ret = walk_tree(larg.apidp->xport_phys, &larg, DINFOCPYALL | DINFOPATH,
789fcf3ce44SJohn Forte 			&walkarg, FPCFGA_WALK_NODE, &larg.l_errno);
790fcf3ce44SJohn Forte 
791fcf3ce44SJohn Forte 	/*
792fcf3ce44SJohn Forte 	 * ret from walk_tree is either FPCFGA_OK or FPCFGA_ERR.
793fcf3ce44SJohn Forte 	 * larg.ret is used to detect other errors. Make sure larg.ret
794fcf3ce44SJohn Forte 	 * is set to a correct error.
795fcf3ce44SJohn Forte 	 */
796fcf3ce44SJohn Forte 	if (ret != FPCFGA_OK || (ret = larg.ret) != FPCFGA_OK) {
797fcf3ce44SJohn Forte 		if (ret != FPCFGA_APID_NOEXIST) {
798fcf3ce44SJohn Forte 			cfga_err(errstring, larg.l_errno, ERR_LIST, 0);
799fcf3ce44SJohn Forte 		}
800fcf3ce44SJohn Forte 		/* if larg.ret = FPCFGA_APID_NOEXIST return. */
801fcf3ce44SJohn Forte 		list_free(&larg.listp);
802fcf3ce44SJohn Forte 		S_FREE(larg.xport_logp);
803fcf3ce44SJohn Forte 		S_FREE(larg.apidp->xport_phys);
804fcf3ce44SJohn Forte 		S_FREE(larg.apidp->dyncomp);
805fcf3ce44SJohn Forte 		HBA_CloseAdapter(handle);
806fcf3ce44SJohn Forte 		HBA_FreeLibrary();
807fcf3ce44SJohn Forte 		return (ret);
808fcf3ce44SJohn Forte 	}
809fcf3ce44SJohn Forte 
810fcf3ce44SJohn Forte 	assert(larg.listp != NULL);
811fcf3ce44SJohn Forte 
812fcf3ce44SJohn Forte 	n = 0;
813fcf3ce44SJohn Forte 	ret = postprocess_list_data(larg.listp, cmd, larg.chld_config, &n,
814fcf3ce44SJohn Forte 			flags);
815fcf3ce44SJohn Forte 	if (ret != FPCFGA_OK) {
816fcf3ce44SJohn Forte 		cfga_err(errstring, 0, ERR_LIST, 0);
817fcf3ce44SJohn Forte 		list_free(&larg.listp);
818fcf3ce44SJohn Forte 		S_FREE(larg.xport_logp);
819fcf3ce44SJohn Forte 		S_FREE(larg.apidp->xport_phys);
820fcf3ce44SJohn Forte 		S_FREE(larg.apidp->dyncomp);
821fcf3ce44SJohn Forte 		HBA_CloseAdapter(handle);
822fcf3ce44SJohn Forte 		HBA_FreeLibrary();
823fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
824fcf3ce44SJohn Forte 	}
825fcf3ce44SJohn Forte 
826fcf3ce44SJohn Forte 	*nelemp = n;
827fcf3ce44SJohn Forte 	*llpp = larg.listp;
828fcf3ce44SJohn Forte 	ret = FPCFGA_OK;
829fcf3ce44SJohn Forte 	S_FREE(larg.xport_logp);
830fcf3ce44SJohn Forte 	S_FREE(larg.apidp->xport_phys);
831fcf3ce44SJohn Forte 	S_FREE(larg.apidp->dyncomp);
832fcf3ce44SJohn Forte 	HBA_CloseAdapter(handle);
833fcf3ce44SJohn Forte 	HBA_FreeLibrary();
834fcf3ce44SJohn Forte 	return (FPCFGA_OK);
835fcf3ce44SJohn Forte }
836fcf3ce44SJohn Forte 
837fcf3ce44SJohn Forte /*
838fcf3ce44SJohn Forte  * This routine returns initialize struct fcp_ioctl.
839fcf3ce44SJohn Forte  */
840fcf3ce44SJohn Forte static void
init_fcp_scsi_cmd(struct fcp_scsi_cmd * fscsi,uchar_t * lun_num,la_wwn_t * pwwn,void * scmdbuf,size_t scmdbuf_len,void * respbuf,size_t respbuf_len,void * sensebuf,size_t sensebuf_len)841fcf3ce44SJohn Forte init_fcp_scsi_cmd(
842fcf3ce44SJohn Forte 	struct fcp_scsi_cmd *fscsi,
843fcf3ce44SJohn Forte 	uchar_t *lun_num,
844fcf3ce44SJohn Forte 	la_wwn_t *pwwn,
845fcf3ce44SJohn Forte 	void *scmdbuf,
846fcf3ce44SJohn Forte 	size_t scmdbuf_len,
847fcf3ce44SJohn Forte 	void *respbuf,
848fcf3ce44SJohn Forte 	size_t respbuf_len,
849fcf3ce44SJohn Forte 	void *sensebuf,
850fcf3ce44SJohn Forte 	size_t sensebuf_len)
851fcf3ce44SJohn Forte {
852fcf3ce44SJohn Forte 	memset(fscsi, 0, sizeof (struct fcp_scsi_cmd));
853fcf3ce44SJohn Forte 	memset(scmdbuf, 0, scmdbuf_len);
854fcf3ce44SJohn Forte 	memcpy(fscsi->scsi_fc_pwwn.raw_wwn, pwwn, sizeof (u_longlong_t));
855fcf3ce44SJohn Forte 	fscsi->scsi_fc_rspcode = 0;
856fcf3ce44SJohn Forte 	fscsi->scsi_flags = FCP_SCSI_READ;
857fcf3ce44SJohn Forte 	fscsi->scsi_timeout = FCP_SCSI_CMD_TIMEOUT;  /* second */
858fcf3ce44SJohn Forte 	fscsi->scsi_cdbbufaddr = (caddr_t)scmdbuf;
859fcf3ce44SJohn Forte 	fscsi->scsi_cdblen = scmdbuf_len;
860fcf3ce44SJohn Forte 	fscsi->scsi_bufaddr = (caddr_t)respbuf;
861fcf3ce44SJohn Forte 	fscsi->scsi_buflen = respbuf_len;
862fcf3ce44SJohn Forte 	fscsi->scsi_bufresid = 0;
863fcf3ce44SJohn Forte 	fscsi->scsi_bufstatus = 0;
864fcf3ce44SJohn Forte 	fscsi->scsi_rqbufaddr = (caddr_t)sensebuf;
865fcf3ce44SJohn Forte 	fscsi->scsi_rqlen = sensebuf_len;
866fcf3ce44SJohn Forte 	fscsi->scsi_rqresid = 0;
867fcf3ce44SJohn Forte 	memcpy(&fscsi->scsi_lun, lun_num, sizeof (fscsi->scsi_lun));
868fcf3ce44SJohn Forte }
869fcf3ce44SJohn Forte 
870fcf3ce44SJohn Forte /*
871fcf3ce44SJohn Forte  * This routine returns issues FCP_TGT_SEND_SCSI
872fcf3ce44SJohn Forte  */
873fcf3ce44SJohn Forte static fpcfga_ret_t
issue_fcp_scsi_cmd(const char * xport_phys,struct fcp_scsi_cmd * fscsi,int * l_errnop)874fcf3ce44SJohn Forte issue_fcp_scsi_cmd(
875fcf3ce44SJohn Forte 	const char *xport_phys,
876fcf3ce44SJohn Forte 	struct fcp_scsi_cmd *fscsi,
877fcf3ce44SJohn Forte 	int *l_errnop)
878fcf3ce44SJohn Forte {
879fcf3ce44SJohn Forte 	struct stat	stbuf;
880fcf3ce44SJohn Forte 	int fcp_fd, retry, rv;
881fcf3ce44SJohn Forte 
882fcf3ce44SJohn Forte 	if (stat(xport_phys, &stbuf) < 0) {
883fcf3ce44SJohn Forte 		*l_errnop = errno;
884fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
885fcf3ce44SJohn Forte 	}
886fcf3ce44SJohn Forte 
887fcf3ce44SJohn Forte 	fscsi->scsi_fc_port_num = (uint32_t)minor(stbuf.st_rdev);
888fcf3ce44SJohn Forte 	fcp_fd = open(FCP_PATH, O_RDONLY | O_NDELAY);
889fcf3ce44SJohn Forte 	retry = 0;
890fcf3ce44SJohn Forte 	while (fcp_fd < 0 && retry++ < OPEN_RETRY_COUNT && (
891fcf3ce44SJohn Forte 		errno == EBUSY || errno == EAGAIN)) {
892fcf3ce44SJohn Forte 		(void) usleep(OPEN_RETRY_INTERVAL);
893fcf3ce44SJohn Forte 		fcp_fd = open(FCP_PATH, O_RDONLY|O_NDELAY);
894fcf3ce44SJohn Forte 	}
895fcf3ce44SJohn Forte 	if (fcp_fd < 0) {
896fcf3ce44SJohn Forte 		*l_errnop = errno;
897fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
898fcf3ce44SJohn Forte 	}
899fcf3ce44SJohn Forte 
900fcf3ce44SJohn Forte 	rv = ioctl(fcp_fd, FCP_TGT_SEND_SCSI, fscsi);
901fcf3ce44SJohn Forte 	retry = 0;
902fcf3ce44SJohn Forte 	while ((rv != 0 && retry++ < IOCTL_RETRY_COUNT &&
903fcf3ce44SJohn Forte 			(errno == EBUSY || errno == EAGAIN)) ||
904fcf3ce44SJohn Forte 			(retry++ < IOCTL_RETRY_COUNT &&
905fcf3ce44SJohn Forte 			((uchar_t)fscsi->scsi_bufstatus & STATUS_MASK)
906fcf3ce44SJohn Forte 			== STATUS_BUSY)) {
907fcf3ce44SJohn Forte 		(void) usleep(IOCTL_RETRY_INTERVAL);
908fcf3ce44SJohn Forte 		rv = ioctl(fcp_fd, FCP_TGT_SEND_SCSI, fscsi);
909fcf3ce44SJohn Forte 	}
910fcf3ce44SJohn Forte 	close(fcp_fd);
911fcf3ce44SJohn Forte 
912fcf3ce44SJohn Forte 	if (fscsi->scsi_fc_status == FC_DEVICE_NOT_TGT) {
913fcf3ce44SJohn Forte 		return (FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT);
914fcf3ce44SJohn Forte 	} else if (rv != 0 || fscsi->scsi_bufstatus != 0) {
915fcf3ce44SJohn Forte 		*l_errnop = errno;
916fcf3ce44SJohn Forte 		return (FPCFGA_FCP_TGT_SEND_SCSI_FAILED);
917fcf3ce44SJohn Forte 	}
918fcf3ce44SJohn Forte 	return (FPCFGA_OK);
919fcf3ce44SJohn Forte }
920fcf3ce44SJohn Forte 
921fcf3ce44SJohn Forte /*
922fcf3ce44SJohn Forte  * This routine returns standard inq data for
923fcf3ce44SJohn Forte  * a target represented by dyncomp.
924fcf3ce44SJohn Forte  *
925fcf3ce44SJohn Forte  * Calls FCP passthru ioctl FCP_TGT_SEND_SCSI to get inquiry data.
926fcf3ce44SJohn Forte  *
927fcf3ce44SJohn Forte  * Caller should free the *inq_buf.
928fcf3ce44SJohn Forte  */
929fcf3ce44SJohn Forte static fpcfga_ret_t
get_standard_inq_data(const char * xport_phys,const char * dyncomp,uchar_t * lun_num,struct scsi_inquiry ** inq_buf,int * l_errnop)930fcf3ce44SJohn Forte get_standard_inq_data(
931fcf3ce44SJohn Forte 	const char *xport_phys,
932fcf3ce44SJohn Forte 	const char *dyncomp,
933fcf3ce44SJohn Forte 	uchar_t *lun_num,
934fcf3ce44SJohn Forte 	struct scsi_inquiry **inq_buf,
935fcf3ce44SJohn Forte 	int *l_errnop)
936fcf3ce44SJohn Forte {
937fcf3ce44SJohn Forte 	struct fcp_scsi_cmd	fscsi;
938fcf3ce44SJohn Forte 	struct scsi_extended_sense sensebuf;
939fcf3ce44SJohn Forte 	union scsi_cdb  scsi_inq_req;
940fcf3ce44SJohn Forte 	la_wwn_t	pwwn;
941fcf3ce44SJohn Forte 	int 	alloc_len;
942fcf3ce44SJohn Forte 	fpcfga_ret_t ret;
943fcf3ce44SJohn Forte 
944fcf3ce44SJohn Forte 
945fcf3ce44SJohn Forte 	alloc_len = sizeof (struct scsi_inquiry);
946fcf3ce44SJohn Forte 	if ((*inq_buf = (struct scsi_inquiry *)calloc(1, alloc_len)) == NULL) {
947fcf3ce44SJohn Forte 		*l_errnop = errno;
948fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
949fcf3ce44SJohn Forte 	}
950fcf3ce44SJohn Forte 
951fcf3ce44SJohn Forte 	if (cvt_dyncomp_to_lawwn(dyncomp, &pwwn) != 0) {
952fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
953fcf3ce44SJohn Forte 	}
954fcf3ce44SJohn Forte 
955fcf3ce44SJohn Forte 	init_fcp_scsi_cmd(&fscsi, lun_num, &pwwn, &scsi_inq_req,
956fcf3ce44SJohn Forte 		sizeof (scsi_inq_req), *inq_buf, alloc_len, &sensebuf,
957fcf3ce44SJohn Forte 		sizeof (struct scsi_extended_sense));
958fcf3ce44SJohn Forte 	scsi_inq_req.scc_cmd = SCMD_INQUIRY;
959fcf3ce44SJohn Forte 	scsi_inq_req.g0_count0 = sizeof (struct scsi_inquiry);
960fcf3ce44SJohn Forte 
961fcf3ce44SJohn Forte 	if ((ret = issue_fcp_scsi_cmd(xport_phys, &fscsi, l_errnop))
962fcf3ce44SJohn Forte 			!= FPCFGA_OK) {
963fcf3ce44SJohn Forte 		S_FREE(*inq_buf);
964fcf3ce44SJohn Forte 		return (ret);
965fcf3ce44SJohn Forte 	}
966fcf3ce44SJohn Forte 
967fcf3ce44SJohn Forte 	return (FPCFGA_OK);
968fcf3ce44SJohn Forte }
969fcf3ce44SJohn Forte 
970fcf3ce44SJohn Forte /*
971fcf3ce44SJohn Forte  * This routine returns report lun data and number of luns found
972fcf3ce44SJohn Forte  * on a target represented by dyncomp.
973fcf3ce44SJohn Forte  *
974fcf3ce44SJohn Forte  * Calls FCP passthru ioctl FCP_TGT_SEND_SCSI to get report lun data.
975fcf3ce44SJohn Forte  *
976fcf3ce44SJohn Forte  * Caller should free the *resp_buf when FPCFGA_OK is returned.
977fcf3ce44SJohn Forte  */
978fcf3ce44SJohn Forte fpcfga_ret_t
get_report_lun_data(const char * xport_phys,const char * dyncomp,int * num_luns,report_lun_resp_t ** resp_buf,struct scsi_extended_sense * sensebuf,int * l_errnop)979fcf3ce44SJohn Forte get_report_lun_data(
980fcf3ce44SJohn Forte 	const char *xport_phys,
981fcf3ce44SJohn Forte 	const char *dyncomp,
982fcf3ce44SJohn Forte 	int *num_luns,
983fcf3ce44SJohn Forte 	report_lun_resp_t **resp_buf,
984fcf3ce44SJohn Forte 	struct scsi_extended_sense *sensebuf,
985fcf3ce44SJohn Forte 	int *l_errnop)
986fcf3ce44SJohn Forte {
987fcf3ce44SJohn Forte 	struct fcp_scsi_cmd	fscsi;
988fcf3ce44SJohn Forte 	union scsi_cdb  scsi_rl_req;
989fcf3ce44SJohn Forte 	la_wwn_t	pwwn;
990fcf3ce44SJohn Forte 	int 	alloc_len;
991fcf3ce44SJohn Forte 	fpcfga_ret_t 	ret;
992fcf3ce44SJohn Forte 	uchar_t		lun_data[SAM_LUN_SIZE];
993fcf3ce44SJohn Forte 
994fcf3ce44SJohn Forte 	alloc_len = sizeof (struct report_lun_resp);
995fcf3ce44SJohn Forte 	if ((*resp_buf = (report_lun_resp_t *)calloc(1, alloc_len)) == NULL) {
996fcf3ce44SJohn Forte 		*l_errnop = errno;
997fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
998fcf3ce44SJohn Forte 	}
999fcf3ce44SJohn Forte 
1000fcf3ce44SJohn Forte 	if (cvt_dyncomp_to_lawwn(dyncomp, &pwwn) != 0) {
1001fcf3ce44SJohn Forte 		S_FREE(*resp_buf);
1002fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
1003fcf3ce44SJohn Forte 	}
1004fcf3ce44SJohn Forte 
1005fcf3ce44SJohn Forte 	/* sending to LUN 0 so initializing lun_data buffer to be 0 */
1006fcf3ce44SJohn Forte 	memset(lun_data, 0, sizeof (lun_data));
1007fcf3ce44SJohn Forte 	init_fcp_scsi_cmd(&fscsi, lun_data, &pwwn, &scsi_rl_req,
1008fcf3ce44SJohn Forte 	    sizeof (scsi_rl_req), *resp_buf, alloc_len, sensebuf,
1009fcf3ce44SJohn Forte 	    sizeof (struct scsi_extended_sense));
1010fcf3ce44SJohn Forte 	scsi_rl_req.scc_cmd = FP_SCMD_REPORT_LUN;
1011fcf3ce44SJohn Forte 	FORMG5COUNT(&scsi_rl_req, alloc_len);
1012fcf3ce44SJohn Forte 
1013fcf3ce44SJohn Forte 	if ((ret = issue_fcp_scsi_cmd(xport_phys, &fscsi, l_errnop))
1014fcf3ce44SJohn Forte 			!= FPCFGA_OK) {
1015fcf3ce44SJohn Forte 		S_FREE(*resp_buf);
1016fcf3ce44SJohn Forte 		return (ret);
1017fcf3ce44SJohn Forte 	}
1018fcf3ce44SJohn Forte 
1019fcf3ce44SJohn Forte 	if (ntohl((*resp_buf)->num_lun) >
1020fcf3ce44SJohn Forte 		(sizeof (struct report_lun_resp) - REPORT_LUN_HDR_SIZE)) {
1021fcf3ce44SJohn Forte 		alloc_len = (*resp_buf)->num_lun + REPORT_LUN_HDR_SIZE;
1022fcf3ce44SJohn Forte 		S_FREE(*resp_buf);
1023fcf3ce44SJohn Forte 		if ((*resp_buf = (report_lun_resp_t *)calloc(1, alloc_len))
1024fcf3ce44SJohn Forte 		    == NULL) {
1025fcf3ce44SJohn Forte 			*l_errnop = errno;
1026fcf3ce44SJohn Forte 			return (FPCFGA_LIB_ERR);
1027fcf3ce44SJohn Forte 		}
1028fcf3ce44SJohn Forte 		(void) memset((char *)*resp_buf, 0, alloc_len);
1029fcf3ce44SJohn Forte 		FORMG5COUNT(&scsi_rl_req, alloc_len);
1030fcf3ce44SJohn Forte 
1031fcf3ce44SJohn Forte 		fscsi.scsi_bufaddr = (caddr_t)*resp_buf;
1032fcf3ce44SJohn Forte 		fscsi.scsi_buflen = alloc_len;
1033fcf3ce44SJohn Forte 
1034fcf3ce44SJohn Forte 		if ((ret = issue_fcp_scsi_cmd(xport_phys, &fscsi, l_errnop))
1035fcf3ce44SJohn Forte 				!= FPCFGA_OK) {
1036fcf3ce44SJohn Forte 			S_FREE(*resp_buf);
1037fcf3ce44SJohn Forte 			return (ret);
1038fcf3ce44SJohn Forte 		}
1039fcf3ce44SJohn Forte 	}
1040fcf3ce44SJohn Forte 
1041fcf3ce44SJohn Forte 	/* num_lun represent number of luns * 8. */
1042fcf3ce44SJohn Forte 	*num_luns = ntohl((*resp_buf)->num_lun) >> 3;
1043fcf3ce44SJohn Forte 
1044fcf3ce44SJohn Forte 	return (FPCFGA_OK);
1045fcf3ce44SJohn Forte }
1046fcf3ce44SJohn Forte 
1047fcf3ce44SJohn Forte /*
1048fcf3ce44SJohn Forte  * Routine for consturct ldata list for each FCP SCSI LUN device
1049fcf3ce44SJohn Forte  * for a discovered target device.
1050fcf3ce44SJohn Forte  * It calls get_report_lun_data to get report lun data and
1051fcf3ce44SJohn Forte  * construct ldata list per each lun.
1052fcf3ce44SJohn Forte  *
1053fcf3ce44SJohn Forte  * It is called only when show_FCP_dev option is given.
1054fcf3ce44SJohn Forte  *
1055fcf3ce44SJohn Forte  * Overall algorithm:
1056fcf3ce44SJohn Forte  * Get the report lun data thru FCP passthru ioctl.
1057fcf3ce44SJohn Forte  * Call init_ldata_for_accessible_FCP_dev to process the report LUN data.
1058fcf3ce44SJohn Forte  * For each LUN found standard inquiry is issued to get device type.
1059fcf3ce44SJohn Forte  */
1060fcf3ce44SJohn Forte static fpcfga_ret_t
get_accessible_FCP_dev_ldata(const char * dyncomp,fpcfga_list_t * lap,int * l_errnop)1061fcf3ce44SJohn Forte get_accessible_FCP_dev_ldata(
1062fcf3ce44SJohn Forte 	const char *dyncomp,
1063fcf3ce44SJohn Forte 	fpcfga_list_t *lap,
1064fcf3ce44SJohn Forte 	int *l_errnop)
1065fcf3ce44SJohn Forte {
1066fcf3ce44SJohn Forte 	report_lun_resp_t	    *resp_buf;
1067fcf3ce44SJohn Forte 	struct scsi_extended_sense  sense;
1068fcf3ce44SJohn Forte 	int			    num_luns;
1069fcf3ce44SJohn Forte 	fpcfga_ret_t		    ret;
1070fcf3ce44SJohn Forte 
1071fcf3ce44SJohn Forte 	memset(&sense, 0, sizeof (sense));
1072fcf3ce44SJohn Forte 	if ((ret = get_report_lun_data(lap->apidp->xport_phys, dyncomp,
1073fcf3ce44SJohn Forte 		&num_luns, &resp_buf, &sense, l_errnop)) != FPCFGA_OK) {
1074fcf3ce44SJohn Forte 		/*
1075fcf3ce44SJohn Forte 		 * when report lun data fails then return FPCFGA_OK thus
1076fcf3ce44SJohn Forte 		 * keep the ldata for the target which is acquired previously.
1077fcf3ce44SJohn Forte 		 * For remote hba node this will be normal.
1078fcf3ce44SJohn Forte 		 * For a target error may already be detected through
1079fcf3ce44SJohn Forte 		 * FCP_TGT_INQ.
1080fcf3ce44SJohn Forte 		 */
1081fcf3ce44SJohn Forte 		if ((ret == FPCFGA_FCP_TGT_SEND_SCSI_FAILED) ||
1082fcf3ce44SJohn Forte 		    (ret == FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT)) {
1083fcf3ce44SJohn Forte 			ret = FPCFGA_OK;
1084fcf3ce44SJohn Forte 		}
1085fcf3ce44SJohn Forte 		return (ret);
1086fcf3ce44SJohn Forte 	}
1087fcf3ce44SJohn Forte 
1088fcf3ce44SJohn Forte 	if (num_luns > 0) {
1089fcf3ce44SJohn Forte 		ret = init_ldata_for_accessible_FCP_dev(
1090fcf3ce44SJohn Forte 			dyncomp, num_luns, resp_buf, lap, l_errnop);
1091fcf3ce44SJohn Forte 	} else {
1092fcf3ce44SJohn Forte 		/*
1093fcf3ce44SJohn Forte 		 * proceed with to stat if no lun found.
1094fcf3ce44SJohn Forte 		 * This will make the target apid will be kept.
1095fcf3ce44SJohn Forte 		 */
1096fcf3ce44SJohn Forte 		ret = FPCFGA_OK;
1097fcf3ce44SJohn Forte 	}
1098fcf3ce44SJohn Forte 
1099fcf3ce44SJohn Forte 	S_FREE(resp_buf);
1100fcf3ce44SJohn Forte 	return (ret);
1101fcf3ce44SJohn Forte }
1102fcf3ce44SJohn Forte 
1103fcf3ce44SJohn Forte /*
1104fcf3ce44SJohn Forte  * Routine for checking validity of ldata list based on input argumemnt.
1105fcf3ce44SJohn Forte  * Set the occupant state of hba port if the list is valid.
1106fcf3ce44SJohn Forte  */
1107fcf3ce44SJohn Forte static fpcfga_ret_t
postprocess_list_data(const ldata_list_t * listp,fpcfga_cmd_t cmd,cfga_stat_t chld_config,int * np,uint_t flags)1108fcf3ce44SJohn Forte postprocess_list_data(
1109fcf3ce44SJohn Forte 	const ldata_list_t *listp,
1110fcf3ce44SJohn Forte 	fpcfga_cmd_t cmd,
1111fcf3ce44SJohn Forte 	cfga_stat_t chld_config,
1112fcf3ce44SJohn Forte 	int *np,
1113fcf3ce44SJohn Forte 	uint_t flags)
1114fcf3ce44SJohn Forte {
1115fcf3ce44SJohn Forte 	ldata_list_t *tmplp = NULL;
1116fcf3ce44SJohn Forte 	cfga_list_data_t *xport_ldatap = NULL;
1117fcf3ce44SJohn Forte 	int i;
1118fcf3ce44SJohn Forte 
1119fcf3ce44SJohn Forte 
1120fcf3ce44SJohn Forte 	*np = 0;
1121fcf3ce44SJohn Forte 
1122fcf3ce44SJohn Forte 	if (listp == NULL) {
1123fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
1124fcf3ce44SJohn Forte 	}
1125fcf3ce44SJohn Forte 
1126fcf3ce44SJohn Forte 	tmplp = (ldata_list_t *)listp;
1127fcf3ce44SJohn Forte 	for (i = 0; tmplp != NULL; tmplp = tmplp->next) {
1128fcf3ce44SJohn Forte 		i++;
1129fcf3ce44SJohn Forte 		if (GET_DYN(tmplp->ldata.ap_phys_id) == NULL) {
1130fcf3ce44SJohn Forte 			/* A bus stat data */
1131fcf3ce44SJohn Forte 			assert(GET_DYN(tmplp->ldata.ap_log_id) == NULL);
1132fcf3ce44SJohn Forte 			xport_ldatap = &tmplp->ldata;
1133fcf3ce44SJohn Forte #ifdef DEBUG
1134fcf3ce44SJohn Forte 		} else {
1135fcf3ce44SJohn Forte 			assert(GET_DYN(tmplp->ldata.ap_log_id) != NULL);
1136fcf3ce44SJohn Forte #endif
1137fcf3ce44SJohn Forte 		}
1138fcf3ce44SJohn Forte 	}
1139fcf3ce44SJohn Forte 
1140fcf3ce44SJohn Forte 	switch (cmd) {
1141fcf3ce44SJohn Forte 	case FPCFGA_STAT_FC_DEV:
1142fcf3ce44SJohn Forte 		if ((flags & FLAG_FCP_DEV) == FLAG_FCP_DEV) {
1143fcf3ce44SJohn Forte 			if (i < 1 || xport_ldatap != NULL) {
1144fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
1145fcf3ce44SJohn Forte 			}
1146fcf3ce44SJohn Forte 		} else {
1147fcf3ce44SJohn Forte 			if (i != 1 || xport_ldatap != NULL) {
1148fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
1149fcf3ce44SJohn Forte 			}
1150fcf3ce44SJohn Forte 		}
1151fcf3ce44SJohn Forte 		break;
1152fcf3ce44SJohn Forte 	case FPCFGA_STAT_FCA_PORT:
1153fcf3ce44SJohn Forte 		if (i != 1 || xport_ldatap == NULL) {
1154fcf3ce44SJohn Forte 			return (FPCFGA_LIB_ERR);
1155fcf3ce44SJohn Forte 		}
1156fcf3ce44SJohn Forte 		break;
1157fcf3ce44SJohn Forte 	case FPCFGA_STAT_ALL:
1158fcf3ce44SJohn Forte 		if (i < 1 || xport_ldatap == NULL) {
1159fcf3ce44SJohn Forte 			return (FPCFGA_LIB_ERR);
1160fcf3ce44SJohn Forte 		}
1161fcf3ce44SJohn Forte 		break;
1162fcf3ce44SJohn Forte 	default:
1163fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
1164fcf3ce44SJohn Forte 	}
1165fcf3ce44SJohn Forte 
1166fcf3ce44SJohn Forte 	*np = i;
1167fcf3ce44SJohn Forte 
1168fcf3ce44SJohn Forte 	/* Fill in the occupant (child) state. */
1169fcf3ce44SJohn Forte 	if (xport_ldatap != NULL) {
1170fcf3ce44SJohn Forte 		xport_ldatap->ap_o_state = chld_config;
1171fcf3ce44SJohn Forte 	}
1172fcf3ce44SJohn Forte 	return (FPCFGA_OK);
1173fcf3ce44SJohn Forte }
1174fcf3ce44SJohn Forte 
1175fcf3ce44SJohn Forte /*
1176fcf3ce44SJohn Forte  * Routine for checking each target device found in device tree.
1177fcf3ce44SJohn Forte  * When the matching port WWN dev is found from the accessble ldata list
1178fcf3ce44SJohn Forte  * the target device is updated with configured ostate.
1179fcf3ce44SJohn Forte  *
1180fcf3ce44SJohn Forte  * Overall algorithm:
1181fcf3ce44SJohn Forte  * Parse the device tree to find configured devices which matches with
1182fcf3ce44SJohn Forte  * list argument.  If cmd is stat on a specific target device it
1183fcf3ce44SJohn Forte  * matches port WWN and continues to further processing.  If cmd is
1184fcf3ce44SJohn Forte  * stat on hba port all the device target under the hba are processed.
1185fcf3ce44SJohn Forte  */
1186fcf3ce44SJohn Forte static int
stat_fc_dev(di_node_t node,void * arg)1187fcf3ce44SJohn Forte stat_fc_dev(di_node_t node, void *arg)
1188fcf3ce44SJohn Forte {
1189fcf3ce44SJohn Forte 	fpcfga_list_t *lap = NULL;
1190fcf3ce44SJohn Forte 	char *devfsp = NULL, *nodepath = NULL;
1191fcf3ce44SJohn Forte 	size_t len = 0;
1192fcf3ce44SJohn Forte 	int limited_stat = 0, match_minor, rv;
1193fcf3ce44SJohn Forte 	fpcfga_ret_t ret;
1194fcf3ce44SJohn Forte 	di_prop_t prop = DI_PROP_NIL;
1195fcf3ce44SJohn Forte 	uchar_t	*port_wwn_data;
1196fcf3ce44SJohn Forte 	char	port_wwn[WWN_SIZE*2+1];
1197fcf3ce44SJohn Forte 	int	count;
1198fcf3ce44SJohn Forte 
1199fcf3ce44SJohn Forte 	lap = (fpcfga_list_t *)arg;
1200fcf3ce44SJohn Forte 
1201fcf3ce44SJohn Forte 	/*
1202fcf3ce44SJohn Forte 	 * Skip partial nodes
1203fcf3ce44SJohn Forte 	 *
1204fcf3ce44SJohn Forte 	 * This checking is from the scsi plug-in and will be deleted for
1205fcf3ce44SJohn Forte 	 * fp plug-in. The node will be processed for fp even if it is
1206fcf3ce44SJohn Forte 	 * in driver detached state. From fp perspective the node is configured
1207fcf3ce44SJohn Forte 	 * as long as the node is not in offline or down state.
1208fcf3ce44SJohn Forte 	 * scsi plug-in considers the known state when it is offlined
1209fcf3ce44SJohn Forte 	 * regradless of driver detached state or when it is not in driver
1210fcf3ce44SJohn Forte 	 * detached state like normal state.
1211fcf3ce44SJohn Forte 	 * If the node is only in driver detached state it is considered as
1212fcf3ce44SJohn Forte 	 * unknown state.
1213fcf3ce44SJohn Forte 	 *
1214fcf3ce44SJohn Forte 	 * if (!known_state(node) && (lap->cmd != FPCFGA_STAT_FC_DEV)) {
1215fcf3ce44SJohn Forte 	 *	return (DI_WALK_CONTINUE);
1216fcf3ce44SJohn Forte 	 *
1217fcf3ce44SJohn Forte 	 */
1218fcf3ce44SJohn Forte 
1219fcf3ce44SJohn Forte 	devfsp = di_devfs_path(node);
1220fcf3ce44SJohn Forte 	if (devfsp == NULL) {
1221fcf3ce44SJohn Forte 		rv = DI_WALK_CONTINUE;
1222fcf3ce44SJohn Forte 		goto out;
1223fcf3ce44SJohn Forte 	}
1224fcf3ce44SJohn Forte 
1225fcf3ce44SJohn Forte 	len = strlen(DEVICES_DIR) + strlen(devfsp) + 1;
1226fcf3ce44SJohn Forte 
1227fcf3ce44SJohn Forte 	nodepath = calloc(1, len);
1228fcf3ce44SJohn Forte 	if (nodepath == NULL) {
1229fcf3ce44SJohn Forte 		lap->l_errno = errno;
1230fcf3ce44SJohn Forte 		lap->ret = FPCFGA_LIB_ERR;
1231fcf3ce44SJohn Forte 		rv = DI_WALK_TERMINATE;
1232fcf3ce44SJohn Forte 		goto out;
1233fcf3ce44SJohn Forte 	}
1234fcf3ce44SJohn Forte 
1235fcf3ce44SJohn Forte 	(void) snprintf(nodepath, len, "%s%s", DEVICES_DIR, devfsp);
1236fcf3ce44SJohn Forte 
1237fcf3ce44SJohn Forte 	/* Skip node if it is HBA */
1238fcf3ce44SJohn Forte 	match_minor = 0;
1239fcf3ce44SJohn Forte 	if (!dev_cmp(lap->apidp->xport_phys, nodepath, match_minor)) {
1240fcf3ce44SJohn Forte 		rv = DI_WALK_CONTINUE;
1241fcf3ce44SJohn Forte 		goto out;
1242fcf3ce44SJohn Forte 	}
1243fcf3ce44SJohn Forte 
1244fcf3ce44SJohn Forte 	/* If stat'ing a specific device, is this node that device */
1245fcf3ce44SJohn Forte 	if (lap->cmd == FPCFGA_STAT_FC_DEV) {
1246fcf3ce44SJohn Forte 		/* checks port wwn property to find a match */
1247fcf3ce44SJohn Forte 		while ((prop = di_prop_next(node, prop))
1248fcf3ce44SJohn Forte 					!= DI_PROP_NIL) {
1249fcf3ce44SJohn Forte 			if ((strcmp(PORT_WWN_PROP,
1250fcf3ce44SJohn Forte 				di_prop_name(prop)) == 0) &&
1251fcf3ce44SJohn Forte 				(di_prop_type(prop) ==
1252fcf3ce44SJohn Forte 					DI_PROP_TYPE_BYTE)) {
1253fcf3ce44SJohn Forte 				break;
1254fcf3ce44SJohn Forte 			}
1255fcf3ce44SJohn Forte 		}
1256fcf3ce44SJohn Forte 
1257fcf3ce44SJohn Forte 		if (prop != DI_PROP_NIL) {
1258fcf3ce44SJohn Forte 			count = di_prop_bytes(prop, &port_wwn_data);
1259fcf3ce44SJohn Forte 			if (count != WWN_SIZE) {
1260fcf3ce44SJohn Forte 				lap->ret = FPCFGA_LIB_ERR;
1261fcf3ce44SJohn Forte 				rv = DI_WALK_TERMINATE;
1262fcf3ce44SJohn Forte 				goto out;
1263fcf3ce44SJohn Forte 			}
1264fcf3ce44SJohn Forte 			(void) sprintf(port_wwn, "%016llx",
1265fcf3ce44SJohn Forte 				(wwnConversion(port_wwn_data)));
1266fcf3ce44SJohn Forte 			/*
1267fcf3ce44SJohn Forte 			 * port wwn doesn't match contine to walk
1268fcf3ce44SJohn Forte 			 * if match call do_stat_fc_dev.
1269fcf3ce44SJohn Forte 			 */
1270fcf3ce44SJohn Forte 			if (strncmp(port_wwn, lap->apidp->dyncomp,
1271fcf3ce44SJohn Forte 					WWN_SIZE*2)) {
1272fcf3ce44SJohn Forte 				rv = DI_WALK_CONTINUE;
1273fcf3ce44SJohn Forte 				goto out;
1274fcf3ce44SJohn Forte 			}
1275fcf3ce44SJohn Forte 		} else {
1276fcf3ce44SJohn Forte 			rv = DI_WALK_CONTINUE;
1277fcf3ce44SJohn Forte 			goto out;
1278fcf3ce44SJohn Forte 		}
1279fcf3ce44SJohn Forte 	}
1280fcf3ce44SJohn Forte 
1281fcf3ce44SJohn Forte 	/*
1282fcf3ce44SJohn Forte 	 * If stat'ing a xport only, we look at device nodes only to get
1283fcf3ce44SJohn Forte 	 * xport configuration status. So a limited stat will suffice.
1284fcf3ce44SJohn Forte 	 */
1285fcf3ce44SJohn Forte 	if (lap->cmd == FPCFGA_STAT_FCA_PORT) {
1286fcf3ce44SJohn Forte 		limited_stat = 1;
1287fcf3ce44SJohn Forte 	} else {
1288fcf3ce44SJohn Forte 		limited_stat = 0;
1289fcf3ce44SJohn Forte 	}
1290fcf3ce44SJohn Forte 
1291fcf3ce44SJohn Forte 	/*
1292fcf3ce44SJohn Forte 	 * Ignore errors if stat'ing a bus or listing all
1293fcf3ce44SJohn Forte 	 */
1294fcf3ce44SJohn Forte 	ret = do_stat_fc_dev(node, nodepath, lap, limited_stat);
1295fcf3ce44SJohn Forte 	if (ret != FPCFGA_OK) {
1296fcf3ce44SJohn Forte 		if (lap->cmd == FPCFGA_STAT_FC_DEV) {
1297fcf3ce44SJohn Forte 			lap->ret = ret;
1298fcf3ce44SJohn Forte 			rv = DI_WALK_TERMINATE;
1299fcf3ce44SJohn Forte 		} else {
1300fcf3ce44SJohn Forte 			rv = DI_WALK_CONTINUE;
1301fcf3ce44SJohn Forte 		}
1302fcf3ce44SJohn Forte 		goto out;
1303fcf3ce44SJohn Forte 	}
1304fcf3ce44SJohn Forte 
1305fcf3ce44SJohn Forte 	/* Are we done ? */
1306fcf3ce44SJohn Forte 	rv = DI_WALK_CONTINUE;
1307fcf3ce44SJohn Forte 	if (lap->cmd == FPCFGA_STAT_FCA_PORT &&
1308fcf3ce44SJohn Forte 	    lap->chld_config == CFGA_STAT_CONFIGURED) {
1309fcf3ce44SJohn Forte 		rv = DI_WALK_TERMINATE;
1310fcf3ce44SJohn Forte 	} else if (lap->cmd == FPCFGA_STAT_FC_DEV) {
1311fcf3ce44SJohn Forte 		/*
1312fcf3ce44SJohn Forte 		 * If stat'ing a specific device, we are done at this point.
1313fcf3ce44SJohn Forte 		 */
1314fcf3ce44SJohn Forte 		rv = DI_WALK_TERMINATE;
1315fcf3ce44SJohn Forte 	}
1316fcf3ce44SJohn Forte 
1317fcf3ce44SJohn Forte 	/*FALLTHRU*/
1318fcf3ce44SJohn Forte out:
1319fcf3ce44SJohn Forte 	S_FREE(nodepath);
1320fcf3ce44SJohn Forte 	if (devfsp != NULL) di_devfs_path_free(devfsp);
1321fcf3ce44SJohn Forte 	return (rv);
1322fcf3ce44SJohn Forte }
1323fcf3ce44SJohn Forte 
1324fcf3ce44SJohn Forte /*
1325fcf3ce44SJohn Forte  * Routine for checking each FCP SCSI LUN device found in device tree.
1326fcf3ce44SJohn Forte  * When the matching port WWN and LUN are found from the accessble ldata list
1327fcf3ce44SJohn Forte  * the FCP SCSI LUN is updated with configured ostate.
1328fcf3ce44SJohn Forte  *
1329fcf3ce44SJohn Forte  * Overall algorithm:
1330fcf3ce44SJohn Forte  * Parse the device tree to find configured devices which matches with
1331fcf3ce44SJohn Forte  * list argument.  If cmd is stat on a specific target device it
1332fcf3ce44SJohn Forte  * matches port WWN and continues to further processing.  If cmd is
1333fcf3ce44SJohn Forte  * stat on hba port all the FCP SCSI LUN under the hba are processed.
1334fcf3ce44SJohn Forte  */
1335fcf3ce44SJohn Forte static int
stat_FCP_dev(di_node_t node,void * arg)1336fcf3ce44SJohn Forte stat_FCP_dev(di_node_t node, void *arg)
1337fcf3ce44SJohn Forte {
1338fcf3ce44SJohn Forte 	fpcfga_list_t *lap = NULL;
1339fcf3ce44SJohn Forte 	char *devfsp = NULL, *nodepath = NULL;
1340fcf3ce44SJohn Forte 	size_t len = 0;
1341fcf3ce44SJohn Forte 	int limited_stat = 0, match_minor, rv, di_ret;
1342fcf3ce44SJohn Forte 	fpcfga_ret_t ret;
1343fcf3ce44SJohn Forte 	uchar_t	*port_wwn_data;
1344fcf3ce44SJohn Forte 	char	port_wwn[WWN_SIZE*2+1];
1345fcf3ce44SJohn Forte 
1346fcf3ce44SJohn Forte 	lap = (fpcfga_list_t *)arg;
1347fcf3ce44SJohn Forte 
1348fcf3ce44SJohn Forte 	devfsp = di_devfs_path(node);
1349fcf3ce44SJohn Forte 	if (devfsp == NULL) {
1350fcf3ce44SJohn Forte 		rv = DI_WALK_CONTINUE;
1351fcf3ce44SJohn Forte 		goto out;
1352fcf3ce44SJohn Forte 	}
1353fcf3ce44SJohn Forte 
1354fcf3ce44SJohn Forte 	len = strlen(DEVICES_DIR) + strlen(devfsp) + 1;
1355fcf3ce44SJohn Forte 
1356fcf3ce44SJohn Forte 	nodepath = calloc(1, len);
1357fcf3ce44SJohn Forte 	if (nodepath == NULL) {
1358fcf3ce44SJohn Forte 		lap->l_errno = errno;
1359fcf3ce44SJohn Forte 		lap->ret = FPCFGA_LIB_ERR;
1360fcf3ce44SJohn Forte 		rv = DI_WALK_TERMINATE;
1361fcf3ce44SJohn Forte 		goto out;
1362fcf3ce44SJohn Forte 	}
1363fcf3ce44SJohn Forte 
1364fcf3ce44SJohn Forte 	(void) snprintf(nodepath, len, "%s%s", DEVICES_DIR, devfsp);
1365fcf3ce44SJohn Forte 
1366fcf3ce44SJohn Forte 	/* Skip node if it is HBA */
1367fcf3ce44SJohn Forte 	match_minor = 0;
1368fcf3ce44SJohn Forte 	if (!dev_cmp(lap->apidp->xport_phys, nodepath, match_minor)) {
1369fcf3ce44SJohn Forte 		rv = DI_WALK_CONTINUE;
1370fcf3ce44SJohn Forte 		goto out;
1371fcf3ce44SJohn Forte 	}
1372fcf3ce44SJohn Forte 
1373fcf3ce44SJohn Forte 	/* If stat'ing a specific device, is this node that device */
1374fcf3ce44SJohn Forte 	if (lap->cmd == FPCFGA_STAT_FC_DEV) {
1375fcf3ce44SJohn Forte 		/* checks port wwn property to find a match */
1376fcf3ce44SJohn Forte 		di_ret = di_prop_lookup_bytes(DDI_DEV_T_ANY, node,
1377fcf3ce44SJohn Forte 			PORT_WWN_PROP, &port_wwn_data);
1378fcf3ce44SJohn Forte 		if (di_ret == -1) {
1379fcf3ce44SJohn Forte 			rv = DI_WALK_CONTINUE;
1380fcf3ce44SJohn Forte 			goto out;
1381fcf3ce44SJohn Forte 		} else {
1382fcf3ce44SJohn Forte 			(void) sprintf(port_wwn, "%016llx",
1383fcf3ce44SJohn Forte 				(wwnConversion(port_wwn_data)));
1384fcf3ce44SJohn Forte 			/*
1385fcf3ce44SJohn Forte 			 * port wwn doesn't match contine to walk
1386fcf3ce44SJohn Forte 			 * if match call do_stat_FCP_dev.
1387fcf3ce44SJohn Forte 			 */
1388fcf3ce44SJohn Forte 			if (strncmp(port_wwn, lap->apidp->dyncomp,
1389fcf3ce44SJohn Forte 					WWN_SIZE*2)) {
1390fcf3ce44SJohn Forte 				rv = DI_WALK_CONTINUE;
1391fcf3ce44SJohn Forte 				goto out;
1392fcf3ce44SJohn Forte 			}
1393fcf3ce44SJohn Forte 		}
1394fcf3ce44SJohn Forte 	}
1395fcf3ce44SJohn Forte 
1396fcf3ce44SJohn Forte 	/*
1397fcf3ce44SJohn Forte 	 * If stat'ing a xport only, we look at device nodes only to get
1398fcf3ce44SJohn Forte 	 * xport configuration status. So a limited stat will suffice.
1399fcf3ce44SJohn Forte 	 */
1400fcf3ce44SJohn Forte 	if (lap->cmd == FPCFGA_STAT_FCA_PORT) {
1401fcf3ce44SJohn Forte 		limited_stat = 1;
1402fcf3ce44SJohn Forte 	} else {
1403fcf3ce44SJohn Forte 		limited_stat = 0;
1404fcf3ce44SJohn Forte 	}
1405fcf3ce44SJohn Forte 
1406fcf3ce44SJohn Forte 	/*
1407fcf3ce44SJohn Forte 	 * Ignore errors if stat'ing a bus or listing all
1408fcf3ce44SJohn Forte 	 */
1409fcf3ce44SJohn Forte 	ret = do_stat_FCP_dev(node, nodepath, lap, limited_stat);
1410fcf3ce44SJohn Forte 	if (ret != FPCFGA_OK) {
1411fcf3ce44SJohn Forte 		rv = DI_WALK_CONTINUE;
1412fcf3ce44SJohn Forte 		goto out;
1413fcf3ce44SJohn Forte 	}
1414fcf3ce44SJohn Forte 
1415fcf3ce44SJohn Forte 	/* Are we done ? */
1416fcf3ce44SJohn Forte 	rv = DI_WALK_CONTINUE;
1417fcf3ce44SJohn Forte 	if (lap->cmd == FPCFGA_STAT_FCA_PORT &&
1418fcf3ce44SJohn Forte 	    lap->chld_config == CFGA_STAT_CONFIGURED) {
1419fcf3ce44SJohn Forte 		rv = DI_WALK_TERMINATE;
1420fcf3ce44SJohn Forte 	}
1421fcf3ce44SJohn Forte 
1422fcf3ce44SJohn Forte 	/*FALLTHRU*/
1423fcf3ce44SJohn Forte out:
1424fcf3ce44SJohn Forte 	S_FREE(nodepath);
1425fcf3ce44SJohn Forte 	if (devfsp != NULL) di_devfs_path_free(devfsp);
1426fcf3ce44SJohn Forte 	return (rv);
1427fcf3ce44SJohn Forte }
1428fcf3ce44SJohn Forte 
1429fcf3ce44SJohn Forte static fpcfga_ret_t
do_stat_fca_xport(fpcfga_list_t * lap,int limited_stat,HBA_PORTATTRIBUTES portAttrs)1430fcf3ce44SJohn Forte do_stat_fca_xport(fpcfga_list_t *lap, int limited_stat,
1431fcf3ce44SJohn Forte 	HBA_PORTATTRIBUTES portAttrs)
1432fcf3ce44SJohn Forte {
1433fcf3ce44SJohn Forte 	cfga_list_data_t *clp = NULL;
1434fcf3ce44SJohn Forte 	ldata_list_t *listp = NULL;
1435fcf3ce44SJohn Forte 	int l_errno = 0;
1436fcf3ce44SJohn Forte 	uint_t devinfo_state = 0;
1437fcf3ce44SJohn Forte 	walkarg_t walkarg;
1438fcf3ce44SJohn Forte 	fpcfga_ret_t ret;
1439fcf3ce44SJohn Forte 	cfga_cond_t cond = CFGA_COND_UNKNOWN;
1440fcf3ce44SJohn Forte 
1441fcf3ce44SJohn Forte 	assert(lap->xport_logp != NULL);
1442fcf3ce44SJohn Forte 
1443fcf3ce44SJohn Forte 	/* Get xport state */
1444fcf3ce44SJohn Forte 	if (lap->apidp->flags == FLAG_DEVINFO_FORCE) {
1445fcf3ce44SJohn Forte 		walkarg.flags = FLAG_DEVINFO_FORCE;
1446fcf3ce44SJohn Forte 	} else {
1447fcf3ce44SJohn Forte 		walkarg.flags = 0;
1448fcf3ce44SJohn Forte 	}
1449fcf3ce44SJohn Forte 	walkarg.walkmode.node_args.flags = 0;
1450fcf3ce44SJohn Forte 	walkarg.walkmode.node_args.fcn = get_xport_state;
1451fcf3ce44SJohn Forte 
1452fcf3ce44SJohn Forte 	ret = walk_tree(lap->apidp->xport_phys, &devinfo_state,
1453fcf3ce44SJohn Forte 		DINFOCPYALL | DINFOPATH, &walkarg, FPCFGA_WALK_NODE, &l_errno);
1454fcf3ce44SJohn Forte 	if (ret == FPCFGA_OK) {
1455fcf3ce44SJohn Forte 		lap->xport_rstate = xport_devinfo_to_recep_state(devinfo_state);
1456fcf3ce44SJohn Forte 	} else {
1457fcf3ce44SJohn Forte 		lap->xport_rstate = CFGA_STAT_NONE;
1458fcf3ce44SJohn Forte 	}
1459fcf3ce44SJohn Forte 
1460fcf3ce44SJohn Forte 	/*
1461fcf3ce44SJohn Forte 	 * Get topology works okay even if the fp port is connected
1462fcf3ce44SJohn Forte 	 * to a switch and no devices connected to the switch.
1463fcf3ce44SJohn Forte 	 * In this case the list will only shows fp port info without
1464fcf3ce44SJohn Forte 	 * any device listed.
1465fcf3ce44SJohn Forte 	 */
1466fcf3ce44SJohn Forte 	switch (portAttrs.PortType) {
1467fcf3ce44SJohn Forte 		case HBA_PORTTYPE_NLPORT:
1468fcf3ce44SJohn Forte 			(void) snprintf(lap->xport_type,
1469fcf3ce44SJohn Forte 				sizeof (lap->xport_type), "%s",
1470fcf3ce44SJohn Forte 				FP_FC_PUBLIC_PORT_TYPE);
1471fcf3ce44SJohn Forte 			break;
1472fcf3ce44SJohn Forte 		case HBA_PORTTYPE_NPORT:
1473fcf3ce44SJohn Forte 			(void) snprintf(lap->xport_type,
1474fcf3ce44SJohn Forte 				sizeof (lap->xport_type), "%s",
1475fcf3ce44SJohn Forte 				FP_FC_FABRIC_PORT_TYPE);
1476fcf3ce44SJohn Forte 			break;
1477fcf3ce44SJohn Forte 		case HBA_PORTTYPE_LPORT:
1478fcf3ce44SJohn Forte 			(void) snprintf(lap->xport_type,
1479fcf3ce44SJohn Forte 				sizeof (lap->xport_type), "%s",
1480fcf3ce44SJohn Forte 				FP_FC_PRIVATE_PORT_TYPE);
1481fcf3ce44SJohn Forte 			break;
1482fcf3ce44SJohn Forte 		case HBA_PORTTYPE_PTP:
1483fcf3ce44SJohn Forte 			(void) snprintf(lap->xport_type,
1484fcf3ce44SJohn Forte 				sizeof (lap->xport_type), "%s",
1485fcf3ce44SJohn Forte 				FP_FC_PT_TO_PT_PORT_TYPE);
1486fcf3ce44SJohn Forte 			break;
1487fcf3ce44SJohn Forte 		/*
1488fcf3ce44SJohn Forte 		 * HBA_PORTTYPE_UNKNOWN means nothing is connected
1489fcf3ce44SJohn Forte 		 */
1490fcf3ce44SJohn Forte 		case HBA_PORTTYPE_UNKNOWN:
1491fcf3ce44SJohn Forte 			(void) snprintf(lap->xport_type,
1492fcf3ce44SJohn Forte 				sizeof (lap->xport_type), "%s",
1493fcf3ce44SJohn Forte 				FP_FC_PORT_TYPE);
1494fcf3ce44SJohn Forte 			break;
1495fcf3ce44SJohn Forte 		/* NOT_PRESENT, OTHER, FPORT, FLPORT */
1496fcf3ce44SJohn Forte 		default:
1497fcf3ce44SJohn Forte 			(void) snprintf(lap->xport_type,
1498fcf3ce44SJohn Forte 				sizeof (lap->xport_type), "%s",
1499fcf3ce44SJohn Forte 				FP_FC_PORT_TYPE);
1500fcf3ce44SJohn Forte 			cond = CFGA_COND_FAILED;
1501fcf3ce44SJohn Forte 			break;
1502fcf3ce44SJohn Forte 	}
1503fcf3ce44SJohn Forte 
1504fcf3ce44SJohn Forte 	if (limited_stat) {
1505fcf3ce44SJohn Forte 		/* We only want to know bus(receptacle) connect status */
1506fcf3ce44SJohn Forte 		return (FPCFGA_OK);
1507fcf3ce44SJohn Forte 	}
1508fcf3ce44SJohn Forte 
1509fcf3ce44SJohn Forte 	listp = calloc(1, sizeof (ldata_list_t));
1510fcf3ce44SJohn Forte 	if (listp == NULL) {
1511fcf3ce44SJohn Forte 		lap->l_errno = errno;
1512fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
1513fcf3ce44SJohn Forte 	}
1514fcf3ce44SJohn Forte 
1515fcf3ce44SJohn Forte 	clp = &listp->ldata;
1516fcf3ce44SJohn Forte 
1517fcf3ce44SJohn Forte 	(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s",
1518fcf3ce44SJohn Forte 	    lap->xport_logp);
1519fcf3ce44SJohn Forte 	(void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s",
1520fcf3ce44SJohn Forte 	    lap->apidp->xport_phys);
1521fcf3ce44SJohn Forte 
1522fcf3ce44SJohn Forte 	clp->ap_class[0] = '\0';	/* Filled by libcfgadm */
1523fcf3ce44SJohn Forte 	clp->ap_r_state = lap->xport_rstate;
1524fcf3ce44SJohn Forte 	clp->ap_o_state = lap->chld_config;
1525fcf3ce44SJohn Forte 	clp->ap_cond = cond;
1526fcf3ce44SJohn Forte 	clp->ap_busy = 0;
1527fcf3ce44SJohn Forte 	clp->ap_status_time = (time_t)-1;
1528fcf3ce44SJohn Forte 	clp->ap_info[0] = '\0';
1529fcf3ce44SJohn Forte 	(void) strncpy(clp->ap_type, lap->xport_type, sizeof (clp->ap_type));
1530fcf3ce44SJohn Forte 
1531fcf3ce44SJohn Forte 	/* Link it in.  lap->listp is NULL originally. */
1532fcf3ce44SJohn Forte 	listp->next = lap->listp;
1533fcf3ce44SJohn Forte 	/* lap->listp now gets cfga_list_data for the fca port. */
1534fcf3ce44SJohn Forte 	lap->listp = listp;
1535fcf3ce44SJohn Forte 
1536fcf3ce44SJohn Forte 	return (FPCFGA_OK);
1537fcf3ce44SJohn Forte }
1538fcf3ce44SJohn Forte 
1539fcf3ce44SJohn Forte 
1540fcf3ce44SJohn Forte static int
get_xport_state(di_node_t node,void * arg)1541fcf3ce44SJohn Forte get_xport_state(di_node_t node, void *arg)
1542fcf3ce44SJohn Forte {
1543fcf3ce44SJohn Forte 	uint_t *di_statep = (uint_t *)arg;
1544fcf3ce44SJohn Forte 
1545fcf3ce44SJohn Forte 	*di_statep = di_state(node);
1546fcf3ce44SJohn Forte 
1547fcf3ce44SJohn Forte 	return (DI_WALK_TERMINATE);
1548fcf3ce44SJohn Forte }
1549fcf3ce44SJohn Forte 
1550fcf3ce44SJohn Forte /*
1551fcf3ce44SJohn Forte  * Routine for updating ldata list based on the state of device node.
1552fcf3ce44SJohn Forte  * When no matching accessible ldata is found a new ldata is created
1553fcf3ce44SJohn Forte  * with proper state information.
1554fcf3ce44SJohn Forte  *
1555fcf3ce44SJohn Forte  * Overall algorithm:
1556fcf3ce44SJohn Forte  * If the device node is online and the matching ldata is found
1557fcf3ce44SJohn Forte  * the target device is updated with configued and unknown condition.
1558fcf3ce44SJohn Forte  * If the device node is offline or down and the matching ldata is found
1559fcf3ce44SJohn Forte  * the target device is updated with configued and unusable condition.
1560fcf3ce44SJohn Forte  * If the device node is online but the matching ldata is not found
1561fcf3ce44SJohn Forte  * the target device is created with configued and failing condition.
1562fcf3ce44SJohn Forte  * If the device node is offline or down and the matching ldata is not found
1563fcf3ce44SJohn Forte  * the target device is created with configued and unusable condition.
1564fcf3ce44SJohn Forte  */
1565fcf3ce44SJohn Forte static fpcfga_ret_t
do_stat_fc_dev(const di_node_t node,const char * nodepath,fpcfga_list_t * lap,int limited_stat)1566fcf3ce44SJohn Forte do_stat_fc_dev(
1567fcf3ce44SJohn Forte 	const di_node_t node,
1568fcf3ce44SJohn Forte 	const char *nodepath,
1569fcf3ce44SJohn Forte 	fpcfga_list_t *lap,
1570fcf3ce44SJohn Forte 	int limited_stat)
1571fcf3ce44SJohn Forte {
1572fcf3ce44SJohn Forte 	uint_t dctl_state = 0, devinfo_state = 0;
1573fcf3ce44SJohn Forte 	char *dyncomp = NULL;
1574fcf3ce44SJohn Forte 	cfga_list_data_t *clp = NULL;
1575fcf3ce44SJohn Forte 	cfga_busy_t busy;
1576fcf3ce44SJohn Forte 	ldata_list_t *listp = NULL;
1577fcf3ce44SJohn Forte 	ldata_list_t *matchldp = NULL;
1578fcf3ce44SJohn Forte 	int l_errno = 0;
1579fcf3ce44SJohn Forte 	cfga_stat_t ostate;
1580fcf3ce44SJohn Forte 	cfga_cond_t cond;
1581fcf3ce44SJohn Forte 	fpcfga_ret_t ret;
1582fcf3ce44SJohn Forte 
1583fcf3ce44SJohn Forte 	assert(lap->apidp->xport_phys != NULL);
1584fcf3ce44SJohn Forte 	assert(lap->xport_logp != NULL);
1585fcf3ce44SJohn Forte 
1586fcf3ce44SJohn Forte 	cond = CFGA_COND_UNKNOWN;
1587fcf3ce44SJohn Forte 
1588fcf3ce44SJohn Forte 	devinfo_state = di_state(node);
1589fcf3ce44SJohn Forte 	ostate = dev_devinfo_to_occupant_state(devinfo_state);
1590fcf3ce44SJohn Forte 
1591fcf3ce44SJohn Forte 	/*
1592fcf3ce44SJohn Forte 	 * NOTE: The framework cannot currently detect layered driver
1593fcf3ce44SJohn Forte 	 * opens, so the busy indicator is not very reliable. Also,
1594fcf3ce44SJohn Forte 	 * non-root users will not be able to determine busy
1595fcf3ce44SJohn Forte 	 * status (libdevice needs root permissions).
1596fcf3ce44SJohn Forte 	 * This should probably be fixed by adding a DI_BUSY to the di_state()
1597fcf3ce44SJohn Forte 	 * routine in libdevinfo.
1598fcf3ce44SJohn Forte 	 */
1599fcf3ce44SJohn Forte 	if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE, &dctl_state,
1600fcf3ce44SJohn Forte 	    &l_errno) == FPCFGA_OK) {
1601fcf3ce44SJohn Forte 		busy = ((dctl_state & DEVICE_BUSY) == DEVICE_BUSY) ? 1 : 0;
1602fcf3ce44SJohn Forte 	} else {
1603fcf3ce44SJohn Forte 		busy = 0;
1604fcf3ce44SJohn Forte 	}
1605fcf3ce44SJohn Forte 
1606fcf3ce44SJohn Forte 	/* We only want to know device config state */
1607fcf3ce44SJohn Forte 	if (limited_stat) {
1608fcf3ce44SJohn Forte 		if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) ||
1609fcf3ce44SJohn Forte 			strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) {
1610fcf3ce44SJohn Forte 			lap->chld_config = CFGA_STAT_CONFIGURED;
1611fcf3ce44SJohn Forte 		} else {
1612fcf3ce44SJohn Forte 			if (ostate != CFGA_STAT_UNCONFIGURED) {
1613fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
1614fcf3ce44SJohn Forte 			}
1615fcf3ce44SJohn Forte 		}
1616fcf3ce44SJohn Forte 		return (FPCFGA_OK);
1617fcf3ce44SJohn Forte 	}
1618fcf3ce44SJohn Forte 
1619fcf3ce44SJohn Forte 	/*
1620fcf3ce44SJohn Forte 	 * If child device is configured, see if it is accessible also
1621fcf3ce44SJohn Forte 	 * for FPCFGA_STAT_FC_DEV cmd.
1622fcf3ce44SJohn Forte 	 */
1623fcf3ce44SJohn Forte 	if (lap->cmd == FPCFGA_STAT_FC_DEV) {
1624fcf3ce44SJohn Forte 		switch (ostate) {
1625fcf3ce44SJohn Forte 		case CFGA_STAT_CONFIGURED:
1626fcf3ce44SJohn Forte 			/*
1627fcf3ce44SJohn Forte 			 * if configured and not accessble, the device is
1628fcf3ce44SJohn Forte 			 * till be displayed with failing condition.
1629fcf3ce44SJohn Forte 			 * return code should be FPCFGA_OK to display it.
1630fcf3ce44SJohn Forte 			 */
1631fcf3ce44SJohn Forte 		case CFGA_STAT_NONE:
1632fcf3ce44SJohn Forte 			/*
1633fcf3ce44SJohn Forte 			 * If not unconfigured and not attached
1634fcf3ce44SJohn Forte 			 * the state is set to CFGA_STAT_NONE currently.
1635fcf3ce44SJohn Forte 			 * This is okay for the detached node due to
1636fcf3ce44SJohn Forte 			 * the driver being unloaded.
1637fcf3ce44SJohn Forte 			 * May need to define another state to
1638fcf3ce44SJohn Forte 			 * isolate the detached only state.
1639fcf3ce44SJohn Forte 			 *
1640fcf3ce44SJohn Forte 			 * handle the same way as configured.
1641fcf3ce44SJohn Forte 			 */
1642fcf3ce44SJohn Forte 			if (lap->ret != FPCFGA_ACCESS_OK) {
1643fcf3ce44SJohn Forte 				cond = CFGA_COND_FAILING;
1644fcf3ce44SJohn Forte 			}
1645fcf3ce44SJohn Forte 			lap->chld_config = CFGA_STAT_CONFIGURED;
1646fcf3ce44SJohn Forte 			break;
1647fcf3ce44SJohn Forte 		case CFGA_STAT_UNCONFIGURED:
1648fcf3ce44SJohn Forte 			/*
1649fcf3ce44SJohn Forte 			 * if unconfigured - offline or down,
1650fcf3ce44SJohn Forte 			 * set to cond to unusable regardless of accessibility.
1651fcf3ce44SJohn Forte 			 * This behavior needs to be examined further.
1652fcf3ce44SJohn Forte 			 * When the device is not accessible the node
1653fcf3ce44SJohn Forte 			 * may get offline or down. In that case failing
1654fcf3ce44SJohn Forte 			 * cond may make more sense.
1655fcf3ce44SJohn Forte 			 * In anycase the ostate will be set to configured
1656fcf3ce44SJohn Forte 			 * configured.
1657fcf3ce44SJohn Forte 			 */
1658fcf3ce44SJohn Forte 			cond = CFGA_COND_UNUSABLE;
1659fcf3ce44SJohn Forte 			/*
1660fcf3ce44SJohn Forte 			 * For fabric port the fca port is considered as
1661fcf3ce44SJohn Forte 			 * configured since user configured previously
1662fcf3ce44SJohn Forte 			 * for any existing node.  Otherwise when the
1663fcf3ce44SJohn Forte 			 * device was accessible, the hba is considered as
1664fcf3ce44SJohn Forte 			 * configured.
1665fcf3ce44SJohn Forte 			 */
1666fcf3ce44SJohn Forte 			if (((strcmp(lap->xport_type,
1667fcf3ce44SJohn Forte 				FP_FC_PUBLIC_PORT_TYPE) == 0) ||
1668fcf3ce44SJohn Forte 				(strcmp(lap->xport_type,
1669fcf3ce44SJohn Forte 				FP_FC_FABRIC_PORT_TYPE) == 0)) ||
1670fcf3ce44SJohn Forte 				(lap->ret == FPCFGA_ACCESS_OK)) {
1671fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
1672fcf3ce44SJohn Forte 			} else {
1673fcf3ce44SJohn Forte 				lap->ret = FPCFGA_APID_NOEXIST;
1674fcf3ce44SJohn Forte 				return (FPCFGA_OK);
1675fcf3ce44SJohn Forte 			}
1676fcf3ce44SJohn Forte 			break;
1677fcf3ce44SJohn Forte 		default:
1678fcf3ce44SJohn Forte 			break;
1679fcf3ce44SJohn Forte 		}
1680fcf3ce44SJohn Forte 
1681fcf3ce44SJohn Forte 		/* if device found in disco ports, ldata already created. */
1682fcf3ce44SJohn Forte 		if (lap->ret == FPCFGA_ACCESS_OK) {
1683fcf3ce44SJohn Forte 			/*
1684fcf3ce44SJohn Forte 			 * if cond is not changed then don't update
1685fcf3ce44SJohn Forte 			 * condition to keep the previous condition.
1686fcf3ce44SJohn Forte 			 */
1687fcf3ce44SJohn Forte 			if (cond != CFGA_COND_UNKNOWN) {
1688fcf3ce44SJohn Forte 				lap->listp->ldata.ap_cond = cond;
1689fcf3ce44SJohn Forte 			}
1690fcf3ce44SJohn Forte 			lap->listp->ldata.ap_o_state = CFGA_STAT_CONFIGURED;
1691fcf3ce44SJohn Forte 			lap->listp->ldata.ap_busy = busy;
1692fcf3ce44SJohn Forte 			lap->ret = FPCFGA_OK;
1693fcf3ce44SJohn Forte 			return (FPCFGA_OK);
1694fcf3ce44SJohn Forte 		}
1695fcf3ce44SJohn Forte 	}
1696fcf3ce44SJohn Forte 
1697fcf3ce44SJohn Forte 	/*
1698fcf3ce44SJohn Forte 	 * if cmd is stat all check ldata list
1699fcf3ce44SJohn Forte 	 * to see if the node exist on the dev list.  Otherwise create
1700fcf3ce44SJohn Forte 	 * the list element.
1701fcf3ce44SJohn Forte 	 */
1702fcf3ce44SJohn Forte 	if (lap->cmd == FPCFGA_STAT_ALL) {
1703fcf3ce44SJohn Forte 		if (lap->listp != NULL) {
1704fcf3ce44SJohn Forte 			if ((ret = make_dyncomp_from_dinode(node,
1705fcf3ce44SJohn Forte 					&dyncomp, &l_errno)) != FPCFGA_OK) {
1706fcf3ce44SJohn Forte 				return (ret);
1707fcf3ce44SJohn Forte 			}
1708fcf3ce44SJohn Forte 			ret = is_dyn_ap_on_ldata_list(dyncomp, lap->listp,
1709fcf3ce44SJohn Forte 					&matchldp, &l_errno);
1710fcf3ce44SJohn Forte 			switch (ret) {
1711fcf3ce44SJohn Forte 			case FPCFGA_ACCESS_OK:
1712fcf3ce44SJohn Forte 				/* node exists so set ostate to configured. */
1713fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
1714fcf3ce44SJohn Forte 				matchldp->ldata.ap_o_state =
1715fcf3ce44SJohn Forte 					CFGA_STAT_CONFIGURED;
1716fcf3ce44SJohn Forte 				matchldp->ldata.ap_busy = busy;
1717fcf3ce44SJohn Forte 				clp = &matchldp->ldata;
1718fcf3ce44SJohn Forte 				switch (ostate) {
1719fcf3ce44SJohn Forte 				case CFGA_STAT_CONFIGURED:
1720fcf3ce44SJohn Forte 				/*
1721fcf3ce44SJohn Forte 				 * If not unconfigured and not attached
1722fcf3ce44SJohn Forte 				 * the state is set to CFGA_STAT_NONE currently.
1723fcf3ce44SJohn Forte 				 * This is okay for the detached node due to
1724fcf3ce44SJohn Forte 				 * the driver being unloaded.
1725fcf3ce44SJohn Forte 				 * May need to define another state to
1726fcf3ce44SJohn Forte 				 * isolate the detached only state.
1727fcf3ce44SJohn Forte 				 */
1728fcf3ce44SJohn Forte 				case CFGA_STAT_NONE:
1729fcf3ce44SJohn Forte 					/* update ap_type and ap_info */
1730fcf3ce44SJohn Forte 					get_hw_info(node, clp);
1731fcf3ce44SJohn Forte 					break;
1732fcf3ce44SJohn Forte 				/*
1733fcf3ce44SJohn Forte 				 * node is offline or down.
1734fcf3ce44SJohn Forte 				 * set cond to unusable.
1735fcf3ce44SJohn Forte 				 */
1736fcf3ce44SJohn Forte 				case CFGA_STAT_UNCONFIGURED:
1737fcf3ce44SJohn Forte 					/*
1738fcf3ce44SJohn Forte 					 * if cond is not unknown
1739fcf3ce44SJohn Forte 					 * we already set the cond from
1740fcf3ce44SJohn Forte 					 * a different node with the same
1741fcf3ce44SJohn Forte 					 * port WWN or initial probing
1742fcf3ce44SJohn Forte 					 * was failed so don't update again.
1743fcf3ce44SJohn Forte 					 */
1744fcf3ce44SJohn Forte 					if (matchldp->ldata.ap_cond ==
1745fcf3ce44SJohn Forte 						CFGA_COND_UNKNOWN) {
1746fcf3ce44SJohn Forte 						matchldp->ldata.ap_cond =
1747fcf3ce44SJohn Forte 						CFGA_COND_UNUSABLE;
1748fcf3ce44SJohn Forte 					}
1749fcf3ce44SJohn Forte 					break;
1750fcf3ce44SJohn Forte 				default:
1751fcf3ce44SJohn Forte 					break;
1752fcf3ce44SJohn Forte 				}
1753fcf3ce44SJohn Forte 				/* node found in ldata list so just return. */
1754fcf3ce44SJohn Forte 				lap->ret = FPCFGA_OK;
1755fcf3ce44SJohn Forte 				S_FREE(dyncomp);
1756fcf3ce44SJohn Forte 				return (FPCFGA_OK);
1757fcf3ce44SJohn Forte 			case FPCFGA_LIB_ERR:
1758fcf3ce44SJohn Forte 				lap->l_errno = l_errno;
1759fcf3ce44SJohn Forte 				S_FREE(dyncomp);
1760fcf3ce44SJohn Forte 				return (ret);
1761fcf3ce44SJohn Forte 			case FPCFGA_APID_NOACCESS:
1762fcf3ce44SJohn Forte 				switch (ostate) {
1763fcf3ce44SJohn Forte 				/* node is attached but not in dev list */
1764fcf3ce44SJohn Forte 				case CFGA_STAT_CONFIGURED:
1765fcf3ce44SJohn Forte 				case CFGA_STAT_NONE:
1766fcf3ce44SJohn Forte 					lap->chld_config = CFGA_STAT_CONFIGURED;
1767fcf3ce44SJohn Forte 					cond = CFGA_COND_FAILING;
1768fcf3ce44SJohn Forte 					break;
1769fcf3ce44SJohn Forte 				/*
1770fcf3ce44SJohn Forte 				 * node is offline or down.
1771fcf3ce44SJohn Forte 				 * set cond to unusable.
1772fcf3ce44SJohn Forte 				 */
1773fcf3ce44SJohn Forte 				case CFGA_STAT_UNCONFIGURED:
1774fcf3ce44SJohn Forte 					/*
1775fcf3ce44SJohn Forte 					 * For fabric port the fca port is
1776fcf3ce44SJohn Forte 					 * considered as configured since user
1777fcf3ce44SJohn Forte 					 * configured previously for any
1778fcf3ce44SJohn Forte 					 * existing node.
1779fcf3ce44SJohn Forte 					 */
1780fcf3ce44SJohn Forte 					cond = CFGA_COND_UNUSABLE;
1781fcf3ce44SJohn Forte 					if ((strcmp(lap->xport_type,
1782fcf3ce44SJohn Forte 						FP_FC_PUBLIC_PORT_TYPE) == 0) ||
1783fcf3ce44SJohn Forte 						(strcmp(lap->xport_type,
1784fcf3ce44SJohn Forte 						FP_FC_FABRIC_PORT_TYPE) == 0)) {
1785fcf3ce44SJohn Forte 						lap->chld_config =
1786fcf3ce44SJohn Forte 						CFGA_STAT_CONFIGURED;
1787fcf3ce44SJohn Forte 					} else {
1788fcf3ce44SJohn Forte 						lap->ret = FPCFGA_OK;
1789fcf3ce44SJohn Forte 						S_FREE(dyncomp);
1790fcf3ce44SJohn Forte 						return (FPCFGA_OK);
1791fcf3ce44SJohn Forte 					}
1792fcf3ce44SJohn Forte 					break;
1793fcf3ce44SJohn Forte 				default:
1794fcf3ce44SJohn Forte 				/*
1795fcf3ce44SJohn Forte 				 * continue to create ldata_list struct for
1796fcf3ce44SJohn Forte 				 * this node
1797fcf3ce44SJohn Forte 				 */
1798fcf3ce44SJohn Forte 					break;
1799fcf3ce44SJohn Forte 				}
1800fcf3ce44SJohn Forte 			default:
1801fcf3ce44SJohn Forte 				break;
1802fcf3ce44SJohn Forte 			}
1803fcf3ce44SJohn Forte 		} else {
1804fcf3ce44SJohn Forte 			/*
1805fcf3ce44SJohn Forte 			 * dev_list is null so there is no accessible dev.
1806fcf3ce44SJohn Forte 			 * set the cond and continue to create ldata.
1807fcf3ce44SJohn Forte 			 */
1808fcf3ce44SJohn Forte 			switch (ostate) {
1809fcf3ce44SJohn Forte 			case CFGA_STAT_CONFIGURED:
1810fcf3ce44SJohn Forte 			case CFGA_STAT_NONE:
1811fcf3ce44SJohn Forte 				cond = CFGA_COND_FAILING;
1812fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
1813fcf3ce44SJohn Forte 				break;
1814fcf3ce44SJohn Forte 			/*
1815fcf3ce44SJohn Forte 			 * node is offline or down.
1816fcf3ce44SJohn Forte 			 * set cond to unusable.
1817fcf3ce44SJohn Forte 			 */
1818fcf3ce44SJohn Forte 			case CFGA_STAT_UNCONFIGURED:
1819fcf3ce44SJohn Forte 				cond = CFGA_COND_UNUSABLE;
1820fcf3ce44SJohn Forte 				/*
1821fcf3ce44SJohn Forte 				 * For fabric port the fca port is
1822fcf3ce44SJohn Forte 				 * considered as configured since user
1823fcf3ce44SJohn Forte 				 * configured previously for any
1824fcf3ce44SJohn Forte 				 * existing node.
1825fcf3ce44SJohn Forte 				 */
1826fcf3ce44SJohn Forte 				if ((strcmp(lap->xport_type,
1827fcf3ce44SJohn Forte 					FP_FC_PUBLIC_PORT_TYPE) == 0) ||
1828fcf3ce44SJohn Forte 					(strcmp(lap->xport_type,
1829fcf3ce44SJohn Forte 					FP_FC_FABRIC_PORT_TYPE) == 0)) {
1830fcf3ce44SJohn Forte 					lap->chld_config =
1831fcf3ce44SJohn Forte 					CFGA_STAT_CONFIGURED;
1832fcf3ce44SJohn Forte 				} else {
1833fcf3ce44SJohn Forte 					lap->ret = FPCFGA_OK;
1834fcf3ce44SJohn Forte 					S_FREE(dyncomp);
1835fcf3ce44SJohn Forte 					return (FPCFGA_OK);
1836fcf3ce44SJohn Forte 				}
1837fcf3ce44SJohn Forte 				break;
1838fcf3ce44SJohn Forte 			default:
1839fcf3ce44SJohn Forte 				break;
1840fcf3ce44SJohn Forte 			}
1841fcf3ce44SJohn Forte 		}
1842fcf3ce44SJohn Forte 	}
1843fcf3ce44SJohn Forte 
1844fcf3ce44SJohn Forte 	listp = calloc(1, sizeof (ldata_list_t));
1845fcf3ce44SJohn Forte 	if (listp == NULL) {
1846fcf3ce44SJohn Forte 		lap->l_errno = errno;
1847fcf3ce44SJohn Forte 		S_FREE(dyncomp);
1848fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
1849fcf3ce44SJohn Forte 	}
1850fcf3ce44SJohn Forte 
1851fcf3ce44SJohn Forte 	clp = &listp->ldata;
1852fcf3ce44SJohn Forte 
1853fcf3ce44SJohn Forte 	/* Create the dynamic component. */
1854fcf3ce44SJohn Forte 	if (dyncomp == NULL) {
1855fcf3ce44SJohn Forte 		ret = make_dyncomp_from_dinode(node, &dyncomp, &l_errno);
1856fcf3ce44SJohn Forte 		if (ret != FPCFGA_OK) {
1857fcf3ce44SJohn Forte 			S_FREE(listp);
1858fcf3ce44SJohn Forte 			return (ret);
1859fcf3ce44SJohn Forte 		}
1860fcf3ce44SJohn Forte 	}
1861fcf3ce44SJohn Forte 
1862fcf3ce44SJohn Forte 	/* Create logical and physical ap_id */
1863fcf3ce44SJohn Forte 	(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s",
1864fcf3ce44SJohn Forte 	    lap->xport_logp, DYN_SEP, dyncomp);
1865fcf3ce44SJohn Forte 
1866fcf3ce44SJohn Forte 	(void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s",
1867fcf3ce44SJohn Forte 	    lap->apidp->xport_phys, DYN_SEP, dyncomp);
1868fcf3ce44SJohn Forte 
1869fcf3ce44SJohn Forte 	S_FREE(dyncomp);
1870fcf3ce44SJohn Forte 
1871fcf3ce44SJohn Forte 	clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */
1872fcf3ce44SJohn Forte 	clp->ap_r_state = lap->xport_rstate;
1873fcf3ce44SJohn Forte 	/* set to ostate to configured and set cond with info. */
1874fcf3ce44SJohn Forte 	clp->ap_o_state = CFGA_STAT_CONFIGURED;
1875fcf3ce44SJohn Forte 	clp->ap_cond = cond;
1876fcf3ce44SJohn Forte 	clp->ap_busy = busy;
1877fcf3ce44SJohn Forte 	clp->ap_status_time = (time_t)-1;
1878fcf3ce44SJohn Forte 
1879fcf3ce44SJohn Forte 	/* get ap_type and ap_info. */
1880fcf3ce44SJohn Forte 	get_hw_info(node, clp);
1881fcf3ce44SJohn Forte 
1882fcf3ce44SJohn Forte 	/* Link it in */
1883fcf3ce44SJohn Forte 	listp->next = lap->listp;
1884fcf3ce44SJohn Forte 	lap->listp = listp;
1885fcf3ce44SJohn Forte 
1886fcf3ce44SJohn Forte 	lap->ret = FPCFGA_OK;
1887fcf3ce44SJohn Forte 	return (FPCFGA_OK);
1888fcf3ce44SJohn Forte }
1889fcf3ce44SJohn Forte 
1890fcf3ce44SJohn Forte /*
1891fcf3ce44SJohn Forte  * Wrapper routine for handling path info.
1892fcf3ce44SJohn Forte  *
1893fcf3ce44SJohn Forte  * When show_FCP_dev option is given stat_path_info_FCP_dev() is called.
1894fcf3ce44SJohn Forte  * Otherwise stat_path_info_fc_dev() is called.
1895fcf3ce44SJohn Forte  */
1896fcf3ce44SJohn Forte int
stat_path_info_node(di_node_t root,void * arg,int * l_errnop)1897fcf3ce44SJohn Forte stat_path_info_node(
1898fcf3ce44SJohn Forte 	di_node_t 	root,
1899fcf3ce44SJohn Forte 	void 		*arg,
1900fcf3ce44SJohn Forte 	int 		*l_errnop)
1901fcf3ce44SJohn Forte {
1902fcf3ce44SJohn Forte 	fpcfga_list_t *lap = NULL;
1903fcf3ce44SJohn Forte 
1904fcf3ce44SJohn Forte 	lap = (fpcfga_list_t *)arg;
1905fcf3ce44SJohn Forte 	if ((lap->apidp->flags & (FLAG_FCP_DEV)) == FLAG_FCP_DEV) {
1906fcf3ce44SJohn Forte 		return (stat_path_info_FCP_dev(root, lap, l_errnop));
1907fcf3ce44SJohn Forte 	} else {
1908fcf3ce44SJohn Forte 		return (stat_path_info_fc_dev(root, lap, l_errnop));
1909fcf3ce44SJohn Forte 	}
1910fcf3ce44SJohn Forte }
1911fcf3ce44SJohn Forte 
1912fcf3ce44SJohn Forte /*
1913fcf3ce44SJohn Forte  * Routine for updating ldata list based on the state of path info node.
1914fcf3ce44SJohn Forte  * When no matching accessible ldata is found a new ldata is created
1915fcf3ce44SJohn Forte  * with proper state information.
1916fcf3ce44SJohn Forte  *
1917fcf3ce44SJohn Forte  * Overall algorithm:
1918fcf3ce44SJohn Forte  * If the path info node is not offline and the matching ldata is found
1919fcf3ce44SJohn Forte  * the target device is updated with configued and unknown condition.
1920fcf3ce44SJohn Forte  * If the path info node is offline or failed and the matching ldata is found
1921fcf3ce44SJohn Forte  * the target device is updated with configued and unusable condition.
1922fcf3ce44SJohn Forte  * If the path info node is online but the matching ldata is not found
1923fcf3ce44SJohn Forte  * the target device is created with configued and failing condition.
1924fcf3ce44SJohn Forte  * If the path info is offline or failed and the matching ldata is not found
1925fcf3ce44SJohn Forte  * the target device is created with configued and unusable condition.
1926fcf3ce44SJohn Forte  */
1927fcf3ce44SJohn Forte static int
stat_path_info_fc_dev(di_node_t root,fpcfga_list_t * lap,int * l_errnop)1928fcf3ce44SJohn Forte stat_path_info_fc_dev(
1929fcf3ce44SJohn Forte 	di_node_t 	root,
1930fcf3ce44SJohn Forte 	fpcfga_list_t	*lap,
1931fcf3ce44SJohn Forte 	int 		*l_errnop)
1932fcf3ce44SJohn Forte {
1933fcf3ce44SJohn Forte 	ldata_list_t *matchldp = NULL;
1934fcf3ce44SJohn Forte 	di_path_t path = DI_PATH_NIL;
1935fcf3ce44SJohn Forte 	uchar_t		*port_wwn_data;
1936fcf3ce44SJohn Forte 	char		port_wwn[WWN_SIZE*2+1];
1937fcf3ce44SJohn Forte 	int		count;
1938fcf3ce44SJohn Forte 	fpcfga_ret_t 	ret;
1939fcf3ce44SJohn Forte 	di_path_state_t	pstate;
1940fcf3ce44SJohn Forte 
1941fcf3ce44SJohn Forte 	if (root == DI_NODE_NIL) {
1942fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
1943fcf3ce44SJohn Forte 	}
1944fcf3ce44SJohn Forte 
1945fcf3ce44SJohn Forte 	/*
1946fcf3ce44SJohn Forte 	 * if stat on a specific dev and walk_node found it okay
1947fcf3ce44SJohn Forte 	 * then just return ok.
1948fcf3ce44SJohn Forte 	 */
1949fcf3ce44SJohn Forte 	if ((lap->cmd == FPCFGA_STAT_FC_DEV) && (lap->ret == FPCFGA_OK)) {
1950fcf3ce44SJohn Forte 		return (FPCFGA_OK);
1951fcf3ce44SJohn Forte 	}
1952fcf3ce44SJohn Forte 
1953fcf3ce44SJohn Forte 	/*
1954fcf3ce44SJohn Forte 	 * if stat on a fca xport and chld_config is set
1955fcf3ce44SJohn Forte 	 * then just return ok.
1956fcf3ce44SJohn Forte 	 */
1957fcf3ce44SJohn Forte 	if ((lap->cmd == FPCFGA_STAT_FCA_PORT) &&
1958fcf3ce44SJohn Forte 				(lap->chld_config == CFGA_STAT_CONFIGURED)) {
1959fcf3ce44SJohn Forte 		return (FPCFGA_OK);
1960fcf3ce44SJohn Forte 	}
1961fcf3ce44SJohn Forte 
1962fcf3ce44SJohn Forte 	/*
1963fcf3ce44SJohn Forte 	 * when there is no path_info node return FPCFGA_OK.
1964fcf3ce44SJohn Forte 	 * That way the result from walk_node shall be maintained.
1965fcf3ce44SJohn Forte 	 */
1966fcf3ce44SJohn Forte 	if ((path = di_path_next_client(root, path)) == DI_PATH_NIL) {
1967fcf3ce44SJohn Forte 		/*
1968fcf3ce44SJohn Forte 		 * if the dev was in dev list but not found
1969fcf3ce44SJohn Forte 		 * return OK to indicate is not configured.
1970fcf3ce44SJohn Forte 		 */
1971fcf3ce44SJohn Forte 		if (lap->ret == FPCFGA_ACCESS_OK) {
1972fcf3ce44SJohn Forte 			lap->ret = FPCFGA_OK;
1973fcf3ce44SJohn Forte 		}
1974fcf3ce44SJohn Forte 		return (FPCFGA_OK);
1975fcf3ce44SJohn Forte 	}
1976fcf3ce44SJohn Forte 
1977fcf3ce44SJohn Forte 	/* if stat on fca port return. */
1978fcf3ce44SJohn Forte 	if (lap->cmd == FPCFGA_STAT_FCA_PORT) {
1979fcf3ce44SJohn Forte 		if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) ||
1980fcf3ce44SJohn Forte 			strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) {
1981fcf3ce44SJohn Forte 			lap->chld_config = CFGA_STAT_CONFIGURED;
1982fcf3ce44SJohn Forte 			return (FPCFGA_OK);
1983fcf3ce44SJohn Forte 		} else {
1984fcf3ce44SJohn Forte 			if ((pstate = di_path_state(path)) !=
1985fcf3ce44SJohn Forte 				DI_PATH_STATE_OFFLINE) {
1986fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
1987fcf3ce44SJohn Forte 				return (FPCFGA_OK);
1988fcf3ce44SJohn Forte 			}
1989fcf3ce44SJohn Forte 		}
1990fcf3ce44SJohn Forte 	}
1991fcf3ce44SJohn Forte 	/*
1992fcf3ce44SJohn Forte 	 * now parse the path info node.
1993fcf3ce44SJohn Forte 	 */
1994fcf3ce44SJohn Forte 	do {
1995fcf3ce44SJohn Forte 		count = di_path_prop_lookup_bytes(path, PORT_WWN_PROP,
1996fcf3ce44SJohn Forte 			&port_wwn_data);
1997fcf3ce44SJohn Forte 		if (count != WWN_SIZE) {
1998fcf3ce44SJohn Forte 			ret = FPCFGA_LIB_ERR;
1999fcf3ce44SJohn Forte 			break;
2000fcf3ce44SJohn Forte 		}
2001fcf3ce44SJohn Forte 
2002fcf3ce44SJohn Forte 		(void) sprintf(port_wwn, "%016llx",
2003fcf3ce44SJohn Forte 			(wwnConversion(port_wwn_data)));
2004fcf3ce44SJohn Forte 		switch (lap->cmd) {
2005fcf3ce44SJohn Forte 		case FPCFGA_STAT_FC_DEV:
2006fcf3ce44SJohn Forte 			/* if no match contine to the next path info node. */
2007fcf3ce44SJohn Forte 			if (strncmp(port_wwn, lap->apidp->dyncomp,
2008fcf3ce44SJohn Forte 					WWN_SIZE*2)) {
2009fcf3ce44SJohn Forte 				break;
2010fcf3ce44SJohn Forte 			}
2011fcf3ce44SJohn Forte 			/* if device in dev_list, ldata already created. */
2012fcf3ce44SJohn Forte 			if (lap->ret == FPCFGA_ACCESS_OK) {
2013fcf3ce44SJohn Forte 				lap->listp->ldata.ap_o_state =
2014fcf3ce44SJohn Forte 					CFGA_STAT_CONFIGURED;
2015fcf3ce44SJohn Forte 				if (((pstate = di_path_state(path)) ==
2016fcf3ce44SJohn Forte 					DI_PATH_STATE_OFFLINE) ||
2017fcf3ce44SJohn Forte 					(pstate == DI_PATH_STATE_FAULT)) {
2018fcf3ce44SJohn Forte 					lap->listp->ldata.ap_cond =
2019fcf3ce44SJohn Forte 							CFGA_COND_UNUSABLE;
2020fcf3ce44SJohn Forte 				}
2021fcf3ce44SJohn Forte 				lap->ret = FPCFGA_OK;
2022fcf3ce44SJohn Forte 				return (FPCFGA_OK);
2023fcf3ce44SJohn Forte 			} else {
2024fcf3ce44SJohn Forte 				if ((strcmp(lap->xport_type,
2025fcf3ce44SJohn Forte 					FP_FC_PUBLIC_PORT_TYPE) == 0) ||
2026fcf3ce44SJohn Forte 					(strcmp(lap->xport_type,
2027fcf3ce44SJohn Forte 					FP_FC_FABRIC_PORT_TYPE) == 0)) {
2028fcf3ce44SJohn Forte 					lap->chld_config = CFGA_STAT_CONFIGURED;
2029fcf3ce44SJohn Forte 					return (init_ldata_for_mpath_dev(
2030fcf3ce44SJohn Forte 						path, port_wwn, l_errnop, lap));
2031fcf3ce44SJohn Forte 				} else {
2032fcf3ce44SJohn Forte 					if ((di_path_state(path)) !=
2033fcf3ce44SJohn Forte 						DI_PATH_STATE_OFFLINE) {
2034fcf3ce44SJohn Forte 					    return (init_ldata_for_mpath_dev(
2035fcf3ce44SJohn Forte 						path, port_wwn, l_errnop, lap));
2036fcf3ce44SJohn Forte 					} else {
2037fcf3ce44SJohn Forte 					    lap->ret = FPCFGA_APID_NOEXIST;
2038fcf3ce44SJohn Forte 					    return (FPCFGA_OK);
2039fcf3ce44SJohn Forte 					}
2040fcf3ce44SJohn Forte 				}
2041fcf3ce44SJohn Forte 			}
2042fcf3ce44SJohn Forte 		case FPCFGA_STAT_ALL:
2043fcf3ce44SJohn Forte 			/* check if there is list data. */
2044fcf3ce44SJohn Forte 			if (lap->listp != NULL) {
2045fcf3ce44SJohn Forte 				ret = is_dyn_ap_on_ldata_list(port_wwn,
2046fcf3ce44SJohn Forte 					lap->listp, &matchldp, l_errnop);
2047fcf3ce44SJohn Forte 				if (ret == FPCFGA_ACCESS_OK) {
2048fcf3ce44SJohn Forte 					lap->chld_config = CFGA_STAT_CONFIGURED;
2049fcf3ce44SJohn Forte 					matchldp->ldata.ap_o_state =
2050fcf3ce44SJohn Forte 							CFGA_STAT_CONFIGURED;
2051fcf3ce44SJohn Forte 					/*
2052fcf3ce44SJohn Forte 					 * Update the condition as unusable
2053fcf3ce44SJohn Forte 					 * if the pathinfo state is failed
2054fcf3ce44SJohn Forte 					 * or offline.
2055fcf3ce44SJohn Forte 					 */
2056fcf3ce44SJohn Forte 					if (((pstate = di_path_state(path)) ==
2057fcf3ce44SJohn Forte 						DI_PATH_STATE_OFFLINE) ||
2058fcf3ce44SJohn Forte 						(pstate ==
2059fcf3ce44SJohn Forte 							DI_PATH_STATE_FAULT)) {
2060fcf3ce44SJohn Forte 						matchldp->ldata.ap_cond =
2061fcf3ce44SJohn Forte 							CFGA_COND_UNUSABLE;
2062fcf3ce44SJohn Forte 					}
2063fcf3ce44SJohn Forte 					break;
2064fcf3ce44SJohn Forte 				} else if (ret == FPCFGA_LIB_ERR) {
2065fcf3ce44SJohn Forte 					lap->l_errno = *l_errnop;
2066fcf3ce44SJohn Forte 					return (ret);
2067fcf3ce44SJohn Forte 				}
2068fcf3ce44SJohn Forte 			}
2069fcf3ce44SJohn Forte 			/*
2070fcf3ce44SJohn Forte 			 * now create ldata for this particular path info node.
2071fcf3ce44SJohn Forte 			 * if port top is private loop and pathinfo is in
2072fcf3ce44SJohn Forte 			 * in offline state don't include to ldata list.
2073fcf3ce44SJohn Forte 			 */
2074fcf3ce44SJohn Forte 			if (((strcmp(lap->xport_type,
2075fcf3ce44SJohn Forte 				FP_FC_PUBLIC_PORT_TYPE) == 0) ||
2076fcf3ce44SJohn Forte 				(strcmp(lap->xport_type,
2077fcf3ce44SJohn Forte 					FP_FC_FABRIC_PORT_TYPE) == 0)) ||
2078fcf3ce44SJohn Forte 				(di_path_state(path) !=
2079fcf3ce44SJohn Forte 					DI_PATH_STATE_OFFLINE)) {
2080fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
2081fcf3ce44SJohn Forte 				ret = init_ldata_for_mpath_dev(
2082fcf3ce44SJohn Forte 					path, port_wwn, l_errnop, lap);
2083fcf3ce44SJohn Forte 				if (ret != FPCFGA_OK) {
2084fcf3ce44SJohn Forte 					return (ret);
2085fcf3ce44SJohn Forte 				}
2086fcf3ce44SJohn Forte 			}
2087fcf3ce44SJohn Forte 			break;
2088fcf3ce44SJohn Forte 		case FPCFGA_STAT_FCA_PORT:
2089fcf3ce44SJohn Forte 			if (di_path_state(path) != DI_PATH_STATE_OFFLINE) {
2090fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
2091fcf3ce44SJohn Forte 				return (FPCFGA_OK);
2092fcf3ce44SJohn Forte 			}
2093fcf3ce44SJohn Forte 		}
2094fcf3ce44SJohn Forte 		path = di_path_next_client(root, path);
2095fcf3ce44SJohn Forte 	} while (path != DI_PATH_NIL);
2096fcf3ce44SJohn Forte 
2097fcf3ce44SJohn Forte 	return (FPCFGA_OK);
2098fcf3ce44SJohn Forte 
2099fcf3ce44SJohn Forte }
2100fcf3ce44SJohn Forte 
2101fcf3ce44SJohn Forte /*
2102fcf3ce44SJohn Forte  * Routine for updating ldata list based on the state of path info node.
2103fcf3ce44SJohn Forte  * When no matching accessible ldata is found a new ldata is created
2104fcf3ce44SJohn Forte  * with proper state information.
2105fcf3ce44SJohn Forte  *
2106fcf3ce44SJohn Forte  * The difference from stat_path_info_fc_dev() is
2107fcf3ce44SJohn Forte  * to handle FCP SCSI LUN information. Otherwise overall algorithm is
2108fcf3ce44SJohn Forte  * same.
2109fcf3ce44SJohn Forte  *
2110fcf3ce44SJohn Forte  * Overall algorithm:
2111fcf3ce44SJohn Forte  * If the path info node is not offline and the matching ldata is found
2112fcf3ce44SJohn Forte  * the target device is updated with configued and unknown condition.
2113fcf3ce44SJohn Forte  * If the path info node is offline or failed and the matching ldata is found
2114fcf3ce44SJohn Forte  * the target device is updated with configued and unusable condition.
2115fcf3ce44SJohn Forte  * If the path info node is online but the matching ldata is not found
2116fcf3ce44SJohn Forte  * the target device is created with configued and failing condition.
2117fcf3ce44SJohn Forte  * If the path info is offline or failed and the matching ldata is not found
2118fcf3ce44SJohn Forte  * the target device is created with configued and unusable condition.
2119fcf3ce44SJohn Forte  */
2120fcf3ce44SJohn Forte static int
stat_path_info_FCP_dev(di_node_t root,fpcfga_list_t * lap,int * l_errnop)2121fcf3ce44SJohn Forte stat_path_info_FCP_dev(
2122fcf3ce44SJohn Forte 	di_node_t 	root,
2123fcf3ce44SJohn Forte 	fpcfga_list_t	*lap,
2124fcf3ce44SJohn Forte 	int 		*l_errnop)
2125fcf3ce44SJohn Forte {
2126fcf3ce44SJohn Forte 	ldata_list_t	*matchldp = NULL, *listp = NULL;
2127fcf3ce44SJohn Forte 	cfga_list_data_t	*clp;
2128fcf3ce44SJohn Forte 	di_path_t	path = DI_PATH_NIL;
2129fcf3ce44SJohn Forte 	di_node_t	client_node = DI_NODE_NIL;
2130fcf3ce44SJohn Forte 	char		*port_wwn = NULL, *nodepath = NULL;
2131fcf3ce44SJohn Forte 	int		*lun_nump;
2132fcf3ce44SJohn Forte 	fpcfga_ret_t 	ldata_ret;
2133fcf3ce44SJohn Forte 	di_path_state_t	pstate;
2134fcf3ce44SJohn Forte 	cfga_busy_t	busy;
2135fcf3ce44SJohn Forte 	uint_t		dctl_state = 0;
2136fcf3ce44SJohn Forte 
2137fcf3ce44SJohn Forte 	if (root == DI_NODE_NIL) {
2138fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
2139fcf3ce44SJohn Forte 	}
2140fcf3ce44SJohn Forte 
2141fcf3ce44SJohn Forte 	/*
2142fcf3ce44SJohn Forte 	 * if stat on a fca xport and chld_config is set
2143fcf3ce44SJohn Forte 	 * then just return ok.
2144fcf3ce44SJohn Forte 	 */
2145fcf3ce44SJohn Forte 	if ((lap->cmd == FPCFGA_STAT_FCA_PORT) &&
2146fcf3ce44SJohn Forte 				(lap->chld_config == CFGA_STAT_CONFIGURED)) {
2147fcf3ce44SJohn Forte 		return (FPCFGA_OK);
2148fcf3ce44SJohn Forte 	}
2149fcf3ce44SJohn Forte 	/*
2150fcf3ce44SJohn Forte 	 * when there is no path_info node return FPCFGA_OK.
2151fcf3ce44SJohn Forte 	 * That way the result from walk_node shall be maintained.
2152fcf3ce44SJohn Forte 	 */
2153fcf3ce44SJohn Forte 	if ((path = di_path_next_client(root, path)) == DI_PATH_NIL) {
2154fcf3ce44SJohn Forte 		/*
2155fcf3ce44SJohn Forte 		 * if the dev was in dev list but not found
2156fcf3ce44SJohn Forte 		 * return ok.
2157fcf3ce44SJohn Forte 		 */
2158fcf3ce44SJohn Forte 		if (lap->ret == FPCFGA_ACCESS_OK) {
2159fcf3ce44SJohn Forte 			lap->ret = FPCFGA_OK;
2160fcf3ce44SJohn Forte 		}
2161fcf3ce44SJohn Forte 		return (FPCFGA_OK);
2162fcf3ce44SJohn Forte 	}
2163fcf3ce44SJohn Forte 	/*
2164fcf3ce44SJohn Forte 	 * If stat on fca port and port topology is fabric return here.
2165fcf3ce44SJohn Forte 	 * If not fabric return only when path state is not offfline.
2166fcf3ce44SJohn Forte 	 * The other cases are handbled below.
2167fcf3ce44SJohn Forte 	 */
2168fcf3ce44SJohn Forte 	if (lap->cmd == FPCFGA_STAT_FCA_PORT) {
2169fcf3ce44SJohn Forte 		if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) ||
2170fcf3ce44SJohn Forte 			strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) {
2171fcf3ce44SJohn Forte 			lap->chld_config = CFGA_STAT_CONFIGURED;
2172fcf3ce44SJohn Forte 			return (FPCFGA_OK);
2173fcf3ce44SJohn Forte 		} else {
2174fcf3ce44SJohn Forte 			if ((pstate = di_path_state(path)) !=
2175fcf3ce44SJohn Forte 				DI_PATH_STATE_OFFLINE) {
2176fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
2177fcf3ce44SJohn Forte 				return (FPCFGA_OK);
2178fcf3ce44SJohn Forte 			}
2179fcf3ce44SJohn Forte 		}
2180fcf3ce44SJohn Forte 	}
2181fcf3ce44SJohn Forte 	/*
2182fcf3ce44SJohn Forte 	 * now parse the path info node.
2183fcf3ce44SJohn Forte 	 */
2184fcf3ce44SJohn Forte 	do {
2185fcf3ce44SJohn Forte 		switch (lap->cmd) {
2186fcf3ce44SJohn Forte 		case FPCFGA_STAT_FC_DEV:
2187fcf3ce44SJohn Forte 			if ((make_portwwn_luncomp_from_pinode(path, &port_wwn,
2188fcf3ce44SJohn Forte 				&lun_nump, l_errnop)) != FPCFGA_OK) {
2189fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
2190fcf3ce44SJohn Forte 			}
2191fcf3ce44SJohn Forte 
2192fcf3ce44SJohn Forte 			if ((ldata_ret = is_FCP_dev_ap_on_ldata_list(port_wwn,
2193fcf3ce44SJohn Forte 				*lun_nump, lap->listp, &matchldp))
2194fcf3ce44SJohn Forte 				== FPCFGA_LIB_ERR) {
2195fcf3ce44SJohn Forte 				S_FREE(port_wwn);
2196fcf3ce44SJohn Forte 				return (ldata_ret);
2197fcf3ce44SJohn Forte 			}
2198fcf3ce44SJohn Forte 
2199fcf3ce44SJohn Forte 			if (ldata_ret == FPCFGA_ACCESS_OK) {
2200fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
2201fcf3ce44SJohn Forte 				matchldp->ldata.ap_o_state =
2202fcf3ce44SJohn Forte 						CFGA_STAT_CONFIGURED;
2203fcf3ce44SJohn Forte 				/*
2204fcf3ce44SJohn Forte 				 * Update the condition as unusable
2205fcf3ce44SJohn Forte 				 * if the pathinfo state is failed
2206fcf3ce44SJohn Forte 				 * or offline.
2207fcf3ce44SJohn Forte 				 */
2208fcf3ce44SJohn Forte 				if (((pstate = di_path_state(path)) ==
2209fcf3ce44SJohn Forte 					DI_PATH_STATE_OFFLINE) ||
2210fcf3ce44SJohn Forte 					(pstate == DI_PATH_STATE_FAULT)) {
2211fcf3ce44SJohn Forte 					matchldp->ldata.ap_cond =
2212fcf3ce44SJohn Forte 							CFGA_COND_UNUSABLE;
2213fcf3ce44SJohn Forte 				}
2214fcf3ce44SJohn Forte 				lap->ret = FPCFGA_OK;
2215fcf3ce44SJohn Forte 				break;
2216fcf3ce44SJohn Forte 			}
2217fcf3ce44SJohn Forte 
2218fcf3ce44SJohn Forte 			if (strncmp(port_wwn, lap->apidp->dyncomp, WWN_SIZE*2)
2219fcf3ce44SJohn Forte 					!= 0) {
2220fcf3ce44SJohn Forte 				break;
2221fcf3ce44SJohn Forte 			}
2222fcf3ce44SJohn Forte 			/*
2223fcf3ce44SJohn Forte 			 * now create ldata for this particular path info node.
2224fcf3ce44SJohn Forte 			 * if port top is private loop and pathinfo is in
2225fcf3ce44SJohn Forte 			 * in offline state don't include to ldata list.
2226fcf3ce44SJohn Forte 			 */
2227fcf3ce44SJohn Forte 			if (((strcmp(lap->xport_type,
2228fcf3ce44SJohn Forte 				FP_FC_PUBLIC_PORT_TYPE) == 0) ||
2229fcf3ce44SJohn Forte 				(strcmp(lap->xport_type,
2230fcf3ce44SJohn Forte 					FP_FC_FABRIC_PORT_TYPE) == 0)) ||
2231fcf3ce44SJohn Forte 				(di_path_state(path) !=
2232fcf3ce44SJohn Forte 					DI_PATH_STATE_OFFLINE)) {
2233fcf3ce44SJohn Forte 			    lap->chld_config = CFGA_STAT_CONFIGURED;
2234fcf3ce44SJohn Forte 				/* create ldata for this pi node. */
2235fcf3ce44SJohn Forte 			    client_node = di_path_client_node(path);
2236fcf3ce44SJohn Forte 			    if (client_node == DI_NODE_NIL) {
2237fcf3ce44SJohn Forte 				*l_errnop = errno;
2238fcf3ce44SJohn Forte 				S_FREE(port_wwn);
2239fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
2240fcf3ce44SJohn Forte 			    }
2241fcf3ce44SJohn Forte 			    if ((construct_nodepath_from_dinode(
2242fcf3ce44SJohn Forte 				client_node, &nodepath, l_errnop))
2243fcf3ce44SJohn Forte 					!= FPCFGA_OK) {
2244fcf3ce44SJohn Forte 				S_FREE(port_wwn);
2245fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
2246fcf3ce44SJohn Forte 			    }
2247fcf3ce44SJohn Forte 
2248fcf3ce44SJohn Forte 			    listp = calloc(1, sizeof (ldata_list_t));
2249fcf3ce44SJohn Forte 			    if (listp == NULL) {
2250fcf3ce44SJohn Forte 				S_FREE(port_wwn);
2251fcf3ce44SJohn Forte 				S_FREE(nodepath);
2252fcf3ce44SJohn Forte 				lap->l_errno = errno;
2253fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
2254fcf3ce44SJohn Forte 			    }
2255fcf3ce44SJohn Forte 
2256fcf3ce44SJohn Forte 			    clp = &listp->ldata;
2257fcf3ce44SJohn Forte 
2258fcf3ce44SJohn Forte 			    /* Create logical and physical ap_id */
2259fcf3ce44SJohn Forte 			    (void) snprintf(clp->ap_log_id,
2260fcf3ce44SJohn Forte 				sizeof (clp->ap_log_id), "%s%s%s%s%d",
2261fcf3ce44SJohn Forte 				lap->xport_logp, DYN_SEP, port_wwn,
2262fcf3ce44SJohn Forte 				LUN_COMP_SEP, *lun_nump);
2263fcf3ce44SJohn Forte 			    (void) snprintf(clp->ap_phys_id,
2264fcf3ce44SJohn Forte 				sizeof (clp->ap_phys_id), "%s%s%s%s%d",
2265fcf3ce44SJohn Forte 				lap->apidp->xport_phys, DYN_SEP, port_wwn,
2266fcf3ce44SJohn Forte 				LUN_COMP_SEP, *lun_nump);
2267fcf3ce44SJohn Forte 				/*
2268fcf3ce44SJohn Forte 				 * We reached here since FCP dev is not found
2269fcf3ce44SJohn Forte 				 * in ldata list but path info node exists.
2270fcf3ce44SJohn Forte 				 *
2271fcf3ce44SJohn Forte 				 * Update the condition as failing
2272fcf3ce44SJohn Forte 				 * if the pathinfo state was normal.
2273fcf3ce44SJohn Forte 				 * Update the condition as unusable
2274fcf3ce44SJohn Forte 				 * if the pathinfo state is failed
2275fcf3ce44SJohn Forte 				 * or offline.
2276fcf3ce44SJohn Forte 				 */
2277fcf3ce44SJohn Forte 			    clp->ap_class[0] = '\0'; /* Filled by libcfgadm */
2278fcf3ce44SJohn Forte 			    clp->ap_o_state = CFGA_STAT_CONFIGURED;
2279fcf3ce44SJohn Forte 			    if (((pstate = di_path_state(path))
2280fcf3ce44SJohn Forte 					== DI_PATH_STATE_OFFLINE) ||
2281fcf3ce44SJohn Forte 				(pstate == DI_PATH_STATE_FAULT)) {
2282fcf3ce44SJohn Forte 				clp->ap_cond = CFGA_COND_UNUSABLE;
2283fcf3ce44SJohn Forte 			    } else {
2284fcf3ce44SJohn Forte 				clp->ap_cond = CFGA_COND_FAILING;
2285fcf3ce44SJohn Forte 			    }
2286fcf3ce44SJohn Forte 			    clp->ap_r_state = lap->xport_rstate;
2287fcf3ce44SJohn Forte 			    clp->ap_info[0] = '\0';
2288fcf3ce44SJohn Forte 				/* update ap_type and ap_info */
2289fcf3ce44SJohn Forte 			    get_hw_info(client_node, clp);
2290fcf3ce44SJohn Forte 			    if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE,
2291fcf3ce44SJohn Forte 				&dctl_state, l_errnop) == FPCFGA_OK) {
2292fcf3ce44SJohn Forte 				busy = ((dctl_state & DEVICE_BUSY)
2293fcf3ce44SJohn Forte 					== DEVICE_BUSY) ? 1 : 0;
2294fcf3ce44SJohn Forte 			    } else {
2295fcf3ce44SJohn Forte 				busy = 0;
2296fcf3ce44SJohn Forte 			    }
2297fcf3ce44SJohn Forte 			    clp->ap_busy = busy;
2298fcf3ce44SJohn Forte 			    clp->ap_status_time = (time_t)-1;
2299fcf3ce44SJohn Forte 
2300fcf3ce44SJohn Forte 			    (void) insert_ldata_to_ldatalist(port_wwn,
2301fcf3ce44SJohn Forte 				lun_nump, listp, &(lap->listp));
2302fcf3ce44SJohn Forte 			}
2303fcf3ce44SJohn Forte 			break;
2304fcf3ce44SJohn Forte 		case FPCFGA_STAT_ALL:
2305fcf3ce44SJohn Forte 			if ((make_portwwn_luncomp_from_pinode(path, &port_wwn,
2306fcf3ce44SJohn Forte 				&lun_nump, l_errnop)) != FPCFGA_OK) {
2307fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
2308fcf3ce44SJohn Forte 			}
2309fcf3ce44SJohn Forte 
2310fcf3ce44SJohn Forte 			if ((ldata_ret = is_FCP_dev_ap_on_ldata_list(port_wwn,
2311fcf3ce44SJohn Forte 				*lun_nump, lap->listp, &matchldp))
2312fcf3ce44SJohn Forte 				== FPCFGA_LIB_ERR) {
2313fcf3ce44SJohn Forte 				S_FREE(port_wwn);
2314fcf3ce44SJohn Forte 				return (ldata_ret);
2315fcf3ce44SJohn Forte 			}
2316fcf3ce44SJohn Forte 
2317fcf3ce44SJohn Forte 			if (ldata_ret == FPCFGA_ACCESS_OK) {
2318fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
2319fcf3ce44SJohn Forte 				matchldp->ldata.ap_o_state =
2320fcf3ce44SJohn Forte 						CFGA_STAT_CONFIGURED;
2321fcf3ce44SJohn Forte 				/*
2322fcf3ce44SJohn Forte 				 * Update the condition as unusable
2323fcf3ce44SJohn Forte 				 * if the pathinfo state is failed
2324fcf3ce44SJohn Forte 				 * or offline.
2325fcf3ce44SJohn Forte 				 */
2326fcf3ce44SJohn Forte 				if (((pstate = di_path_state(path)) ==
2327fcf3ce44SJohn Forte 					DI_PATH_STATE_OFFLINE) ||
2328fcf3ce44SJohn Forte 					(pstate == DI_PATH_STATE_FAULT)) {
2329fcf3ce44SJohn Forte 					matchldp->ldata.ap_cond =
2330fcf3ce44SJohn Forte 							CFGA_COND_UNUSABLE;
2331fcf3ce44SJohn Forte 				}
2332fcf3ce44SJohn Forte 				break;
2333fcf3ce44SJohn Forte 			}
2334fcf3ce44SJohn Forte 			/*
2335fcf3ce44SJohn Forte 			 * now create ldata for this particular path info node.
2336fcf3ce44SJohn Forte 			 * if port top is private loop and pathinfo is in
2337fcf3ce44SJohn Forte 			 * in offline state don't include to ldata list.
2338fcf3ce44SJohn Forte 			 */
2339fcf3ce44SJohn Forte 			if (((strcmp(lap->xport_type,
2340fcf3ce44SJohn Forte 				FP_FC_PUBLIC_PORT_TYPE) == 0) ||
2341fcf3ce44SJohn Forte 				(strcmp(lap->xport_type,
2342fcf3ce44SJohn Forte 					FP_FC_FABRIC_PORT_TYPE) == 0)) ||
2343fcf3ce44SJohn Forte 				(di_path_state(path) !=
2344fcf3ce44SJohn Forte 					DI_PATH_STATE_OFFLINE)) {
2345fcf3ce44SJohn Forte 			    lap->chld_config = CFGA_STAT_CONFIGURED;
2346fcf3ce44SJohn Forte 				/* create ldata for this pi node. */
2347fcf3ce44SJohn Forte 			    client_node = di_path_client_node(path);
2348fcf3ce44SJohn Forte 			    if (client_node == DI_NODE_NIL) {
2349fcf3ce44SJohn Forte 				*l_errnop = errno;
2350fcf3ce44SJohn Forte 				S_FREE(port_wwn);
2351fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
2352fcf3ce44SJohn Forte 			    }
2353fcf3ce44SJohn Forte 			    if ((construct_nodepath_from_dinode(
2354fcf3ce44SJohn Forte 				client_node, &nodepath, l_errnop))
2355fcf3ce44SJohn Forte 					!= FPCFGA_OK) {
2356fcf3ce44SJohn Forte 				S_FREE(port_wwn);
2357fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
2358fcf3ce44SJohn Forte 			    }
2359fcf3ce44SJohn Forte 
2360fcf3ce44SJohn Forte 			    listp = calloc(1, sizeof (ldata_list_t));
2361fcf3ce44SJohn Forte 			    if (listp == NULL) {
2362fcf3ce44SJohn Forte 				S_FREE(port_wwn);
2363fcf3ce44SJohn Forte 				S_FREE(nodepath);
2364fcf3ce44SJohn Forte 				lap->l_errno = errno;
2365fcf3ce44SJohn Forte 				return (FPCFGA_LIB_ERR);
2366fcf3ce44SJohn Forte 			    }
2367fcf3ce44SJohn Forte 
2368fcf3ce44SJohn Forte 			    clp = &listp->ldata;
2369fcf3ce44SJohn Forte 
2370fcf3ce44SJohn Forte 			    /* Create logical and physical ap_id */
2371fcf3ce44SJohn Forte 			    (void) snprintf(clp->ap_log_id,
2372fcf3ce44SJohn Forte 				sizeof (clp->ap_log_id), "%s%s%s%s%d",
2373fcf3ce44SJohn Forte 				lap->xport_logp, DYN_SEP, port_wwn,
2374fcf3ce44SJohn Forte 				LUN_COMP_SEP, *lun_nump);
2375fcf3ce44SJohn Forte 			    (void) snprintf(clp->ap_phys_id,
2376fcf3ce44SJohn Forte 				sizeof (clp->ap_phys_id), "%s%s%s%s%d",
2377fcf3ce44SJohn Forte 				lap->apidp->xport_phys, DYN_SEP, port_wwn,
2378fcf3ce44SJohn Forte 				LUN_COMP_SEP, *lun_nump);
2379fcf3ce44SJohn Forte 				/*
2380fcf3ce44SJohn Forte 				 * We reached here since FCP dev is not found
2381fcf3ce44SJohn Forte 				 * in ldata list but path info node exists.
2382fcf3ce44SJohn Forte 				 *
2383fcf3ce44SJohn Forte 				 * Update the condition as failing
2384fcf3ce44SJohn Forte 				 * if the pathinfo state was normal.
2385fcf3ce44SJohn Forte 				 * Update the condition as unusable
2386fcf3ce44SJohn Forte 				 * if the pathinfo state is failed
2387fcf3ce44SJohn Forte 				 * or offline.
2388fcf3ce44SJohn Forte 				 */
2389fcf3ce44SJohn Forte 			    clp->ap_class[0] = '\0'; /* Filled by libcfgadm */
2390fcf3ce44SJohn Forte 			    clp->ap_o_state = CFGA_STAT_CONFIGURED;
2391fcf3ce44SJohn Forte 			    if (((pstate = di_path_state(path))
2392fcf3ce44SJohn Forte 					== DI_PATH_STATE_OFFLINE) ||
2393fcf3ce44SJohn Forte 				(pstate == DI_PATH_STATE_FAULT)) {
2394fcf3ce44SJohn Forte 				clp->ap_cond = CFGA_COND_UNUSABLE;
2395fcf3ce44SJohn Forte 			    } else {
2396fcf3ce44SJohn Forte 				clp->ap_cond = CFGA_COND_FAILING;
2397fcf3ce44SJohn Forte 			    }
2398fcf3ce44SJohn Forte 			    clp->ap_r_state = lap->xport_rstate;
2399fcf3ce44SJohn Forte 			    clp->ap_info[0] = '\0';
2400fcf3ce44SJohn Forte 				/* update ap_type and ap_info */
2401fcf3ce44SJohn Forte 			    get_hw_info(client_node, clp);
2402fcf3ce44SJohn Forte 			    if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE,
2403fcf3ce44SJohn Forte 				&dctl_state, l_errnop) == FPCFGA_OK) {
2404fcf3ce44SJohn Forte 				busy = ((dctl_state & DEVICE_BUSY)
2405fcf3ce44SJohn Forte 					== DEVICE_BUSY) ? 1 : 0;
2406fcf3ce44SJohn Forte 			    } else {
2407fcf3ce44SJohn Forte 				busy = 0;
2408fcf3ce44SJohn Forte 			    }
2409fcf3ce44SJohn Forte 			    clp->ap_busy = busy;
2410fcf3ce44SJohn Forte 			    clp->ap_status_time = (time_t)-1;
2411fcf3ce44SJohn Forte 
2412fcf3ce44SJohn Forte 			    (void) insert_ldata_to_ldatalist(port_wwn,
2413fcf3ce44SJohn Forte 				lun_nump, listp, &(lap->listp));
2414fcf3ce44SJohn Forte 			}
2415fcf3ce44SJohn Forte 			break;
2416fcf3ce44SJohn Forte 		case FPCFGA_STAT_FCA_PORT:
2417fcf3ce44SJohn Forte 			if (di_path_state(path) != DI_PATH_STATE_OFFLINE) {
2418fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
2419fcf3ce44SJohn Forte 				lap->ret = FPCFGA_OK;
2420fcf3ce44SJohn Forte 				return (FPCFGA_OK);
2421fcf3ce44SJohn Forte 			}
2422fcf3ce44SJohn Forte 		}
2423fcf3ce44SJohn Forte 		path = di_path_next_client(root, path);
2424fcf3ce44SJohn Forte 	} while (path != DI_PATH_NIL);
2425fcf3ce44SJohn Forte 
2426fcf3ce44SJohn Forte 	lap->ret = FPCFGA_OK;
2427fcf3ce44SJohn Forte 	S_FREE(port_wwn);
2428fcf3ce44SJohn Forte 	S_FREE(nodepath);
2429fcf3ce44SJohn Forte 	return (FPCFGA_OK);
2430fcf3ce44SJohn Forte 
2431fcf3ce44SJohn Forte }
2432fcf3ce44SJohn Forte 
2433fcf3ce44SJohn Forte /*
2434fcf3ce44SJohn Forte  * Routine for updating ldata list based on the state of device node.
2435fcf3ce44SJohn Forte  * When no matching accessible ldata is found a new ldata is created
2436fcf3ce44SJohn Forte  * with proper state information.
2437fcf3ce44SJohn Forte  *
2438fcf3ce44SJohn Forte  * The difference from do_stat_fc_dev() is
2439fcf3ce44SJohn Forte  * to handle FCP SCSI LUN information. Otherwise overall algorithm is
2440fcf3ce44SJohn Forte  * same.
2441fcf3ce44SJohn Forte  *
2442fcf3ce44SJohn Forte  * Overall algorithm:
2443fcf3ce44SJohn Forte  * If the device node is online and the matching ldata is found
2444fcf3ce44SJohn Forte  * the target device is updated with configued and unknown condition.
2445fcf3ce44SJohn Forte  * If the device node is offline or down and the matching ldata is found
2446fcf3ce44SJohn Forte  * the target device is updated with configued and unusable condition.
2447fcf3ce44SJohn Forte  * If the device node is online but the matching ldata is not found
2448fcf3ce44SJohn Forte  * the target device is created with configued and failing condition.
2449fcf3ce44SJohn Forte  * If the device node is offline or down and the matching ldata is not found
2450fcf3ce44SJohn Forte  * the target device is created with configued and unusable condition.
2451fcf3ce44SJohn Forte  */
2452fcf3ce44SJohn Forte static fpcfga_ret_t
do_stat_FCP_dev(const di_node_t node,const char * nodepath,fpcfga_list_t * lap,int limited_stat)2453fcf3ce44SJohn Forte do_stat_FCP_dev(
2454fcf3ce44SJohn Forte 	const di_node_t node,
2455fcf3ce44SJohn Forte 	const char *nodepath,
2456fcf3ce44SJohn Forte 	fpcfga_list_t *lap,
2457fcf3ce44SJohn Forte 	int limited_stat)
2458fcf3ce44SJohn Forte {
2459fcf3ce44SJohn Forte 	uint_t dctl_state = 0, devinfo_state = 0;
2460fcf3ce44SJohn Forte 	char *port_wwn = NULL;
2461fcf3ce44SJohn Forte 	cfga_list_data_t *clp = NULL;
2462fcf3ce44SJohn Forte 	cfga_busy_t busy;
2463fcf3ce44SJohn Forte 	ldata_list_t *listp = NULL;
2464fcf3ce44SJohn Forte 	ldata_list_t *matchldp = NULL;
2465fcf3ce44SJohn Forte 	int l_errno = 0, *lun_nump;
2466fcf3ce44SJohn Forte 	cfga_stat_t ostate;
2467fcf3ce44SJohn Forte 	cfga_cond_t cond;
2468fcf3ce44SJohn Forte 	fpcfga_ret_t ldata_ret;
2469fcf3ce44SJohn Forte 
2470fcf3ce44SJohn Forte 	assert(lap->apidp->xport_phys != NULL);
2471fcf3ce44SJohn Forte 	assert(lap->xport_logp != NULL);
2472fcf3ce44SJohn Forte 
2473fcf3ce44SJohn Forte 	cond = CFGA_COND_UNKNOWN;
2474fcf3ce44SJohn Forte 
2475fcf3ce44SJohn Forte 	devinfo_state = di_state(node);
2476fcf3ce44SJohn Forte 	ostate = dev_devinfo_to_occupant_state(devinfo_state);
2477fcf3ce44SJohn Forte 
2478fcf3ce44SJohn Forte 	/*
2479fcf3ce44SJohn Forte 	 * NOTE: The devctl framework cannot currently detect layered driver
2480fcf3ce44SJohn Forte 	 * opens, so the busy indicator is not very reliable. Also,
2481fcf3ce44SJohn Forte 	 * non-root users will not be able to determine busy
2482fcf3ce44SJohn Forte 	 * status (libdevice needs root permissions).
2483fcf3ce44SJohn Forte 	 * This should probably be fixed by adding a DI_BUSY to the di_state()
2484fcf3ce44SJohn Forte 	 * routine in libdevinfo.
2485fcf3ce44SJohn Forte 	 */
2486fcf3ce44SJohn Forte 	if (devctl_cmd(nodepath, FPCFGA_DEV_GETSTATE, &dctl_state,
2487fcf3ce44SJohn Forte 	    &l_errno) == FPCFGA_OK) {
2488fcf3ce44SJohn Forte 		busy = ((dctl_state & DEVICE_BUSY) == DEVICE_BUSY) ? 1 : 0;
2489fcf3ce44SJohn Forte 	} else {
2490fcf3ce44SJohn Forte 		busy = 0;
2491fcf3ce44SJohn Forte 	}
2492fcf3ce44SJohn Forte 
2493fcf3ce44SJohn Forte 	/* We only want to know device config state */
2494fcf3ce44SJohn Forte 	if (limited_stat) {
2495fcf3ce44SJohn Forte 		if (((strcmp(lap->xport_type, FP_FC_FABRIC_PORT_TYPE) == 0) ||
2496fcf3ce44SJohn Forte 			strcmp(lap->xport_type, FP_FC_PUBLIC_PORT_TYPE) == 0)) {
2497fcf3ce44SJohn Forte 			lap->chld_config = CFGA_STAT_CONFIGURED;
2498fcf3ce44SJohn Forte 		} else {
2499fcf3ce44SJohn Forte 			if (ostate != CFGA_STAT_UNCONFIGURED) {
2500fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
2501fcf3ce44SJohn Forte 			}
2502fcf3ce44SJohn Forte 		}
2503fcf3ce44SJohn Forte 		return (FPCFGA_OK);
2504fcf3ce44SJohn Forte 	}
2505fcf3ce44SJohn Forte 
2506fcf3ce44SJohn Forte 	/*
2507fcf3ce44SJohn Forte 	 * If child device is configured, see if it is accessible also
2508fcf3ce44SJohn Forte 	 * for FPCFGA_STAT_FC_DEV cmd.
2509fcf3ce44SJohn Forte 	 */
2510fcf3ce44SJohn Forte 	if ((make_portwwn_luncomp_from_dinode(node, &port_wwn, &lun_nump,
2511fcf3ce44SJohn Forte 			&l_errno)) != FPCFGA_OK) {
2512fcf3ce44SJohn Forte 		lap->l_errno = l_errno;
2513fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
2514fcf3ce44SJohn Forte 	}
2515fcf3ce44SJohn Forte 
2516fcf3ce44SJohn Forte 	if ((ldata_ret = is_FCP_dev_ap_on_ldata_list(port_wwn, *lun_nump,
2517fcf3ce44SJohn Forte 			lap->listp, &matchldp)) == FPCFGA_LIB_ERR) {
2518fcf3ce44SJohn Forte 		lap->l_errno = l_errno;
2519fcf3ce44SJohn Forte 		S_FREE(port_wwn);
2520fcf3ce44SJohn Forte 		return (ldata_ret);
2521fcf3ce44SJohn Forte 	}
2522fcf3ce44SJohn Forte 
2523fcf3ce44SJohn Forte 	if (lap->cmd == FPCFGA_STAT_FC_DEV) {
2524fcf3ce44SJohn Forte 		switch (ostate) {
2525fcf3ce44SJohn Forte 		case CFGA_STAT_CONFIGURED:
2526fcf3ce44SJohn Forte 			/*
2527fcf3ce44SJohn Forte 			 * if configured and not accessble, the device is
2528fcf3ce44SJohn Forte 			 * till be displayed with failing condition.
2529fcf3ce44SJohn Forte 			 * return code should be FPCFGA_OK to display it.
2530fcf3ce44SJohn Forte 			 */
2531fcf3ce44SJohn Forte 		case CFGA_STAT_NONE:
2532fcf3ce44SJohn Forte 			/*
2533fcf3ce44SJohn Forte 			 * If not unconfigured and not attached
2534fcf3ce44SJohn Forte 			 * the state is set to CFGA_STAT_NONE currently.
2535fcf3ce44SJohn Forte 			 * This is okay for the detached node due to
2536fcf3ce44SJohn Forte 			 * the driver being unloaded.
2537fcf3ce44SJohn Forte 			 * May need to define another state to
2538fcf3ce44SJohn Forte 			 * isolate the detached only state.
2539fcf3ce44SJohn Forte 			 *
2540fcf3ce44SJohn Forte 			 * handle the same way as configured.
2541fcf3ce44SJohn Forte 			 */
2542fcf3ce44SJohn Forte 			if (ldata_ret != FPCFGA_ACCESS_OK) {
2543fcf3ce44SJohn Forte 				cond = CFGA_COND_FAILING;
2544fcf3ce44SJohn Forte 			}
2545fcf3ce44SJohn Forte 			lap->chld_config = CFGA_STAT_CONFIGURED;
2546fcf3ce44SJohn Forte 			break;
2547fcf3ce44SJohn Forte 		case CFGA_STAT_UNCONFIGURED:
2548fcf3ce44SJohn Forte 			/*
2549fcf3ce44SJohn Forte 			 * if unconfigured - offline or down,
2550fcf3ce44SJohn Forte 			 * set to cond to unusable regardless of accessibility.
2551fcf3ce44SJohn Forte 			 * This behavior needs to be examined further.
2552fcf3ce44SJohn Forte 			 * When the device is not accessible the node
2553fcf3ce44SJohn Forte 			 * may get offline or down. In that case failing
2554fcf3ce44SJohn Forte 			 * cond may make more sense.
2555fcf3ce44SJohn Forte 			 * In anycase the ostate will be set to configured
2556fcf3ce44SJohn Forte 			 * configured.
2557fcf3ce44SJohn Forte 			 */
2558fcf3ce44SJohn Forte 			cond = CFGA_COND_UNUSABLE;
2559fcf3ce44SJohn Forte 			/*
2560fcf3ce44SJohn Forte 			 * For fabric port the fca port is considered as
2561fcf3ce44SJohn Forte 			 * configured since user configured previously
2562fcf3ce44SJohn Forte 			 * for any existing node.  Otherwise when the
2563fcf3ce44SJohn Forte 			 * device was accessible, the hba is considered as
2564fcf3ce44SJohn Forte 			 * configured.
2565fcf3ce44SJohn Forte 			 */
2566fcf3ce44SJohn Forte 			if (((strcmp(lap->xport_type,
2567fcf3ce44SJohn Forte 				FP_FC_PUBLIC_PORT_TYPE) == 0) ||
2568fcf3ce44SJohn Forte 				(strcmp(lap->xport_type,
2569fcf3ce44SJohn Forte 				FP_FC_FABRIC_PORT_TYPE) == 0)) ||
2570fcf3ce44SJohn Forte 				(lap->ret == FPCFGA_ACCESS_OK)) {
2571fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
2572fcf3ce44SJohn Forte 			} else {
2573fcf3ce44SJohn Forte 				/*
2574fcf3ce44SJohn Forte 				 * if lap->ret is okay there is at least
2575fcf3ce44SJohn Forte 				 * one matching ldata exist.  Need to keep
2576fcf3ce44SJohn Forte 				 * okay ret to display the matching ones.
2577fcf3ce44SJohn Forte 				 */
2578fcf3ce44SJohn Forte 				if (lap->ret != FPCFGA_OK) {
2579fcf3ce44SJohn Forte 					lap->ret = FPCFGA_APID_NOEXIST;
2580fcf3ce44SJohn Forte 				}
2581fcf3ce44SJohn Forte 				S_FREE(port_wwn);
2582fcf3ce44SJohn Forte 				return (FPCFGA_OK);
2583fcf3ce44SJohn Forte 			}
2584fcf3ce44SJohn Forte 			break;
2585fcf3ce44SJohn Forte 		default:
2586fcf3ce44SJohn Forte 			break;
2587fcf3ce44SJohn Forte 		}
2588fcf3ce44SJohn Forte 
2589fcf3ce44SJohn Forte 		/* if device found in dev_list, ldata already created. */
2590fcf3ce44SJohn Forte 		if (ldata_ret == FPCFGA_ACCESS_OK) {
2591fcf3ce44SJohn Forte 			/*
2592fcf3ce44SJohn Forte 			 * if cond is not changed then don't update
2593fcf3ce44SJohn Forte 			 * condition to keep any condtion
2594fcf3ce44SJohn Forte 			 * from initial discovery. If the initial
2595fcf3ce44SJohn Forte 			 * cond was failed the same condition will be kept.
2596fcf3ce44SJohn Forte 			 */
2597fcf3ce44SJohn Forte 			if (cond != CFGA_COND_UNKNOWN) {
2598fcf3ce44SJohn Forte 				matchldp->ldata.ap_cond = cond;
2599fcf3ce44SJohn Forte 			}
2600fcf3ce44SJohn Forte 			matchldp->ldata.ap_o_state = CFGA_STAT_CONFIGURED;
2601fcf3ce44SJohn Forte 			matchldp->ldata.ap_busy = busy;
2602fcf3ce44SJohn Forte 			/* update ap_info via inquiry */
2603fcf3ce44SJohn Forte 			clp = &matchldp->ldata;
2604fcf3ce44SJohn Forte 			/* update ap_type and ap_info */
2605fcf3ce44SJohn Forte 			get_hw_info(node, clp);
2606fcf3ce44SJohn Forte 			lap->ret = FPCFGA_OK;
2607fcf3ce44SJohn Forte 			S_FREE(port_wwn);
2608fcf3ce44SJohn Forte 			return (FPCFGA_OK);
2609fcf3ce44SJohn Forte 		}
2610fcf3ce44SJohn Forte 	}
2611fcf3ce44SJohn Forte 
2612fcf3ce44SJohn Forte 	/*
2613fcf3ce44SJohn Forte 	 * if cmd is stat all check ldata list
2614fcf3ce44SJohn Forte 	 * to see if the node exist on the dev list.  Otherwise create
2615fcf3ce44SJohn Forte 	 * the list element.
2616fcf3ce44SJohn Forte 	 */
2617fcf3ce44SJohn Forte 	if (lap->cmd == FPCFGA_STAT_ALL) {
2618fcf3ce44SJohn Forte 		switch (ldata_ret) {
2619fcf3ce44SJohn Forte 		case FPCFGA_ACCESS_OK:
2620fcf3ce44SJohn Forte 			/* node exists so set ostate to configured. */
2621fcf3ce44SJohn Forte 			lap->chld_config = CFGA_STAT_CONFIGURED;
2622fcf3ce44SJohn Forte 			matchldp->ldata.ap_o_state =
2623fcf3ce44SJohn Forte 				CFGA_STAT_CONFIGURED;
2624fcf3ce44SJohn Forte 			matchldp->ldata.ap_busy = busy;
2625fcf3ce44SJohn Forte 			clp = &matchldp->ldata;
2626fcf3ce44SJohn Forte 			switch (ostate) {
2627fcf3ce44SJohn Forte 			case CFGA_STAT_CONFIGURED:
2628fcf3ce44SJohn Forte 			/*
2629fcf3ce44SJohn Forte 			 * If not unconfigured and not attached
2630fcf3ce44SJohn Forte 			 * the state is set to CFGA_STAT_NONE currently.
2631fcf3ce44SJohn Forte 			 * This is okay for the detached node due to
2632fcf3ce44SJohn Forte 			 * the driver being unloaded.
2633fcf3ce44SJohn Forte 			 * May need to define another state to
2634fcf3ce44SJohn Forte 			 * isolate the detached only state.
2635fcf3ce44SJohn Forte 			 */
2636fcf3ce44SJohn Forte 			case CFGA_STAT_NONE:
2637fcf3ce44SJohn Forte 				/* update ap_type and ap_info */
2638fcf3ce44SJohn Forte 				get_hw_info(node, clp);
2639fcf3ce44SJohn Forte 				break;
2640fcf3ce44SJohn Forte 			/*
2641fcf3ce44SJohn Forte 			 * node is offline or down.
2642fcf3ce44SJohn Forte 			 * set cond to unusable.
2643fcf3ce44SJohn Forte 			 */
2644fcf3ce44SJohn Forte 			case CFGA_STAT_UNCONFIGURED:
2645fcf3ce44SJohn Forte 				/*
2646fcf3ce44SJohn Forte 				 * if cond is not unknown
2647fcf3ce44SJohn Forte 				 * initial probing was failed
2648fcf3ce44SJohn Forte 				 * so don't update again.
2649fcf3ce44SJohn Forte 				 */
2650fcf3ce44SJohn Forte 				if (matchldp->ldata.ap_cond ==
2651fcf3ce44SJohn Forte 					CFGA_COND_UNKNOWN) {
2652fcf3ce44SJohn Forte 					matchldp->ldata.ap_cond =
2653fcf3ce44SJohn Forte 					CFGA_COND_UNUSABLE;
2654fcf3ce44SJohn Forte 				}
2655fcf3ce44SJohn Forte 				break;
2656fcf3ce44SJohn Forte 			default:
2657fcf3ce44SJohn Forte 				break;
2658fcf3ce44SJohn Forte 			}
2659fcf3ce44SJohn Forte 			/* node found in ldata list so just return. */
2660fcf3ce44SJohn Forte 			lap->ret = FPCFGA_OK;
2661fcf3ce44SJohn Forte 			S_FREE(port_wwn);
2662fcf3ce44SJohn Forte 			return (FPCFGA_OK);
2663fcf3ce44SJohn Forte 		case FPCFGA_APID_NOACCESS:
2664fcf3ce44SJohn Forte 			switch (ostate) {
2665fcf3ce44SJohn Forte 			/* node is attached but not in dev list */
2666fcf3ce44SJohn Forte 			case CFGA_STAT_CONFIGURED:
2667fcf3ce44SJohn Forte 			case CFGA_STAT_NONE:
2668fcf3ce44SJohn Forte 				lap->chld_config = CFGA_STAT_CONFIGURED;
2669fcf3ce44SJohn Forte 				cond = CFGA_COND_FAILING;
2670fcf3ce44SJohn Forte 				break;
2671fcf3ce44SJohn Forte 			/*
2672fcf3ce44SJohn Forte 			 * node is offline or down.
2673fcf3ce44SJohn Forte 			 * set cond to unusable.
2674fcf3ce44SJohn Forte 			 */
2675fcf3ce44SJohn Forte 			case CFGA_STAT_UNCONFIGURED:
2676fcf3ce44SJohn Forte 				/*
2677fcf3ce44SJohn Forte 				 * For fabric port the fca port is
2678fcf3ce44SJohn Forte 				 * considered as configured since user
2679fcf3ce44SJohn Forte 				 * configured previously for any
2680fcf3ce44SJohn Forte 				 * existing node.
2681fcf3ce44SJohn Forte 				 */
2682fcf3ce44SJohn Forte 				cond = CFGA_COND_UNUSABLE;
2683fcf3ce44SJohn Forte 				if ((strcmp(lap->xport_type,
2684fcf3ce44SJohn Forte 					FP_FC_PUBLIC_PORT_TYPE) == 0) ||
2685fcf3ce44SJohn Forte 					(strcmp(lap->xport_type,
2686fcf3ce44SJohn Forte 					FP_FC_FABRIC_PORT_TYPE) == 0)) {
2687fcf3ce44SJohn Forte 					lap->chld_config =
2688fcf3ce44SJohn Forte 					CFGA_STAT_CONFIGURED;
2689fcf3ce44SJohn Forte 				} else {
2690fcf3ce44SJohn Forte 					lap->ret = FPCFGA_OK;
2691fcf3ce44SJohn Forte 					S_FREE(port_wwn);
2692fcf3ce44SJohn Forte 					return (FPCFGA_OK);
2693fcf3ce44SJohn Forte 				}
2694fcf3ce44SJohn Forte 				break;
2695fcf3ce44SJohn Forte 			default:
2696fcf3ce44SJohn Forte 			/*
2697fcf3ce44SJohn Forte 			 * continue to create ldata_list struct for
2698fcf3ce44SJohn Forte 			 * this node
2699fcf3ce44SJohn Forte 			 */
2700fcf3ce44SJohn Forte 				break;
2701fcf3ce44SJohn Forte 			}
2702fcf3ce44SJohn Forte 		default:
2703fcf3ce44SJohn Forte 			break;
2704fcf3ce44SJohn Forte 		}
2705fcf3ce44SJohn Forte 	}
2706fcf3ce44SJohn Forte 
2707fcf3ce44SJohn Forte 	listp = calloc(1, sizeof (ldata_list_t));
2708fcf3ce44SJohn Forte 	if (listp == NULL) {
2709fcf3ce44SJohn Forte 		lap->l_errno = errno;
2710fcf3ce44SJohn Forte 		S_FREE(port_wwn);
2711fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
2712fcf3ce44SJohn Forte 	}
2713fcf3ce44SJohn Forte 
2714fcf3ce44SJohn Forte 	clp = &listp->ldata;
2715fcf3ce44SJohn Forte 
2716fcf3ce44SJohn Forte 	/* Create logical and physical ap_id */
2717fcf3ce44SJohn Forte 	(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id),
2718fcf3ce44SJohn Forte 		"%s%s%s%s%d", lap->xport_logp, DYN_SEP, port_wwn,
2719fcf3ce44SJohn Forte 		LUN_COMP_SEP, *lun_nump);
2720fcf3ce44SJohn Forte 	(void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id),
2721fcf3ce44SJohn Forte 		"%s%s%s%s%d", lap->apidp->xport_phys, DYN_SEP, port_wwn,
2722fcf3ce44SJohn Forte 		LUN_COMP_SEP, *lun_nump);
2723fcf3ce44SJohn Forte 	clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */
2724fcf3ce44SJohn Forte 	clp->ap_r_state = lap->xport_rstate;
2725fcf3ce44SJohn Forte 	clp->ap_o_state = CFGA_STAT_CONFIGURED;
2726fcf3ce44SJohn Forte 	clp->ap_cond = cond;
2727fcf3ce44SJohn Forte 	clp->ap_busy = busy;
2728fcf3ce44SJohn Forte 	clp->ap_status_time = (time_t)-1;
2729fcf3ce44SJohn Forte 	clp->ap_info[0] = '\0';
2730fcf3ce44SJohn Forte 
2731fcf3ce44SJohn Forte 	get_hw_info(node, clp);
2732fcf3ce44SJohn Forte 
2733fcf3ce44SJohn Forte 	(void) insert_ldata_to_ldatalist(port_wwn, lun_nump, listp,
2734fcf3ce44SJohn Forte 		&(lap->listp));
2735fcf3ce44SJohn Forte 
2736fcf3ce44SJohn Forte 	lap->ret = FPCFGA_OK;
2737fcf3ce44SJohn Forte 	S_FREE(port_wwn);
2738fcf3ce44SJohn Forte 	return (FPCFGA_OK);
2739fcf3ce44SJohn Forte }
2740fcf3ce44SJohn Forte 
2741fcf3ce44SJohn Forte /*
2742fcf3ce44SJohn Forte  * Searches the ldata_list to find if the the input port_wwn exist.
2743fcf3ce44SJohn Forte  *
2744fcf3ce44SJohn Forte  * Input:  port_wwn, ldata_list.
2745fcf3ce44SJohn Forte  * Return value: FPCFGA_APID_NOACCESS if not found on ldata_list.
2746fcf3ce44SJohn Forte  *		 FPCFGA_ACCESS_OK if found on ldata_list.
2747fcf3ce44SJohn Forte  */
2748fcf3ce44SJohn Forte static fpcfga_ret_t
is_dyn_ap_on_ldata_list(const char * port_wwn,const ldata_list_t * listp,ldata_list_t ** matchldpp,int * l_errnop)2749fcf3ce44SJohn Forte is_dyn_ap_on_ldata_list(const char *port_wwn, const ldata_list_t *listp,
2750fcf3ce44SJohn Forte 			ldata_list_t **matchldpp, int *l_errnop)
2751fcf3ce44SJohn Forte {
2752fcf3ce44SJohn Forte 	char		*dyn = NULL, *dyncomp = NULL;
2753fcf3ce44SJohn Forte 	int		len;
2754fcf3ce44SJohn Forte 	ldata_list_t	*tmplp;
2755fcf3ce44SJohn Forte 	fpcfga_ret_t 	ret;
2756fcf3ce44SJohn Forte 
2757fcf3ce44SJohn Forte 
2758fcf3ce44SJohn Forte 	ret = FPCFGA_APID_NOACCESS;
2759fcf3ce44SJohn Forte 
2760fcf3ce44SJohn Forte 	tmplp = (ldata_list_t *)listp;
2761fcf3ce44SJohn Forte 	while (tmplp != NULL) {
2762fcf3ce44SJohn Forte 		if ((dyn = GET_DYN(tmplp->ldata.ap_phys_id)) != NULL) {
2763fcf3ce44SJohn Forte 			len = strlen(DYN_TO_DYNCOMP(dyn)) + 1;
2764fcf3ce44SJohn Forte 			dyncomp = calloc(1, len);
2765fcf3ce44SJohn Forte 			if (dyncomp == NULL) {
2766fcf3ce44SJohn Forte 				*l_errnop = errno;
2767fcf3ce44SJohn Forte 				ret = FPCFGA_LIB_ERR;
2768fcf3ce44SJohn Forte 				break;
2769fcf3ce44SJohn Forte 			}
2770fcf3ce44SJohn Forte 			(void) strcpy(dyncomp, DYN_TO_DYNCOMP(dyn));
2771fcf3ce44SJohn Forte 			if (!(strncmp(port_wwn, dyncomp, WWN_SIZE*2))) {
2772fcf3ce44SJohn Forte 				*matchldpp = tmplp;
2773fcf3ce44SJohn Forte 				S_FREE(dyncomp);
2774fcf3ce44SJohn Forte 				ret = FPCFGA_ACCESS_OK;
2775fcf3ce44SJohn Forte 				break;
2776fcf3ce44SJohn Forte 			}
2777fcf3ce44SJohn Forte 			S_FREE(dyncomp);
2778fcf3ce44SJohn Forte 		}
2779fcf3ce44SJohn Forte 		tmplp = tmplp->next;
2780fcf3ce44SJohn Forte 	}
2781fcf3ce44SJohn Forte 
2782fcf3ce44SJohn Forte 	return (ret);
2783fcf3ce44SJohn Forte }
2784fcf3ce44SJohn Forte 
2785fcf3ce44SJohn Forte /*
2786fcf3ce44SJohn Forte  * Searches the ldata_list to find if the the input port_wwn and lun exist.
2787fcf3ce44SJohn Forte  *
2788fcf3ce44SJohn Forte  * Input:  port_wwn, ldata_list.
2789fcf3ce44SJohn Forte  * Return value: FPCFGA_APID_NOACCESS if not found on ldata_list.
2790fcf3ce44SJohn Forte  *		 FPCFGA_ACCESS_OK if found on ldata_list.
2791fcf3ce44SJohn Forte  */
2792fcf3ce44SJohn Forte static fpcfga_ret_t
is_FCP_dev_ap_on_ldata_list(const char * port_wwn,const int lun_num,ldata_list_t * ldatap,ldata_list_t ** matchldpp)2793fcf3ce44SJohn Forte is_FCP_dev_ap_on_ldata_list(const char *port_wwn, const int lun_num,
2794fcf3ce44SJohn Forte 			ldata_list_t *ldatap,
2795fcf3ce44SJohn Forte 			ldata_list_t **matchldpp)
2796fcf3ce44SJohn Forte {
2797fcf3ce44SJohn Forte 	ldata_list_t *curlp = NULL;
2798fcf3ce44SJohn Forte 	char *dyn = NULL, *dyncomp = NULL;
2799fcf3ce44SJohn Forte 	char *lun_dyn = NULL, *lunp = NULL;
2800fcf3ce44SJohn Forte 	int ldata_lun;
2801fcf3ce44SJohn Forte 	fpcfga_ret_t ret;
2802fcf3ce44SJohn Forte 
2803fcf3ce44SJohn Forte 	/*
2804fcf3ce44SJohn Forte 	 * if there is no list data just return the FCP dev list.
2805fcf3ce44SJohn Forte 	 * Normally this should not occur since list data should
2806fcf3ce44SJohn Forte 	 * be created through discoveredPort list.
2807fcf3ce44SJohn Forte 	 */
2808fcf3ce44SJohn Forte 	ret = FPCFGA_APID_NOACCESS;
2809fcf3ce44SJohn Forte 	if (ldatap == NULL) {
2810fcf3ce44SJohn Forte 		return (ret);
2811fcf3ce44SJohn Forte 	}
2812fcf3ce44SJohn Forte 
2813fcf3ce44SJohn Forte 	dyn = GET_DYN(ldatap->ldata.ap_phys_id);
2814fcf3ce44SJohn Forte 	if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
2815fcf3ce44SJohn Forte 	if ((dyncomp != NULL) &&
2816fcf3ce44SJohn Forte 			(strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) {
2817fcf3ce44SJohn Forte 		lun_dyn = GET_LUN_DYN(dyncomp);
2818fcf3ce44SJohn Forte 		if (lun_dyn != NULL) {
2819fcf3ce44SJohn Forte 			lunp = LUN_DYN_TO_LUNCOMP(lun_dyn);
2820fcf3ce44SJohn Forte 			if ((ldata_lun = atoi(lunp)) == lun_num) {
2821fcf3ce44SJohn Forte 				*matchldpp = ldatap;
2822fcf3ce44SJohn Forte 				return (FPCFGA_ACCESS_OK);
2823fcf3ce44SJohn Forte 			} else if (ldata_lun > lun_num) {
2824fcf3ce44SJohn Forte 				return (ret);
2825fcf3ce44SJohn Forte 			}
2826fcf3ce44SJohn Forte 			/* else continue */
2827fcf3ce44SJohn Forte 		} else {
2828fcf3ce44SJohn Forte 			/* we have match without lun comp. */
2829fcf3ce44SJohn Forte 			*matchldpp = ldatap;
2830fcf3ce44SJohn Forte 			return (FPCFGA_ACCESS_OK);
2831fcf3ce44SJohn Forte 		}
2832fcf3ce44SJohn Forte 	}
2833fcf3ce44SJohn Forte 
2834fcf3ce44SJohn Forte 	curlp = ldatap->next;
2835fcf3ce44SJohn Forte 
2836fcf3ce44SJohn Forte 	dyn = dyncomp = NULL;
2837fcf3ce44SJohn Forte 	lun_dyn = lunp = NULL;
2838fcf3ce44SJohn Forte 	while (curlp != NULL) {
2839fcf3ce44SJohn Forte 		dyn = GET_DYN(curlp->ldata.ap_phys_id);
2840fcf3ce44SJohn Forte 		if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
2841fcf3ce44SJohn Forte 		if ((dyncomp != NULL) &&
2842fcf3ce44SJohn Forte 				(strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) {
2843fcf3ce44SJohn Forte 			lun_dyn = GET_LUN_DYN(dyncomp);
2844fcf3ce44SJohn Forte 			if (lun_dyn != NULL) {
2845fcf3ce44SJohn Forte 				lunp = LUN_DYN_TO_LUNCOMP(lun_dyn);
2846fcf3ce44SJohn Forte 				if ((ldata_lun = atoi(lunp)) == lun_num) {
2847fcf3ce44SJohn Forte 					*matchldpp = curlp;
2848fcf3ce44SJohn Forte 					return (FPCFGA_ACCESS_OK);
2849fcf3ce44SJohn Forte 				} else if (ldata_lun > lun_num) {
2850fcf3ce44SJohn Forte 					return (ret);
2851fcf3ce44SJohn Forte 				}
2852fcf3ce44SJohn Forte 				/* else continue */
2853fcf3ce44SJohn Forte 			} else {
2854fcf3ce44SJohn Forte 				/* we have match without lun comp. */
2855fcf3ce44SJohn Forte 				*matchldpp = curlp;
2856fcf3ce44SJohn Forte 				return (FPCFGA_ACCESS_OK);
2857fcf3ce44SJohn Forte 			}
2858fcf3ce44SJohn Forte 		}
2859fcf3ce44SJohn Forte 		dyn = dyncomp = NULL;
2860fcf3ce44SJohn Forte 		lun_dyn = lunp = NULL;
2861fcf3ce44SJohn Forte 		curlp = curlp->next;
2862fcf3ce44SJohn Forte 	}
2863fcf3ce44SJohn Forte 
2864fcf3ce44SJohn Forte 	return (ret);
2865fcf3ce44SJohn Forte 
2866fcf3ce44SJohn Forte }
2867fcf3ce44SJohn Forte 
2868fcf3ce44SJohn Forte /*
2869fcf3ce44SJohn Forte  * This routine is called when a pathinfo without matching pwwn in dev_list
2870fcf3ce44SJohn Forte  * is found.
2871fcf3ce44SJohn Forte  */
2872fcf3ce44SJohn Forte static fpcfga_ret_t
init_ldata_for_mpath_dev(di_path_t path,char * pwwn,int * l_errnop,fpcfga_list_t * lap)2873fcf3ce44SJohn Forte init_ldata_for_mpath_dev(di_path_t path, char *pwwn, int *l_errnop,
2874fcf3ce44SJohn Forte 	fpcfga_list_t *lap)
2875fcf3ce44SJohn Forte {
2876fcf3ce44SJohn Forte 	ldata_list_t *listp = NULL;
2877fcf3ce44SJohn Forte 	cfga_list_data_t *clp = NULL;
2878fcf3ce44SJohn Forte 	size_t		devlen;
2879fcf3ce44SJohn Forte 	char		*devpath;
2880fcf3ce44SJohn Forte 	di_node_t	client_node = DI_NODE_NIL;
2881fcf3ce44SJohn Forte 	uint_t 		dctl_state = 0;
2882fcf3ce44SJohn Forte 	cfga_busy_t 	busy;
2883fcf3ce44SJohn Forte 	char		*client_path;
2884fcf3ce44SJohn Forte 	di_path_state_t	pstate;
2885fcf3ce44SJohn Forte 
2886fcf3ce44SJohn Forte 	/* get the client node path */
2887fcf3ce44SJohn Forte 	if (path == DI_PATH_NIL) {
2888fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
2889fcf3ce44SJohn Forte 	}
2890fcf3ce44SJohn Forte 	client_node = di_path_client_node(path);
2891fcf3ce44SJohn Forte 	if (client_node == DI_NODE_NIL) {
2892fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
2893fcf3ce44SJohn Forte 	}
2894fcf3ce44SJohn Forte 	if ((client_path = di_devfs_path(client_node)) == NULL) {
2895fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
2896fcf3ce44SJohn Forte 	}
2897fcf3ce44SJohn Forte 	devlen = strlen(DEVICES_DIR) + strlen(client_path) + 1;
2898fcf3ce44SJohn Forte 	devpath = calloc(1, devlen);
2899fcf3ce44SJohn Forte 	if (devpath == NULL) {
2900fcf3ce44SJohn Forte 		di_devfs_path_free(client_path);
2901fcf3ce44SJohn Forte 		*l_errnop = errno;
2902fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
2903fcf3ce44SJohn Forte 	}
2904fcf3ce44SJohn Forte 	(void) snprintf(devpath, devlen, "%s%s", DEVICES_DIR, client_path);
2905fcf3ce44SJohn Forte 
2906fcf3ce44SJohn Forte 	/* now need to create ldata for this dev */
2907fcf3ce44SJohn Forte 	listp = calloc(1, sizeof (ldata_list_t));
2908fcf3ce44SJohn Forte 	if (listp == NULL) {
2909fcf3ce44SJohn Forte 		di_devfs_path_free(client_path);
2910fcf3ce44SJohn Forte 		S_FREE(devpath);
2911fcf3ce44SJohn Forte 		*l_errnop = errno;
2912fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
2913fcf3ce44SJohn Forte 	}
2914fcf3ce44SJohn Forte 
2915fcf3ce44SJohn Forte 	clp = &listp->ldata;
2916fcf3ce44SJohn Forte 
2917fcf3ce44SJohn Forte 	/* Create logical and physical ap_id */
2918fcf3ce44SJohn Forte 	(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s",
2919fcf3ce44SJohn Forte 			lap->xport_logp, DYN_SEP, pwwn);
2920fcf3ce44SJohn Forte 	(void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s",
2921fcf3ce44SJohn Forte 			lap->apidp->xport_phys, DYN_SEP, pwwn);
2922fcf3ce44SJohn Forte 
2923fcf3ce44SJohn Forte 	/* Filled in by libcfgadm */
2924fcf3ce44SJohn Forte 	clp->ap_class[0] = '\0'; /* Filled by libcfgadm */
2925fcf3ce44SJohn Forte 	clp->ap_r_state = lap->xport_rstate;
2926fcf3ce44SJohn Forte 	/* set to ostate to configured. */
2927fcf3ce44SJohn Forte 	clp->ap_o_state = CFGA_STAT_CONFIGURED;
2928fcf3ce44SJohn Forte 	/*
2929fcf3ce44SJohn Forte 	 * This routine is called when a port WWN is not found in dev list
2930fcf3ce44SJohn Forte 	 * but path info node exists.
2931fcf3ce44SJohn Forte 	 *
2932fcf3ce44SJohn Forte 	 * Update the condition as failing if the pathinfo state was normal.
2933fcf3ce44SJohn Forte 	 * Update the condition as unusable if the pathinfo state is failed
2934fcf3ce44SJohn Forte 	 * or offline.
2935fcf3ce44SJohn Forte 	 */
2936fcf3ce44SJohn Forte 	if (((pstate = di_path_state(path)) == DI_PATH_STATE_OFFLINE) ||
2937fcf3ce44SJohn Forte 			(pstate == DI_PATH_STATE_FAULT)) {
2938fcf3ce44SJohn Forte 		clp->ap_cond = CFGA_COND_UNUSABLE;
2939fcf3ce44SJohn Forte 	} else {
2940fcf3ce44SJohn Forte 		clp->ap_cond = CFGA_COND_FAILING;
2941fcf3ce44SJohn Forte 	}
2942fcf3ce44SJohn Forte 	clp->ap_status_time = (time_t)-1;
2943fcf3ce44SJohn Forte 	/* update ap_type and ap_info */
2944fcf3ce44SJohn Forte 	get_hw_info(client_node, clp);
2945fcf3ce44SJohn Forte 
2946fcf3ce44SJohn Forte 	if (devctl_cmd(devpath, FPCFGA_DEV_GETSTATE,
2947fcf3ce44SJohn Forte 		&dctl_state, l_errnop) == FPCFGA_OK) {
2948fcf3ce44SJohn Forte 		busy = ((dctl_state & DEVICE_BUSY) == DEVICE_BUSY) ? 1 : 0;
2949fcf3ce44SJohn Forte 	} else {
2950fcf3ce44SJohn Forte 		busy = 0;
2951fcf3ce44SJohn Forte 	}
2952fcf3ce44SJohn Forte 	clp->ap_busy = busy;
2953fcf3ce44SJohn Forte 	/* Link it in */
2954fcf3ce44SJohn Forte 	listp->next = lap->listp;
2955fcf3ce44SJohn Forte 	lap->listp = listp;
2956fcf3ce44SJohn Forte 
2957fcf3ce44SJohn Forte 	di_devfs_path_free(client_path);
2958fcf3ce44SJohn Forte 	S_FREE(devpath);
2959fcf3ce44SJohn Forte 
2960fcf3ce44SJohn Forte 	/* now return with ok status with ldata. */
2961fcf3ce44SJohn Forte 	lap->ret = FPCFGA_OK;
2962fcf3ce44SJohn Forte 	return (FPCFGA_OK);
2963fcf3ce44SJohn Forte }
2964fcf3ce44SJohn Forte 
2965fcf3ce44SJohn Forte /*
2966fcf3ce44SJohn Forte  * Initialize the cfga_list_data struct for an accessible device
2967fcf3ce44SJohn Forte  * from g_get_dev_list().
2968fcf3ce44SJohn Forte  *
2969fcf3ce44SJohn Forte  * Input:  fca port ldata.
2970fcf3ce44SJohn Forte  * Output: device cfga_list_data.
2971fcf3ce44SJohn Forte  *
2972fcf3ce44SJohn Forte  */
2973fcf3ce44SJohn Forte static fpcfga_ret_t
init_ldata_for_accessible_dev(const char * dyncomp,uchar_t inq_type,fpcfga_list_t * lap)2974fcf3ce44SJohn Forte init_ldata_for_accessible_dev(const char *dyncomp, uchar_t inq_type,
2975fcf3ce44SJohn Forte 							fpcfga_list_t *lap)
2976fcf3ce44SJohn Forte {
2977fcf3ce44SJohn Forte 	ldata_list_t *listp = NULL;
2978fcf3ce44SJohn Forte 	cfga_list_data_t *clp = NULL;
2979fcf3ce44SJohn Forte 	int i;
2980fcf3ce44SJohn Forte 
2981fcf3ce44SJohn Forte 	listp = calloc(1, sizeof (ldata_list_t));
2982fcf3ce44SJohn Forte 	if (listp == NULL) {
2983fcf3ce44SJohn Forte 		lap->l_errno = errno;
2984fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
2985fcf3ce44SJohn Forte 	}
2986fcf3ce44SJohn Forte 
2987fcf3ce44SJohn Forte 	clp = &listp->ldata;
2988fcf3ce44SJohn Forte 
2989fcf3ce44SJohn Forte 	assert(dyncomp != NULL);
2990fcf3ce44SJohn Forte 
2991fcf3ce44SJohn Forte 	/* Create logical and physical ap_id */
2992fcf3ce44SJohn Forte 	(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s%s%s",
2993fcf3ce44SJohn Forte 		lap->xport_logp, DYN_SEP, dyncomp);
2994fcf3ce44SJohn Forte 
2995fcf3ce44SJohn Forte 	(void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id), "%s%s%s",
2996fcf3ce44SJohn Forte 		lap->apidp->xport_phys, DYN_SEP, dyncomp);
2997fcf3ce44SJohn Forte 
2998fcf3ce44SJohn Forte 	clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */
2999fcf3ce44SJohn Forte 	clp->ap_r_state = lap->xport_rstate;
3000fcf3ce44SJohn Forte 	clp->ap_o_state = CFGA_STAT_UNCONFIGURED;
3001fcf3ce44SJohn Forte 	clp->ap_cond = CFGA_COND_UNKNOWN;
3002fcf3ce44SJohn Forte 	clp->ap_busy = 0;
3003fcf3ce44SJohn Forte 	clp->ap_status_time = (time_t)-1;
3004fcf3ce44SJohn Forte 	clp->ap_info[0] = '\0';
3005fcf3ce44SJohn Forte 	for (i = 0; i < N_DEVICE_TYPES; i++) {
3006fcf3ce44SJohn Forte 		if (inq_type == device_list[i].itype) {
3007fcf3ce44SJohn Forte 			(void) snprintf(clp->ap_type, sizeof (clp->ap_type),
3008fcf3ce44SJohn Forte 			"%s", (char *)device_list[i].name);
3009fcf3ce44SJohn Forte 		break;
3010fcf3ce44SJohn Forte 		}
3011fcf3ce44SJohn Forte 	}
3012fcf3ce44SJohn Forte 	if (i == N_DEVICE_TYPES) {
3013fcf3ce44SJohn Forte 		if (inq_type == ERR_INQ_DTYPE) {
3014fcf3ce44SJohn Forte 			clp->ap_cond = CFGA_COND_FAILED;
3015fcf3ce44SJohn Forte 			snprintf(clp->ap_type, sizeof (clp->ap_type), "%s",
3016fcf3ce44SJohn Forte 			    (char *)GET_MSG_STR(ERR_UNAVAILABLE));
3017fcf3ce44SJohn Forte 		} else {
3018fcf3ce44SJohn Forte 			(void) snprintf(clp->ap_type, sizeof (clp->ap_type),
3019fcf3ce44SJohn Forte 				"%s", "unknown");
3020fcf3ce44SJohn Forte 		}
3021fcf3ce44SJohn Forte 	}
3022fcf3ce44SJohn Forte 
3023fcf3ce44SJohn Forte 	/* Link it in */
3024fcf3ce44SJohn Forte 	(void) insert_ldata_to_ldatalist(dyncomp, NULL, listp, &(lap->listp));
3025fcf3ce44SJohn Forte 
3026fcf3ce44SJohn Forte 	return (FPCFGA_OK);
3027fcf3ce44SJohn Forte }
3028fcf3ce44SJohn Forte 
3029fcf3ce44SJohn Forte /*
3030fcf3ce44SJohn Forte  * Initialize the cfga_list_data struct for an accessible FCP SCSI LUN device
3031fcf3ce44SJohn Forte  * from the report lun data.
3032fcf3ce44SJohn Forte  *
3033fcf3ce44SJohn Forte  * Input:  fca port ldata. report lun info
3034fcf3ce44SJohn Forte  * Output: device cfga_list_data.
3035fcf3ce44SJohn Forte  *
3036fcf3ce44SJohn Forte  */
3037fcf3ce44SJohn Forte static fpcfga_ret_t
init_ldata_for_accessible_FCP_dev(const char * port_wwn,int num_luns,struct report_lun_resp * resp_buf,fpcfga_list_t * lap,int * l_errnop)3038fcf3ce44SJohn Forte init_ldata_for_accessible_FCP_dev(
3039fcf3ce44SJohn Forte 	const char *port_wwn,
3040fcf3ce44SJohn Forte 	int num_luns,
3041fcf3ce44SJohn Forte 	struct report_lun_resp *resp_buf,
3042fcf3ce44SJohn Forte 	fpcfga_list_t	*lap,
3043fcf3ce44SJohn Forte 	int *l_errnop)
3044fcf3ce44SJohn Forte {
3045fcf3ce44SJohn Forte 	ldata_list_t *listp = NULL, *listp_start = NULL, *listp_end = NULL,
3046fcf3ce44SJohn Forte 		*prevlp = NULL, *curlp = NULL, *matchp_start = NULL,
3047fcf3ce44SJohn Forte 		*matchp_end = NULL;
3048fcf3ce44SJohn Forte 	cfga_list_data_t *clp = NULL;
3049fcf3ce44SJohn Forte 	char *dyn = NULL, *dyncomp = NULL;
3050fcf3ce44SJohn Forte 	uchar_t *lun_string;
3051fcf3ce44SJohn Forte 	uint16_t lun_num;
3052fcf3ce44SJohn Forte 	int i, j, str_ret;
3053fcf3ce44SJohn Forte 	fpcfga_ret_t ret;
3054fcf3ce44SJohn Forte 	char dtype[CFGA_TYPE_LEN];
3055fcf3ce44SJohn Forte 	struct scsi_inquiry *inq_buf;
3056fcf3ce44SJohn Forte 	uchar_t	peri_qual;
3057fcf3ce44SJohn Forte 	cfga_cond_t cond = CFGA_COND_UNKNOWN;
3058fcf3ce44SJohn Forte 	uchar_t lun_num_raw[SAM_LUN_SIZE];
3059fcf3ce44SJohn Forte 
3060fcf3ce44SJohn Forte 	/* when number of lun is 0 it is not an error. so just return ok. */
3061fcf3ce44SJohn Forte 	if (num_luns == 0) {
3062fcf3ce44SJohn Forte 		return (FPCFGA_OK);
3063fcf3ce44SJohn Forte 	}
3064fcf3ce44SJohn Forte 
3065fcf3ce44SJohn Forte 	for (i = 0; i < num_luns; i++) {
3066fcf3ce44SJohn Forte 	    lun_string = (uchar_t *)&(resp_buf->lun_string[i]);
3067fcf3ce44SJohn Forte 	    memcpy(lun_num_raw, lun_string, sizeof (lun_num_raw));
3068fcf3ce44SJohn Forte 	    if ((ret = get_standard_inq_data(lap->apidp->xport_phys, port_wwn,
3069fcf3ce44SJohn Forte 		lun_num_raw, &inq_buf, l_errnop))
3070fcf3ce44SJohn Forte 		!= FPCFGA_OK) {
3071fcf3ce44SJohn Forte 		if (ret == FPCFGA_FCP_TGT_SEND_SCSI_FAILED) {
3072fcf3ce44SJohn Forte 			(void) strlcpy(dtype,
3073fcf3ce44SJohn Forte 			(char *)GET_MSG_STR(ERR_UNAVAILABLE), CFGA_TYPE_LEN);
3074fcf3ce44SJohn Forte 			cond = CFGA_COND_FAILED;
3075fcf3ce44SJohn Forte 		} else {
3076fcf3ce44SJohn Forte 			S_FREE(inq_buf);
3077fcf3ce44SJohn Forte 			return (FPCFGA_LIB_ERR);
3078fcf3ce44SJohn Forte 		}
3079fcf3ce44SJohn Forte 	    } else {
3080fcf3ce44SJohn Forte 		peri_qual = inq_buf->inq_dtype & FP_PERI_QUAL_MASK;
3081fcf3ce44SJohn Forte 		/*
3082fcf3ce44SJohn Forte 		 * peripheral qualifier is not 0 so the device node should not
3083fcf3ce44SJohn Forte 		 * included in the ldata list. There should not be a device
3084fcf3ce44SJohn Forte 		 * node for the lun either.
3085fcf3ce44SJohn Forte 		 */
3086fcf3ce44SJohn Forte 		if (peri_qual != DPQ_POSSIBLE) {
3087fcf3ce44SJohn Forte 			S_FREE(inq_buf);
3088fcf3ce44SJohn Forte 			continue;
3089fcf3ce44SJohn Forte 		}
3090*21f023dfSToomas Soome 		*dtype = '\0';
3091fcf3ce44SJohn Forte 		for (j = 0; j < N_DEVICE_TYPES; j++) {
3092fcf3ce44SJohn Forte 		    if ((inq_buf->inq_dtype & DTYPE_MASK)
3093fcf3ce44SJohn Forte 				== device_list[j].itype) {
3094fcf3ce44SJohn Forte 			(void) strlcpy(dtype, (char *)device_list[j].name,
3095fcf3ce44SJohn Forte 					CFGA_TYPE_LEN);
3096fcf3ce44SJohn Forte 			break;
3097fcf3ce44SJohn Forte 		    }
3098fcf3ce44SJohn Forte 		}
3099*21f023dfSToomas Soome 		if (*dtype == '\0') {
3100fcf3ce44SJohn Forte 			(void) strlcpy(dtype,
3101fcf3ce44SJohn Forte 				(char *)device_list[DTYPE_UNKNOWN_INDEX].name,
3102fcf3ce44SJohn Forte 				CFGA_TYPE_LEN);
3103fcf3ce44SJohn Forte 		}
3104fcf3ce44SJohn Forte 	    }
3105fcf3ce44SJohn Forte 		/*
3106fcf3ce44SJohn Forte 		 * Followed FCP driver for getting lun number from report
3107fcf3ce44SJohn Forte 		 * lun data.
3108fcf3ce44SJohn Forte 		 * According to SAM-2 there are multiple address method for
3109fcf3ce44SJohn Forte 		 * FCP SCIS LUN.  Logincal unit addressing, peripheral device
3110fcf3ce44SJohn Forte 		 * addressing, flat space addressing, and extended logical
3111fcf3ce44SJohn Forte 		 * unit addressing.
3112fcf3ce44SJohn Forte 		 *
3113fcf3ce44SJohn Forte 		 * as of 11/2001 FCP supports logical unit addressing and
3114fcf3ce44SJohn Forte 		 * peripheral device addressing even thoough 3 defined.
3115fcf3ce44SJohn Forte 		 * SSFCP_LUN_ADDRESSING 0x80
3116fcf3ce44SJohn Forte 		 * SSFCP_PD_ADDRESSING 0x00
3117fcf3ce44SJohn Forte 		 * SSFCP_VOLUME_ADDRESSING 0x40
3118fcf3ce44SJohn Forte 		 *
3119fcf3ce44SJohn Forte 		 * the menthod below is used by FCP when (lun_string[0] & 0xC0)
3120fcf3ce44SJohn Forte 		 * is either SSFCP_LUN_ADDRESSING or SSFCP_PD_ADDRESSING mode.
3121fcf3ce44SJohn Forte 		 */
3122fcf3ce44SJohn Forte 	    lun_num = ((lun_string[0] & 0x3F) << 8) | lun_string[1];
3123fcf3ce44SJohn Forte 	    listp = calloc(1, sizeof (ldata_list_t));
3124fcf3ce44SJohn Forte 	    if (listp == NULL) {
3125fcf3ce44SJohn Forte 		*l_errnop = errno;
3126fcf3ce44SJohn Forte 		list_free(&listp_start);
3127fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
3128fcf3ce44SJohn Forte 	    }
3129fcf3ce44SJohn Forte 
3130fcf3ce44SJohn Forte 	    clp = &listp->ldata;
3131fcf3ce44SJohn Forte 		/* Create logical and physical ap_id */
3132fcf3ce44SJohn Forte 	    (void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id),
3133fcf3ce44SJohn Forte 		"%s%s%s%s%d", lap->xport_logp, DYN_SEP, port_wwn,
3134fcf3ce44SJohn Forte 		LUN_COMP_SEP, lun_num);
3135fcf3ce44SJohn Forte 	    (void) snprintf(clp->ap_phys_id, sizeof (clp->ap_phys_id),
3136fcf3ce44SJohn Forte 		"%s%s%s%s%d", lap->apidp->xport_phys, DYN_SEP, port_wwn,
3137fcf3ce44SJohn Forte 		LUN_COMP_SEP, lun_num);
3138fcf3ce44SJohn Forte 	    (void) strncpy(clp->ap_type, dtype, strlen(dtype));
3139fcf3ce44SJohn Forte 	    clp->ap_class[0] = '\0'; /* Filled in by libcfgadm */
3140fcf3ce44SJohn Forte 	    clp->ap_r_state = lap->xport_rstate;
3141fcf3ce44SJohn Forte 	    clp->ap_o_state = CFGA_STAT_UNCONFIGURED;
3142fcf3ce44SJohn Forte 	    clp->ap_cond = cond;
3143fcf3ce44SJohn Forte 	    clp->ap_busy = 0;
3144fcf3ce44SJohn Forte 	    clp->ap_status_time = (time_t)-1;
3145fcf3ce44SJohn Forte 	    clp->ap_info[0] = '\0';
3146fcf3ce44SJohn Forte 	    if (listp_start == NULL) {
3147fcf3ce44SJohn Forte 		listp_start = listp;
3148fcf3ce44SJohn Forte 	    } else {
3149fcf3ce44SJohn Forte 		if ((ret = insert_FCP_dev_ldata(
3150fcf3ce44SJohn Forte 			port_wwn, lun_num, listp,
3151fcf3ce44SJohn Forte 			&listp_start)) != FPCFGA_OK) {
3152fcf3ce44SJohn Forte 			list_free(&listp_start);
3153fcf3ce44SJohn Forte 			return (ret);
3154fcf3ce44SJohn Forte 		}
3155fcf3ce44SJohn Forte 	    }
3156fcf3ce44SJohn Forte 	    listp = NULL;
3157fcf3ce44SJohn Forte 	    S_FREE(inq_buf);
3158fcf3ce44SJohn Forte 	}
3159fcf3ce44SJohn Forte 
3160fcf3ce44SJohn Forte 	/*
3161fcf3ce44SJohn Forte 	 * list data can be null when device peripheral qualifier is not 0
3162fcf3ce44SJohn Forte 	 * for any luns.  Return ok to continue.
3163fcf3ce44SJohn Forte 	 */
3164fcf3ce44SJohn Forte 	if (listp_start == NULL) {
3165fcf3ce44SJohn Forte 		return (FPCFGA_OK);
3166fcf3ce44SJohn Forte 	}
3167fcf3ce44SJohn Forte 	/*
3168fcf3ce44SJohn Forte 	 * get the end of list for later uses.
3169fcf3ce44SJohn Forte 	 */
3170fcf3ce44SJohn Forte 	curlp = listp_start->next;
3171fcf3ce44SJohn Forte 	prevlp = listp_start;
3172fcf3ce44SJohn Forte 	while (curlp) {
3173fcf3ce44SJohn Forte 		prevlp = curlp;
3174fcf3ce44SJohn Forte 		curlp = curlp->next;
3175fcf3ce44SJohn Forte 	}
3176fcf3ce44SJohn Forte 	listp_end = prevlp;
3177fcf3ce44SJohn Forte 
3178fcf3ce44SJohn Forte 	/*
3179fcf3ce44SJohn Forte 	 * if there is no list data just return the FCP dev list.
3180fcf3ce44SJohn Forte 	 * Normally this should not occur since list data should
3181fcf3ce44SJohn Forte 	 * be created through g_get_dev_list().
3182fcf3ce44SJohn Forte 	 */
3183fcf3ce44SJohn Forte 	if (lap->listp == NULL) {
3184fcf3ce44SJohn Forte 		lap->listp = listp_start;
3185fcf3ce44SJohn Forte 		for (listp = listp_start; listp != NULL; listp = listp->next) {
3186fcf3ce44SJohn Forte 			listp->ldata.ap_cond = CFGA_COND_FAILING;
3187fcf3ce44SJohn Forte 		}
3188fcf3ce44SJohn Forte 		return (FPCFGA_OK);
3189fcf3ce44SJohn Forte 	}
3190fcf3ce44SJohn Forte 
3191fcf3ce44SJohn Forte 	dyn = GET_DYN(lap->listp->ldata.ap_phys_id);
3192fcf3ce44SJohn Forte 	if ((dyn != NULL) && ((dyncomp = DYN_TO_DYNCOMP(dyn)) != NULL)) {
3193fcf3ce44SJohn Forte 		if ((str_ret = strncmp(dyncomp, port_wwn, WWN_SIZE*2)) == 0) {
3194fcf3ce44SJohn Forte 			matchp_start = matchp_end = lap->listp;
3195fcf3ce44SJohn Forte 			while (matchp_end->next != NULL) {
3196fcf3ce44SJohn Forte 				dyn = GET_DYN(
3197fcf3ce44SJohn Forte 					matchp_end->next->ldata.ap_phys_id);
3198fcf3ce44SJohn Forte 				if ((dyn != NULL) &&
3199fcf3ce44SJohn Forte 				((dyncomp = DYN_TO_DYNCOMP(dyn)) != NULL)) {
3200fcf3ce44SJohn Forte 					if ((str_ret = strncmp(dyncomp,
3201fcf3ce44SJohn Forte 						port_wwn, WWN_SIZE*2)) == 0) {
3202fcf3ce44SJohn Forte 						matchp_end = matchp_end->next;
3203fcf3ce44SJohn Forte 					} else {
3204fcf3ce44SJohn Forte 						break;
3205fcf3ce44SJohn Forte 					}
3206fcf3ce44SJohn Forte 				} else {
3207fcf3ce44SJohn Forte 					break;
3208fcf3ce44SJohn Forte 				}
3209fcf3ce44SJohn Forte 			}
3210fcf3ce44SJohn Forte 			/* fillup inqdtype */
3211fcf3ce44SJohn Forte 			for (listp = listp_start; listp != NULL;
3212fcf3ce44SJohn Forte 					listp = listp->next) {
3213fcf3ce44SJohn Forte 				listp->ldata.ap_cond =
3214fcf3ce44SJohn Forte 					lap->listp->ldata.ap_cond;
3215fcf3ce44SJohn Forte 			}
3216fcf3ce44SJohn Forte 			/* link the new elem of lap->listp. */
3217fcf3ce44SJohn Forte 			listp_end->next = matchp_end->next;
3218fcf3ce44SJohn Forte 			/* free the one matching wwn. */
3219fcf3ce44SJohn Forte 			matchp_end->next = NULL;
3220fcf3ce44SJohn Forte 			list_free(&matchp_start);
3221fcf3ce44SJohn Forte 			/* link lap->listp to listp_start. */
3222fcf3ce44SJohn Forte 			lap->listp = listp_start;
3223fcf3ce44SJohn Forte 			return (FPCFGA_OK);
3224fcf3ce44SJohn Forte 		} else if (str_ret > 0) {
3225fcf3ce44SJohn Forte 			for (listp = listp_start; listp != NULL;
3226fcf3ce44SJohn Forte 					listp = listp->next) {
3227fcf3ce44SJohn Forte 				listp->ldata.ap_cond = CFGA_COND_FAILING;
3228fcf3ce44SJohn Forte 			}
3229fcf3ce44SJohn Forte 			listp_end->next = lap->listp->next;
3230fcf3ce44SJohn Forte 			lap->listp = listp_start;
3231fcf3ce44SJohn Forte 			return (FPCFGA_OK);
3232fcf3ce44SJohn Forte 		}
3233fcf3ce44SJohn Forte 	}
3234fcf3ce44SJohn Forte 
3235fcf3ce44SJohn Forte 	prevlp = lap->listp;
3236fcf3ce44SJohn Forte 	curlp = lap->listp->next;
3237fcf3ce44SJohn Forte 
3238fcf3ce44SJohn Forte 	dyn = dyncomp = NULL;
3239fcf3ce44SJohn Forte 	while (curlp != NULL) {
3240fcf3ce44SJohn Forte 		dyn = GET_DYN(curlp->ldata.ap_phys_id);
3241fcf3ce44SJohn Forte 		if ((dyn != NULL) &&
3242fcf3ce44SJohn Forte 			((dyncomp = DYN_TO_DYNCOMP(dyn)) != NULL)) {
3243fcf3ce44SJohn Forte 			if ((str_ret = strncmp(dyncomp, port_wwn,
3244fcf3ce44SJohn Forte 					WWN_SIZE*2)) == 0) {
3245fcf3ce44SJohn Forte 				matchp_start = matchp_end = curlp;
3246fcf3ce44SJohn Forte 				while (matchp_end->next != NULL) {
3247fcf3ce44SJohn Forte 					dyn = GET_DYN(
3248fcf3ce44SJohn Forte 					matchp_end->next->ldata.ap_phys_id);
3249fcf3ce44SJohn Forte 					if ((dyn != NULL) &&
3250fcf3ce44SJohn Forte 						((dyncomp = DYN_TO_DYNCOMP(dyn))
3251fcf3ce44SJohn Forte 						!= NULL)) {
3252fcf3ce44SJohn Forte 						if ((str_ret = strncmp(dyncomp,
3253fcf3ce44SJohn Forte 							port_wwn, WWN_SIZE*2))
3254fcf3ce44SJohn Forte 							== 0) {
3255fcf3ce44SJohn Forte 							matchp_end =
3256fcf3ce44SJohn Forte 							matchp_end->next;
3257fcf3ce44SJohn Forte 						} else {
3258fcf3ce44SJohn Forte 							break;
3259fcf3ce44SJohn Forte 						}
3260fcf3ce44SJohn Forte 					} else {
3261fcf3ce44SJohn Forte 						break;
3262fcf3ce44SJohn Forte 					}
3263fcf3ce44SJohn Forte 				}
3264fcf3ce44SJohn Forte 				for (listp = listp_start; listp != NULL;
3265fcf3ce44SJohn Forte 						listp = listp->next) {
3266fcf3ce44SJohn Forte 				    listp->ldata.ap_cond = curlp->ldata.ap_cond;
3267fcf3ce44SJohn Forte 				}
3268fcf3ce44SJohn Forte 				/* link the next elem to listp_end. */
3269fcf3ce44SJohn Forte 				listp_end->next = matchp_end->next;
3270fcf3ce44SJohn Forte 				/* link prevlp to listp_start to drop curlp. */
3271fcf3ce44SJohn Forte 				prevlp->next = listp_start;
3272fcf3ce44SJohn Forte 				/* free matching pwwn elem. */
3273fcf3ce44SJohn Forte 				matchp_end->next = NULL;
3274fcf3ce44SJohn Forte 				list_free(&matchp_start);
3275fcf3ce44SJohn Forte 				return (FPCFGA_OK);
3276fcf3ce44SJohn Forte 			} else if (str_ret > 0) {
3277fcf3ce44SJohn Forte 				for (listp = listp_start; listp != NULL;
3278fcf3ce44SJohn Forte 						listp = listp->next) {
3279fcf3ce44SJohn Forte 					/*
3280fcf3ce44SJohn Forte 					 * Dev not found from accessible
3281fcf3ce44SJohn Forte 					 * fc dev list but the node should
3282fcf3ce44SJohn Forte 					 * exist. Set to failing cond now
3283fcf3ce44SJohn Forte 					 * and check the node state later.
3284fcf3ce44SJohn Forte 					 */
3285fcf3ce44SJohn Forte 				    listp->ldata.ap_cond = CFGA_COND_FAILING;
3286fcf3ce44SJohn Forte 				}
3287fcf3ce44SJohn Forte 				/* keep the cur elem by linking to list_end. */
3288fcf3ce44SJohn Forte 				listp_end->next = curlp;
3289fcf3ce44SJohn Forte 				prevlp->next = listp_start;
3290fcf3ce44SJohn Forte 				return (FPCFGA_OK);
3291fcf3ce44SJohn Forte 			}
3292fcf3ce44SJohn Forte 		}
3293fcf3ce44SJohn Forte 		dyn = dyncomp = NULL;
3294fcf3ce44SJohn Forte 		prevlp = curlp;
3295fcf3ce44SJohn Forte 		curlp = curlp->next;
3296fcf3ce44SJohn Forte 	}
3297fcf3ce44SJohn Forte 
3298fcf3ce44SJohn Forte 	prevlp->next = listp_start;
3299fcf3ce44SJohn Forte 	for (listp = listp_start; listp != NULL; listp = listp->next) {
3300fcf3ce44SJohn Forte 		listp->ldata.ap_cond = CFGA_COND_FAILING;
3301fcf3ce44SJohn Forte 	}
3302fcf3ce44SJohn Forte 
3303fcf3ce44SJohn Forte 	return (FPCFGA_OK);
3304fcf3ce44SJohn Forte 
3305fcf3ce44SJohn Forte }
3306fcf3ce44SJohn Forte 
3307fcf3ce44SJohn Forte /* fill in device type, vid, pid from properties */
3308fcf3ce44SJohn Forte static void
get_hw_info(di_node_t node,cfga_list_data_t * clp)3309fcf3ce44SJohn Forte get_hw_info(di_node_t node, cfga_list_data_t *clp)
3310fcf3ce44SJohn Forte {
3311fcf3ce44SJohn Forte 	char *cp = NULL;
3312fcf3ce44SJohn Forte 	char *inq_vid, *inq_pid;
3313fcf3ce44SJohn Forte 	int i;
3314fcf3ce44SJohn Forte 
3315fcf3ce44SJohn Forte 	/*
3316fcf3ce44SJohn Forte 	 * if the type is not previously assigned with valid SCSI device type
3317fcf3ce44SJohn Forte 	 * check devinfo to find the type.
3318fcf3ce44SJohn Forte 	 * once device is configured it should have a valid device type.
3319fcf3ce44SJohn Forte 	 * device node is configured but no valid device type is found
3320fcf3ce44SJohn Forte 	 * the type will be set to unavailable.
3321fcf3ce44SJohn Forte 	 */
3322fcf3ce44SJohn Forte 	if (clp->ap_type != NULL) {
3323fcf3ce44SJohn Forte 		/*
3324fcf3ce44SJohn Forte 		 * if the type is not one of defined SCSI device type
3325fcf3ce44SJohn Forte 		 * check devinfo to find the type.
3326fcf3ce44SJohn Forte 		 *
3327fcf3ce44SJohn Forte 		 * Note: unknown type is not a valid device type.
3328fcf3ce44SJohn Forte 		 *	It is added in to the device list table to provide
3329fcf3ce44SJohn Forte 		 *	constant string of "unknown".
3330fcf3ce44SJohn Forte 		 */
3331fcf3ce44SJohn Forte 	    for (i = 0; i < (N_DEVICE_TYPES -1); i++) {
3332fcf3ce44SJohn Forte 		if (strncmp((char *)clp->ap_type, (char *)device_list[i].name,
3333fcf3ce44SJohn Forte 			sizeof (clp->ap_type)) == 0) {
3334fcf3ce44SJohn Forte 			break;
3335fcf3ce44SJohn Forte 		}
3336fcf3ce44SJohn Forte 	    }
3337fcf3ce44SJohn Forte 	    if (i == (N_DEVICE_TYPES - 1)) {
3338fcf3ce44SJohn Forte 		cp = (char *)get_device_type(node);
3339fcf3ce44SJohn Forte 		if (cp == NULL) {
3340fcf3ce44SJohn Forte 			cp = (char *)GET_MSG_STR(ERR_UNAVAILABLE);
3341fcf3ce44SJohn Forte 		}
3342fcf3ce44SJohn Forte 		(void) snprintf(clp->ap_type, sizeof (clp->ap_type), "%s",
3343fcf3ce44SJohn Forte 			S_STR(cp));
3344fcf3ce44SJohn Forte 	    }
3345fcf3ce44SJohn Forte 	} else {
3346fcf3ce44SJohn Forte 		cp = (char *)get_device_type(node);
3347fcf3ce44SJohn Forte 		if (cp == NULL) {
3348fcf3ce44SJohn Forte 			cp = (char *)GET_MSG_STR(ERR_UNAVAILABLE);
3349fcf3ce44SJohn Forte 		}
3350fcf3ce44SJohn Forte 		(void) snprintf(clp->ap_type, sizeof (clp->ap_type), "%s",
3351fcf3ce44SJohn Forte 			S_STR(cp));
3352fcf3ce44SJohn Forte 	}
3353fcf3ce44SJohn Forte 
3354fcf3ce44SJohn Forte 	/*
3355fcf3ce44SJohn Forte 	 * Fill in vendor and product ID.
3356fcf3ce44SJohn Forte 	 */
3357fcf3ce44SJohn Forte 	if ((di_prop_lookup_strings(DDI_DEV_T_ANY, node,
3358fcf3ce44SJohn Forte 	    "inquiry-product-id", &inq_pid) == 1) &&
3359fcf3ce44SJohn Forte 	    (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
3360fcf3ce44SJohn Forte 	    "inquiry-vendor-id", &inq_vid) == 1)) {
3361fcf3ce44SJohn Forte 		(void) snprintf(clp->ap_info, sizeof (clp->ap_info),
3362fcf3ce44SJohn Forte 		    "%s %s", inq_vid, inq_pid);
3363fcf3ce44SJohn Forte 	}
3364fcf3ce44SJohn Forte }
3365fcf3ce44SJohn Forte 
3366fcf3ce44SJohn Forte /*
3367fcf3ce44SJohn Forte  * Get dtype from "inquiry-device-type" property. If not present,
3368fcf3ce44SJohn Forte  * derive it from minor node type
3369fcf3ce44SJohn Forte  */
3370fcf3ce44SJohn Forte static const char *
get_device_type(di_node_t node)3371fcf3ce44SJohn Forte get_device_type(di_node_t node)
3372fcf3ce44SJohn Forte {
3373fcf3ce44SJohn Forte 	char *name = NULL;
3374fcf3ce44SJohn Forte 	int *inq_dtype;
3375fcf3ce44SJohn Forte 	int i;
3376fcf3ce44SJohn Forte 
3377fcf3ce44SJohn Forte 	if (node == DI_NODE_NIL) {
3378fcf3ce44SJohn Forte 		return (NULL);
3379fcf3ce44SJohn Forte 	}
3380fcf3ce44SJohn Forte 
3381fcf3ce44SJohn Forte 	/* first, derive type based on inquiry property */
3382fcf3ce44SJohn Forte 	if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type",
3383fcf3ce44SJohn Forte 	    &inq_dtype) != -1) {
3384fcf3ce44SJohn Forte 		int itype = (*inq_dtype) & DTYPE_MASK;
3385fcf3ce44SJohn Forte 
3386fcf3ce44SJohn Forte 		for (i = 0; i < N_DEVICE_TYPES; i++) {
3387fcf3ce44SJohn Forte 			if (itype == device_list[i].itype) {
3388fcf3ce44SJohn Forte 				name = (char *)device_list[i].name;
3389fcf3ce44SJohn Forte 				break;
3390fcf3ce44SJohn Forte 			}
3391fcf3ce44SJohn Forte 		}
3392fcf3ce44SJohn Forte 		/*
3393fcf3ce44SJohn Forte 		 * when found to be unknown type, set name to null to check
3394fcf3ce44SJohn Forte 		 * device minor node type.
3395fcf3ce44SJohn Forte 		 */
3396fcf3ce44SJohn Forte 		if (i == (N_DEVICE_TYPES - 1)) {
3397fcf3ce44SJohn Forte 			name = NULL;
3398fcf3ce44SJohn Forte 		}
3399fcf3ce44SJohn Forte 	}
3400fcf3ce44SJohn Forte 
3401fcf3ce44SJohn Forte 	/* if property fails, use minor nodetype */
3402fcf3ce44SJohn Forte 	if (name == NULL) {
3403fcf3ce44SJohn Forte 		char *nodetype;
3404fcf3ce44SJohn Forte 		di_minor_t minor = di_minor_next(node, DI_MINOR_NIL);
3405fcf3ce44SJohn Forte 
3406fcf3ce44SJohn Forte 		if ((minor != DI_MINOR_NIL) &&
3407fcf3ce44SJohn Forte 		    ((nodetype = di_minor_nodetype(minor)) != NULL)) {
3408fcf3ce44SJohn Forte 			for (i = 0; i < N_DEVICE_TYPES; i++) {
3409fcf3ce44SJohn Forte 				if (device_list[i].ntype &&
3410fcf3ce44SJohn Forte 				    (strcmp(nodetype, device_list[i].ntype)
3411fcf3ce44SJohn Forte 				    == 0)) {
3412fcf3ce44SJohn Forte 					name = (char *)device_list[i].name;
3413fcf3ce44SJohn Forte 					break;
3414fcf3ce44SJohn Forte 				}
3415fcf3ce44SJohn Forte 			}
3416fcf3ce44SJohn Forte 		}
3417fcf3ce44SJohn Forte 	}
3418fcf3ce44SJohn Forte 
3419fcf3ce44SJohn Forte 	return (name);
3420fcf3ce44SJohn Forte }
3421fcf3ce44SJohn Forte 
3422fcf3ce44SJohn Forte /* Transform list data to stat data */
3423fcf3ce44SJohn Forte fpcfga_ret_t
list_ext_postprocess(ldata_list_t ** llpp,int nelem,cfga_list_data_t ** ap_id_list,int * nlistp,char ** errstring)3424fcf3ce44SJohn Forte list_ext_postprocess(
3425fcf3ce44SJohn Forte 	ldata_list_t		**llpp,
3426fcf3ce44SJohn Forte 	int			nelem,
3427fcf3ce44SJohn Forte 	cfga_list_data_t	**ap_id_list,
3428fcf3ce44SJohn Forte 	int			*nlistp,
3429fcf3ce44SJohn Forte 	char			**errstring)
3430fcf3ce44SJohn Forte {
3431fcf3ce44SJohn Forte 	cfga_list_data_t *ldatap = NULL;
3432fcf3ce44SJohn Forte 	ldata_list_t *tmplp = NULL;
3433fcf3ce44SJohn Forte 	int i = -1;
3434fcf3ce44SJohn Forte 
3435fcf3ce44SJohn Forte 	*ap_id_list = NULL;
3436fcf3ce44SJohn Forte 	*nlistp = 0;
3437fcf3ce44SJohn Forte 
3438fcf3ce44SJohn Forte 	if (*llpp == NULL || nelem < 0) {
3439fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
3440fcf3ce44SJohn Forte 	}
3441fcf3ce44SJohn Forte 
3442fcf3ce44SJohn Forte 	if (nelem == 0) {
3443fcf3ce44SJohn Forte 		return (FPCFGA_APID_NOEXIST);
3444fcf3ce44SJohn Forte 	}
3445fcf3ce44SJohn Forte 
3446fcf3ce44SJohn Forte 	ldatap = calloc(nelem, sizeof (cfga_list_data_t));
3447fcf3ce44SJohn Forte 	if (ldatap == NULL) {
3448fcf3ce44SJohn Forte 		cfga_err(errstring, errno, ERR_LIST, 0);
3449fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
3450fcf3ce44SJohn Forte 	}
3451fcf3ce44SJohn Forte 
3452fcf3ce44SJohn Forte 	/* Extract the list_data structures from the linked list */
3453fcf3ce44SJohn Forte 	tmplp = *llpp;
3454fcf3ce44SJohn Forte 	for (i = 0; i < nelem && tmplp != NULL; i++) {
3455fcf3ce44SJohn Forte 		ldatap[i] = tmplp->ldata;
3456fcf3ce44SJohn Forte 		tmplp = tmplp->next;
3457fcf3ce44SJohn Forte 	}
3458fcf3ce44SJohn Forte 
3459fcf3ce44SJohn Forte 	if (i < nelem || tmplp != NULL) {
3460fcf3ce44SJohn Forte 		S_FREE(ldatap);
3461fcf3ce44SJohn Forte 		return (FPCFGA_LIB_ERR);
3462fcf3ce44SJohn Forte 	}
3463fcf3ce44SJohn Forte 
3464fcf3ce44SJohn Forte 	*nlistp = nelem;
3465fcf3ce44SJohn Forte 	*ap_id_list = ldatap;
3466fcf3ce44SJohn Forte 
3467fcf3ce44SJohn Forte 	return (FPCFGA_OK);
3468fcf3ce44SJohn Forte }
3469fcf3ce44SJohn Forte 
3470fcf3ce44SJohn Forte /*
3471fcf3ce44SJohn Forte  * Convert bus state to receptacle state
3472fcf3ce44SJohn Forte  */
3473fcf3ce44SJohn Forte static cfga_stat_t
xport_devinfo_to_recep_state(uint_t xport_di_state)3474fcf3ce44SJohn Forte xport_devinfo_to_recep_state(uint_t xport_di_state)
3475fcf3ce44SJohn Forte {
3476fcf3ce44SJohn Forte 	cfga_stat_t rs;
3477fcf3ce44SJohn Forte 
3478fcf3ce44SJohn Forte 	switch (xport_di_state) {
3479fcf3ce44SJohn Forte 	case DI_BUS_QUIESCED:
3480fcf3ce44SJohn Forte 	case DI_BUS_DOWN:
3481fcf3ce44SJohn Forte 		rs = CFGA_STAT_DISCONNECTED;
3482fcf3ce44SJohn Forte 		break;
3483fcf3ce44SJohn Forte 	/*
3484fcf3ce44SJohn Forte 	 * NOTE: An explicit flag for active should probably be added to
3485fcf3ce44SJohn Forte 	 * libdevinfo.
3486fcf3ce44SJohn Forte 	 */
3487fcf3ce44SJohn Forte 	default:
3488fcf3ce44SJohn Forte 		rs = CFGA_STAT_CONNECTED;
3489fcf3ce44SJohn Forte 		break;
3490fcf3ce44SJohn Forte 	}
3491fcf3ce44SJohn Forte 
3492fcf3ce44SJohn Forte 	return (rs);
3493fcf3ce44SJohn Forte }
3494fcf3ce44SJohn Forte 
3495fcf3ce44SJohn Forte /*
3496fcf3ce44SJohn Forte  * Convert device state to occupant state
3497fcf3ce44SJohn Forte  * if driver is attached the node is configured.
3498fcf3ce44SJohn Forte  * if offline or down the node is unconfigured.
3499fcf3ce44SJohn Forte  * if only driver detached it is none state which is treated the same
3500fcf3ce44SJohn Forte  * way as configured state.
3501fcf3ce44SJohn Forte  */
3502fcf3ce44SJohn Forte static cfga_stat_t
dev_devinfo_to_occupant_state(uint_t dev_di_state)3503fcf3ce44SJohn Forte dev_devinfo_to_occupant_state(uint_t dev_di_state)
3504fcf3ce44SJohn Forte {
3505fcf3ce44SJohn Forte 	/* Driver attached ? */
3506fcf3ce44SJohn Forte 	if ((dev_di_state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
3507fcf3ce44SJohn Forte 		return (CFGA_STAT_CONFIGURED);
3508fcf3ce44SJohn Forte 	}
3509fcf3ce44SJohn Forte 
3510fcf3ce44SJohn Forte 	if ((dev_di_state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE ||
3511fcf3ce44SJohn Forte 	    (dev_di_state & DI_DEVICE_DOWN) == DI_DEVICE_DOWN) {
3512fcf3ce44SJohn Forte 		return (CFGA_STAT_UNCONFIGURED);
3513fcf3ce44SJohn Forte 	} else {
3514fcf3ce44SJohn Forte 		return (CFGA_STAT_NONE);
3515fcf3ce44SJohn Forte 	}
3516fcf3ce44SJohn Forte }
3517fcf3ce44SJohn Forte 
3518fcf3ce44SJohn Forte /*
3519fcf3ce44SJohn Forte  * Wrapper routine for inserting ldata to make an sorted ldata list.
3520fcf3ce44SJohn Forte  *
3521fcf3ce44SJohn Forte  * When show_FCP_dev option is given insert_FCP_dev_ldata() is called.
3522fcf3ce44SJohn Forte  * Otherwise insert_fc_dev_ldata() is called.
3523fcf3ce44SJohn Forte  */
3524fcf3ce44SJohn Forte static fpcfga_ret_t
insert_ldata_to_ldatalist(const char * port_wwn,int * lun_nump,ldata_list_t * listp,ldata_list_t ** ldatapp)3525fcf3ce44SJohn Forte insert_ldata_to_ldatalist(
3526fcf3ce44SJohn Forte 	const char *port_wwn,
3527fcf3ce44SJohn Forte 	int *lun_nump,
3528fcf3ce44SJohn Forte 	ldata_list_t *listp,
3529fcf3ce44SJohn Forte 	ldata_list_t **ldatapp)
3530fcf3ce44SJohn Forte {
3531fcf3ce44SJohn Forte 
3532fcf3ce44SJohn Forte 	if (lun_nump == NULL) {
3533fcf3ce44SJohn Forte 		return (insert_fc_dev_ldata(port_wwn, listp, ldatapp));
3534fcf3ce44SJohn Forte 	} else {
3535fcf3ce44SJohn Forte 		return
3536fcf3ce44SJohn Forte 		(insert_FCP_dev_ldata(port_wwn, *lun_nump, listp, ldatapp));
3537fcf3ce44SJohn Forte 	}
3538fcf3ce44SJohn Forte }
3539fcf3ce44SJohn Forte 
3540fcf3ce44SJohn Forte /*
3541fcf3ce44SJohn Forte  * Insert an input ldata to ldata list to make sorted ldata list.
3542fcf3ce44SJohn Forte  */
3543fcf3ce44SJohn Forte static fpcfga_ret_t
insert_fc_dev_ldata(const char * port_wwn,ldata_list_t * listp,ldata_list_t ** ldatapp)3544fcf3ce44SJohn Forte insert_fc_dev_ldata(
3545fcf3ce44SJohn Forte 	const char *port_wwn,
3546fcf3ce44SJohn Forte 	ldata_list_t *listp,
3547fcf3ce44SJohn Forte 	ldata_list_t **ldatapp)
3548fcf3ce44SJohn Forte {
3549fcf3ce44SJohn Forte 	ldata_list_t *prevlp = NULL, *curlp = NULL;
3550fcf3ce44SJohn Forte 	char *dyn = NULL, *dyncomp = NULL;
3551fcf3ce44SJohn Forte 
3552fcf3ce44SJohn Forte 	if (*ldatapp == NULL) {
3553fcf3ce44SJohn Forte 		*ldatapp = listp;
3554fcf3ce44SJohn Forte 		return (FPCFGA_OK);
3555fcf3ce44SJohn Forte 	}
3556fcf3ce44SJohn Forte 
3557fcf3ce44SJohn Forte 	dyn = GET_DYN((*ldatapp)->ldata.ap_phys_id);
3558fcf3ce44SJohn Forte 	if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
3559fcf3ce44SJohn Forte 	if ((dyncomp != NULL) &&
3560fcf3ce44SJohn Forte 		(strncmp(dyncomp, port_wwn, WWN_SIZE*2) >= 0)) {
3561fcf3ce44SJohn Forte 			listp->next = *ldatapp;
3562fcf3ce44SJohn Forte 			*ldatapp = listp;
3563fcf3ce44SJohn Forte 			return (FPCFGA_OK);
3564fcf3ce44SJohn Forte 	}
3565fcf3ce44SJohn Forte 	/* else continue */
3566fcf3ce44SJohn Forte 
3567fcf3ce44SJohn Forte 	prevlp = *ldatapp;
3568fcf3ce44SJohn Forte 	curlp = (*ldatapp)->next;
3569fcf3ce44SJohn Forte 
3570fcf3ce44SJohn Forte 	dyn = dyncomp = NULL;
3571fcf3ce44SJohn Forte 	while (curlp != NULL) {
3572fcf3ce44SJohn Forte 		dyn = GET_DYN(curlp->ldata.ap_phys_id);
3573fcf3ce44SJohn Forte 		if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
3574fcf3ce44SJohn Forte 		if ((dyncomp != NULL) &&
3575fcf3ce44SJohn Forte 				(strncmp(dyncomp, port_wwn, WWN_SIZE*2) >= 0)) {
3576fcf3ce44SJohn Forte 			listp->next = prevlp->next;
3577fcf3ce44SJohn Forte 			prevlp->next = listp;
3578fcf3ce44SJohn Forte 			return (FPCFGA_OK);
3579fcf3ce44SJohn Forte 		}
3580fcf3ce44SJohn Forte 		dyn = dyncomp = NULL;
3581fcf3ce44SJohn Forte 		prevlp = curlp;
3582fcf3ce44SJohn Forte 		curlp = curlp->next;
3583fcf3ce44SJohn Forte 	}
3584fcf3ce44SJohn Forte 
3585fcf3ce44SJohn Forte 	/* add the ldata to the end of the list. */
3586fcf3ce44SJohn Forte 	prevlp->next = listp;
3587fcf3ce44SJohn Forte 	return (FPCFGA_OK);
3588fcf3ce44SJohn Forte }
3589fcf3ce44SJohn Forte 
3590fcf3ce44SJohn Forte /*
3591fcf3ce44SJohn Forte  * Insert an input ldata to ldata list to make sorted ldata list.
3592fcf3ce44SJohn Forte  */
3593fcf3ce44SJohn Forte static fpcfga_ret_t
insert_FCP_dev_ldata(const char * port_wwn,int lun_num,ldata_list_t * listp,ldata_list_t ** ldatapp)3594fcf3ce44SJohn Forte insert_FCP_dev_ldata(
3595fcf3ce44SJohn Forte 	const char *port_wwn,
3596fcf3ce44SJohn Forte 	int lun_num,
3597fcf3ce44SJohn Forte 	ldata_list_t *listp,
3598fcf3ce44SJohn Forte 	ldata_list_t **ldatapp)
3599fcf3ce44SJohn Forte {
3600fcf3ce44SJohn Forte 	ldata_list_t *prevlp = NULL, *curlp = NULL;
3601fcf3ce44SJohn Forte 	char *dyn = NULL, *dyncomp = NULL;
3602fcf3ce44SJohn Forte 	char *lun_dyn = NULL, *lunp = NULL;
3603fcf3ce44SJohn Forte 
3604fcf3ce44SJohn Forte 	if (*ldatapp == NULL) {
3605fcf3ce44SJohn Forte 		*ldatapp = listp;
3606fcf3ce44SJohn Forte 		return (FPCFGA_OK);
3607fcf3ce44SJohn Forte 	}
3608fcf3ce44SJohn Forte 
3609fcf3ce44SJohn Forte 	dyn = GET_DYN((*ldatapp)->ldata.ap_phys_id);
3610fcf3ce44SJohn Forte 	if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
3611fcf3ce44SJohn Forte 	if ((dyncomp != NULL) &&
3612fcf3ce44SJohn Forte 		(strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) {
3613fcf3ce44SJohn Forte 		lun_dyn = GET_LUN_DYN(dyncomp);
3614fcf3ce44SJohn Forte 		if (lun_dyn != NULL) {
3615fcf3ce44SJohn Forte 			lunp = LUN_DYN_TO_LUNCOMP(lun_dyn);
3616fcf3ce44SJohn Forte 			if ((atoi(lunp)) >= lun_num) {
3617fcf3ce44SJohn Forte 				listp->next = *ldatapp;
3618fcf3ce44SJohn Forte 				*ldatapp = listp;
3619fcf3ce44SJohn Forte 				return (FPCFGA_OK);
3620fcf3ce44SJohn Forte 			}
3621fcf3ce44SJohn Forte 		}
3622fcf3ce44SJohn Forte 	} else if ((dyncomp != NULL) &&
3623fcf3ce44SJohn Forte 			(strncmp(dyncomp, port_wwn, WWN_SIZE*2) > 0)) {
3624fcf3ce44SJohn Forte 		listp->next = *ldatapp;
3625fcf3ce44SJohn Forte 		*ldatapp = listp;
3626fcf3ce44SJohn Forte 		return (FPCFGA_OK);
3627fcf3ce44SJohn Forte 	}
3628fcf3ce44SJohn Forte 
3629fcf3ce44SJohn Forte 	prevlp = *ldatapp;
3630fcf3ce44SJohn Forte 	curlp = (*ldatapp)->next;
3631fcf3ce44SJohn Forte 
3632fcf3ce44SJohn Forte 	dyn = dyncomp = NULL;
3633fcf3ce44SJohn Forte 	lun_dyn = lunp = NULL;
3634fcf3ce44SJohn Forte 	while (curlp != NULL) {
3635fcf3ce44SJohn Forte 		dyn = GET_DYN(curlp->ldata.ap_phys_id);
3636fcf3ce44SJohn Forte 		if (dyn != NULL) dyncomp = DYN_TO_DYNCOMP(dyn);
3637fcf3ce44SJohn Forte 
3638fcf3ce44SJohn Forte 		if ((dyncomp != NULL) &&
3639fcf3ce44SJohn Forte 				(strncmp(dyncomp, port_wwn, WWN_SIZE*2) == 0)) {
3640fcf3ce44SJohn Forte 			lun_dyn = GET_LUN_DYN(dyncomp);
3641fcf3ce44SJohn Forte 			if (lun_dyn != NULL) {
3642fcf3ce44SJohn Forte 				lunp = LUN_DYN_TO_LUNCOMP(lun_dyn);
3643fcf3ce44SJohn Forte 				if ((atoi(lunp)) >= lun_num) {
3644fcf3ce44SJohn Forte 					listp->next = prevlp->next;
3645fcf3ce44SJohn Forte 					prevlp->next = listp;
3646fcf3ce44SJohn Forte 					return (FPCFGA_OK);
3647fcf3ce44SJohn Forte 				}
3648fcf3ce44SJohn Forte 			}
3649fcf3ce44SJohn Forte 			/* else continue */
3650fcf3ce44SJohn Forte 		} else if ((dyncomp != NULL) &&
3651fcf3ce44SJohn Forte 				(strncmp(dyncomp, port_wwn, WWN_SIZE*2) > 0)) {
3652fcf3ce44SJohn Forte 			listp->next = prevlp->next;
3653fcf3ce44SJohn Forte 			prevlp->next = listp;
3654fcf3ce44SJohn Forte 			return (FPCFGA_OK);
3655fcf3ce44SJohn Forte 		}
3656fcf3ce44SJohn Forte 		/* else continue */
3657fcf3ce44SJohn Forte 
3658fcf3ce44SJohn Forte 		dyn = dyncomp = NULL;
3659fcf3ce44SJohn Forte 		lun_dyn = lunp = NULL;
3660fcf3ce44SJohn Forte 		prevlp = curlp;
3661fcf3ce44SJohn Forte 		curlp = curlp->next;
3662fcf3ce44SJohn Forte 	}
3663fcf3ce44SJohn Forte 
3664fcf3ce44SJohn Forte 	/* add the ldata to the end of the list. */
3665fcf3ce44SJohn Forte 	prevlp->next = listp;
3666fcf3ce44SJohn Forte 	return (FPCFGA_OK);
3667fcf3ce44SJohn Forte }
3668fcf3ce44SJohn Forte 
3669fcf3ce44SJohn Forte /*
3670fcf3ce44SJohn Forte  * This function will return the dtype for the given device
3671fcf3ce44SJohn Forte  * It will first issue a report lun to lun 0 and then it will issue a SCSI
3672fcf3ce44SJohn Forte  * Inquiry to the first lun returned by report luns.
3673fcf3ce44SJohn Forte  *
3674fcf3ce44SJohn Forte  * If everything is successful, the dtype will be returned with the peri
3675fcf3ce44SJohn Forte  * qualifier masked out.
3676fcf3ce44SJohn Forte  *
3677fcf3ce44SJohn Forte  * If either the report lun or the scsi inquiry fails, we will first check
3678fcf3ce44SJohn Forte  * the return status.  If the return status is SCSI_DEVICE_NOT_TGT, then
3679fcf3ce44SJohn Forte  * we will assume this is a remote HBA and return an UNKNOWN DTYPE
3680fcf3ce44SJohn Forte  * for all other failures, we will return a dtype of ERR_INQ_DTYPE
3681fcf3ce44SJohn Forte  */
3682fcf3ce44SJohn Forte static uchar_t
get_inq_dtype(char * xport_phys,char * dyncomp,HBA_HANDLE handle,HBA_PORTATTRIBUTES * portAttrs,HBA_PORTATTRIBUTES * discPortAttrs)3683fcf3ce44SJohn Forte get_inq_dtype(char *xport_phys, char *dyncomp, HBA_HANDLE handle,
3684fcf3ce44SJohn Forte     HBA_PORTATTRIBUTES *portAttrs, HBA_PORTATTRIBUTES *discPortAttrs) {
3685fcf3ce44SJohn Forte 	HBA_STATUS		    status;
3686fcf3ce44SJohn Forte 	report_lun_resp_t	    *resp_buf;
3687fcf3ce44SJohn Forte 	int			    num_luns = 0, ret, l_errno;
3688fcf3ce44SJohn Forte 	uchar_t			    *lun_string;
3689fcf3ce44SJohn Forte 	uint64_t		    lun = 0;
3690fcf3ce44SJohn Forte 	struct scsi_inquiry	    inq;
3691fcf3ce44SJohn Forte 	struct scsi_extended_sense  sense;
3692fcf3ce44SJohn Forte 	HBA_UINT8		    scsiStatus;
3693fcf3ce44SJohn Forte 	uint32_t		    inquirySize = sizeof (inq);
3694fcf3ce44SJohn Forte 	uint32_t		    senseSize = sizeof (sense);
3695fcf3ce44SJohn Forte 
3696fcf3ce44SJohn Forte 	memset(&inq, 0, sizeof (inq));
3697fcf3ce44SJohn Forte 	memset(&sense, 0, sizeof (sense));
3698fcf3ce44SJohn Forte 	if ((ret = get_report_lun_data(xport_phys, dyncomp,
3699fcf3ce44SJohn Forte 			    &num_luns, &resp_buf, &sense, &l_errno))
3700fcf3ce44SJohn Forte 	    != FPCFGA_OK) {
3701fcf3ce44SJohn Forte 		/*
3702fcf3ce44SJohn Forte 		 * Checking the sense key data as well as the additional
3703fcf3ce44SJohn Forte 		 * sense key.  The SES Node is not required to repond
3704fcf3ce44SJohn Forte 		 * to Report LUN.  In the case of Minnow, the SES node
3705fcf3ce44SJohn Forte 		 * returns with KEY_ILLEGAL_REQUEST and the additional
3706fcf3ce44SJohn Forte 		 * sense key of 0x20.  In this case we will blindly
3707fcf3ce44SJohn Forte 		 * send the SCSI Inquiry call to lun 0
3708fcf3ce44SJohn Forte 		 *
3709fcf3ce44SJohn Forte 		 * if we get any other error we will set the inq_type
3710fcf3ce44SJohn Forte 		 * appropriately
3711fcf3ce44SJohn Forte 		 */
3712fcf3ce44SJohn Forte 		if ((sense.es_key == KEY_ILLEGAL_REQUEST) &&
3713fcf3ce44SJohn Forte 		    (sense.es_add_code == 0x20)) {
3714fcf3ce44SJohn Forte 			lun = 0;
3715fcf3ce44SJohn Forte 		} else {
3716fcf3ce44SJohn Forte 			if (ret == FPCFGA_FCP_SEND_SCSI_DEV_NOT_TGT) {
3717fcf3ce44SJohn Forte 				inq.inq_dtype = DTYPE_UNKNOWN;
3718fcf3ce44SJohn Forte 			} else {
3719fcf3ce44SJohn Forte 				inq.inq_dtype = ERR_INQ_DTYPE;
3720fcf3ce44SJohn Forte 			}
3721fcf3ce44SJohn Forte 			return (inq.inq_dtype);
3722fcf3ce44SJohn Forte 		}
3723fcf3ce44SJohn Forte 	} else {
3724fcf3ce44SJohn Forte 		/* send the inquiry to the first lun */
3725fcf3ce44SJohn Forte 		lun_string = (uchar_t *)&(resp_buf->lun_string[0]);
3726fcf3ce44SJohn Forte 		memcpy(&lun, lun_string, sizeof (lun));
3727fcf3ce44SJohn Forte 		S_FREE(resp_buf);
3728fcf3ce44SJohn Forte 	}
3729fcf3ce44SJohn Forte 
3730fcf3ce44SJohn Forte 	memset(&sense, 0, sizeof (sense));
3731fcf3ce44SJohn Forte 	status = HBA_ScsiInquiryV2(handle,
3732fcf3ce44SJohn Forte 	    portAttrs->PortWWN, discPortAttrs->PortWWN, lun, 0, 0,
3733fcf3ce44SJohn Forte 	    &inq, &inquirySize, &scsiStatus, &sense, &senseSize);
3734fcf3ce44SJohn Forte 	if (status == HBA_STATUS_OK) {
3735fcf3ce44SJohn Forte 		inq.inq_dtype = inq.inq_dtype & DTYPE_MASK;
3736fcf3ce44SJohn Forte 	} else if (status == HBA_STATUS_ERROR_NOT_A_TARGET) {
3737fcf3ce44SJohn Forte 		inq.inq_dtype = DTYPE_UNKNOWN;
3738fcf3ce44SJohn Forte 	} else {
3739fcf3ce44SJohn Forte 		inq.inq_dtype = ERR_INQ_DTYPE;
3740fcf3ce44SJohn Forte 	}
3741fcf3ce44SJohn Forte 	return (inq.inq_dtype);
3742fcf3ce44SJohn Forte }
3743