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.