1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at
9  * http://www.opensource.org/licenses/cddl1.txt.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2004-2012 Emulex. All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <emlxs.h>
28 
29 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
30 EMLXS_MSG_DEF(EMLXS_DFC_C);
31 
32 static int32_t		emlxs_dfc_get_rev(emlxs_hba_t *hba, dfc_t *dfc,
33 				int32_t mode);
34 static int32_t		emlxs_dfc_get_hbainfo(emlxs_hba_t *hba, dfc_t *dfc,
35 				int32_t mode);
36 static int32_t		emlxs_dfc_get_hbastats(emlxs_hba_t *hba, dfc_t *dfc,
37 				int32_t mode);
38 static int32_t		emlxs_dfc_get_drvstats(emlxs_hba_t *hba, dfc_t *dfc,
39 				int32_t mode);
40 static int32_t		emlxs_dfc_set_diag(emlxs_hba_t *hba, dfc_t *dfc,
41 				int32_t mode);
42 static int32_t		emlxs_dfc_send_mbox(emlxs_hba_t *hba, dfc_t *dfc,
43 				int32_t mode);
44 static int32_t		emlxs_dfc_read_pci(emlxs_hba_t *hba, dfc_t *dfc,
45 				int32_t mode);
46 static int32_t		emlxs_dfc_write_pci(emlxs_hba_t *hba, dfc_t *dfc,
47 				int32_t mode);
48 static int32_t		emlxs_dfc_get_cfg(emlxs_hba_t *hba, dfc_t *dfc,
49 				int32_t mode);
50 static int32_t		emlxs_dfc_set_cfg(emlxs_hba_t *hba, dfc_t *dfc,
51 				int32_t mode);
52 static int32_t		emlxs_dfc_send_menlo(emlxs_hba_t *hba, dfc_t *dfc,
53 				int32_t mode);
54 static int32_t		emlxs_dfc_send_ct(emlxs_hba_t *hba, dfc_t *dfc,
55 				int32_t mode);
56 static int32_t		emlxs_dfc_send_ct_rsp(emlxs_hba_t *hba, dfc_t *dfc,
57 				int32_t mode);
58 static int32_t		emlxs_dfc_write_flash(emlxs_hba_t *hba, dfc_t *dfc,
59 				int32_t mode);
60 static int32_t		emlxs_dfc_read_flash(emlxs_hba_t *hba, dfc_t *dfc,
61 				int32_t mode);
62 static int32_t		emlxs_dfc_send_els(emlxs_hba_t *hba, dfc_t *dfc,
63 				int32_t mode);
64 static int32_t		emlxs_dfc_loopback_test(emlxs_hba_t *hba, dfc_t *dfc,
65 				int32_t mode);
66 static int32_t		emlxs_dfc_reset_port(emlxs_hba_t *hba, dfc_t *dfc,
67 				int32_t mode);
68 static int32_t		emlxs_dfc_get_dump_region(emlxs_hba_t *hba, dfc_t *dfc,
69 				int32_t mode);
70 static int32_t		emlxs_dfc_loopback_mode(emlxs_hba_t *hba, dfc_t *dfc,
71 				int32_t mode);
72 static int32_t		emlxs_dfc_get_ioinfo(emlxs_hba_t *hba, dfc_t *dfc,
73 				int32_t mode);
74 static int32_t		emlxs_dfc_get_linkinfo(emlxs_hba_t *hba, dfc_t *dfc,
75 				int32_t mode);
76 static int32_t		emlxs_dfc_read_mem(emlxs_hba_t *hba, dfc_t *dfc,
77 				int32_t mode);
78 static int32_t		emlxs_dfc_write_mem(emlxs_hba_t *hba, dfc_t *dfc,
79 				int32_t mode);
80 static int32_t		emlxs_dfc_write_ctlreg(emlxs_hba_t *hba, dfc_t *dfc,
81 				int32_t mode);
82 static int32_t		emlxs_dfc_read_ctlreg(emlxs_hba_t *hba, dfc_t *dfc,
83 				int32_t mode);
84 static int32_t		emlxs_dfc_get_event(emlxs_hba_t *hba, dfc_t *dfc,
85 				int32_t mode);
86 static int32_t		emlxs_dfc_set_event(emlxs_hba_t *hba, dfc_t *dfc,
87 				int32_t mode);
88 static int32_t		emlxs_dfc_get_eventinfo(emlxs_hba_t *hba, dfc_t *dfc,
89 				int32_t mode);
90 static int32_t		emlxs_dfc_get_nodeinfo(emlxs_hba_t *hba, dfc_t *dfc,
91 				int32_t mode);
92 
93 #ifdef SFCT_SUPPORT
94 static int32_t		emlxs_dfc_get_fctstat(emlxs_hba_t *hba, dfc_t *dfc,
95 				int32_t mode);
96 #endif /* SFCT_SUPPORT */
97 
98 static int32_t		emlxs_dfc_create_vport(emlxs_hba_t *hba, dfc_t *dfc,
99 				int32_t mode);
100 static int32_t		emlxs_dfc_destroy_vport(emlxs_hba_t *hba, dfc_t *dfc,
101 				int32_t mode);
102 static int32_t		emlxs_dfc_get_vportinfo(emlxs_hba_t *hba, dfc_t *dfc,
103 				int32_t mode);
104 static int32_t		emlxs_dfc_npiv_resource(emlxs_hba_t *hba, dfc_t *dfc,
105 				int32_t mode);
106 static int32_t		emlxs_dfc_npiv_test(emlxs_hba_t *hba, dfc_t *dfc,
107 				int32_t mode);
108 static emlxs_port_t	*emlxs_vport_find_wwpn(emlxs_hba_t *hba, uint8_t *wwpn);
109 
110 #ifdef DHCHAP_SUPPORT
111 static int32_t		emlxs_dfc_init_auth(emlxs_hba_t *hba, dfc_t *dfc,
112 				int32_t mode);
113 static int32_t		emlxs_dfc_get_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc,
114 				int32_t mode);
115 static int32_t		emlxs_dfc_set_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc,
116 				int32_t mode);
117 static int32_t		emlxs_dfc_get_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc,
118 				int32_t mode);
119 static int32_t		emlxs_dfc_set_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc,
120 				int32_t mode);
121 static int32_t		emlxs_dfc_get_auth_status(emlxs_hba_t *hba, dfc_t *dfc,
122 				int32_t mode);
123 static int32_t		emlxs_dfc_get_auth_cfg_table(emlxs_hba_t *hba,
124 				dfc_t *dfc, int32_t mode);
125 static int32_t		emlxs_dfc_get_auth_key_table(emlxs_hba_t *hba,
126 				dfc_t *dfc, int32_t mode);
127 #endif	/* DHCHAP_SUPPORT */
128 
129 #ifdef SAN_DIAG_SUPPORT
130 static int32_t		emlxs_dfc_sd_set_bucket(emlxs_hba_t *hba, dfc_t *dfc,
131 				int32_t mode);
132 static int32_t		emlxs_dfc_sd_destroy_bucket(emlxs_hba_t *hba,
133 				dfc_t *dfc, int32_t mode);
134 static int32_t		emlxs_dfc_sd_get_bucket(emlxs_hba_t *hba, dfc_t *dfc,
135 				int32_t mode);
136 static int32_t		emlxs_dfc_sd_start_collection(emlxs_hba_t *hba,
137 				dfc_t *dfc, int32_t mode);
138 static int32_t		emlxs_dfc_sd_stop_collection(emlxs_hba_t *hba,
139 				dfc_t *dfc, int32_t mode);
140 static int32_t		emlxs_dfc_sd_reset_collection(emlxs_hba_t *hba,
141 				dfc_t *dfc, int32_t mode);
142 static int32_t		emlxs_dfc_sd_get_data(emlxs_hba_t *hba, dfc_t *dfc,
143 				int32_t mode);
144 static int32_t		emlxs_dfc_sd_set_event(emlxs_hba_t *hba, dfc_t *dfc,
145 				int32_t mode);
146 static int32_t		emlxs_dfc_sd_get_event(emlxs_hba_t *hba, dfc_t *dfc,
147 				int32_t mode);
148 #endif	/* SAN_DIAG_SUPPORT */
149 
150 static int32_t		emlxs_dfc_send_scsi_fcp(emlxs_hba_t *hba, dfc_t *dfc,
151 				int32_t mode);
152 #ifdef FCIO_SUPPORT
153 static int32_t		emlxs_fcio_manage(emlxs_hba_t *hba, dfc_t *dfc,
154 				int32_t mode);
155 static int32_t		emlxs_fcio_get_num_devs(emlxs_port_t *port,
156 				fcio_t *fcio, int32_t mode);
157 static int32_t		emlxs_fcio_get_dev_list(emlxs_port_t *port,
158 				fcio_t *fcio, int32_t mode);
159 static int32_t		emlxs_fcio_get_sym_pname(emlxs_port_t *port,
160 				fcio_t *fcio, int32_t mode);
161 static int32_t		emlxs_fcio_get_sym_nname(emlxs_port_t *port,
162 				fcio_t *fcio, int32_t mode);
163 static int32_t		emlxs_fcio_unsupported(emlxs_port_t *port,
164 				fcio_t *fcio, int32_t mode);
165 static int32_t		emlxs_fcio_get_logi_params(emlxs_port_t *port,
166 				fcio_t *fcio, int32_t mode);
167 static int32_t		emlxs_fcio_get_state(emlxs_port_t *port,
168 				fcio_t *fcio, int32_t mode);
169 static int32_t		emlxs_fcio_get_fcode_rev(emlxs_port_t *port,
170 				fcio_t *fcio, int32_t mode);
171 static int32_t		emlxs_fcio_get_fw_rev(emlxs_port_t *port,
172 				fcio_t *fcio, int32_t mode);
173 static int32_t		emlxs_fcio_get_dump_size(emlxs_port_t *port,
174 				fcio_t *fcio, int32_t mode);
175 static int32_t		emlxs_fcio_force_dump(emlxs_port_t *port,
176 				fcio_t *fcio, int32_t mode);
177 static int32_t		emlxs_fcio_get_dump(emlxs_port_t *port,
178 				fcio_t *fcio, int32_t mode);
179 static int32_t		emlxs_fcio_get_topology(emlxs_port_t *port,
180 				fcio_t *fcio, int32_t mode);
181 static int32_t		emlxs_fcio_reset_link(emlxs_port_t *port,
182 				fcio_t *fcio, int32_t mode);
183 static int32_t		emlxs_fcio_reset_hard(emlxs_port_t *port,
184 				fcio_t *fcio, int32_t mode);
185 static int32_t		emlxs_fcio_diag(emlxs_port_t *port,
186 				fcio_t *fcio, int32_t mode);
187 static int32_t		emlxs_fcio_download_fw(emlxs_port_t *port,
188 				fcio_t *fcio, int32_t mode);
189 static int32_t		emlxs_fcio_get_host_params(emlxs_port_t *port,
190 				fcio_t *fcio, int32_t mode);
191 static int32_t		emlxs_fcio_get_link_status(emlxs_port_t *port,
192 				fcio_t *fcio, int32_t mode);
193 static int32_t		emlxs_fcio_download_fcode(emlxs_port_t *port,
194 				fcio_t *fcio, int32_t mode);
195 static int32_t		emlxs_fcio_get_node_id(emlxs_port_t *port,
196 				fcio_t *fcio, int32_t mode);
197 static int32_t		emlxs_fcio_set_node_id(emlxs_port_t *port,
198 				fcio_t *fcio, int32_t mode);
199 static int32_t		emlxs_fcio_get_adapter_attrs(emlxs_port_t *port,
200 				fcio_t *fcio, int32_t mode);
201 static int32_t		emlxs_fcio_get_other_adapter_ports(emlxs_port_t *port,
202 				fcio_t *fcio, int32_t mode);
203 static int32_t		emlxs_fcio_get_adapter_port_attrs(emlxs_port_t *port,
204 				fcio_t *fcio, int32_t mode);
205 static int32_t		emlxs_fcio_get_disc_port_attrs(emlxs_port_t *port,
206 				fcio_t *fcio, int32_t mode);
207 static int32_t		emlxs_fcio_get_port_attrs(emlxs_port_t *port,
208 				fcio_t *fcio, int32_t mode);
209 #endif	/* FCIO_SUPPORT */
210 
211 static int32_t		emlxs_dfc_get_persist_linkdown(emlxs_hba_t *hba,
212 				dfc_t *dfc, int32_t mode);
213 static int32_t		emlxs_dfc_set_persist_linkdown(emlxs_hba_t *hba,
214 				dfc_t *dfc, int32_t mode);
215 
216 /* SLI-4 ioctls */
217 static int32_t		emlxs_dfc_get_fcflist(emlxs_hba_t *hba, dfc_t *dfc,
218 				int32_t mode);
219 static int32_t		emlxs_dfc_send_mbox4(emlxs_hba_t *hba, dfc_t *dfc,
220 				int32_t mode);
221 static int		emlxs_dfc_rd_be_fcf(emlxs_hba_t *hba, dfc_t *dfc,
222 			    int32_t mode);
223 static int		emlxs_dfc_set_be_dcbx(emlxs_hba_t *hba, dfc_t *dfc,
224 			    int32_t mode);
225 static int		emlxs_dfc_get_be_dcbx(emlxs_hba_t *hba, dfc_t *dfc,
226 			    int32_t mode);
227 static int		emlxs_dfc_get_qos(emlxs_hba_t *hba, dfc_t *dfc,
228 			    int32_t mode);
229 
230 uint32_t	emlxs_loopback_tmo = 60;
231 
232 typedef struct
233 {
234 	uint32_t	code;
235 	char		string[32];
236 	int		(*func)(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode);
237 } emlxs_dfc_table_t;
238 
239 emlxs_dfc_table_t emlxs_dfc_table[] = {
240 	{EMLXS_GET_HBAINFO, "GET_HBAINFO", emlxs_dfc_get_hbainfo},
241 	{EMLXS_GET_REV, "GET_REV", emlxs_dfc_get_rev},
242 	{EMLXS_SET_DIAG, "SET_DIAG", emlxs_dfc_set_diag},
243 	{EMLXS_SEND_MBOX, "SEND_MBOX", emlxs_dfc_send_mbox},
244 	{EMLXS_READ_PCI, "READ_PCI", emlxs_dfc_read_pci},
245 	{EMLXS_WRITE_PCI, "WRITE_PCI", emlxs_dfc_write_pci},
246 	{EMLXS_GET_CFG, "GET_CFG", emlxs_dfc_get_cfg},
247 	{EMLXS_SET_CFG, "SET_CFG", emlxs_dfc_set_cfg},
248 	{EMLXS_SEND_CT, "SEND_CT", emlxs_dfc_send_ct},
249 	{EMLXS_SEND_CT_RSP, "SEND_CT_RSP", emlxs_dfc_send_ct_rsp},
250 	{EMLXS_WRITE_FLASH, "WRITE_FLASH", emlxs_dfc_write_flash},
251 	{EMLXS_READ_FLASH, "READ_FLASH", emlxs_dfc_read_flash},
252 	{EMLXS_SEND_ELS, "SEND_ELS", emlxs_dfc_send_els},
253 	{EMLXS_LOOPBACK_TEST, "LOOPBACK_TEST", emlxs_dfc_loopback_test},
254 	{EMLXS_RESET_PORT, "RESET_PORT", emlxs_dfc_reset_port},
255 	{EMLXS_GET_DUMPREGION, "GET_DUMPREGION", emlxs_dfc_get_dump_region},
256 	{EMLXS_LOOPBACK_MODE, "LOOPBACK_MODE", emlxs_dfc_loopback_mode},
257 	{EMLXS_GET_IOINFO, "GET_IOINFO", emlxs_dfc_get_ioinfo},
258 	{EMLXS_GET_LINKINFO, "GET_LINKINFO", emlxs_dfc_get_linkinfo},
259 	{EMLXS_GET_NODEINFO, "GET_NODEINFO", emlxs_dfc_get_nodeinfo},
260 	{EMLXS_READ_MEM, "READ_MEM", emlxs_dfc_read_mem},
261 	{EMLXS_WRITE_MEM, "WRITE_MEM", emlxs_dfc_write_mem},
262 	{EMLXS_WRITE_CTLREG, "WRITE_CTLREG", emlxs_dfc_write_ctlreg},
263 	{EMLXS_READ_CTLREG, "READ_CTLREG", emlxs_dfc_read_ctlreg},
264 	{EMLXS_SEND_SCSI, "SEND_SCSI", emlxs_dfc_send_scsi_fcp},
265 	{EMLXS_GET_EVENT, "GET_EVENT", emlxs_dfc_get_event},
266 	{EMLXS_SET_EVENT, "SET_EVENT", emlxs_dfc_set_event},
267 	{EMLXS_GET_EVENTINFO, "GET_EVENTINFO", emlxs_dfc_get_eventinfo},
268 	{EMLXS_GET_HBASTATS, "GET_HBASTATS", emlxs_dfc_get_hbastats},
269 	{EMLXS_GET_DRVSTATS, "GET_DRVSTATS", emlxs_dfc_get_drvstats},
270 	{EMLXS_CREATE_VPORT, "CREATE_VPORT", emlxs_dfc_create_vport},
271 	{EMLXS_DESTROY_VPORT, "DESTROY_VPORT", emlxs_dfc_destroy_vport},
272 	{EMLXS_GET_VPORTINFO, "GET_VPORTINFO", emlxs_dfc_get_vportinfo},
273 	{EMLXS_NPIV_RESOURCE, "NPIV_RESOURCE", emlxs_dfc_npiv_resource},
274 	{EMLXS_NPIV_TEST, "NPIV_TEST", emlxs_dfc_npiv_test},
275 	{EMLXS_GET_PERSIST_LINKDOWN, "GET_PERSIST_LINKDOWN",
276 	    emlxs_dfc_get_persist_linkdown},
277 	{EMLXS_SET_PERSIST_LINKDOWN, "SET_PERSIST_LINKDOWN",
278 	    emlxs_dfc_set_persist_linkdown},
279 	{EMLXS_GET_FCOE_FCFLIST, "GET_FCOE_FCFLIST", emlxs_dfc_get_fcflist},
280 	{EMLXS_SEND_MBOX4, "SEND_MBOX4", emlxs_dfc_send_mbox4},
281 	{EMLXS_RD_BE_FCF, "RD_BE_FCF", emlxs_dfc_rd_be_fcf},
282 	{EMLXS_SET_BE_DCBX, "SET_BE_DCBX", emlxs_dfc_set_be_dcbx},
283 	{EMLXS_GET_BE_DCBX, "GET_BE_DCBX", emlxs_dfc_get_be_dcbx},
284 	{EMLXS_GET_QOS, "GET_QOS", emlxs_dfc_get_qos},
285 #ifdef MENLO_SUPPORT
286 	{EMLXS_SEND_MENLO, "SEND_MENLO", emlxs_dfc_send_menlo},
287 #endif /* MENLO_SUPPORT */
288 #ifdef DHCHAP_SUPPORT
289 	{EMLXS_INIT_AUTH, "INIT_AUTH", emlxs_dfc_init_auth},
290 	{EMLXS_GET_AUTH_CFG, "GET_AUTH_CFG", emlxs_dfc_get_auth_cfg},
291 	{EMLXS_SET_AUTH_CFG, "SET_AUTH_CFG", emlxs_dfc_set_auth_cfg},
292 	{EMLXS_GET_AUTH_PASSWORD, "GET_AUTH_PASSWORD", emlxs_dfc_get_auth_pwd},
293 	{EMLXS_SET_AUTH_PASSWORD, "SET_AUTH_PASSWORD", emlxs_dfc_set_auth_pwd},
294 	{EMLXS_GET_AUTH_STATUS, "GET_AUTH_STATUS", emlxs_dfc_get_auth_status},
295 	{EMLXS_GET_AUTH_CFG_TABLE, "GET_AUTH_CFG_TABLE",
296 	    emlxs_dfc_get_auth_cfg_table},
297 	{EMLXS_GET_AUTH_KEY_TABLE, "GET_AUTH_KEY_TABLE",
298 	    emlxs_dfc_get_auth_key_table},
299 #endif	/* DHCHAP_SUPPORT */
300 #ifdef FCIO_SUPPORT
301 	{EMLXS_FCIO_CMD, "FCIO_CMD", emlxs_fcio_manage},
302 #endif /* FCIO_SUPPORT */
303 #ifdef SFCT_SUPPORT
304 	{EMLXS_GET_FCTSTAT, "GET_FCTSTAT", emlxs_dfc_get_fctstat},
305 #endif /* SFCT_SUPPORT */
306 #ifdef SAN_DIAG_SUPPORT
307 	{EMLXS_SD_SET_BUCKET, "SD_SET_BUCKET", emlxs_dfc_sd_set_bucket},
308 	{EMLXS_SD_DESTROY_BUCKET, "SD_DESTROY_BUCKET",
309 	    emlxs_dfc_sd_destroy_bucket},
310 	{EMLXS_SD_GET_BUCKET, "SD_GET_BUCKET", emlxs_dfc_sd_get_bucket},
311 	{EMLXS_SD_START_DATA_COLLECTION, "SD_START_DATA_COLLECTION",
312 	    emlxs_dfc_sd_start_collection},
313 	{EMLXS_SD_STOP_DATA_COLLECTION, "SD_STOP_DATA_COLLECTION",
314 	    emlxs_dfc_sd_stop_collection},
315 	{EMLXS_SD_RESET_DATA_COLLECTION, "SD_RESET_DATA_COLLECTION",
316 	    emlxs_dfc_sd_reset_collection},
317 	{EMLXS_SD_GET_DATA, "SD_GET_DATA", emlxs_dfc_sd_get_data},
318 	{EMLXS_SD_SET_EVENT, "SD_SET_EVENT", emlxs_dfc_sd_set_event},
319 	{EMLXS_SD_GET_EVENT, "SD_GET_EVENT", emlxs_dfc_sd_get_event},
320 #endif	/* SAN_DIAG_SUPPORT */
321 };	/* emlxs_dfc_table */
322 
323 
324 emlxs_table_t emlxs_dfc_event_table[] = {
325 	{FC_REG_LINK_EVENT,		"LINK_EVENT"},
326 	{FC_REG_RSCN_EVENT,		"RSCN_EVENT"},
327 	{FC_REG_CT_EVENT,		"CT_EVENT"},
328 	{FC_REG_DUMP_EVENT,		"DUMP_EVENT"},
329 	{FC_REG_TEMP_EVENT,		"TEMP_EVENT"},
330 	{FC_REG_VPORTRSCN_EVENT,	"VPORTRSCN_EVENT"},
331 	{FC_REG_FCOE_EVENT,		"FCOE_EVENT"},
332 
333 };	/* emlxs_dfc_event_table */
334 
335 
336 #ifdef SAN_DIAG_SUPPORT
337 kmutex_t		emlxs_sd_bucket_mutex;
338 sd_bucket_info_t	emlxs_sd_bucket;
339 #endif	/* SAN_DIAG_SUPPORT */
340 
341 extern char    *
342 emlxs_dfc_xlate(uint16_t cmd)
343 {
344 	static char	buffer[32];
345 	uint32_t	i;
346 	uint32_t	count;
347 
348 	count = sizeof (emlxs_dfc_table) / sizeof (emlxs_dfc_table_t);
349 	for (i = 0; i < count; i++) {
350 		if (cmd == emlxs_dfc_table[i].code) {
351 			return (emlxs_dfc_table[i].string);
352 		}
353 	}
354 
355 	(void) snprintf(buffer, sizeof (buffer), "Cmd=0x%x", cmd);
356 	return (buffer);
357 
358 } /* emlxs_dfc_xlate() */
359 
360 
361 static int
362 emlxs_dfc_func(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
363 {
364 	emlxs_port_t *port = &PPORT;
365 	uint32_t	i;
366 	uint32_t	count;
367 	int		rval;
368 
369 	count = sizeof (emlxs_dfc_table) / sizeof (emlxs_dfc_table_t);
370 	for (i = 0; i < count; i++) {
371 		if (dfc->cmd == emlxs_dfc_table[i].code) {
372 			if ((dfc->cmd != EMLXS_FCIO_CMD) ||
373 			    (dfc->data1 != FCIO_DIAG) ||
374 			    (dfc->data2 != EMLXS_LOG_GET)) {
375 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
376 				    "%s requested.",
377 				    emlxs_dfc_table[i].string);
378 			}
379 
380 			rval = emlxs_dfc_table[i].func(hba, dfc, mode);
381 			return (rval);
382 		}
383 	}
384 
385 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
386 	    "Unknown DFC command. (0x%x)", dfc->cmd);
387 
388 	return (DFC_ARG_INVALID);
389 
390 } /* emlxs_dfc_func() */
391 
392 
393 extern char    *
394 emlxs_dfc_event_xlate(uint32_t event)
395 {
396 	static char	buffer[32];
397 	uint32_t	i;
398 	uint32_t	count;
399 
400 	count = sizeof (emlxs_dfc_event_table) / sizeof (emlxs_table_t);
401 	for (i = 0; i < count; i++) {
402 		if (event == emlxs_dfc_event_table[i].code) {
403 			return (emlxs_dfc_event_table[i].string);
404 		}
405 	}
406 
407 	(void) snprintf(buffer, sizeof (buffer), "Event=0x%x", event);
408 	return (buffer);
409 
410 } /* emlxs_dfc_event_xlate() */
411 
412 
413 static int32_t
414 emlxs_dfc_copyin(emlxs_hba_t *hba, void *arg, dfc_t *dfc1, dfc_t *dfc2,
415     int32_t mode)
416 {
417 	emlxs_port_t	*port = &PPORT;
418 	int		rval = 0;
419 	uint32_t	use32 = 0;
420 
421 #ifdef	_MULTI_DATAMODEL
422 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
423 		use32 = 1;
424 	}
425 #endif	/* _MULTI_DATAMODEL */
426 
427 	if (use32) {
428 		dfc32_t dfc32;
429 
430 		if (ddi_copyin((void *)arg, (void *)&dfc32,
431 		    sizeof (dfc32_t), mode)) {
432 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
433 			    "ddi_copyin32 failed.");
434 
435 			rval = DFC_COPYIN_ERROR;
436 			goto done;
437 		}
438 
439 		dfc1->cmd = dfc32.cmd;
440 		dfc1->flag = dfc32.flag;
441 		dfc1->buf1 = (void *)((uintptr_t)dfc32.buf1);
442 		dfc1->buf1_size = dfc32.buf1_size;
443 		dfc1->data1 = dfc32.data1;
444 		dfc1->buf2 = (void *)((uintptr_t)dfc32.buf2);
445 		dfc1->buf2_size = dfc32.buf2_size;
446 		dfc1->data2 = dfc32.data2;
447 		dfc1->buf3 = (void *)((uintptr_t)dfc32.buf3);
448 		dfc1->buf3_size = dfc32.buf3_size;
449 		dfc1->data3 = dfc32.data3;
450 		dfc1->buf4 = (void *)((uintptr_t)dfc32.buf4);
451 		dfc1->buf4_size = dfc32.buf4_size;
452 		dfc1->data4 = dfc32.data4;
453 
454 	} else {
455 		if (ddi_copyin((void *)arg, (void *)dfc1, sizeof (dfc_t),
456 		    mode)) {
457 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
458 			    "ddi_copyin failed.");
459 
460 			rval = DFC_COPYIN_ERROR;
461 			goto done;
462 		}
463 	}
464 
465 	/* Map dfc1 to dfc2 */
466 	dfc2->cmd   = dfc1->cmd;
467 	dfc2->flag  = dfc1->flag;
468 	dfc2->data1 = dfc1->data1;
469 	dfc2->data2 = dfc1->data2;
470 	dfc2->data3 = dfc1->data3;
471 	dfc2->data4 = dfc1->data4;
472 	dfc2->buf1  = 0;
473 	dfc2->buf1_size = 0;
474 	dfc2->buf2  = 0;
475 	dfc2->buf2_size = 0;
476 	dfc2->buf3  = 0;
477 	dfc2->buf3_size = 0;
478 	dfc2->buf4  = 0;
479 	dfc2->buf4_size = 0;
480 
481 	/* Copyin data buffers */
482 	if (dfc1->buf1_size && dfc1->buf1) {
483 		dfc2->buf1_size = dfc1->buf1_size;
484 		dfc2->buf1 = kmem_zalloc(dfc1->buf1_size, KM_SLEEP);
485 
486 		if (ddi_copyin(dfc1->buf1, dfc2->buf1, dfc1->buf1_size,
487 		    mode)) {
488 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
489 			    "%s: buf1 ddi_copyin failed. (size=%d)",
490 			    emlxs_dfc_xlate(dfc1->cmd),
491 			    dfc1->buf1_size);
492 
493 			rval = DFC_COPYIN_ERROR;
494 			goto done;
495 		}
496 	}
497 
498 	if (dfc1->buf2_size && dfc1->buf2) {
499 		dfc2->buf2_size = dfc1->buf2_size;
500 		dfc2->buf2 = kmem_zalloc(dfc1->buf2_size, KM_SLEEP);
501 
502 		if (ddi_copyin(dfc1->buf2, dfc2->buf2, dfc1->buf2_size,
503 		    mode)) {
504 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
505 			    "%s: buf2 ddi_copyin failed. (size=%d)",
506 			    emlxs_dfc_xlate(dfc1->cmd),
507 			    dfc1->buf2_size);
508 
509 			rval = DFC_COPYIN_ERROR;
510 			goto done;
511 		}
512 	}
513 
514 	if (dfc1->buf3_size && dfc1->buf3) {
515 		dfc2->buf3_size = dfc1->buf3_size;
516 		dfc2->buf3 = kmem_zalloc(dfc1->buf3_size, KM_SLEEP);
517 
518 		if (ddi_copyin(dfc1->buf3, dfc2->buf3, dfc1->buf3_size,
519 		    mode)) {
520 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
521 			    "%s buf3 ddi_copyin failed. (size=%d)",
522 			    emlxs_dfc_xlate(dfc1->cmd),
523 			    dfc1->buf3_size);
524 
525 			rval = DFC_COPYIN_ERROR;
526 			goto done;
527 		}
528 	}
529 
530 	if (dfc1->buf4_size && dfc1->buf4) {
531 		dfc2->buf4_size = dfc1->buf4_size;
532 		dfc2->buf4 = kmem_zalloc(dfc1->buf4_size, KM_SLEEP);
533 
534 		if (ddi_copyin(dfc1->buf4, dfc2->buf4, dfc1->buf4_size,
535 		    mode)) {
536 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
537 			    "%s: buf4 ddi_copyin failed. (size=%d)",
538 			    emlxs_dfc_xlate(dfc1->cmd),
539 			    dfc1->buf4_size);
540 
541 			rval = DFC_COPYIN_ERROR;
542 			goto done;
543 		}
544 	}
545 
546 done:
547 	return (rval);
548 
549 } /* emlxs_dfc_copyin() */
550 
551 
552 static int32_t
553 emlxs_dfc_copyout(emlxs_hba_t *hba, void *arg, dfc_t *dfc2, dfc_t *dfc1,
554     int32_t mode)
555 {
556 	emlxs_port_t	*port = &PPORT;
557 	int		rval = 0;
558 	uint32_t	use32 = 0;
559 
560 #ifdef	_MULTI_DATAMODEL
561 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
562 		use32 = 1;
563 	}
564 #endif	/* _MULTI_DATAMODEL */
565 
566 	/* Copyout data buffers */
567 	if (dfc2->buf1) {
568 		if (ddi_copyout(dfc2->buf1, dfc1->buf1, dfc1->buf1_size,
569 		    mode)) {
570 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
571 			    "%s: buf1 ddi_copyout failed. (size=%d)",
572 			    emlxs_dfc_xlate(dfc2->cmd),
573 			    dfc2->buf1_size);
574 
575 			rval = DFC_COPYOUT_ERROR;
576 		}
577 		kmem_free(dfc2->buf1, dfc2->buf1_size);
578 		dfc2->buf1 = 0;
579 	}
580 
581 	if (dfc2->buf2) {
582 		if (ddi_copyout(dfc2->buf2, dfc1->buf2, dfc1->buf2_size,
583 		    mode)) {
584 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
585 			    "%s: buf2 ddi_copyout failed. (size=%d)",
586 			    emlxs_dfc_xlate(dfc2->cmd),
587 			    dfc2->buf2_size);
588 
589 			rval = DFC_COPYOUT_ERROR;
590 		}
591 		kmem_free(dfc2->buf2, dfc2->buf2_size);
592 		dfc2->buf2 = 0;
593 	}
594 
595 	if (dfc2->buf3) {
596 		if (ddi_copyout(dfc2->buf3, dfc1->buf3, dfc1->buf3_size,
597 		    mode)) {
598 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
599 			    "%s buf3 ddi_copyout failed. (size=%d)",
600 			    emlxs_dfc_xlate(dfc2->cmd),
601 			    dfc2->buf3_size);
602 
603 			rval = DFC_COPYOUT_ERROR;
604 		}
605 		kmem_free(dfc2->buf3, dfc2->buf3_size);
606 		dfc2->buf3 = 0;
607 	}
608 
609 	if (dfc2->buf4) {
610 		if (ddi_copyout(dfc2->buf4, dfc1->buf4, dfc1->buf4_size,
611 		    mode)) {
612 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
613 			    "%s: buf4 ddi_copyout failed. (size=%d)",
614 			    emlxs_dfc_xlate(dfc2->cmd),
615 			    dfc2->buf4_size);
616 
617 			rval = DFC_COPYOUT_ERROR;
618 		}
619 		kmem_free(dfc2->buf4, dfc2->buf4_size);
620 		dfc2->buf4 = 0;
621 	}
622 
623 	if (use32) {
624 		dfc32_t dfc32;
625 
626 		dfc32.cmd = dfc1->cmd;
627 		dfc32.flag = dfc1->flag;
628 		dfc32.buf1 = (uint32_t)((uintptr_t)dfc1->buf1);
629 		dfc32.buf1_size = dfc1->buf1_size;
630 		dfc32.data1 = dfc1->data1;
631 		dfc32.buf2 = (uint32_t)((uintptr_t)dfc1->buf2);
632 		dfc32.buf2_size = dfc1->buf2_size;
633 		dfc32.data2 = dfc1->data2;
634 		dfc32.buf3 = (uint32_t)((uintptr_t)dfc1->buf3);
635 		dfc32.buf3_size = dfc1->buf3_size;
636 		dfc32.data3 = dfc1->data3;
637 		dfc32.buf4 = (uint32_t)((uintptr_t)dfc1->buf4);
638 		dfc32.buf4_size = dfc1->buf4_size;
639 		dfc32.data4 = dfc1->data4;
640 
641 		if (ddi_copyout((void *)&dfc32, (void *)arg,
642 		    sizeof (dfc32_t), mode)) {
643 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
644 			    "ddi_copyout32 failed.");
645 
646 			rval = DFC_COPYOUT_ERROR;
647 			goto done;
648 		}
649 	} else {
650 		if (ddi_copyout((void *)dfc1, (void *)arg, sizeof (dfc_t),
651 		    mode)) {
652 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
653 			    "ddi_copyout failed.");
654 
655 			rval = DFC_COPYOUT_ERROR;
656 			goto done;
657 		}
658 	}
659 
660 done:
661 	return (rval);
662 
663 } /* emlxs_dfc_copyout() */
664 
665 
666 extern int32_t
667 emlxs_dfc_manage(emlxs_hba_t *hba, void *arg, int32_t mode)
668 {
669 	dfc_t		dfc1;
670 	dfc_t		dfc2;
671 	int		rval = 0;
672 
673 	/* This copies arg data to dfc1 space, */
674 	/* then creates local dfc2 buffers */
675 	rval = emlxs_dfc_copyin(hba, arg, &dfc1, &dfc2, mode);
676 
677 	if (rval) {
678 		return (rval);
679 	}
680 
681 	rval = emlxs_dfc_func(hba, &dfc2, mode);
682 
683 	if (rval) {
684 		return (rval);
685 	}
686 
687 	/* This copies dfc2 local buffers back to dfc1 addresses */
688 	rval = emlxs_dfc_copyout(hba, arg, &dfc2, &dfc1, mode);
689 
690 	return (rval);
691 
692 } /* emlxs_dfc_manage() */
693 
694 
695 #ifdef FCIO_SUPPORT
696 typedef struct
697 {
698 	uint32_t	code;
699 	char		string[32];
700 	int		(*func)(emlxs_port_t *port, fcio_t *fcio, int32_t mode);
701 } emlxs_fcio_table_t;
702 
703 emlxs_fcio_table_t emlxs_fcio_table[] = {
704 	{FCIO_GET_NUM_DEVS, "GET_NUM_DEVS", emlxs_fcio_get_num_devs},
705 	{FCIO_GET_DEV_LIST, "GET_DEV_LIST", emlxs_fcio_get_dev_list},
706 	{FCIO_GET_SYM_PNAME, "GET_SYM_PNAME", emlxs_fcio_get_sym_pname},
707 	{FCIO_GET_SYM_NNAME, "GET_SYM_NNAME", emlxs_fcio_get_sym_nname},
708 	{FCIO_SET_SYM_PNAME, "SET_SYM_PNAME", emlxs_fcio_unsupported},
709 	{FCIO_SET_SYM_NNAME, "SET_SYM_NNAME", emlxs_fcio_unsupported},
710 	{FCIO_GET_LOGI_PARAMS, "GET_LOGI_PARAMS", emlxs_fcio_get_logi_params},
711 	{FCIO_DEV_LOGIN, "DEV_LOGIN", emlxs_fcio_unsupported},
712 	{FCIO_DEV_LOGOUT, "DEV_LOGOUT", emlxs_fcio_unsupported},
713 	{FCIO_GET_STATE, "GET_STATE", emlxs_fcio_get_state},
714 	{FCIO_DEV_REMOVE, "DEV_REMOVE", emlxs_fcio_unsupported},
715 	{FCIO_GET_FCODE_REV, "GET_FCODE_REV", emlxs_fcio_get_fcode_rev},
716 	{FCIO_GET_FW_REV, "GET_FW_REV", emlxs_fcio_get_fw_rev},
717 	{FCIO_GET_DUMP_SIZE, "GET_DUMP_SIZE", emlxs_fcio_get_dump_size},
718 	{FCIO_FORCE_DUMP, "FORCE_DUMP", emlxs_fcio_force_dump},
719 	{FCIO_GET_DUMP, "GET_DUMP", emlxs_fcio_get_dump},
720 	{FCIO_GET_TOPOLOGY, "GET_TOPOLOGY", emlxs_fcio_get_topology},
721 	{FCIO_RESET_LINK, "RESET_LINK", emlxs_fcio_reset_link},
722 	{FCIO_RESET_HARD, "RESET_HARD", emlxs_fcio_reset_hard},
723 	{FCIO_RESET_HARD_CORE, "RESET_HARD_CORE", emlxs_fcio_reset_hard},
724 	{FCIO_DIAG, "DIAG", emlxs_fcio_diag},
725 	{FCIO_NS, "NS", emlxs_fcio_unsupported},
726 	{FCIO_DOWNLOAD_FW, "DOWNLOAD_FW", emlxs_fcio_download_fw},
727 	{FCIO_GET_HOST_PARAMS, "GET_HOST_PARAMS", emlxs_fcio_get_host_params},
728 	{FCIO_LINK_STATUS, "LINK_STATUS", emlxs_fcio_get_link_status},
729 	{FCIO_DOWNLOAD_FCODE, "DOWNLOAD_FCODE", emlxs_fcio_download_fcode},
730 	{FCIO_GET_NODE_ID, "GET_NODE_ID", emlxs_fcio_get_node_id},
731 	{FCIO_SET_NODE_ID, "SET_NODE_ID", emlxs_fcio_set_node_id},
732 	{FCIO_SEND_NODE_ID, "SEND_NODE_ID", emlxs_fcio_unsupported},
733 	/* {FCIO_GET_P2P_INFO, "GET_P2P_INFO", emlxs_fcio_get_p2p_info}, */
734 	{FCIO_GET_ADAPTER_ATTRIBUTES, "GET_ADAPTER_ATTRIBUTES",
735 	    emlxs_fcio_get_adapter_attrs},
736 	{FCIO_GET_OTHER_ADAPTER_PORTS, "GET_OTHER_ADAPTER_PORTS",
737 	    emlxs_fcio_get_other_adapter_ports},
738 	{FCIO_GET_ADAPTER_PORT_ATTRIBUTES, "GET_ADAPTER_PORT_ATTRIBUTES",
739 	    emlxs_fcio_get_adapter_port_attrs},
740 	{FCIO_GET_DISCOVERED_PORT_ATTRIBUTES, "GET_DISCOVERED_PORT_ATTRIBUTES",
741 	    emlxs_fcio_get_disc_port_attrs},
742 	{FCIO_GET_PORT_ATTRIBUTES, "GET_PORT_ATTRIBUTES",
743 	    emlxs_fcio_get_port_attrs},
744 	{FCIO_GET_ADAPTER_PORT_STATS, "GET_ADAPTER_PORT_STATS",
745 	    emlxs_fcio_unsupported},
746 };	/* emlxs_fcio_table */
747 
748 
749 extern char *
750 emlxs_fcio_xlate(uint16_t cmd)
751 {
752 	static char	buffer[32];
753 	uint32_t	i;
754 	uint32_t	count;
755 
756 	count = sizeof (emlxs_fcio_table) / sizeof (emlxs_fcio_table_t);
757 	for (i = 0; i < count; i++) {
758 		if (cmd == emlxs_fcio_table[i].code) {
759 			return (emlxs_fcio_table[i].string);
760 		}
761 	}
762 
763 	(void) snprintf(buffer, sizeof (buffer), "Cmd=0x%x", cmd);
764 	return (buffer);
765 
766 } /* emlxs_fcio_xlate() */
767 
768 
769 static int
770 emlxs_fcio_func(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
771 {
772 	uint32_t	i;
773 	uint32_t	count;
774 	int		rval;
775 
776 	count = sizeof (emlxs_fcio_table) / sizeof (emlxs_fcio_table_t);
777 	for (i = 0; i < count; i++) {
778 		if (fcio->fcio_cmd == emlxs_fcio_table[i].code) {
779 			if ((fcio->fcio_cmd != FCIO_DIAG) ||
780 			    (fcio->fcio_cmd_flags != EMLXS_LOG_GET)) {
781 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
782 				    "%s requested.",
783 				    emlxs_fcio_table[i].string);
784 			}
785 
786 			rval = emlxs_fcio_table[i].func(port, fcio, mode);
787 			return (rval);
788 		}
789 	}
790 
791 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
792 	    "Unknown FCIO command. (0x%x)", fcio->fcio_cmd);
793 
794 	return (EFAULT);
795 
796 } /* emlxs_fcio_func() */
797 
798 
799 /* This is used by FCT ports to mimic SFS ports for FCIO support */
800 /*ARGSUSED*/
801 extern int32_t
802 emlxs_fcio_manage(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
803 {
804 	emlxs_port_t	*port = &PPORT;
805 	int32_t		rval = 0;
806 	fcio_t		fcio;
807 	uint32_t	vpi;
808 
809 	/* Map DFC to FCIO */
810 	vpi = (dfc->data4 < MAX_VPORTS)? dfc->data4:0;
811 	port = &VPORT(vpi);
812 
813 	bzero(&fcio, sizeof (fcio_t));
814 	fcio.fcio_flags		= dfc->flag;
815 	fcio.fcio_cmd		= dfc->data1;
816 	fcio.fcio_cmd_flags	= dfc->data2;
817 	fcio.fcio_xfer		= dfc->data3;
818 
819 	if (dfc->buf1_size && dfc->buf1) {
820 		fcio.fcio_ilen = dfc->buf1_size;
821 		fcio.fcio_ibuf = dfc->buf1;
822 	}
823 
824 	if (dfc->buf2_size && dfc->buf2) {
825 		fcio.fcio_olen = dfc->buf2_size;
826 		fcio.fcio_obuf = dfc->buf2;
827 	}
828 
829 	if (dfc->buf3_size && dfc->buf3) {
830 		fcio.fcio_alen = dfc->buf3_size;
831 		fcio.fcio_abuf = dfc->buf3;
832 	}
833 
834 	if (!dfc->buf4 || (dfc->buf4_size < sizeof (uint32_t))) {
835 		EMLXS_MSGF(EMLXS_CONTEXT,
836 		    &emlxs_dfc_error_msg,
837 		    "%s: %s: buf4 invalid. (buf4=%p size=%d)",
838 		    emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1),
839 		    dfc->buf4, dfc->buf4_size);
840 
841 		rval = EFAULT;
842 		goto done;
843 	}
844 
845 	rval = emlxs_fcio_func(port, &fcio, mode);
846 
847 	/* Map FCIO to DFC */
848 	dfc->flag  = fcio.fcio_flags;
849 	dfc->data1 = fcio.fcio_cmd;
850 	dfc->data2 = fcio.fcio_cmd_flags;
851 	dfc->data3 = fcio.fcio_xfer;
852 
853 done:
854 	/* Set fcio_errno if needed */
855 	if ((rval != 0) && (fcio.fcio_errno == 0)) {
856 		fcio.fcio_errno = FC_FAILURE;
857 	}
858 
859 	bcopy((void *)&fcio.fcio_errno, (void *)dfc->buf4, sizeof (uint32_t));
860 
861 	return (rval);
862 
863 } /* emlxs_fcio_manage() */
864 
865 
866 /*ARGSUSED*/
867 static int32_t
868 emlxs_fcio_diag(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
869 {
870 	fc_fca_pm_t 	pm;
871 	int32_t		rval = 0;
872 
873 	bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
874 
875 	pm.pm_cmd_len   = fcio->fcio_ilen;
876 	pm.pm_cmd_buf   = fcio->fcio_ibuf;
877 	pm.pm_data_len  = fcio->fcio_alen;
878 	pm.pm_data_buf  = fcio->fcio_abuf;
879 	pm.pm_stat_len  = fcio->fcio_olen;
880 	pm.pm_stat_buf  = fcio->fcio_obuf;
881 	pm.pm_cmd_code  = FC_PORT_DIAG;
882 	pm.pm_cmd_flags = fcio->fcio_cmd_flags;
883 
884 	rval = emlxs_fca_port_manage(port, &pm);
885 
886 	if (rval != FC_SUCCESS) {
887 		fcio->fcio_errno = rval;
888 
889 		if (rval == FC_INVALID_REQUEST) {
890 			rval = ENOTTY;
891 		} else {
892 			rval = EIO;
893 		}
894 	}
895 	if (fcio->fcio_olen > pm.pm_stat_len) {
896 		fcio->fcio_olen = pm.pm_stat_len;
897 	}
898 
899 	return (rval);
900 
901 } /* emlxs_fcio_diag() */
902 
903 
904 #ifndef _MULTI_DATAMODEL
905 /* ARGSUSED */
906 #endif
907 static int32_t
908 emlxs_fcio_get_host_params(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
909 {
910 	emlxs_hba_t	*hba = HBA;
911 	int32_t		rval = 0;
912 	uint32_t	use32 = 0;
913 	emlxs_config_t	*cfg  = &CFG;
914 
915 #ifdef	_MULTI_DATAMODEL
916 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
917 		use32 = 1;
918 	}
919 #endif	/* _MULTI_DATAMODEL */
920 
921 	if (use32) {
922 		fc_port_dev32_t *port_dev;
923 		uint32_t i;
924 
925 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
926 		    fcio->fcio_olen != sizeof (fc_port_dev32_t)) {
927 			rval = EINVAL;
928 			goto done;
929 		}
930 
931 		port_dev = (fc_port_dev32_t *)fcio->fcio_obuf;
932 
933 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
934 		    "fcio_get_host_params: fct_flags=%x ulp_statec=%x",
935 		    port->fct_flags, port->ulp_statec);
936 
937 		if ((port->mode == MODE_TARGET) &&
938 		    (port->fct_port) &&
939 		    (port->fct_flags & FCT_STATE_PORT_ONLINE)) {
940 			port_dev->dev_state = port->ulp_statec;
941 			port_dev->dev_did.port_id = port->did;
942 
943 			if (hba->topology == TOPOLOGY_LOOP) {
944 				for (i = 0; i < port->alpa_map[0]; i++) {
945 				if (port->alpa_map[i + 1] == port->did) {
946 					port_dev->dev_did.priv_lilp_posit =
947 					    (uint8_t)(i & 0xff);
948 					goto done;
949 				}
950 				}
951 			}
952 
953 		} else {
954 			port_dev->dev_state = FC_STATE_OFFLINE;
955 			port_dev->dev_did.port_id = 0;
956 		}
957 
958 		port_dev->dev_hard_addr.hard_addr =
959 		    cfg[CFG_ASSIGN_ALPA].current;
960 
961 		bcopy((caddr_t)&port->wwpn,
962 		    (caddr_t)&port_dev->dev_pwwn, 8);
963 		bcopy((caddr_t)&port->wwnn,
964 		    (caddr_t)&port_dev->dev_nwwn, 8);
965 
966 		port_dev->dev_type[0] = LE_SWAP32(0x00000120);
967 		port_dev->dev_type[1] = LE_SWAP32(0x00000001);
968 
969 	} else {
970 
971 		fc_port_dev_t *port_dev;
972 		uint32_t i;
973 
974 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
975 		    fcio->fcio_olen != sizeof (fc_port_dev_t)) {
976 			rval = EINVAL;
977 			goto done;
978 		}
979 
980 		port_dev = (fc_port_dev_t *)fcio->fcio_obuf;
981 
982 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
983 		    "fcio_get_host_params: fct_flags=%x ulp_statec=%x",
984 		    port->fct_flags, port->ulp_statec);
985 
986 		if ((port->mode == MODE_TARGET) &&
987 		    (port->fct_port) &&
988 		    (port->fct_flags & FCT_STATE_PORT_ONLINE)) {
989 			port_dev->dev_state = port->ulp_statec;
990 			port_dev->dev_did.port_id = port->did;
991 
992 			if (hba->topology == TOPOLOGY_LOOP) {
993 				for (i = 0; i < port->alpa_map[0]; i++) {
994 				if (port->alpa_map[i + 1] == port->did) {
995 					port_dev->dev_did.priv_lilp_posit =
996 					    (uint8_t)(i & 0xff);
997 					goto done;
998 				}
999 				}
1000 			}
1001 
1002 		} else {
1003 			port_dev->dev_state = FC_STATE_OFFLINE;
1004 			port_dev->dev_did.port_id = 0;
1005 		}
1006 
1007 		port_dev->dev_hard_addr.hard_addr =
1008 		    cfg[CFG_ASSIGN_ALPA].current;
1009 
1010 		bcopy((caddr_t)&port->wwpn,
1011 		    (caddr_t)&port_dev->dev_pwwn, 8);
1012 		bcopy((caddr_t)&port->wwnn,
1013 		    (caddr_t)&port_dev->dev_nwwn, 8);
1014 
1015 		port_dev->dev_type[0] = LE_SWAP32(0x00000120);
1016 		port_dev->dev_type[1] = LE_SWAP32(0x00000001);
1017 	}
1018 
1019 done:
1020 	return (rval);
1021 
1022 } /* emlxs_fcio_get_host_params() */
1023 
1024 
1025 /*ARGSUSED*/
1026 static int32_t
1027 emlxs_fcio_reset_link(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
1028 {
1029 	int32_t		rval = 0;
1030 	uint8_t		null_wwn[8];
1031 
1032 	if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
1033 	    fcio->fcio_ilen != 8) {
1034 		rval = EINVAL;
1035 		goto done;
1036 	}
1037 
1038 	if (port->mode != MODE_TARGET) {
1039 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
1040 		    "fcio_reset_link failed. Port is not in target mode.");
1041 
1042 		fcio->fcio_errno = FC_FAILURE;
1043 		rval = EIO;
1044 		goto done;
1045 	}
1046 
1047 	bzero(null_wwn, 8);
1048 
1049 	if (bcmp((uint8_t *)fcio->fcio_ibuf, null_wwn, 8) == 0) {
1050 		rval = emlxs_fca_reset(port, FC_FCA_LINK_RESET);
1051 
1052 		if (rval != FC_SUCCESS) {
1053 			fcio->fcio_errno = rval;
1054 			rval = EIO;
1055 		}
1056 	} else {
1057 		rval = ENOTSUP;
1058 	}
1059 
1060 done:
1061 	return (rval);
1062 
1063 } /* emlxs_fcio_reset_link() */
1064 
1065 
1066 /*ARGSUSED*/
1067 static int32_t
1068 emlxs_fcio_reset_hard(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
1069 {
1070 	int32_t		rval = 0;
1071 
1072 	if (port->mode != MODE_TARGET) {
1073 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
1074 		    "fcio_reset_hard failed. Port is not in target mode.");
1075 
1076 		fcio->fcio_errno = FC_FAILURE;
1077 		rval = EIO;
1078 		goto done;
1079 	}
1080 
1081 	rval = emlxs_reset(port, FC_FCA_RESET);
1082 
1083 	if (rval != FC_SUCCESS) {
1084 		fcio->fcio_errno = rval;
1085 		rval = EIO;
1086 	}
1087 
1088 done:
1089 	return (rval);
1090 
1091 } /* emlxs_fcio_reset_hard() */
1092 
1093 
1094 /*ARGSUSED*/
1095 static int32_t
1096 emlxs_fcio_download_fw(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
1097 {
1098 	int32_t		rval = 0;
1099 	fc_fca_pm_t	pm;
1100 
1101 	if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
1102 	    fcio->fcio_ilen == 0) {
1103 		rval = EINVAL;
1104 		goto done;
1105 	}
1106 
1107 	bzero((caddr_t)&pm, sizeof (pm));
1108 
1109 	pm.pm_cmd_flags = FC_FCA_PM_WRITE;
1110 	pm.pm_cmd_code  = FC_PORT_DOWNLOAD_FW;
1111 	pm.pm_data_len  = fcio->fcio_ilen;
1112 	pm.pm_data_buf  = fcio->fcio_ibuf;
1113 
1114 	rval = emlxs_fca_port_manage(port, &pm);
1115 
1116 	if ((rval != FC_SUCCESS) && (rval != EMLXS_REBOOT_REQUIRED)) {
1117 		fcio->fcio_errno = rval;
1118 		rval = EIO;
1119 	}
1120 
1121 done:
1122 	return (rval);
1123 
1124 } /* emlxs_fcio_download_fw() */
1125 
1126 
1127 /*ARGSUSED*/
1128 static int32_t
1129 emlxs_fcio_get_fw_rev(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
1130 {
1131 	int32_t		rval = 0;
1132 	fc_fca_pm_t	pm;
1133 
1134 	if (fcio->fcio_xfer != FCIO_XFER_READ ||
1135 	    fcio->fcio_olen < FC_FW_REV_SIZE) {
1136 		rval = EINVAL;
1137 		goto done;
1138 	}
1139 
1140 	bzero((caddr_t)&pm, sizeof (pm));
1141 
1142 	pm.pm_cmd_flags = FC_FCA_PM_READ;
1143 	pm.pm_cmd_code  = FC_PORT_GET_FW_REV;
1144 	pm.pm_data_len  = fcio->fcio_olen;
1145 	pm.pm_data_buf  = fcio->fcio_obuf;
1146 
1147 	rval = emlxs_fca_port_manage(port, &pm);
1148 
1149 	if (rval != FC_SUCCESS) {
1150 		fcio->fcio_errno = rval;
1151 		rval = EIO;
1152 	}
1153 
1154 done:
1155 	return (rval);
1156 
1157 } /* emlxs_fcio_get_fw_rev() */
1158 
1159 
1160 /*ARGSUSED*/
1161 static int32_t
1162 emlxs_fcio_get_fcode_rev(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
1163 {
1164 	int32_t		rval = 0;
1165 	fc_fca_pm_t	pm;
1166 
1167 	if (fcio->fcio_xfer != FCIO_XFER_READ ||
1168 	    fcio->fcio_olen < FC_FCODE_REV_SIZE) {
1169 		rval = EINVAL;
1170 		goto done;
1171 	}
1172 
1173 	bzero((caddr_t)&pm, sizeof (pm));
1174 
1175 	pm.pm_cmd_flags = FC_FCA_PM_READ;
1176 	pm.pm_cmd_code  = FC_PORT_GET_FCODE_REV;
1177 	pm.pm_data_len  = fcio->fcio_olen;
1178 	pm.pm_data_buf  = fcio->fcio_obuf;
1179 
1180 	rval = emlxs_fca_port_manage(port, &pm);
1181 
1182 	if (rval != FC_SUCCESS) {
1183 		fcio->fcio_errno = rval;
1184 		rval = EIO;
1185 	}
1186 
1187 done:
1188 	return (rval);
1189 
1190 } /* emlxs_fcio_get_fcode_rev() */
1191 
1192 
1193 /*ARGSUSED*/
1194 static int32_t
1195 emlxs_fcio_download_fcode(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
1196 {
1197 	int32_t		rval = 0;
1198 	fc_fca_pm_t	pm;
1199 
1200 	if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
1201 	    fcio->fcio_ilen == 0) {
1202 		rval = EINVAL;
1203 		goto done;
1204 	}
1205 
1206 	bzero((caddr_t)&pm, sizeof (pm));
1207 
1208 	pm.pm_cmd_flags = FC_FCA_PM_WRITE;
1209 	pm.pm_cmd_code  = FC_PORT_DOWNLOAD_FCODE;
1210 	pm.pm_data_len  = fcio->fcio_ilen;
1211 	pm.pm_data_buf  = fcio->fcio_ibuf;
1212 
1213 	rval = emlxs_fca_port_manage(port, &pm);
1214 
1215 	if (rval != FC_SUCCESS) {
1216 		fcio->fcio_errno = rval;
1217 		rval = EIO;
1218 	}
1219 
1220 done:
1221 	return (rval);
1222 
1223 } /* emlxs_fcio_download_fcode() */
1224 
1225 
1226 #ifndef _MULTI_DATAMODEL
1227 /* ARGSUSED */
1228 #endif
1229 static int32_t
1230 emlxs_fcio_get_adapter_attrs(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
1231 {
1232 	emlxs_hba_t	*hba = HBA;
1233 	int32_t		rval = 0;
1234 	uint32_t	use32 = 0;
1235 	emlxs_vpd_t	*vpd = &VPD;
1236 
1237 #ifdef	_MULTI_DATAMODEL
1238 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
1239 		use32 = 1;
1240 	}
1241 #endif	/* _MULTI_DATAMODEL */
1242 
1243 	if (use32) {
1244 		fc_hba_adapter_attributes32_t	*hba_attrs;
1245 
1246 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
1247 		    fcio->fcio_olen <
1248 		    sizeof (fc_hba_adapter_attributes32_t)) {
1249 			rval = EINVAL;
1250 			goto done;
1251 		}
1252 
1253 		hba_attrs =
1254 		    (fc_hba_adapter_attributes32_t *)fcio->fcio_obuf;
1255 
1256 		hba_attrs->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION;
1257 		(void) strncpy(hba_attrs->Manufacturer, "Emulex",
1258 		    (sizeof (hba_attrs->Manufacturer)-1));
1259 		(void) strncpy(hba_attrs->SerialNumber, vpd->serial_num,
1260 		    (sizeof (hba_attrs->SerialNumber)-1));
1261 		(void) strncpy(hba_attrs->Model, hba->model_info.model,
1262 		    (sizeof (hba_attrs->Model)-1));
1263 		(void) strncpy(hba_attrs->ModelDescription,
1264 		    hba->model_info.model_desc,
1265 		    (sizeof (hba_attrs->ModelDescription)-1));
1266 		bcopy((caddr_t)&port->wwnn,
1267 		    (caddr_t)&hba_attrs->NodeWWN, 8);
1268 		(void) strncpy((caddr_t)hba_attrs->NodeSymbolicName,
1269 		    (caddr_t)port->snn,
1270 		    (sizeof (hba_attrs->NodeSymbolicName)-1));
1271 		(void) snprintf(hba_attrs->HardwareVersion,
1272 		    (sizeof (hba_attrs->HardwareVersion)-1),
1273 		    "%x", vpd->biuRev);
1274 		(void) snprintf(hba_attrs->DriverVersion,
1275 		    (sizeof (hba_attrs->DriverVersion)-1),
1276 		    "%s (%s)", emlxs_version, emlxs_revision);
1277 		(void) strncpy(hba_attrs->OptionROMVersion,
1278 		    vpd->fcode_version,
1279 		    (sizeof (hba_attrs->OptionROMVersion)-1));
1280 		(void) snprintf(hba_attrs->FirmwareVersion,
1281 		    (sizeof (hba_attrs->FirmwareVersion)-1),
1282 		    "%s (%s)", vpd->fw_version, vpd->fw_label);
1283 		(void) strncpy(hba_attrs->DriverName, DRIVER_NAME,
1284 		    (sizeof (hba_attrs->DriverName)-1));
1285 		hba_attrs->VendorSpecificID =
1286 		    ((hba->model_info.device_id << 16) |
1287 		    PCI_VENDOR_ID_EMULEX);
1288 		hba_attrs->NumberOfPorts = hba->num_of_ports;
1289 	} else {
1290 		fc_hba_adapter_attributes_t	*hba_attrs;
1291 
1292 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
1293 		    fcio->fcio_olen <
1294 		    sizeof (fc_hba_adapter_attributes_t)) {
1295 			rval = EINVAL;
1296 			goto done;
1297 		}
1298 
1299 		hba_attrs =
1300 		    (fc_hba_adapter_attributes_t *)fcio->fcio_obuf;
1301 
1302 		hba_attrs->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION;
1303 		(void) strncpy(hba_attrs->Manufacturer, "Emulex",
1304 		    (sizeof (hba_attrs->Manufacturer)-1));
1305 		(void) strncpy(hba_attrs->SerialNumber, vpd->serial_num,
1306 		    (sizeof (hba_attrs->SerialNumber)-1));
1307 		(void) strncpy(hba_attrs->Model, hba->model_info.model,
1308 		    (sizeof (hba_attrs->Model)-1));
1309 		(void) strncpy(hba_attrs->ModelDescription,
1310 		    hba->model_info.model_desc,
1311 		    (sizeof (hba_attrs->ModelDescription)-1));
1312 		bcopy((caddr_t)&port->wwnn,
1313 		    (caddr_t)&hba_attrs->NodeWWN, 8);
1314 		(void) strncpy((caddr_t)hba_attrs->NodeSymbolicName,
1315 		    (caddr_t)port->snn,
1316 		    (sizeof (hba_attrs->NodeSymbolicName)-1));
1317 		(void) snprintf(hba_attrs->HardwareVersion,
1318 		    (sizeof (hba_attrs->HardwareVersion)-1),
1319 		    "%x", vpd->biuRev);
1320 		(void) snprintf(hba_attrs->DriverVersion,
1321 		    (sizeof (hba_attrs->DriverVersion)-1),
1322 		    "%s (%s)", emlxs_version, emlxs_revision);
1323 		(void) strncpy(hba_attrs->OptionROMVersion,
1324 		    vpd->fcode_version,
1325 		    (sizeof (hba_attrs->OptionROMVersion)-1));
1326 		(void) snprintf(hba_attrs->FirmwareVersion,
1327 		    (sizeof (hba_attrs->FirmwareVersion)-1),
1328 		    "%s (%s)", vpd->fw_version, vpd->fw_label);
1329 		(void) strncpy(hba_attrs->DriverName, DRIVER_NAME,
1330 		    (sizeof (hba_attrs->DriverName)-1));
1331 		hba_attrs->VendorSpecificID =
1332 		    ((hba->model_info.device_id << 16) |
1333 		    PCI_VENDOR_ID_EMULEX);
1334 		hba_attrs->NumberOfPorts = hba->num_of_ports;
1335 	}
1336 
1337 done:
1338 	return (rval);
1339 
1340 } /* emlxs_fcio_get_adapter_attrs() */
1341 
1342 
1343 #ifndef _MULTI_DATAMODEL
1344 /* ARGSUSED */
1345 #endif
1346 static int32_t
1347 emlxs_fcio_get_adapter_port_attrs(emlxs_port_t *port, fcio_t *fcio,
1348     int32_t mode)
1349 {
1350 	emlxs_hba_t	*hba = HBA;
1351 	int32_t		rval = 0;
1352 	uint32_t	use32 = 0;
1353 	emlxs_vpd_t	*vpd = &VPD;
1354 
1355 #ifdef	_MULTI_DATAMODEL
1356 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
1357 		use32 = 1;
1358 	}
1359 #endif	/* _MULTI_DATAMODEL */
1360 
1361 	if (use32) {
1362 		fc_hba_port_attributes32_t  *port_attrs;
1363 		uint32_t value1;
1364 		uint32_t value2;
1365 
1366 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
1367 		    fcio->fcio_olen <
1368 		    sizeof (fc_hba_port_attributes32_t)) {
1369 			rval = EINVAL;
1370 			goto done;
1371 		}
1372 
1373 		port_attrs =
1374 		    (fc_hba_port_attributes32_t *)fcio->fcio_obuf;
1375 
1376 		port_attrs->version    = FC_HBA_PORT_ATTRIBUTES_VERSION;
1377 		port_attrs->lastChange = 0;
1378 		port_attrs->fp_minor   = 0;
1379 		bcopy((caddr_t)&port->wwnn,
1380 		    (caddr_t)&port_attrs->NodeWWN, 8);
1381 		bcopy((caddr_t)&port->wwpn,
1382 		    (caddr_t)&port_attrs->PortWWN, 8);
1383 
1384 		if ((port->mode != MODE_TARGET) ||
1385 		    (port->ulp_statec == FC_STATE_OFFLINE)) {
1386 			/* port_attrs->PortFcId   */
1387 			/* port_attrs->PortType   */
1388 			/* port_attrs->PortSpeed  */
1389 			/* port_attrs->FabricName */
1390 			port_attrs->PortState =
1391 			    FC_HBA_PORTSTATE_OFFLINE;
1392 		} else {
1393 			port_attrs->PortFcId  = port->did;
1394 			port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE;
1395 
1396 			if (hba->topology == TOPOLOGY_LOOP) {
1397 				if (hba->flag & FC_FABRIC_ATTACHED) {
1398 					port_attrs->PortType =
1399 					    FC_HBA_PORTTYPE_NLPORT;
1400 				} else {
1401 					port_attrs->PortType =
1402 					    FC_HBA_PORTTYPE_LPORT;
1403 				}
1404 
1405 			} else {
1406 				if (hba->flag & FC_PT_TO_PT) {
1407 					port_attrs->PortType =
1408 					    FC_HBA_PORTTYPE_PTP;
1409 				} else {
1410 					port_attrs->PortType =
1411 					    FC_HBA_PORTTYPE_NPORT;
1412 				}
1413 			}
1414 
1415 			if (hba->flag & FC_FABRIC_ATTACHED) {
1416 				bcopy(&port->fabric_sparam.portName,
1417 				    (caddr_t)&port_attrs->FabricName,
1418 				    sizeof (port_attrs->FabricName));
1419 			}
1420 
1421 			switch (hba->linkspeed) {
1422 			case 0:
1423 				port_attrs->PortSpeed =
1424 				    HBA_PORTSPEED_1GBIT;
1425 				break;
1426 			case LA_1GHZ_LINK:
1427 				port_attrs->PortSpeed =
1428 				    HBA_PORTSPEED_1GBIT;
1429 				break;
1430 			case LA_2GHZ_LINK:
1431 				port_attrs->PortSpeed =
1432 				    HBA_PORTSPEED_2GBIT;
1433 				break;
1434 			case LA_4GHZ_LINK:
1435 				port_attrs->PortSpeed =
1436 				    HBA_PORTSPEED_4GBIT;
1437 				break;
1438 			case LA_8GHZ_LINK:
1439 				port_attrs->PortSpeed =
1440 				    HBA_PORTSPEED_8GBIT;
1441 				break;
1442 			case LA_10GHZ_LINK:
1443 				port_attrs->PortSpeed =
1444 				    HBA_PORTSPEED_10GBIT;
1445 				break;
1446 			case LA_16GHZ_LINK:
1447 				port_attrs->PortSpeed =
1448 				    HBA_PORTSPEED_16GBIT;
1449 				break;
1450 			default:
1451 				port_attrs->PortSpeed =
1452 				    HBA_PORTSPEED_UNKNOWN;
1453 			}
1454 
1455 			port_attrs->NumberofDiscoveredPorts =
1456 			    emlxs_nport_count(port);
1457 		}
1458 
1459 		port_attrs->PortSupportedClassofService =
1460 		    LE_SWAP32(FC_NS_CLASS3);
1461 		(void) strncpy((caddr_t)port_attrs->PortSymbolicName,
1462 		    (caddr_t)port->spn,
1463 		    (sizeof (port_attrs->PortSymbolicName)-1));
1464 
1465 		/* Set the hba speed limit */
1466 		if (vpd->link_speed & LMT_16GB_CAPABLE) {
1467 			port_attrs->PortSupportedSpeed |=
1468 			    FC_HBA_PORTSPEED_16GBIT;
1469 		}
1470 		if (vpd->link_speed & LMT_10GB_CAPABLE) {
1471 			port_attrs->PortSupportedSpeed |=
1472 			    FC_HBA_PORTSPEED_10GBIT;
1473 		}
1474 		if (vpd->link_speed & LMT_8GB_CAPABLE) {
1475 			port_attrs->PortSupportedSpeed |=
1476 			    FC_HBA_PORTSPEED_8GBIT;
1477 		}
1478 		if (vpd->link_speed & LMT_4GB_CAPABLE) {
1479 			port_attrs->PortSupportedSpeed |=
1480 			    FC_HBA_PORTSPEED_4GBIT;
1481 		}
1482 		if (vpd->link_speed & LMT_2GB_CAPABLE) {
1483 			port_attrs->PortSupportedSpeed |=
1484 			    FC_HBA_PORTSPEED_2GBIT;
1485 		}
1486 		if (vpd->link_speed & LMT_1GB_CAPABLE) {
1487 			port_attrs->PortSupportedSpeed |=
1488 			    FC_HBA_PORTSPEED_1GBIT;
1489 		}
1490 
1491 		value1 = 0x00000120;
1492 		value2 = 0x00000001;
1493 
1494 		bcopy((caddr_t)&value1,
1495 		    (caddr_t)&port_attrs->PortSupportedFc4Types[0], 4);
1496 		bcopy((caddr_t)&value2,
1497 		    (caddr_t)&port_attrs->PortSupportedFc4Types[4], 4);
1498 
1499 		bcopy((caddr_t)&value1,
1500 		    (caddr_t)&port_attrs->PortActiveFc4Types[0], 4);
1501 		bcopy((caddr_t)&value2,
1502 		    (caddr_t)&port_attrs->PortActiveFc4Types[4], 4);
1503 
1504 		port_attrs->PortMaxFrameSize = FF_FRAME_SIZE;
1505 
1506 	} else {
1507 
1508 		fc_hba_port_attributes_t  *port_attrs;
1509 		uint32_t value1;
1510 		uint32_t value2;
1511 
1512 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
1513 		    fcio->fcio_olen <
1514 		    sizeof (fc_hba_port_attributes_t)) {
1515 			rval = EINVAL;
1516 			goto done;
1517 		}
1518 
1519 		port_attrs =
1520 		    (fc_hba_port_attributes_t *)fcio->fcio_obuf;
1521 
1522 		port_attrs->version    = FC_HBA_PORT_ATTRIBUTES_VERSION;
1523 		port_attrs->lastChange = 0;
1524 		port_attrs->fp_minor   = 0;
1525 		bcopy((caddr_t)&port->wwnn,
1526 		    (caddr_t)&port_attrs->NodeWWN, 8);
1527 		bcopy((caddr_t)&port->wwpn,
1528 		    (caddr_t)&port_attrs->PortWWN, 8);
1529 
1530 		if (port->mode != MODE_TARGET ||
1531 		    (port->ulp_statec == FC_STATE_OFFLINE)) {
1532 			/* port_attrs->PortFcId   */
1533 			/* port_attrs->PortType   */
1534 			/* port_attrs->PortSpeed  */
1535 			/* port_attrs->FabricName */
1536 			port_attrs->PortState =
1537 			    FC_HBA_PORTSTATE_OFFLINE;
1538 		} else {
1539 			port_attrs->PortFcId  = port->did;
1540 			port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE;
1541 
1542 			if (hba->topology == TOPOLOGY_LOOP) {
1543 				if (hba->flag & FC_FABRIC_ATTACHED) {
1544 					port_attrs->PortType =
1545 					    FC_HBA_PORTTYPE_NLPORT;
1546 				} else {
1547 					port_attrs->PortType =
1548 					    FC_HBA_PORTTYPE_LPORT;
1549 				}
1550 
1551 			} else {
1552 				if (hba->flag & FC_PT_TO_PT) {
1553 					port_attrs->PortType =
1554 					    FC_HBA_PORTTYPE_PTP;
1555 				} else {
1556 					port_attrs->PortType =
1557 					    FC_HBA_PORTTYPE_NPORT;
1558 				}
1559 			}
1560 
1561 			if (hba->flag & FC_FABRIC_ATTACHED) {
1562 				bcopy(&port->fabric_sparam.portName,
1563 				    (caddr_t)&port_attrs->FabricName,
1564 				    sizeof (port_attrs->FabricName));
1565 			}
1566 
1567 			switch (hba->linkspeed) {
1568 			case 0:
1569 				port_attrs->PortSpeed =
1570 				    HBA_PORTSPEED_1GBIT;
1571 				break;
1572 			case LA_1GHZ_LINK:
1573 				port_attrs->PortSpeed =
1574 				    HBA_PORTSPEED_1GBIT;
1575 				break;
1576 			case LA_2GHZ_LINK:
1577 				port_attrs->PortSpeed =
1578 				    HBA_PORTSPEED_2GBIT;
1579 				break;
1580 			case LA_4GHZ_LINK:
1581 				port_attrs->PortSpeed =
1582 				    HBA_PORTSPEED_4GBIT;
1583 				break;
1584 			case LA_8GHZ_LINK:
1585 				port_attrs->PortSpeed =
1586 				    HBA_PORTSPEED_8GBIT;
1587 				break;
1588 			case LA_10GHZ_LINK:
1589 				port_attrs->PortSpeed =
1590 				    HBA_PORTSPEED_10GBIT;
1591 				break;
1592 			case LA_16GHZ_LINK:
1593 				port_attrs->PortSpeed =
1594 				    HBA_PORTSPEED_16GBIT;
1595 				break;
1596 			default:
1597 				port_attrs->PortSpeed =
1598 				    HBA_PORTSPEED_UNKNOWN;
1599 			}
1600 
1601 			port_attrs->NumberofDiscoveredPorts =
1602 			    emlxs_nport_count(port);
1603 		}
1604 
1605 		port_attrs->PortSupportedClassofService =
1606 		    LE_SWAP32(FC_NS_CLASS3);
1607 		(void) strncpy((caddr_t)port_attrs->PortSymbolicName,
1608 		    (caddr_t)port->spn,
1609 		    (sizeof (port_attrs->PortSymbolicName)-1));
1610 
1611 		/* Set the hba speed limit */
1612 		if (vpd->link_speed & LMT_16GB_CAPABLE) {
1613 			port_attrs->PortSupportedSpeed |=
1614 			    FC_HBA_PORTSPEED_16GBIT;
1615 		}
1616 		if (vpd->link_speed & LMT_10GB_CAPABLE) {
1617 			port_attrs->PortSupportedSpeed |=
1618 			    FC_HBA_PORTSPEED_10GBIT;
1619 		}
1620 		if (vpd->link_speed & LMT_8GB_CAPABLE) {
1621 			port_attrs->PortSupportedSpeed |=
1622 			    FC_HBA_PORTSPEED_8GBIT;
1623 		}
1624 		if (vpd->link_speed & LMT_4GB_CAPABLE) {
1625 			port_attrs->PortSupportedSpeed |=
1626 			    FC_HBA_PORTSPEED_4GBIT;
1627 		}
1628 		if (vpd->link_speed & LMT_2GB_CAPABLE) {
1629 			port_attrs->PortSupportedSpeed |=
1630 			    FC_HBA_PORTSPEED_2GBIT;
1631 		}
1632 		if (vpd->link_speed & LMT_1GB_CAPABLE) {
1633 			port_attrs->PortSupportedSpeed |=
1634 			    FC_HBA_PORTSPEED_1GBIT;
1635 		}
1636 
1637 		value1 = 0x00000120;
1638 		value2 = 0x00000001;
1639 
1640 		bcopy((caddr_t)&value1,
1641 		    (caddr_t)&port_attrs->PortSupportedFc4Types[0], 4);
1642 		bcopy((caddr_t)&value2,
1643 		    (caddr_t)&port_attrs->PortSupportedFc4Types[4], 4);
1644 
1645 		bcopy((caddr_t)&value1,
1646 		    (caddr_t)&port_attrs->PortActiveFc4Types[0], 4);
1647 		bcopy((caddr_t)&value2,
1648 		    (caddr_t)&port_attrs->PortActiveFc4Types[4], 4);
1649 
1650 		port_attrs->PortMaxFrameSize = FF_FRAME_SIZE;
1651 	}
1652 
1653 done:
1654 	return (rval);
1655 
1656 } /* emlxs_fcio_get_adapter_port_attrs() */
1657 
1658 
1659 /*ARGSUSED*/
1660 static int32_t
1661 emlxs_fcio_get_node_id(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
1662 {
1663 	int32_t		rval = 0;
1664 	fc_fca_pm_t	pm;
1665 
1666 	if (fcio->fcio_xfer != FCIO_XFER_READ ||
1667 	    fcio->fcio_olen < sizeof (fc_rnid_t)) {
1668 		rval = EINVAL;
1669 		goto done;
1670 	}
1671 
1672 	bzero((caddr_t)&pm, sizeof (pm));
1673 
1674 	pm.pm_cmd_flags = FC_FCA_PM_READ;
1675 	pm.pm_cmd_code  = FC_PORT_GET_NODE_ID;
1676 	pm.pm_data_len  = fcio->fcio_olen;
1677 	pm.pm_data_buf  = fcio->fcio_obuf;
1678 
1679 	rval = emlxs_fca_port_manage(port, &pm);
1680 
1681 	if (rval != FC_SUCCESS) {
1682 		fcio->fcio_errno = rval;
1683 		rval = EIO;
1684 	}
1685 
1686 done:
1687 	return (rval);
1688 
1689 } /* emlxs_fcio_get_node_id() */
1690 
1691 
1692 /*ARGSUSED*/
1693 static int32_t
1694 emlxs_fcio_set_node_id(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
1695 {
1696 	int32_t		rval = 0;
1697 	fc_fca_pm_t	pm;
1698 
1699 	if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
1700 	    fcio->fcio_ilen < sizeof (fc_rnid_t)) {
1701 		rval = EINVAL;
1702 		goto done;
1703 	}
1704 
1705 	bzero((caddr_t)&pm, sizeof (pm));
1706 
1707 	pm.pm_cmd_flags = FC_FCA_PM_READ;
1708 	pm.pm_cmd_code  = FC_PORT_SET_NODE_ID;
1709 	pm.pm_data_len  = fcio->fcio_ilen;
1710 	pm.pm_data_buf  = fcio->fcio_ibuf;
1711 
1712 	rval = emlxs_fca_port_manage(port, &pm);
1713 
1714 	if (rval != FC_SUCCESS) {
1715 		fcio->fcio_errno = rval;
1716 		rval = EIO;
1717 	}
1718 
1719 done:
1720 	return (rval);
1721 
1722 } /* emlxs_fcio_set_node_id() */
1723 
1724 
1725 
1726 
1727 /*ARGSUSED*/
1728 static int32_t
1729 emlxs_fcio_get_num_devs(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
1730 {
1731 	int32_t		rval = 0;
1732 
1733 	if (fcio->fcio_xfer != FCIO_XFER_READ ||
1734 	    fcio->fcio_olen < sizeof (uint32_t)) {
1735 		rval = EINVAL;
1736 		goto done;
1737 	}
1738 
1739 	if (port->mode == MODE_TARGET) {
1740 		*(uint32_t *)fcio->fcio_obuf = emlxs_nport_count(port);
1741 	}
1742 
1743 done:
1744 	return (rval);
1745 
1746 } /* emlxs_fcio_get_num_devs() */
1747 
1748 
1749 #ifndef _MULTI_DATAMODEL
1750 /* ARGSUSED */
1751 #endif
1752 static int32_t
1753 emlxs_fcio_get_dev_list(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
1754 {
1755 	emlxs_hba_t	*hba = HBA;
1756 	int32_t		rval = 0;
1757 	uint32_t	use32 = 0;
1758 
1759 #ifdef	_MULTI_DATAMODEL
1760 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
1761 		use32 = 1;
1762 	}
1763 #endif	/* _MULTI_DATAMODEL */
1764 
1765 	if (use32) {
1766 		fc_port_dev32_t *port_dev;
1767 		uint32_t max_count;
1768 		uint32_t i;
1769 		uint32_t j;
1770 		emlxs_node_t *nlp;
1771 		uint32_t nport_count = 0;
1772 
1773 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
1774 		    fcio->fcio_alen < sizeof (uint32_t)) {
1775 			rval = EINVAL;
1776 			goto done;
1777 		}
1778 
1779 		port_dev = (fc_port_dev32_t *)fcio->fcio_obuf;
1780 		max_count = fcio->fcio_olen / sizeof (fc_port_dev32_t);
1781 
1782 		rw_enter(&port->node_rwlock, RW_READER);
1783 
1784 		if (port->mode == MODE_TARGET) {
1785 			nport_count = emlxs_nport_count(port);
1786 		}
1787 
1788 		*(uint32_t *)fcio->fcio_abuf = nport_count;
1789 
1790 		if (nport_count == 0) {
1791 			rw_exit(&port->node_rwlock);
1792 
1793 			fcio->fcio_errno = FC_NO_MAP;
1794 			rval = EIO;
1795 			goto done;
1796 		}
1797 
1798 		if (nport_count > max_count) {
1799 			rw_exit(&port->node_rwlock);
1800 
1801 			fcio->fcio_errno = FC_TOOMANY;
1802 			rval = EIO;
1803 			goto done;
1804 		}
1805 
1806 		for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1807 			nlp = port->node_table[i];
1808 			while (nlp != NULL) {
1809 			if ((nlp->nlp_DID & 0xFFF000) != 0xFFF000) {
1810 				port_dev->dev_dtype = 0;
1811 				port_dev->dev_type[0] =
1812 				    BE_SWAP32(0x00000100);
1813 				port_dev->dev_state =
1814 				    PORT_DEVICE_LOGGED_IN;
1815 				port_dev->dev_did.port_id =
1816 				    nlp->nlp_DID;
1817 				port_dev->dev_did.priv_lilp_posit = 0;
1818 				port_dev->dev_hard_addr.hard_addr = 0;
1819 
1820 		if (hba->topology == TOPOLOGY_LOOP) {
1821 			for (j = 1; j < port->alpa_map[0]; j++) {
1822 				if (nlp->nlp_DID == port->alpa_map[j]) {
1823 					port_dev->dev_did.priv_lilp_posit = j-1;
1824 					goto done;
1825 				}
1826 			}
1827 			port_dev->dev_hard_addr.hard_addr = nlp->nlp_DID;
1828 		}
1829 
1830 				bcopy((caddr_t)&nlp->nlp_portname,
1831 				    (caddr_t)&port_dev->dev_pwwn, 8);
1832 				bcopy((caddr_t)&nlp->nlp_nodename,
1833 				    (caddr_t)&port_dev->dev_nwwn, 8);
1834 				port_dev++;
1835 			}
1836 
1837 			nlp = (NODELIST *) nlp->nlp_list_next;
1838 			}
1839 		}
1840 		rw_exit(&port->node_rwlock);
1841 
1842 	} else {
1843 
1844 		fc_port_dev_t *port_dev;
1845 		uint32_t max_count;
1846 		uint32_t i;
1847 		uint32_t j;
1848 		emlxs_node_t *nlp;
1849 		uint32_t nport_count = 0;
1850 
1851 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
1852 		    fcio->fcio_alen < sizeof (uint32_t)) {
1853 			rval = EINVAL;
1854 			goto done;
1855 		}
1856 
1857 		port_dev = (fc_port_dev_t *)fcio->fcio_obuf;
1858 		max_count = fcio->fcio_olen / sizeof (fc_port_dev_t);
1859 
1860 		rw_enter(&port->node_rwlock, RW_READER);
1861 
1862 		if (port->mode == MODE_TARGET) {
1863 			nport_count = emlxs_nport_count(port);
1864 		}
1865 
1866 		*(uint32_t *)fcio->fcio_abuf = nport_count;
1867 
1868 		if (nport_count == 0) {
1869 			rw_exit(&port->node_rwlock);
1870 
1871 			fcio->fcio_errno = FC_NO_MAP;
1872 			rval = EIO;
1873 			goto done;
1874 		}
1875 
1876 		if (nport_count > max_count) {
1877 			rw_exit(&port->node_rwlock);
1878 
1879 			fcio->fcio_errno = FC_TOOMANY;
1880 			rval = EIO;
1881 			goto done;
1882 		}
1883 
1884 		for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1885 			nlp = port->node_table[i];
1886 			while (nlp != NULL) {
1887 			if ((nlp->nlp_DID & 0xFFF000) != 0xFFF000) {
1888 				port_dev->dev_dtype = 0;
1889 				port_dev->dev_type[0] =
1890 				    BE_SWAP32(0x00000100);
1891 				port_dev->dev_state =
1892 				    PORT_DEVICE_LOGGED_IN;
1893 				port_dev->dev_did.port_id =
1894 				    nlp->nlp_DID;
1895 				port_dev->dev_did.priv_lilp_posit = 0;
1896 				port_dev->dev_hard_addr.hard_addr = 0;
1897 
1898 		if (hba->topology == TOPOLOGY_LOOP) {
1899 			for (j = 1; j < port->alpa_map[0]; j++) {
1900 				if (nlp->nlp_DID == port->alpa_map[j]) {
1901 					port_dev->dev_did.priv_lilp_posit = j-1;
1902 					goto done;
1903 				}
1904 			}
1905 			port_dev->dev_hard_addr.hard_addr = nlp->nlp_DID;
1906 		}
1907 
1908 				bcopy((caddr_t)&nlp->nlp_portname,
1909 				    (caddr_t)&port_dev->dev_pwwn, 8);
1910 				bcopy((caddr_t)&nlp->nlp_nodename,
1911 				    (caddr_t)&port_dev->dev_nwwn, 8);
1912 				port_dev++;
1913 			}
1914 
1915 			nlp = (NODELIST *) nlp->nlp_list_next;
1916 			}
1917 		}
1918 		rw_exit(&port->node_rwlock);
1919 	}
1920 
1921 done:
1922 	return (rval);
1923 
1924 } /* emlxs_fcio_get_dev_list() */
1925 
1926 
1927 /*ARGSUSED*/
1928 static int32_t
1929 emlxs_fcio_get_logi_params(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
1930 {
1931 	int32_t		rval = 0;
1932 	uint8_t 	null_wwn[8];
1933 	uint8_t 	*wwpn;
1934 	emlxs_node_t	*ndlp;
1935 
1936 	if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
1937 	    (fcio->fcio_xfer & FCIO_XFER_READ) == 0 ||
1938 	    (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) {
1939 		rval = EINVAL;
1940 		goto done;
1941 	}
1942 
1943 	bzero(null_wwn, 8);
1944 	wwpn = (uint8_t *)fcio->fcio_ibuf;
1945 
1946 	if ((bcmp((caddr_t)wwpn, (caddr_t)null_wwn, 8) == 0) ||
1947 	    (bcmp((caddr_t)wwpn, (caddr_t)&port->wwpn, 8) == 0)) {
1948 		bcopy((caddr_t)&port->sparam,
1949 		    (caddr_t)fcio->fcio_obuf, fcio->fcio_olen);
1950 	} else {
1951 		ndlp = emlxs_node_find_wwpn(port, wwpn, 1);
1952 
1953 		if (ndlp) {
1954 			bcopy((caddr_t)&ndlp->sparm,
1955 			    (caddr_t)fcio->fcio_obuf,
1956 			    fcio->fcio_olen);
1957 		} else {
1958 			rval = ENXIO;
1959 		}
1960 	}
1961 
1962 done:
1963 	return (rval);
1964 
1965 } /* emlxs_fcio_get_logi_params() */
1966 
1967 
1968 /*ARGSUSED*/
1969 static int32_t
1970 emlxs_fcio_get_state(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
1971 {
1972 	int32_t		rval = 0;
1973 	uint8_t		null_wwn[8];
1974 	uint32_t	*statep;
1975 	uint8_t 	*wwpn;
1976 	emlxs_node_t	*ndlp;
1977 
1978 	if (fcio->fcio_ilen != 8 ||
1979 	    fcio->fcio_olen != 4 ||
1980 	    (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 ||
1981 	    (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
1982 		rval = EINVAL;
1983 		goto done;
1984 	}
1985 
1986 	bzero(null_wwn, 8);
1987 	wwpn   = (uint8_t *)fcio->fcio_ibuf;
1988 	statep = (uint32_t *)fcio->fcio_obuf;
1989 
1990 	if ((bcmp((caddr_t)wwpn, (caddr_t)null_wwn, 8) == 0) ||
1991 	    (bcmp((caddr_t)wwpn, (caddr_t)&port->wwpn, 8) == 0)) {
1992 		*statep = PORT_DEVICE_VALID;
1993 	} else {
1994 		ndlp = emlxs_node_find_wwpn(port, wwpn, 1);
1995 
1996 		if (ndlp) {
1997 			*statep = PORT_DEVICE_VALID;
1998 		} else {
1999 			*statep = PORT_DEVICE_INVALID;
2000 		}
2001 	}
2002 
2003 done:
2004 	return (rval);
2005 
2006 } /* emlxs_fcio_get_state() */
2007 
2008 
2009 /*ARGSUSED*/
2010 static int32_t
2011 emlxs_fcio_get_topology(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
2012 {
2013 	emlxs_hba_t	*hba = HBA;
2014 	int32_t		rval = 0;
2015 	uint32_t	*tp;
2016 	emlxs_node_t	*ndlp;
2017 
2018 	if (fcio->fcio_olen != 4 ||
2019 	    (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
2020 		rval = EINVAL;
2021 		goto done;
2022 	}
2023 
2024 	tp = (uint32_t *)fcio->fcio_obuf;
2025 
2026 	if ((port->mode != MODE_TARGET) ||
2027 	    (port->ulp_statec == FC_STATE_OFFLINE)) {
2028 		*tp = FC_TOP_UNKNOWN;
2029 	} else {
2030 		ndlp = emlxs_node_find_did(port, FABRIC_DID, 1);
2031 
2032 		if (hba->topology == TOPOLOGY_LOOP) {
2033 			if (ndlp) {
2034 				*tp = FC_TOP_PUBLIC_LOOP;
2035 			} else {
2036 				*tp = FC_TOP_PRIVATE_LOOP;
2037 			}
2038 		} else {
2039 			if (ndlp) {
2040 				*tp = FC_TOP_FABRIC;
2041 			} else {
2042 				*tp = FC_TOP_PT_PT;
2043 			}
2044 		}
2045 	}
2046 
2047 done:
2048 	return (rval);
2049 
2050 } /* emlxs_fcio_get_topology() */
2051 
2052 
2053 /*ARGSUSED*/
2054 static int32_t
2055 emlxs_fcio_get_link_status(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
2056 {
2057 	int32_t		rval = 0;
2058 	fc_portid_t	*portid;
2059 	fc_rls_acc_t	*rls;
2060 	fc_fca_pm_t	pm;
2061 
2062 	if (fcio->fcio_ilen != sizeof (fc_portid_t) ||
2063 	    fcio->fcio_olen != sizeof (fc_rls_acc_t) ||
2064 	    fcio->fcio_xfer != FCIO_XFER_RW) {
2065 		rval = EINVAL;
2066 		goto done;
2067 	}
2068 
2069 	if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) &&
2070 	    (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) {
2071 		rval = EINVAL;
2072 		goto done;
2073 	}
2074 
2075 	portid = (fc_portid_t *)fcio->fcio_ibuf;
2076 	rls    = (fc_rls_acc_t *)fcio->fcio_obuf;
2077 
2078 	if (portid->port_id == 0 || portid->port_id == port->did) {
2079 		bzero((caddr_t)&pm, sizeof (pm));
2080 
2081 		pm.pm_cmd_flags = FC_FCA_PM_READ;
2082 		pm.pm_cmd_code  = FC_PORT_RLS;
2083 		pm.pm_data_len  = sizeof (fc_rls_acc_t);
2084 		pm.pm_data_buf  = (caddr_t)rls;
2085 
2086 		rval = emlxs_fca_port_manage(port, &pm);
2087 
2088 		if (rval != FC_SUCCESS) {
2089 			fcio->fcio_errno = rval;
2090 			rval = EIO;
2091 		}
2092 	} else {
2093 		rval = ENOTSUP;
2094 	}
2095 
2096 done:
2097 	return (rval);
2098 
2099 } /* emlxs_fcio_get_link_status() */
2100 
2101 
2102 /*ARGSUSED*/
2103 static int32_t
2104 emlxs_fcio_get_other_adapter_ports(emlxs_port_t *port, fcio_t *fcio,
2105     int32_t mode)
2106 {
2107 	emlxs_hba_t	*hba = HBA;
2108 	int32_t		rval = 0;
2109 	uint32_t	index;
2110 	char		*path;
2111 
2112 	if (fcio->fcio_olen < MAXPATHLEN ||
2113 	    fcio->fcio_ilen != sizeof (uint32_t)) {
2114 		rval = EINVAL;
2115 		goto done;
2116 	}
2117 
2118 	index = *(uint32_t *)fcio->fcio_ibuf;
2119 	path  = (char *)fcio->fcio_obuf;
2120 
2121 	if (index > hba->vpi_max) {
2122 		fcio->fcio_errno = FC_BADPORT;
2123 		rval = EFAULT;
2124 		goto done;
2125 	}
2126 
2127 	(void) ddi_pathname(hba->dip, path);
2128 
2129 done:
2130 	return (rval);
2131 
2132 } /* emlxs_fcio_get_other_adapter_ports() */
2133 
2134 
2135 /*ARGSUSED*/
2136 static int32_t
2137 emlxs_fcio_get_disc_port_attrs(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
2138 {
2139 	emlxs_hba_t	*hba = HBA;
2140 	int32_t		rval = 0;
2141 	uint32_t	index;
2142 	emlxs_node_t	*ndlp;
2143 	uint32_t	use32 = 0;
2144 
2145 #ifdef	_MULTI_DATAMODEL
2146 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2147 		use32 = 1;
2148 	}
2149 #endif	/* _MULTI_DATAMODEL */
2150 
2151 	if (use32) {
2152 		fc_hba_port_attributes32_t  *port_attrs;
2153 
2154 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
2155 		    fcio->fcio_ilen < sizeof (uint32_t) ||
2156 		    fcio->fcio_olen < sizeof (fc_hba_port_attributes32_t)) {
2157 			rval = EINVAL;
2158 			goto done;
2159 		}
2160 
2161 		index = *(uint32_t *)fcio->fcio_ibuf;
2162 		ndlp  = emlxs_node_find_index(port, index, 1);
2163 
2164 		if (!ndlp) {
2165 			fcio->fcio_errno = FC_OUTOFBOUNDS;
2166 			rval = EINVAL;
2167 			goto done;
2168 		}
2169 
2170 		port_attrs = (fc_hba_port_attributes32_t *)fcio->fcio_obuf;
2171 
2172 		port_attrs->version    = FC_HBA_PORT_ATTRIBUTES_VERSION;
2173 		/* port_attrs->lastChange */
2174 		/* port_attrs->fp_minor   */
2175 		bcopy((caddr_t)&ndlp->nlp_nodename,
2176 		    (caddr_t)&port_attrs->NodeWWN, 8);
2177 		bcopy((caddr_t)&ndlp->nlp_portname,
2178 		    (caddr_t)&port_attrs->PortWWN, 8);
2179 
2180 		port_attrs->PortSpeed = HBA_PORTSPEED_UNKNOWN;
2181 		port_attrs->PortType  = FC_HBA_PORTTYPE_UNKNOWN;
2182 		port_attrs->PortState = FC_HBA_PORTSTATE_OFFLINE;
2183 
2184 		if ((port->mode == MODE_TARGET) &&
2185 		    (hba->state >= FC_LINK_UP)) {
2186 			port_attrs->PortFcId  = ndlp->nlp_DID;
2187 			port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE;
2188 
2189 			/* no switch */
2190 			if (!(hba->flag & FC_FABRIC_ATTACHED)) {
2191 				if (hba->topology == TOPOLOGY_LOOP) {
2192 					port_attrs->PortType =
2193 					    FC_HBA_PORTTYPE_LPORT;
2194 				} else {
2195 					port_attrs->PortType =
2196 					    FC_HBA_PORTTYPE_PTP;
2197 				}
2198 
2199 				/* We share a common speed */
2200 				switch (hba->linkspeed) {
2201 				case 0:
2202 					port_attrs->PortSpeed =
2203 					    HBA_PORTSPEED_1GBIT;
2204 					break;
2205 				case LA_1GHZ_LINK:
2206 					port_attrs->PortSpeed =
2207 					    HBA_PORTSPEED_1GBIT;
2208 					break;
2209 				case LA_2GHZ_LINK:
2210 					port_attrs->PortSpeed =
2211 					    HBA_PORTSPEED_2GBIT;
2212 					break;
2213 				case LA_4GHZ_LINK:
2214 					port_attrs->PortSpeed =
2215 					    HBA_PORTSPEED_4GBIT;
2216 					break;
2217 				case LA_8GHZ_LINK:
2218 					port_attrs->PortSpeed =
2219 					    HBA_PORTSPEED_8GBIT;
2220 					break;
2221 				case LA_10GHZ_LINK:
2222 					port_attrs->PortSpeed =
2223 					    HBA_PORTSPEED_10GBIT;
2224 					break;
2225 				case LA_16GHZ_LINK:
2226 					port_attrs->PortSpeed =
2227 					    HBA_PORTSPEED_16GBIT;
2228 					break;
2229 				}
2230 			}
2231 			/* public loop */
2232 			else if (hba->topology == TOPOLOGY_LOOP) {
2233 				/* Check for common area and domain */
2234 				if ((ndlp->nlp_DID & 0xFFFF00) ==
2235 				    (port->did & 0xFFFF00)) {
2236 					port_attrs->PortType =
2237 					    FC_HBA_PORTTYPE_NLPORT;
2238 
2239 					/* We share a common speed */
2240 					switch (hba->linkspeed) {
2241 					case 0:
2242 						port_attrs->PortSpeed =
2243 						    HBA_PORTSPEED_1GBIT;
2244 						break;
2245 					case LA_1GHZ_LINK:
2246 						port_attrs->PortSpeed =
2247 						    HBA_PORTSPEED_1GBIT;
2248 						break;
2249 					case LA_2GHZ_LINK:
2250 						port_attrs->PortSpeed =
2251 						    HBA_PORTSPEED_2GBIT;
2252 						break;
2253 					case LA_4GHZ_LINK:
2254 						port_attrs->PortSpeed =
2255 						    HBA_PORTSPEED_4GBIT;
2256 						break;
2257 					case LA_8GHZ_LINK:
2258 						port_attrs->PortSpeed =
2259 						    HBA_PORTSPEED_8GBIT;
2260 						break;
2261 					case LA_10GHZ_LINK:
2262 						port_attrs->PortSpeed =
2263 						    HBA_PORTSPEED_10GBIT;
2264 						break;
2265 					case LA_16GHZ_LINK:
2266 						port_attrs->PortSpeed =
2267 						    HBA_PORTSPEED_16GBIT;
2268 						break;
2269 					}
2270 				}
2271 			}
2272 		}
2273 
2274 		port_attrs->PortSupportedClassofService =
2275 		    LE_SWAP32(FC_NS_CLASS3);
2276 		/* port_attrs->PortSymbolicName		*/
2277 		/* port_attrs->PortSupportedSpeed	*/
2278 		/* port_attrs->PortSupportedFc4Types	*/
2279 		/* port_attrs->PortActiveFc4Types	*/
2280 		/* port_attrs->PortMaxFrameSize		*/
2281 		/* port_attrs->NumberofDiscoveredPorts	*/
2282 
2283 	} else {
2284 		fc_hba_port_attributes_t  *port_attrs;
2285 
2286 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
2287 		    fcio->fcio_ilen < sizeof (uint32_t) ||
2288 		    fcio->fcio_olen < sizeof (fc_hba_port_attributes_t)) {
2289 			rval = EINVAL;
2290 			goto done;
2291 		}
2292 
2293 		index = *(uint32_t *)fcio->fcio_ibuf;
2294 		ndlp  = emlxs_node_find_index(port, index, 1);
2295 
2296 		if (!ndlp) {
2297 			fcio->fcio_errno = FC_OUTOFBOUNDS;
2298 			rval = EINVAL;
2299 			goto done;
2300 		}
2301 
2302 		port_attrs = (fc_hba_port_attributes_t *)fcio->fcio_obuf;
2303 
2304 		port_attrs->version    = FC_HBA_PORT_ATTRIBUTES_VERSION;
2305 		/* port_attrs->lastChange */
2306 		/* port_attrs->fp_minor   */
2307 		bcopy((caddr_t)&ndlp->nlp_nodename,
2308 		    (caddr_t)&port_attrs->NodeWWN, 8);
2309 		bcopy((caddr_t)&ndlp->nlp_portname,
2310 		    (caddr_t)&port_attrs->PortWWN, 8);
2311 
2312 		port_attrs->PortSpeed = HBA_PORTSPEED_UNKNOWN;
2313 		port_attrs->PortType  = FC_HBA_PORTTYPE_UNKNOWN;
2314 		port_attrs->PortState = FC_HBA_PORTSTATE_OFFLINE;
2315 
2316 		if ((port->mode == MODE_TARGET) &&
2317 		    (hba->state >= FC_LINK_UP)) {
2318 			port_attrs->PortFcId  = ndlp->nlp_DID;
2319 			port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE;
2320 
2321 			/* no switch */
2322 			if (!(hba->flag & FC_FABRIC_ATTACHED)) {
2323 				if (hba->topology == TOPOLOGY_LOOP) {
2324 					port_attrs->PortType =
2325 					    FC_HBA_PORTTYPE_LPORT;
2326 				} else {
2327 					port_attrs->PortType =
2328 					    FC_HBA_PORTTYPE_PTP;
2329 				}
2330 
2331 				/* We share a common speed */
2332 				switch (hba->linkspeed) {
2333 				case 0:
2334 					port_attrs->PortSpeed =
2335 					    HBA_PORTSPEED_1GBIT;
2336 					break;
2337 				case LA_1GHZ_LINK:
2338 					port_attrs->PortSpeed =
2339 					    HBA_PORTSPEED_1GBIT;
2340 					break;
2341 				case LA_2GHZ_LINK:
2342 					port_attrs->PortSpeed =
2343 					    HBA_PORTSPEED_2GBIT;
2344 					break;
2345 				case LA_4GHZ_LINK:
2346 					port_attrs->PortSpeed =
2347 					    HBA_PORTSPEED_4GBIT;
2348 					break;
2349 				case LA_8GHZ_LINK:
2350 					port_attrs->PortSpeed =
2351 					    HBA_PORTSPEED_8GBIT;
2352 					break;
2353 				case LA_10GHZ_LINK:
2354 					port_attrs->PortSpeed =
2355 					    HBA_PORTSPEED_10GBIT;
2356 					break;
2357 				case LA_16GHZ_LINK:
2358 					port_attrs->PortSpeed =
2359 					    HBA_PORTSPEED_16GBIT;
2360 					break;
2361 				}
2362 			}
2363 			/* public loop */
2364 			else if (hba->topology == TOPOLOGY_LOOP) {
2365 				/* Check for common area and domain */
2366 				if ((ndlp->nlp_DID & 0xFFFF00) ==
2367 				    (port->did & 0xFFFF00)) {
2368 					port_attrs->PortType =
2369 					    FC_HBA_PORTTYPE_NLPORT;
2370 
2371 					/* We share a common speed */
2372 					switch (hba->linkspeed) {
2373 					case 0:
2374 						port_attrs->PortSpeed =
2375 						    HBA_PORTSPEED_1GBIT;
2376 						break;
2377 					case LA_1GHZ_LINK:
2378 						port_attrs->PortSpeed =
2379 						    HBA_PORTSPEED_1GBIT;
2380 						break;
2381 					case LA_2GHZ_LINK:
2382 						port_attrs->PortSpeed =
2383 						    HBA_PORTSPEED_2GBIT;
2384 						break;
2385 					case LA_4GHZ_LINK:
2386 						port_attrs->PortSpeed =
2387 						    HBA_PORTSPEED_4GBIT;
2388 						break;
2389 					case LA_8GHZ_LINK:
2390 						port_attrs->PortSpeed =
2391 						    HBA_PORTSPEED_8GBIT;
2392 						break;
2393 					case LA_10GHZ_LINK:
2394 						port_attrs->PortSpeed =
2395 						    HBA_PORTSPEED_10GBIT;
2396 						break;
2397 					case LA_16GHZ_LINK:
2398 						port_attrs->PortSpeed =
2399 						    HBA_PORTSPEED_16GBIT;
2400 						break;
2401 					}
2402 				}
2403 			}
2404 		}
2405 
2406 		port_attrs->PortSupportedClassofService =
2407 		    LE_SWAP32(FC_NS_CLASS3);
2408 		/* port_attrs->PortSymbolicName		*/
2409 		/* port_attrs->PortSupportedSpeed	*/
2410 		/* port_attrs->PortSupportedFc4Types	*/
2411 		/* port_attrs->PortActiveFc4Types	*/
2412 		/* port_attrs->PortMaxFrameSize		*/
2413 		/* port_attrs->NumberofDiscoveredPorts	*/
2414 	}
2415 
2416 done:
2417 	return (rval);
2418 
2419 } /* emlxs_fcio_get_disc_port_attrs() */
2420 
2421 
2422 /*ARGSUSED*/
2423 static int32_t
2424 emlxs_fcio_get_port_attrs(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
2425 {
2426 	emlxs_hba_t	*hba = HBA;
2427 	int32_t		rval = 0;
2428 	emlxs_node_t	*ndlp;
2429 	uint8_t		*wwpn;
2430 	uint32_t	use32 = 0;
2431 
2432 #ifdef	_MULTI_DATAMODEL
2433 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
2434 		use32 = 1;
2435 	}
2436 #endif	/* _MULTI_DATAMODEL */
2437 
2438 	if (use32) {
2439 		fc_hba_port_attributes32_t  *port_attrs;
2440 
2441 		if ((fcio->fcio_xfer != FCIO_XFER_READ) ||
2442 		    (fcio->fcio_ilen < 8) ||
2443 		    (fcio->fcio_olen < sizeof (fc_hba_port_attributes32_t))) {
2444 			rval = EINVAL;
2445 			goto done;
2446 		}
2447 
2448 		wwpn  = (uint8_t *)fcio->fcio_ibuf;
2449 		ndlp  = emlxs_node_find_wwpn(port, wwpn, 1);
2450 
2451 		if (!ndlp) {
2452 			fcio->fcio_errno = FC_NOMAP;
2453 			rval = EINVAL;
2454 			goto done;
2455 		}
2456 
2457 		/* Filter fabric ports */
2458 		if ((ndlp->nlp_DID & 0xFFF000) == 0xFFF000) {
2459 			fcio->fcio_errno = FC_NOMAP;
2460 			rval = EINVAL;
2461 			goto done;
2462 		}
2463 
2464 		port_attrs = (fc_hba_port_attributes32_t *)fcio->fcio_obuf;
2465 
2466 		port_attrs->version    = FC_HBA_PORT_ATTRIBUTES_VERSION;
2467 		/* port_attrs->lastChange */
2468 		/* port_attrs->fp_minor   */
2469 		bcopy((caddr_t)&ndlp->nlp_nodename,
2470 		    (caddr_t)&port_attrs->NodeWWN, 8);
2471 		bcopy((caddr_t)&ndlp->nlp_portname,
2472 		    (caddr_t)&port_attrs->PortWWN, 8);
2473 
2474 		port_attrs->PortSpeed = HBA_PORTSPEED_UNKNOWN;
2475 		port_attrs->PortType  = FC_HBA_PORTTYPE_UNKNOWN;
2476 		port_attrs->PortState = FC_HBA_PORTSTATE_OFFLINE;
2477 
2478 		if ((port->mode == MODE_TARGET) &&
2479 		    (hba->state >= FC_LINK_UP)) {
2480 			port_attrs->PortFcId  = ndlp->nlp_DID;
2481 			port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE;
2482 
2483 			/* no switch */
2484 			if (!(hba->flag & FC_FABRIC_ATTACHED)) {
2485 				if (hba->topology == TOPOLOGY_LOOP) {
2486 					port_attrs->PortType =
2487 					    FC_HBA_PORTTYPE_LPORT;
2488 				} else {
2489 					port_attrs->PortType =
2490 					    FC_HBA_PORTTYPE_PTP;
2491 				}
2492 
2493 				/* We share a common speed */
2494 				switch (hba->linkspeed) {
2495 				case 0:
2496 					port_attrs->PortSpeed =
2497 					    HBA_PORTSPEED_1GBIT;
2498 					break;
2499 				case LA_1GHZ_LINK:
2500 					port_attrs->PortSpeed =
2501 					    HBA_PORTSPEED_1GBIT;
2502 					break;
2503 				case LA_2GHZ_LINK:
2504 					port_attrs->PortSpeed =
2505 					    HBA_PORTSPEED_2GBIT;
2506 					break;
2507 				case LA_4GHZ_LINK:
2508 					port_attrs->PortSpeed =
2509 					    HBA_PORTSPEED_4GBIT;
2510 					break;
2511 				case LA_8GHZ_LINK:
2512 					port_attrs->PortSpeed =
2513 					    HBA_PORTSPEED_8GBIT;
2514 					break;
2515 				case LA_10GHZ_LINK:
2516 					port_attrs->PortSpeed =
2517 					    HBA_PORTSPEED_10GBIT;
2518 					break;
2519 				case LA_16GHZ_LINK:
2520 					port_attrs->PortSpeed =
2521 					    HBA_PORTSPEED_16GBIT;
2522 					break;
2523 				}
2524 			}
2525 			/* public loop */
2526 			else if (hba->topology == TOPOLOGY_LOOP) {
2527 				/* Check for common area and domain */
2528 				if ((ndlp->nlp_DID & 0xFFFF00) ==
2529 				    (port->did & 0xFFFF00)) {
2530 					port_attrs->PortType =
2531 					    FC_HBA_PORTTYPE_NLPORT;
2532 
2533 					/* We share a common speed */
2534 					switch (hba->linkspeed) {
2535 					case 0:
2536 						port_attrs->PortSpeed =
2537 						    HBA_PORTSPEED_1GBIT;
2538 						break;
2539 					case LA_1GHZ_LINK:
2540 						port_attrs->PortSpeed =
2541 						    HBA_PORTSPEED_1GBIT;
2542 						break;
2543 					case LA_2GHZ_LINK:
2544 						port_attrs->PortSpeed =
2545 						    HBA_PORTSPEED_2GBIT;
2546 						break;
2547 					case LA_4GHZ_LINK:
2548 						port_attrs->PortSpeed =
2549 						    HBA_PORTSPEED_4GBIT;
2550 						break;
2551 					case LA_8GHZ_LINK:
2552 						port_attrs->PortSpeed =
2553 						    HBA_PORTSPEED_8GBIT;
2554 						break;
2555 					case LA_10GHZ_LINK:
2556 						port_attrs->PortSpeed =
2557 						    HBA_PORTSPEED_10GBIT;
2558 						break;
2559 					case LA_16GHZ_LINK:
2560 						port_attrs->PortSpeed =
2561 						    HBA_PORTSPEED_16GBIT;
2562 						break;
2563 					}
2564 				}
2565 			}
2566 		}
2567 
2568 		port_attrs->PortSupportedClassofService =
2569 		    LE_SWAP32(FC_NS_CLASS3);
2570 		/* port_attrs->PortSymbolicName		*/
2571 		/* port_attrs->PortSupportedSpeed	*/
2572 		/* port_attrs->PortSupportedFc4Types	*/
2573 		/* port_attrs->PortActiveFc4Types	*/
2574 		/* port_attrs->PortMaxFrameSize		*/
2575 		/* port_attrs->NumberofDiscoveredPorts	*/
2576 
2577 	} else {
2578 		fc_hba_port_attributes_t  *port_attrs;
2579 
2580 		if ((fcio->fcio_xfer != FCIO_XFER_READ) ||
2581 		    (fcio->fcio_ilen < 8) ||
2582 		    (fcio->fcio_olen < sizeof (fc_hba_port_attributes_t))) {
2583 			rval = EINVAL;
2584 			goto done;
2585 		}
2586 
2587 		wwpn  = (uint8_t *)fcio->fcio_ibuf;
2588 		ndlp  = emlxs_node_find_wwpn(port, wwpn, 1);
2589 
2590 		if (!ndlp) {
2591 			fcio->fcio_errno = FC_NOMAP;
2592 			rval = EINVAL;
2593 			goto done;
2594 		}
2595 
2596 		/* Filter fabric ports */
2597 		if ((ndlp->nlp_DID & 0xFFF000) == 0xFFF000) {
2598 			fcio->fcio_errno = FC_NOMAP;
2599 			rval = EINVAL;
2600 			goto done;
2601 		}
2602 
2603 		port_attrs = (fc_hba_port_attributes_t *)fcio->fcio_obuf;
2604 
2605 		port_attrs->version    = FC_HBA_PORT_ATTRIBUTES_VERSION;
2606 		/* port_attrs->lastChange */
2607 		/* port_attrs->fp_minor   */
2608 		bcopy((caddr_t)&ndlp->nlp_nodename,
2609 		    (caddr_t)&port_attrs->NodeWWN, 8);
2610 		bcopy((caddr_t)&ndlp->nlp_portname,
2611 		    (caddr_t)&port_attrs->PortWWN, 8);
2612 
2613 		port_attrs->PortSpeed = HBA_PORTSPEED_UNKNOWN;
2614 		port_attrs->PortType  = FC_HBA_PORTTYPE_UNKNOWN;
2615 		port_attrs->PortState = FC_HBA_PORTSTATE_OFFLINE;
2616 
2617 		if ((port->mode == MODE_TARGET) &&
2618 		    (hba->state >= FC_LINK_UP)) {
2619 			port_attrs->PortFcId  = ndlp->nlp_DID;
2620 			port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE;
2621 
2622 			/* no switch */
2623 			if (!(hba->flag & FC_FABRIC_ATTACHED)) {
2624 				if (hba->topology == TOPOLOGY_LOOP) {
2625 					port_attrs->PortType =
2626 					    FC_HBA_PORTTYPE_LPORT;
2627 				} else {
2628 					port_attrs->PortType =
2629 					    FC_HBA_PORTTYPE_PTP;
2630 				}
2631 
2632 				/* We share a common speed */
2633 				switch (hba->linkspeed) {
2634 				case 0:
2635 					port_attrs->PortSpeed =
2636 					    HBA_PORTSPEED_1GBIT;
2637 					break;
2638 				case LA_1GHZ_LINK:
2639 					port_attrs->PortSpeed =
2640 					    HBA_PORTSPEED_1GBIT;
2641 					break;
2642 				case LA_2GHZ_LINK:
2643 					port_attrs->PortSpeed =
2644 					    HBA_PORTSPEED_2GBIT;
2645 					break;
2646 				case LA_4GHZ_LINK:
2647 					port_attrs->PortSpeed =
2648 					    HBA_PORTSPEED_4GBIT;
2649 					break;
2650 				case LA_8GHZ_LINK:
2651 					port_attrs->PortSpeed =
2652 					    HBA_PORTSPEED_8GBIT;
2653 					break;
2654 				case LA_10GHZ_LINK:
2655 					port_attrs->PortSpeed =
2656 					    HBA_PORTSPEED_10GBIT;
2657 					break;
2658 				case LA_16GHZ_LINK:
2659 					port_attrs->PortSpeed =
2660 					    HBA_PORTSPEED_16GBIT;
2661 					break;
2662 				}
2663 			}
2664 			/* public loop */
2665 			else if (hba->topology == TOPOLOGY_LOOP) {
2666 				/* Check for common area and domain */
2667 				if ((ndlp->nlp_DID & 0xFFFF00) ==
2668 				    (port->did & 0xFFFF00)) {
2669 					port_attrs->PortType =
2670 					    FC_HBA_PORTTYPE_NLPORT;
2671 
2672 					/* We share a common speed */
2673 					switch (hba->linkspeed) {
2674 					case 0:
2675 						port_attrs->PortSpeed =
2676 						    HBA_PORTSPEED_1GBIT;
2677 						break;
2678 					case LA_1GHZ_LINK:
2679 						port_attrs->PortSpeed =
2680 						    HBA_PORTSPEED_1GBIT;
2681 						break;
2682 					case LA_2GHZ_LINK:
2683 						port_attrs->PortSpeed =
2684 						    HBA_PORTSPEED_2GBIT;
2685 						break;
2686 					case LA_4GHZ_LINK:
2687 						port_attrs->PortSpeed =
2688 						    HBA_PORTSPEED_4GBIT;
2689 						break;
2690 					case LA_8GHZ_LINK:
2691 						port_attrs->PortSpeed =
2692 						    HBA_PORTSPEED_8GBIT;
2693 						break;
2694 					case LA_10GHZ_LINK:
2695 						port_attrs->PortSpeed =
2696 						    HBA_PORTSPEED_10GBIT;
2697 						break;
2698 					case LA_16GHZ_LINK:
2699 						port_attrs->PortSpeed =
2700 						    HBA_PORTSPEED_16GBIT;
2701 						break;
2702 					}
2703 				}
2704 			}
2705 		}
2706 
2707 		port_attrs->PortSupportedClassofService =
2708 		    LE_SWAP32(FC_NS_CLASS3);
2709 		/* port_attrs->PortSymbolicName		*/
2710 		/* port_attrs->PortSupportedSpeed	*/
2711 		/* port_attrs->PortSupportedFc4Types	*/
2712 		/* port_attrs->PortActiveFc4Types	*/
2713 		/* port_attrs->PortMaxFrameSize		*/
2714 		/* port_attrs->NumberofDiscoveredPorts	*/
2715 	}
2716 
2717 done:
2718 	return (rval);
2719 
2720 } /* emlxs_fcio_get_port_attrs() */
2721 
2722 
2723 /*ARGSUSED*/
2724 static int32_t
2725 emlxs_fcio_get_sym_pname(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
2726 {
2727 	int32_t		rval = 0;
2728 
2729 	if (fcio->fcio_olen < (strlen(port->spn)+1) ||
2730 	    (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
2731 		rval = EINVAL;
2732 		goto done;
2733 	}
2734 
2735 	(void) strlcpy((caddr_t)fcio->fcio_obuf, (caddr_t)port->spn,
2736 	    fcio->fcio_olen);
2737 
2738 done:
2739 	return (rval);
2740 
2741 } /* emlxs_fcio_get_sym_pname() */
2742 
2743 
2744 /*ARGSUSED*/
2745 static int32_t
2746 emlxs_fcio_get_sym_nname(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
2747 {
2748 	int32_t		rval = 0;
2749 
2750 	if (fcio->fcio_olen < (strlen(port->snn)+1) ||
2751 	    (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
2752 		rval = EINVAL;
2753 		goto done;
2754 	}
2755 
2756 	(void) strlcpy((caddr_t)fcio->fcio_obuf, (caddr_t)port->snn,
2757 	    fcio->fcio_olen);
2758 
2759 done:
2760 	return (rval);
2761 
2762 } /* emlxs_fcio_get_sym_nname() */
2763 
2764 
2765 /*ARGSUSED*/
2766 static int32_t
2767 emlxs_fcio_force_dump(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
2768 {
2769 	int32_t		rval = 0;
2770 
2771 	if (port->mode != MODE_TARGET) {
2772 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
2773 		    "fcio_force_dump failed. Port is not in target mode.");
2774 
2775 		fcio->fcio_errno = FC_FAILURE;
2776 		rval = EIO;
2777 		goto done;
2778 	}
2779 
2780 	rval = emlxs_reset(port, FC_FCA_CORE);
2781 
2782 	if (rval != FC_SUCCESS) {
2783 		fcio->fcio_errno = rval;
2784 		rval = EIO;
2785 		goto done;
2786 	}
2787 
2788 done:
2789 	return (rval);
2790 
2791 } /* emlxs_fcio_force_dump() */
2792 
2793 
2794 /*ARGSUSED*/
2795 static int32_t
2796 emlxs_fcio_get_dump_size(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
2797 {
2798 	int32_t		rval = 0;
2799 	fc_fca_pm_t pm;
2800 
2801 	if (fcio->fcio_olen != sizeof (uint32_t) ||
2802 	    fcio->fcio_xfer != FCIO_XFER_READ) {
2803 		rval = EINVAL;
2804 		goto done;
2805 	}
2806 
2807 	bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
2808 
2809 	pm.pm_data_len  = fcio->fcio_olen;
2810 	pm.pm_data_buf  = fcio->fcio_obuf;
2811 	pm.pm_cmd_code  = FC_PORT_GET_DUMP_SIZE;
2812 	pm.pm_cmd_flags = FC_FCA_PM_READ;
2813 
2814 	rval = emlxs_fca_port_manage(port, &pm);
2815 
2816 	if (rval != FC_SUCCESS) {
2817 		fcio->fcio_errno = rval;
2818 
2819 		if (rval == FC_INVALID_REQUEST) {
2820 			rval = ENOTTY;
2821 		} else {
2822 			rval = EIO;
2823 		}
2824 	}
2825 
2826 done:
2827 	return (rval);
2828 
2829 } /* emlxs_fcio_get_dump_size() */
2830 
2831 
2832 /*ARGSUSED*/
2833 static int32_t
2834 emlxs_fcio_get_dump(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
2835 {
2836 	int32_t		rval = 0;
2837 	fc_fca_pm_t	pm;
2838 	uint32_t	dump_size;
2839 
2840 	if (fcio->fcio_xfer != FCIO_XFER_READ) {
2841 		rval = EINVAL;
2842 		goto done;
2843 	}
2844 
2845 	bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
2846 
2847 	pm.pm_data_len  = sizeof (uint32_t);
2848 	pm.pm_data_buf  = (caddr_t)&dump_size;
2849 	pm.pm_cmd_code  = FC_PORT_GET_DUMP_SIZE;
2850 	pm.pm_cmd_flags = FC_FCA_PM_READ;
2851 
2852 	rval = emlxs_fca_port_manage(port, &pm);
2853 
2854 	if (rval != FC_SUCCESS) {
2855 		fcio->fcio_errno = rval;
2856 
2857 		if (rval == FC_INVALID_REQUEST) {
2858 			rval = ENOTTY;
2859 		} else {
2860 			rval = EIO;
2861 		}
2862 		goto done;
2863 	}
2864 
2865 	if (fcio->fcio_olen != dump_size) {
2866 		fcio->fcio_errno = FC_NOMEM;
2867 		rval = EINVAL;
2868 		goto done;
2869 	}
2870 
2871 	bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
2872 
2873 	pm.pm_data_len  = fcio->fcio_olen;
2874 	pm.pm_data_buf  = fcio->fcio_obuf;
2875 	pm.pm_cmd_code  = FC_PORT_GET_DUMP;
2876 	pm.pm_cmd_flags = FC_FCA_PM_READ;
2877 
2878 	rval = emlxs_fca_port_manage(port, &pm);
2879 
2880 	if (rval != FC_SUCCESS) {
2881 		fcio->fcio_errno = rval;
2882 
2883 		if (rval == FC_INVALID_REQUEST) {
2884 			rval = ENOTTY;
2885 		} else {
2886 			rval = EIO;
2887 		}
2888 	}
2889 
2890 done:
2891 	return (rval);
2892 
2893 } /* emlxs_fcio_get_dump() */
2894 
2895 
2896 /*ARGSUSED*/
2897 static int32_t
2898 emlxs_fcio_unsupported(emlxs_port_t *port, fcio_t *fcio, int32_t mode)
2899 {
2900 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
2901 	    "%s: Command not supported.",
2902 	    emlxs_fcio_xlate(fcio->fcio_cmd));
2903 
2904 	return (ENOTSUP);
2905 
2906 } /* emlxs_fcio_unsupported() */
2907 #endif /* FCIO_SUPPORT */
2908 
2909 
2910 /*ARGSUSED*/
2911 static int32_t
2912 emlxs_dfc_create_vport(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
2913 {
2914 	emlxs_port_t	*port = &PPORT;
2915 	emlxs_config_t	*cfg = &CFG;
2916 	emlxs_port_t	*vport;
2917 	emlxs_port_t	*tport;
2918 	dfc_vportinfo_t	*dfc_vport;
2919 	uint32_t	vpi;
2920 	uint32_t	options;
2921 	char		name[256];
2922 	uint8_t		wwn[8];
2923 
2924 	options = dfc->data1;
2925 
2926 	if (!dfc->buf1 || !dfc->buf1_size) {
2927 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2928 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
2929 
2930 		return (DFC_ARG_NULL);
2931 	}
2932 
2933 	if (dfc->buf1_size < sizeof (dfc_vportinfo_t)) {
2934 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2935 		    "%s: Buffer1 too small. (size=%d)",
2936 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
2937 
2938 		return (DFC_ARG_TOOSMALL);
2939 	}
2940 
2941 	dfc_vport = (dfc_vportinfo_t *)dfc->buf1;
2942 
2943 	if (!(options & VPORT_OPT_AUTORETRY)) {
2944 		if (!(hba->flag & FC_NPIV_ENABLED)) {
2945 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2946 			    "%s: NPIV currently not enabled.",
2947 			    emlxs_dfc_xlate(dfc->cmd));
2948 
2949 			return (DFC_NPIV_DISABLED);
2950 		}
2951 
2952 		if (!(hba->flag & FC_NPIV_SUPPORTED)) {
2953 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2954 			    "%s: NPIV currently not supported.",
2955 			    emlxs_dfc_xlate(dfc->cmd));
2956 
2957 			return (DFC_NPIV_UNSUPPORTED);
2958 		}
2959 	}
2960 
2961 	/*
2962 	 * Only the same WWNN and WWPN can be re-created
2963 	 */
2964 	bzero(wwn, 8);
2965 	if (bcmp(wwn, dfc_vport->wwpn, 8) || bcmp(wwn, dfc_vport->wwnn, 8)) {
2966 		for (vpi = 1; vpi <= hba->vpi_max; vpi++) {
2967 			vport = &VPORT(vpi);
2968 
2969 			if ((bcmp((caddr_t)&vport->wwnn,
2970 			    (caddr_t)dfc_vport->wwnn, 8) == 0) &&
2971 			    (bcmp((caddr_t)&vport->wwpn,
2972 			    (caddr_t)dfc_vport->wwpn, 8) == 0)) {
2973 				if (!(vport->flag & EMLXS_PORT_CONFIG) &&
2974 				    (vport->flag & EMLXS_PORT_BOUND)) {
2975 					dfc_vport->vpi = vpi;
2976 					break;
2977 				} else {
2978 					EMLXS_MSGF(EMLXS_CONTEXT,
2979 					    &emlxs_dfc_error_msg,
2980 					    "%s: VPI already in use.",
2981 					    emlxs_dfc_xlate(dfc->cmd));
2982 
2983 					return (DFC_ARG_INVALID);
2984 				}
2985 			}
2986 		}
2987 	}
2988 
2989 	/* else auto assign */
2990 	/* Acquire a VPI */
2991 	if (dfc_vport->vpi == 0) {
2992 		/* Auto Assign VPI */
2993 		for (vpi = 1; vpi <= hba->vpi_max; vpi++) {
2994 			vport = &VPORT(vpi);
2995 
2996 			if (!(vport->flag & EMLXS_PORT_CONFIG)) {
2997 				break;
2998 			}
2999 		}
3000 
3001 		if (vpi > hba->vpi_max) {
3002 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3003 			    "%s: Out of resources.",
3004 			    emlxs_dfc_xlate(dfc->cmd));
3005 
3006 			return (DFC_DRVRES_ERROR);
3007 		}
3008 
3009 		dfc_vport->vpi = vpi;
3010 	}
3011 
3012 	/* Establish a WWPN */
3013 	bzero(wwn, 8);
3014 	if (!(bcmp(wwn, dfc_vport->wwpn, 8))) {
3015 		/* Generate new WWPN */
3016 		bcopy((caddr_t)&hba->wwpn, (caddr_t)dfc_vport->wwpn, 8);
3017 		dfc_vport->wwpn[0] = 0x20;
3018 		dfc_vport->wwpn[1] = (uint8_t)vpi;
3019 	} else {	/* use one provided */
3020 
3021 		/* Make sure WWPN is unique */
3022 		if (tport = emlxs_vport_find_wwpn(hba, dfc_vport->wwpn)) {
3023 			if ((tport->flag & EMLXS_PORT_CONFIG) &&
3024 			    (tport->flag & EMLXS_PORT_BOUND)) {
3025 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3026 				    "%s: WWPN already exists. vpi=%d",
3027 				    emlxs_dfc_xlate(dfc->cmd), vpi);
3028 				return (DFC_ARG_INVALID);
3029 			}
3030 		}
3031 	}
3032 
3033 	/* Establish a WWNN */
3034 	bzero(wwn, 8);
3035 	if (!(bcmp(wwn, dfc_vport->wwnn, 8))) {
3036 		/* Generate new WWNN */
3037 		bcopy((caddr_t)&hba->wwnn, (caddr_t)dfc_vport->wwnn, 8);
3038 		dfc_vport->wwnn[0] = 0x28;
3039 		dfc_vport->wwnn[1] = (uint8_t)vpi;
3040 	}
3041 	/* else use WWNN provided */
3042 
3043 	/* Generate the symbolic node name */
3044 	if (dfc_vport->snn[0]) {
3045 		(void) strncpy(name, dfc_vport->snn,
3046 		    (sizeof (name)-1));
3047 		(void) snprintf(dfc_vport->snn, (sizeof (dfc_vport->snn)-1),
3048 		    "%s %s", hba->snn, name);
3049 	} else {
3050 		(void) strncpy(dfc_vport->snn, hba->snn,
3051 		    (sizeof (dfc_vport->snn)-1));
3052 	}
3053 
3054 	/* Generate the symbolic port name */
3055 	if (dfc_vport->spn[0]) {
3056 		(void) strncpy(name, dfc_vport->spn,
3057 		    (sizeof (name)-1));
3058 		(void) snprintf(dfc_vport->spn, (sizeof (dfc_vport->spn)-1),
3059 		    "%s VPort-%d VName-%s", hba->spn,
3060 		    vpi, name);
3061 	} else {
3062 		(void) snprintf(dfc_vport->spn, (sizeof (dfc_vport->spn)-1),
3063 		    "%s VPort-%d", hba->spn, vpi);
3064 	}
3065 
3066 	dfc_vport->port_id = 0;
3067 	dfc_vport->ulp_statec = FC_STATE_OFFLINE;
3068 	dfc_vport->flags = VPORT_CONFIG;
3069 
3070 	/* Set the highest configured vpi */
3071 	if (dfc_vport->vpi >= hba->vpi_high) {
3072 		hba->vpi_high = dfc_vport->vpi;
3073 	}
3074 
3075 	/* Configure the port object */
3076 	bcopy((caddr_t)dfc_vport->wwnn, (caddr_t)&vport->wwnn, 8);
3077 	bcopy((caddr_t)dfc_vport->wwpn, (caddr_t)&vport->wwpn, 8);
3078 	(void) strncpy((caddr_t)vport->snn, (caddr_t)dfc_vport->snn,
3079 	    (sizeof (vport->snn)-1));
3080 	(void) strncpy((caddr_t)vport->spn, (caddr_t)dfc_vport->spn,
3081 	    (sizeof (vport->spn)-1));
3082 	vport->flag |= (EMLXS_PORT_CONFIG | EMLXS_PORT_ENABLED);
3083 
3084 	/* Adjust restricted flags */
3085 	vport->options &= ~EMLXS_OPT_RESTRICT_MASK;
3086 	vport->flag &= ~EMLXS_PORT_RESTRICTED;
3087 	if (options & VPORT_OPT_RESTRICT) {
3088 		vport->options |= EMLXS_OPT_RESTRICT;
3089 		vport->flag |= EMLXS_PORT_RESTRICTED;
3090 		dfc_vport->flags |= VPORT_RESTRICTED;
3091 	} else if (options & VPORT_OPT_UNRESTRICT) {
3092 		vport->options |= EMLXS_OPT_UNRESTRICT;
3093 	} else if (cfg[CFG_VPORT_RESTRICTED].current) {
3094 		vport->flag |= EMLXS_PORT_RESTRICTED;
3095 		dfc_vport->flags |= VPORT_RESTRICTED;
3096 	}
3097 
3098 	if (vport->flag & EMLXS_PORT_BOUND) {
3099 		/*
3100 		 * The same WWNN, WWPN and VPI has been re-created.
3101 		 * Bring up the vport now!
3102 		 */
3103 		emlxs_port_online(vport);
3104 	}
3105 
3106 	return (0);
3107 
3108 } /* emlxs_dfc_create_vport() */
3109 
3110 
3111 /*ARGSUSED*/
3112 static int32_t
3113 emlxs_dfc_destroy_vport(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3114 {
3115 	emlxs_port_t	*port = &PPORT;
3116 	emlxs_port_t	*vport;
3117 	uint8_t		wwpn[8];
3118 	fc_packet_t	*pkt = NULL;
3119 	uint32_t	rval = 0;
3120 	ELS_PKT		*els;
3121 	char		buffer[256];
3122 
3123 	if (!dfc->buf1 || !dfc->buf1_size) {
3124 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3125 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3126 
3127 		rval = DFC_ARG_NULL;
3128 		goto done;
3129 	}
3130 
3131 	if (dfc->buf1_size < 8) {
3132 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3133 		    "%s: Buffer1 too small. (size=%d)",
3134 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
3135 
3136 		rval = DFC_ARG_TOOSMALL;
3137 		goto done;
3138 	}
3139 
3140 	/* Read the wwn object */
3141 	bcopy((void *)dfc->buf1, (void *)wwpn, 8);
3142 
3143 	/* Make sure WWPN is unique */
3144 	vport = emlxs_vport_find_wwpn(hba, wwpn);
3145 
3146 	/* Physical does not have EMLXS_PORT_CONFIG set */
3147 	if (!vport || !(vport->flag & EMLXS_PORT_CONFIG)) {
3148 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3149 		    "%s: WWPN does not exists. %s", emlxs_dfc_xlate(dfc->cmd),
3150 		    emlxs_wwn_xlate(buffer, sizeof (buffer), wwpn));
3151 
3152 		rval = DFC_ARG_INVALID;
3153 		goto done;
3154 	}
3155 
3156 	if (vport->did) {
3157 		/* Fabric Logout */
3158 		if (!(pkt = emlxs_pkt_alloc(vport,
3159 		    sizeof (uint32_t) + sizeof (LOGO),
3160 		    sizeof (FCP_RSP), 0, KM_NOSLEEP))) {
3161 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3162 			    "%s: Unable to allocate packet.",
3163 			    emlxs_dfc_xlate(dfc->cmd));
3164 
3165 			rval = DFC_SYSRES_ERROR;
3166 			goto done;
3167 		}
3168 
3169 		/* Make this a polled IO */
3170 		pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
3171 		pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
3172 		pkt->pkt_comp = NULL;
3173 
3174 		pkt->pkt_tran_type = FC_PKT_EXCHANGE;
3175 		pkt->pkt_timeout = 60;
3176 
3177 		/* Build the fc header */
3178 		pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(FABRIC_DID);
3179 		pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
3180 		pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(vport->did);
3181 		pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
3182 		pkt->pkt_cmd_fhdr.f_ctl =
3183 		    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
3184 		pkt->pkt_cmd_fhdr.seq_id = 0;
3185 		pkt->pkt_cmd_fhdr.df_ctl = 0;
3186 		pkt->pkt_cmd_fhdr.seq_cnt = 0;
3187 		pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
3188 		pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
3189 		pkt->pkt_cmd_fhdr.ro = 0;
3190 
3191 		/* Build the command */
3192 		els = (ELS_PKT *) pkt->pkt_cmd;
3193 		els->elsCode = 0x05;	/* LOGO */
3194 		els->un.logo.un.nPortId32 = LE_SWAP32(vport->did);
3195 		bcopy(&vport->wwpn, &els->un.logo.portName, 8);
3196 
3197 		/*
3198 		 * Just send LOGO. Don't worry about result.
3199 		 * This is just a courtesy anyway.
3200 		 */
3201 		(void) emlxs_pkt_send(pkt, 1);
3202 
3203 
3204 		/* Take the port offline */
3205 		(void) emlxs_port_offline(vport, 0xffffffff);
3206 	}
3207 
3208 	vport->flag &= ~(EMLXS_PORT_CONFIG | EMLXS_PORT_ENABLED);
3209 
3210 	rval = 0;
3211 
3212 done:
3213 
3214 	if (pkt) {
3215 		emlxs_pkt_free(pkt);
3216 	}
3217 
3218 	return (rval);
3219 
3220 } /* emlxs_dfc_destroy_vport() */
3221 
3222 
3223 /*ARGSUSED*/
3224 static int32_t
3225 emlxs_dfc_get_vportinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3226 {
3227 	emlxs_port_t	*port = &PPORT;
3228 	emlxs_port_t	*vport;
3229 	dfc_vportinfo_t	*dfc_vport;
3230 	dfc_vportinfo_t	*dfc_vport_list = NULL;
3231 	uint32_t	i;
3232 	uint32_t	size;
3233 	uint32_t	max_count;
3234 	uint32_t	rval = DFC_SUCCESS;
3235 
3236 	if (!dfc->buf1 || !dfc->buf1_size) {
3237 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3238 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3239 
3240 		return (DFC_ARG_NULL);
3241 	}
3242 
3243 	size = (sizeof (dfc_vportinfo_t) * MAX_VPORTS);
3244 
3245 	if (!(dfc_vport_list =
3246 	    (dfc_vportinfo_t *)kmem_zalloc(size, KM_NOSLEEP))) {
3247 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3248 		    "%s: Unable to allocate memory.",
3249 		    emlxs_dfc_xlate(dfc->cmd));
3250 
3251 		return (DFC_SYSRES_ERROR);
3252 	}
3253 
3254 	max_count = 0;
3255 	for (i = 0; i <= hba->vpi_max; i++) {
3256 		vport = &VPORT(i);
3257 		dfc_vport = &dfc_vport_list[i];
3258 
3259 		if (!(vport->flag & EMLXS_PORT_CONFIG)) {
3260 			continue;
3261 		}
3262 
3263 		bcopy(vport->snn, dfc_vport->snn, 256);
3264 		bcopy(vport->spn, dfc_vport->spn, 256);
3265 		bcopy(&vport->wwpn, dfc_vport->wwpn, 8);
3266 		bcopy(&vport->wwnn, dfc_vport->wwnn, 8);
3267 		dfc_vport->port_id = vport->did;
3268 		dfc_vport->vpi = vport->vpi;
3269 		dfc_vport->ulp_statec = vport->ulp_statec;
3270 		dfc_vport->flags = VPORT_CONFIG;
3271 
3272 		if (vport->flag & EMLXS_PORT_ENABLED) {
3273 			dfc_vport->flags |= VPORT_ENABLED;
3274 		}
3275 
3276 		if (vport->flag & EMLXS_PORT_BOUND) {
3277 			dfc_vport->flags |= VPORT_BOUND;
3278 		}
3279 
3280 		if (vport->flag & EMLXS_PORT_IP_UP) {
3281 			dfc_vport->flags |= VPORT_IP;
3282 		}
3283 
3284 		if (vport->flag & EMLXS_PORT_RESTRICTED) {
3285 			dfc_vport->flags |= VPORT_RESTRICTED;
3286 		}
3287 
3288 		max_count++;
3289 	}
3290 
3291 	max_count *= sizeof (dfc_vportinfo_t);
3292 
3293 	if (max_count > dfc->buf1_size) {
3294 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3295 		    "%s: Buffer1 too small. (%d > %d)",
3296 		    emlxs_dfc_xlate(dfc->cmd), max_count, dfc->buf1_size);
3297 
3298 		rval = DFC_ARG_TOOSMALL;
3299 		goto done;
3300 	}
3301 
3302 	bcopy((void *)dfc_vport_list, (void *)dfc->buf1, dfc->buf1_size);
3303 
3304 done:
3305 
3306 	if (dfc_vport_list) {
3307 		kmem_free(dfc_vport_list, size);
3308 	}
3309 
3310 	return (rval);
3311 
3312 } /* emlxs_dfc_get_vportinfo() */
3313 
3314 
3315 static emlxs_port_t *
3316 emlxs_vport_find_wwpn(emlxs_hba_t *hba, uint8_t *wwpn)
3317 {
3318 	emlxs_port_t	*port;
3319 	NODELIST	*nlp;
3320 	int		i, j;
3321 
3322 	for (i = 0; i <= hba->vpi_max; i++) {
3323 		port = &VPORT(i);
3324 
3325 		/* Check Local N-port, including physical port */
3326 		if (bcmp(&port->wwpn, wwpn, 8) == 0) {
3327 			return (port);
3328 		}
3329 
3330 		/* Check Remote N-port */
3331 		rw_enter(&port->node_rwlock, RW_READER);
3332 		for (j = 0; j < EMLXS_NUM_HASH_QUES; j++) {
3333 			nlp = port->node_table[j];
3334 			while (nlp != NULL) {
3335 				/* Check Local N-port */
3336 				if (bcmp(&nlp->nlp_portname, wwpn, 8) == 0) {
3337 					rw_exit(&port->node_rwlock);
3338 					return (port);
3339 				}
3340 				nlp = nlp->nlp_list_next;
3341 			}
3342 		}
3343 
3344 		rw_exit(&port->node_rwlock);
3345 	}
3346 
3347 	return (0);
3348 
3349 } /* emlxs_vport_find_wwpn() */
3350 
3351 
3352 /*ARGSUSED*/
3353 static int32_t
3354 emlxs_dfc_npiv_resource(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3355 {
3356 	emlxs_port_t		*port = &PPORT;
3357 	dfc_vport_resource_t	*vres;
3358 	MAILBOXQ		*mbq = NULL;
3359 	MAILBOX			*mb;
3360 	uint32_t		rval = DFC_SUCCESS;
3361 
3362 	if (!dfc->buf1 || !dfc->buf1_size) {
3363 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3364 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3365 
3366 		return (DFC_ARG_NULL);
3367 	}
3368 
3369 	if (dfc->buf1_size < sizeof (dfc_vport_resource_t)) {
3370 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3371 		    "%s: Buffer1 too small. (size=%d)",
3372 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
3373 
3374 		return (DFC_ARG_TOOSMALL);
3375 	}
3376 
3377 	vres = (dfc_vport_resource_t *)dfc->buf1;
3378 	bzero(vres, sizeof (dfc_vport_resource_t));
3379 
3380 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3381 		int i;
3382 		int total_rpi;
3383 		emlxs_port_t *vport;
3384 
3385 		vres->vpi_max = min(hba->sli.sli4.VPICount, MAX_VPORTS) - 1;
3386 
3387 		total_rpi = 0;
3388 		for (i = 0; i < vres->vpi_max; i++) {
3389 			vport = &VPORT(i);
3390 			total_rpi += vport->vpip->rpi_online;
3391 		}
3392 
3393 		vres->vpi_inuse = (port->vpip->vfip == NULL) ? 0 :
3394 		    (port->vpip->vfip->vpi_online - 1);
3395 		vres->rpi_max = hba->sli.sli4.RPICount;
3396 		vres->rpi_inuse = total_rpi;
3397 
3398 		return (rval);
3399 	}
3400 
3401 	mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
3402 	mb = (MAILBOX *) mbq;
3403 
3404 	emlxs_mb_read_config(hba, mbq);
3405 
3406 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
3407 
3408 	if (rval == MBX_TIMEOUT) {
3409 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3410 		    "%s: Mailbox timed out. cmd=%x",
3411 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
3412 
3413 		rval = DFC_TIMEOUT;
3414 		goto done;
3415 	}
3416 
3417 	if (rval) {
3418 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3419 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
3420 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
3421 
3422 		rval = DFC_IO_ERROR;
3423 		goto done;
3424 	}
3425 
3426 	vres->vpi_max = mb->un.varRdConfig.max_vpi;
3427 	vres->vpi_inuse =
3428 	    (mb->un.varRdConfig.max_vpi <=
3429 	    mb->un.varRdConfig.avail_vpi) ? 0 : mb->un.varRdConfig.max_vpi -
3430 	    mb->un.varRdConfig.avail_vpi;
3431 
3432 	vres->rpi_max = mb->un.varRdConfig.max_rpi;
3433 	vres->rpi_inuse =
3434 	    (mb->un.varRdConfig.max_rpi <=
3435 	    mb->un.varRdConfig.avail_rpi) ? 0 : mb->un.varRdConfig.max_rpi -
3436 	    mb->un.varRdConfig.avail_rpi;
3437 
3438 done:
3439 
3440 	/* Free allocated mbox memory */
3441 	if (mbq) {
3442 		kmem_free(mbq, sizeof (MAILBOXQ));
3443 	}
3444 
3445 	return (rval);
3446 
3447 } /* emlxs_dfc_npiv_resource() */
3448 
3449 
3450 /*ARGSUSED*/
3451 static int32_t
3452 emlxs_dfc_npiv_test(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3453 {
3454 	emlxs_port_t	*port = &PPORT;
3455 	emlxs_port_t	*vport = &VPORT(hba->vpi_max);
3456 	emlxs_config_t	*cfg = &CFG;
3457 	fc_packet_t	*pkt = NULL;
3458 	fc_packet_t	*pkt1 = NULL;
3459 	ELS_PKT		*els;
3460 	LS_RJT		*lsrjt;
3461 	uint32_t	checklist = 0;
3462 	uint32_t	mask = 0;
3463 	uint32_t	rval = DFC_SUCCESS;
3464 	uint8_t		wwn[8];
3465 	emlxs_vpd_t	*vpd = &VPD;
3466 	int		i;
3467 
3468 	if (!dfc->buf1 || !dfc->buf1_size) {
3469 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3470 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3471 
3472 		return (DFC_ARG_NULL);
3473 	}
3474 
3475 	if (dfc->buf1_size < sizeof (uint32_t)) {
3476 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3477 		    "%s: Buffer1 too small. (size=%d)",
3478 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
3479 
3480 		return (DFC_ARG_TOOSMALL);
3481 	}
3482 
3483 	if (cfg[CFG_NPIV_ENABLE].current) {
3484 		checklist |= CL_NPIV_PARM_ENABLE;
3485 	}
3486 
3487 	if (hba->sli_mode >= 3) {
3488 		checklist |= CL_SLI3_ENABLE;
3489 	}
3490 
3491 
3492 	if ((vpd->feaLevelHigh >= 0x09) || (hba->sli_mode >= 4)) {
3493 		checklist |= CL_HBA_SUPPORT_NPIV;
3494 	}
3495 
3496 
3497 	if (hba->num_of_ports <= hba->vpi_max) {
3498 		checklist |= CL_HBA_HAS_RESOURCES;
3499 	}
3500 
3501 	if (hba->state < FC_LINK_UP) {
3502 		goto done;
3503 	}
3504 
3505 	checklist |= CL_HBA_LINKUP;
3506 
3507 	if (hba->topology == TOPOLOGY_LOOP) {
3508 		goto done;
3509 	}
3510 
3511 	if (!(hba->flag & FC_FABRIC_ATTACHED)) {
3512 		goto done;
3513 	}
3514 
3515 	checklist |= CL_P2P_TOPOLOGY;
3516 
3517 	if (!(hba->flag & FC_NPIV_SUPPORTED)) {
3518 		goto done;
3519 	}
3520 
3521 	checklist |= CL_FABRIC_SUPPORTS_NPIV;
3522 
3523 	mask =
3524 	    (CL_NPIV_PARM_ENABLE | CL_SLI3_ENABLE | CL_HBA_SUPPORT_NPIV |
3525 	    CL_HBA_HAS_RESOURCES);
3526 
3527 	/*
3528 	 * Check if those four conditions are met
3529 	 */
3530 	if ((checklist & mask) != mask) {
3531 		/*
3532 		 * One or more conditions are not met
3533 		 */
3534 		goto done;
3535 	}
3536 
3537 	/* Now check if fabric have resources */
3538 	for (i = 1; i <= hba->vpi_max; i++) {
3539 		vport = &VPORT(i);
3540 		if (vport->did) {
3541 			checklist |= CL_FABRIC_HAS_RESOURCES;
3542 			goto done;
3543 		}
3544 	}
3545 
3546 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3547 		(void) emlxs_vpi_port_bind_notify(vport);
3548 		/* wait one second for INIT_VPI completion */
3549 		drv_usecwait(1000000);
3550 	}
3551 
3552 	vport->vpi = hba->vpi_max;
3553 	vport->hba = hba;
3554 
3555 	if (!(pkt = emlxs_pkt_alloc(vport,
3556 	    sizeof (uint32_t) + sizeof (SERV_PARM), sizeof (FCP_RSP),
3557 	    0, KM_NOSLEEP))) {
3558 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3559 		    "Unable to allocate packet.");
3560 		goto done;
3561 	}
3562 
3563 	/* Build (FDISC) the fc header */
3564 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(FABRIC_DID);
3565 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_EXTENDED_SVC | R_CTL_UNSOL_CONTROL;
3566 	pkt->pkt_cmd_fhdr.s_id = 0;
3567 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
3568 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE;
3569 	pkt->pkt_cmd_fhdr.seq_id = 0;
3570 	pkt->pkt_cmd_fhdr.df_ctl = 0;
3571 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
3572 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
3573 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
3574 	pkt->pkt_cmd_fhdr.ro = 0;
3575 
3576 	/* Build the command (FDISC) */
3577 	els = (ELS_PKT *) pkt->pkt_cmd;
3578 	els->elsCode = 0x04;	/* FLOGI - This will be changed automatically */
3579 				/* by the drive (See emlxs_send_els()) */
3580 
3581 	/* Copy latest service parameters to payload */
3582 	bcopy((void *)&port->sparam,
3583 	    (void *)&els->un.logi, sizeof (SERV_PARM));
3584 
3585 	bcopy((caddr_t)&hba->wwnn, (caddr_t)wwn, 8);
3586 	wwn[0] = 0x28;
3587 	wwn[1] = hba->vpi_max;
3588 	bcopy((caddr_t)wwn, (caddr_t)&els->un.logi.nodeName, 8);
3589 	bcopy((caddr_t)wwn, (caddr_t)&vport->wwnn, 8);
3590 
3591 	bcopy((caddr_t)&hba->wwpn, (caddr_t)wwn, 8);
3592 	wwn[0] = 0x20;
3593 	wwn[1] = hba->vpi_max;
3594 	bcopy((caddr_t)wwn, (caddr_t)&els->un.logi.portName, 8);
3595 	bcopy((caddr_t)wwn, (caddr_t)&vport->wwpn, 8);
3596 
3597 	bcopy((void *)&els->un.logi, (void *)&vport->sparam,
3598 	    sizeof (SERV_PARM));
3599 
3600 	/* Make this a polled IO */
3601 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
3602 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
3603 	pkt->pkt_comp = NULL;
3604 
3605 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
3606 	pkt->pkt_timeout = 60;
3607 
3608 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
3609 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3610 		    "%s: Unable to send packet.", emlxs_dfc_xlate(dfc->cmd));
3611 
3612 		goto done;
3613 	}
3614 
3615 	if (pkt->pkt_state == FC_PKT_SUCCESS) {
3616 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3617 			(void) emlxs_vpi_port_unbind_notify(vport, 1);
3618 			checklist |= CL_FABRIC_HAS_RESOURCES;
3619 		} else {
3620 			if (!(pkt1 = emlxs_pkt_alloc(vport,
3621 			    sizeof (uint32_t) + sizeof (LOGO), sizeof (FCP_RSP),
3622 			    0, KM_NOSLEEP))) {
3623 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3624 				    "Unable to allocate LOGO packet.");
3625 				goto free_resc;
3626 			}
3627 
3628 			/* Make this a polled IO */
3629 			pkt1->pkt_tran_flags &= ~FC_TRAN_INTR;
3630 			pkt1->pkt_tran_flags |= FC_TRAN_NO_INTR;
3631 			pkt1->pkt_comp = NULL;
3632 
3633 			pkt1->pkt_tran_type = FC_PKT_EXCHANGE;
3634 			pkt1->pkt_timeout = 60;
3635 
3636 			/* Build (LOGO) the fc header */
3637 			pkt1->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(FABRIC_DID);
3638 			pkt1->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
3639 			pkt1->pkt_cmd_fhdr.s_id =
3640 			    LE_SWAP24_LO(pkt->pkt_resp_fhdr.d_id);
3641 			pkt1->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
3642 			pkt1->pkt_cmd_fhdr.f_ctl =
3643 			    F_CTL_FIRST_SEQ | F_CTL_END_SEQ |
3644 			    F_CTL_SEQ_INITIATIVE;
3645 			pkt1->pkt_cmd_fhdr.seq_id = 0;
3646 			pkt1->pkt_cmd_fhdr.df_ctl = 0;
3647 			pkt1->pkt_cmd_fhdr.seq_cnt = 0;
3648 			pkt1->pkt_cmd_fhdr.ox_id = 0xFFFF;
3649 			pkt1->pkt_cmd_fhdr.rx_id = 0xFFFF;
3650 			pkt1->pkt_cmd_fhdr.ro = 0;
3651 
3652 			/* Build the command (LOGO) */
3653 			els = (ELS_PKT *) pkt1->pkt_cmd;
3654 			els->elsCode = 0x05;	/* LOGO */
3655 			els->un.logo.un.nPortId32 =
3656 			    LE_SWAP32(pkt->pkt_resp_fhdr.d_id);
3657 			bcopy((caddr_t)&hba->wwpn, (caddr_t)wwn, 8);
3658 			wwn[0] = 0x20;
3659 			wwn[1] = hba->vpi_max;
3660 			bcopy(wwn, &els->un.logo.portName, 8);
3661 
3662 			if (emlxs_pkt_send(pkt1, 1) != FC_SUCCESS) {
3663 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3664 				    "%s: Unable to send packet.",
3665 				    emlxs_dfc_xlate(dfc->cmd));
3666 
3667 				goto free_resc;
3668 			}
3669 
3670 			if (pkt1->pkt_state != FC_PKT_SUCCESS) {
3671 				if (pkt1->pkt_state == FC_PKT_TIMEOUT) {
3672 					EMLXS_MSGF(EMLXS_CONTEXT,
3673 					    &emlxs_dfc_error_msg,
3674 					    "%s: Pkt Transport error. "
3675 					    "Pkt Timeout.",
3676 					    emlxs_dfc_xlate(dfc->cmd));
3677 				} else {
3678 					EMLXS_MSGF(EMLXS_CONTEXT,
3679 					    &emlxs_dfc_error_msg,
3680 					    "%s: Pkt Transport error. state=%x",
3681 					    emlxs_dfc_xlate(dfc->cmd),
3682 					    pkt1->pkt_state);
3683 				}
3684 				goto free_resc;
3685 			}
3686 
3687 			checklist |= CL_FABRIC_HAS_RESOURCES;
3688 free_resc:
3689 			/* Free default RPIs and VPI */
3690 			/* Unregister all nodes */
3691 			(void) EMLXS_SLI_UNREG_NODE(vport, 0, 0, 0, 0);
3692 
3693 			(void) emlxs_mb_unreg_vpi(vport);
3694 		}
3695 	} else if (pkt->pkt_state == FC_PKT_LS_RJT) {
3696 		lsrjt = (LS_RJT *) pkt->pkt_resp;
3697 		if (lsrjt->un.b.lsRjtRsnCodeExp != LSEXP_OUT_OF_RESOURCE) {
3698 			checklist |= CL_FABRIC_HAS_RESOURCES;
3699 		}
3700 	}
3701 
3702 done:
3703 	bcopy((void *)&checklist, (void *)dfc->buf1, sizeof (uint32_t));
3704 
3705 	if (pkt) {
3706 		/* Free the pkt */
3707 		emlxs_pkt_free(pkt);
3708 	}
3709 
3710 	if (pkt1) {
3711 		/* Free the pkt */
3712 		emlxs_pkt_free(pkt1);
3713 	}
3714 
3715 	return (rval);
3716 
3717 } /* emlxs_dfc_npiv_test() */
3718 
3719 
3720 /*ARGSUSED*/
3721 static int32_t
3722 emlxs_dfc_get_rev(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3723 {
3724 	emlxs_port_t	*port = &PPORT;
3725 	uint32_t	rev;
3726 
3727 	if (!dfc->buf1 || !dfc->buf1_size) {
3728 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3729 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3730 
3731 		return (DFC_ARG_NULL);
3732 	}
3733 
3734 	if (dfc->buf1_size < sizeof (uint32_t)) {
3735 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3736 		    "%s: Buffer1 too small. (size=%d)",
3737 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
3738 
3739 		return (DFC_ARG_TOOSMALL);
3740 	}
3741 
3742 	rev = DFC_REV;
3743 	bcopy((void *)&rev, (void *)dfc->buf1, sizeof (uint32_t));
3744 
3745 	return (0);
3746 
3747 } /* emlxs_dfc_get_rev() */
3748 
3749 
3750 /*ARGSUSED*/
3751 static int32_t
3752 emlxs_dfc_get_hbainfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3753 {
3754 	emlxs_port_t	*port = &PPORT;
3755 	emlxs_vpd_t	*vpd = &VPD;
3756 	emlxs_config_t	*cfg = &CFG;
3757 	dfc_hbainfo_t	*hbainfo;
3758 	char		pathname[256];
3759 
3760 	if (!dfc->buf1 || !dfc->buf1_size) {
3761 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3762 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3763 
3764 		return (DFC_ARG_NULL);
3765 	}
3766 
3767 	if (dfc->buf1_size < sizeof (dfc_hbainfo_t)) {
3768 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3769 		    "%s: Buffer1 too small. (size=%d)",
3770 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
3771 
3772 		return (DFC_ARG_TOOSMALL);
3773 	}
3774 
3775 	hbainfo = (dfc_hbainfo_t *)dfc->buf1;
3776 	bzero((void *) hbainfo, sizeof (dfc_hbainfo_t));
3777 
3778 	(void) strncpy(hbainfo->vpd_serial_num, vpd->serial_num,
3779 	    (sizeof (hbainfo->vpd_serial_num)-1));
3780 	(void) strncpy(hbainfo->vpd_part_num, vpd->part_num,
3781 	    (sizeof (hbainfo->vpd_part_num)-1));
3782 	(void) strncpy(hbainfo->vpd_port_num, vpd->port_num,
3783 	    (sizeof (hbainfo->vpd_port_num)-1));
3784 	(void) strncpy(hbainfo->vpd_eng_change, vpd->eng_change,
3785 	    (sizeof (hbainfo->vpd_eng_change)-1));
3786 	(void) strncpy(hbainfo->vpd_manufacturer, vpd->manufacturer,
3787 	    (sizeof (hbainfo->vpd_manufacturer)-1));
3788 	(void) strncpy(hbainfo->vpd_model, vpd->model,
3789 	    (sizeof (hbainfo->vpd_model)-1));
3790 	(void) strncpy(hbainfo->vpd_model_desc, vpd->model_desc,
3791 	    (sizeof (hbainfo->vpd_model_desc)-1));
3792 	(void) strncpy(hbainfo->vpd_prog_types, vpd->prog_types,
3793 	    (sizeof (hbainfo->vpd_prog_types)-1));
3794 	(void) strncpy(hbainfo->vpd_id, vpd->id,
3795 	    (sizeof (hbainfo->vpd_id)-1));
3796 
3797 	hbainfo->device_id = hba->model_info.device_id;
3798 	hbainfo->vendor_id =
3799 	    ddi_get32(hba->pci_acc_handle,
3800 	    (uint32_t *)(hba->pci_addr + PCI_VENDOR_ID_REGISTER)) & 0xffff;
3801 
3802 	hbainfo->ports = hba->num_of_ports;
3803 	hbainfo->port_index = vpd->port_index;
3804 
3805 	bcopy(&hba->wwnn, hbainfo->wwnn, sizeof (hbainfo->wwnn));
3806 	(void) strncpy(hbainfo->snn, port->snn, (sizeof (hbainfo->snn)-1));
3807 
3808 	bcopy(&hba->wwpn, hbainfo->wwpn, sizeof (hbainfo->wwpn));
3809 	(void) strncpy(hbainfo->spn, port->spn, (sizeof (hbainfo->spn)-1));
3810 
3811 	hbainfo->biuRev = vpd->biuRev;
3812 	hbainfo->smRev = vpd->smRev;
3813 	hbainfo->smFwRev = vpd->smFwRev;
3814 	hbainfo->endecRev = vpd->endecRev;
3815 	hbainfo->rBit = vpd->rBit;
3816 	hbainfo->fcphHigh = vpd->fcphHigh;
3817 	hbainfo->fcphLow = vpd->fcphLow;
3818 	hbainfo->feaLevelHigh = vpd->feaLevelHigh;
3819 	hbainfo->feaLevelLow = vpd->feaLevelLow;
3820 
3821 	hbainfo->kern_rev = vpd->postKernRev;
3822 	(void) strncpy(hbainfo->kern_name, vpd->postKernName,
3823 	    (sizeof (hbainfo->kern_name)-1));
3824 
3825 	hbainfo->stub_rev = vpd->opFwRev;
3826 	(void) strncpy(hbainfo->stub_name, vpd->opFwName,
3827 	    (sizeof (hbainfo->stub_name)-1));
3828 
3829 	hbainfo->sli1_rev = vpd->sli1FwRev;
3830 	(void) strncpy(hbainfo->sli1_name, vpd->sli1FwName,
3831 	    (sizeof (hbainfo->sli1_name)-1));
3832 
3833 	hbainfo->sli2_rev = vpd->sli2FwRev;
3834 	(void) strncpy(hbainfo->sli2_name, vpd->sli2FwName,
3835 	    (sizeof (hbainfo->sli2_name)-1));
3836 
3837 	hbainfo->sli3_rev = vpd->sli3FwRev;
3838 	(void) strncpy(hbainfo->sli3_name, vpd->sli3FwName,
3839 	    (sizeof (hbainfo->sli3_name)-1));
3840 
3841 	hbainfo->sli4_rev = vpd->sli4FwRev;
3842 	(void) strncpy(hbainfo->sli4_name, vpd->sli4FwName,
3843 	    (sizeof (hbainfo->sli4_name)-1));
3844 
3845 	hbainfo->sli_mode = hba->sli_mode;
3846 	hbainfo->vpi_max  = hba->vpi_max;
3847 	hbainfo->vpi_high = hba->vpi_high;
3848 	hbainfo->flags = 0;
3849 
3850 	/* Set support flags */
3851 	hbainfo->flags  = HBA_FLAG_DYN_WWN;
3852 	hbainfo->flags |= HBA_FLAG_NPIV;
3853 
3854 #ifdef DHCHAP_SUPPORT
3855 	hbainfo->flags |= HBA_FLAG_DHCHAP;
3856 
3857 	if (cfg[CFG_AUTH_E2E].current) {
3858 		hbainfo->flags |= HBA_FLAG_E2E_AUTH;
3859 	}
3860 #endif	/* DHCHAP_SUPPORT */
3861 
3862 #ifdef SAN_DIAG_SUPPORT
3863 	hbainfo->flags |= HBA_FLAG_SAN_DIAG;
3864 #endif	/* SAN_DIAG_SUPPORT */
3865 
3866 #ifdef SFCT_SUPPORT
3867 	hbainfo->flags |= HBA_FLAG_TARGET_MODE;
3868 	if (port->mode == MODE_TARGET) {
3869 		hbainfo->flags |= HBA_FLAG_TARGET_MODE_ENA;
3870 	}
3871 #endif /* SFCT_SUPPORT */
3872 
3873 	hbainfo->flags |= HBA_FLAG_PERSISTLINK;
3874 
3875 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3876 		hbainfo->flags |= HBA_FLAG_EXT_MBOX;
3877 		if (SLI4_FCOE_MODE) {
3878 			hbainfo->flags |= HBA_FLAG_FCOE;
3879 			hbainfo->flags &= ~HBA_FLAG_PERSISTLINK;
3880 		}
3881 	}
3882 
3883 	(void) strncpy(hbainfo->fcode_version, vpd->fcode_version,
3884 	    (sizeof (hbainfo->fcode_version)-1));
3885 	(void) strncpy(hbainfo->boot_version, vpd->boot_version,
3886 	    (sizeof (hbainfo->boot_version)-1));
3887 	(void) strncpy(hbainfo->fw_version, vpd->fw_version,
3888 	    (sizeof (hbainfo->fw_version)-1));
3889 	(void) strncpy(hbainfo->drv_label, emlxs_label,
3890 	    (sizeof (hbainfo->drv_label)-1));
3891 	(void) strncpy(hbainfo->drv_module, emlxs_name,
3892 	    (sizeof (hbainfo->drv_module)-1));
3893 	(void) strncpy(hbainfo->drv_name, DRIVER_NAME,
3894 	    (sizeof (hbainfo->drv_name)-1));
3895 	(void) strncpy(hbainfo->drv_version, emlxs_version,
3896 	    (sizeof (hbainfo->drv_version)-1));
3897 	(void) strncpy(hbainfo->drv_revision, emlxs_revision,
3898 	    (sizeof (hbainfo->drv_revision)-1));
3899 	(void) strncpy(hbainfo->hostname, (char *)utsname.nodename,
3900 	    (sizeof (hbainfo->hostname)-1));
3901 
3902 	(void) ddi_pathname(hba->dip, pathname);
3903 	(void) snprintf(hbainfo->os_devname, (sizeof (hbainfo->os_devname)-1),
3904 	    "/devices%s", pathname);
3905 
3906 	if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
3907 		hbainfo->flags |= HBA_FLAG_OFFLINE;
3908 	}
3909 
3910 	hbainfo->drv_instance = hba->ddiinst;
3911 	hbainfo->port_id = port->did;
3912 	hbainfo->port_type = HBA_PORTTYPE_UNKNOWN;
3913 
3914 #ifdef MENLO_SUPPORT
3915 	if (hba->flag & FC_MENLO_MODE) {
3916 		hbainfo->topology  = LNK_MENLO_MAINTENANCE;
3917 	} else
3918 #endif /* MENLO_SUPPORT */
3919 
3920 	if (hba->state >= FC_LINK_UP) {
3921 		if (hba->topology == TOPOLOGY_LOOP) {
3922 			if (hba->flag & FC_FABRIC_ATTACHED) {
3923 				hbainfo->port_type = HBA_PORTTYPE_NLPORT;
3924 				hbainfo->topology = LNK_PUBLIC_LOOP;
3925 			} else {
3926 				hbainfo->port_type = HBA_PORTTYPE_LPORT;
3927 				hbainfo->topology = LNK_LOOP;
3928 			}
3929 
3930 			hbainfo->alpa_count = port->alpa_map[0];
3931 			bcopy((void *)&port->alpa_map[1], hbainfo->alpa_map,
3932 			    hbainfo->alpa_count);
3933 		} else {
3934 			if (hba->flag & FC_PT_TO_PT) {
3935 				hbainfo->port_type = HBA_PORTTYPE_PTP;
3936 				hbainfo->topology = LNK_PT2PT;
3937 			} else {
3938 				hbainfo->port_type = HBA_PORTTYPE_NPORT;
3939 				hbainfo->topology = LNK_FABRIC;
3940 			}
3941 		}
3942 
3943 		if (hba->flag & FC_FABRIC_ATTACHED) {
3944 			bcopy(&port->fabric_sparam.nodeName,
3945 			    hbainfo->fabric_wwnn,
3946 			    sizeof (hbainfo->fabric_wwnn));
3947 			bcopy(&port->fabric_sparam.portName,
3948 			    hbainfo->fabric_wwpn,
3949 			    sizeof (hbainfo->fabric_wwpn));
3950 		}
3951 
3952 		if (hba->linkspeed == LA_2GHZ_LINK) {
3953 			hbainfo->port_speed = HBA_PORTSPEED_2GBIT;
3954 		} else if (hba->linkspeed == LA_4GHZ_LINK) {
3955 			hbainfo->port_speed = HBA_PORTSPEED_4GBIT;
3956 		} else if (hba->linkspeed == LA_8GHZ_LINK) {
3957 			hbainfo->port_speed = HBA_PORTSPEED_8GBIT;
3958 		} else if (hba->linkspeed == LA_10GHZ_LINK) {
3959 			hbainfo->port_speed = HBA_PORTSPEED_10GBIT;
3960 		} else if (hba->linkspeed == LA_16GHZ_LINK) {
3961 			hbainfo->port_speed = HBA_PORTSPEED_16GBIT;
3962 		} else {
3963 			hbainfo->port_speed = HBA_PORTSPEED_1GBIT;
3964 		}
3965 
3966 		hbainfo->node_count = port->node_count;
3967 	}
3968 
3969 	hbainfo->hard_alpa = cfg[CFG_ASSIGN_ALPA].current;
3970 	hbainfo->supported_cos = LE_SWAP32((FC_NS_CLASS3 | FC_NS_CLASS2));
3971 
3972 	hbainfo->supported_types[0] = LE_SWAP32(0x00000120);
3973 	hbainfo->supported_types[1] = LE_SWAP32(0x00000001);
3974 
3975 	hbainfo->active_types[0] = LE_SWAP32(0x00000120);
3976 	hbainfo->active_types[1] = LE_SWAP32(0x00000001);
3977 
3978 	if (!cfg[CFG_NETWORK_ON].current) {
3979 		hbainfo->active_types[0] &= ~(LE_SWAP32(0x00000020));
3980 	}
3981 
3982 	if (vpd->link_speed & LMT_16GB_CAPABLE) {
3983 		hbainfo->supported_speeds |= FC_HBA_PORTSPEED_16GBIT;
3984 	}
3985 	if (vpd->link_speed & LMT_10GB_CAPABLE) {
3986 		hbainfo->supported_speeds |= FC_HBA_PORTSPEED_10GBIT;
3987 	}
3988 	if (vpd->link_speed & LMT_8GB_CAPABLE) {
3989 		hbainfo->supported_speeds |= FC_HBA_PORTSPEED_8GBIT;
3990 	}
3991 	if (vpd->link_speed & LMT_4GB_CAPABLE) {
3992 		hbainfo->supported_speeds |= FC_HBA_PORTSPEED_4GBIT;
3993 	}
3994 	if (vpd->link_speed & LMT_2GB_CAPABLE) {
3995 		hbainfo->supported_speeds |= FC_HBA_PORTSPEED_2GBIT;
3996 	}
3997 	if (vpd->link_speed & LMT_1GB_CAPABLE) {
3998 		hbainfo->supported_speeds |= FC_HBA_PORTSPEED_1GBIT;
3999 	}
4000 
4001 	hbainfo->max_frame_size = FF_FRAME_SIZE;
4002 
4003 	if (hba->bus_type == SBUS_FC) {
4004 		hbainfo->flags |= HBA_FLAG_SBUS;
4005 	}
4006 
4007 	if (hba->flag & (FC_ONLINING_MODE | FC_OFFLINING_MODE)) {
4008 		hbainfo->flags |= HBA_FLAG_OFFLINE;
4009 		hbainfo->port_state = HBA_PORTSTATE_UNKNOWN;
4010 	} else if (hba->flag & FC_ONLINE_MODE) {
4011 		if (hba->flag & FC_LOOPBACK_MODE) {
4012 			hbainfo->port_state = HBA_PORTSTATE_LOOPBACK;
4013 		} else if (hba->state <= FC_LINK_DOWN) {
4014 			hbainfo->port_state = HBA_PORTSTATE_LINKDOWN;
4015 		}
4016 #ifdef MENLO_SUPPORT
4017 		else if (hba->flag & FC_MENLO_MODE) {
4018 			hbainfo->port_state = HBA_PORTSTATE_LINKDOWN;
4019 		}
4020 #endif /* MENLO_SUPPORT */
4021 		else {
4022 			hbainfo->port_state = HBA_PORTSTATE_ONLINE;
4023 		}
4024 	} else {
4025 		hbainfo->flags |= HBA_FLAG_OFFLINE;
4026 
4027 		if (hba->state == FC_ERROR) {
4028 			hbainfo->port_state = HBA_PORTSTATE_ERROR;
4029 		} else {
4030 			hbainfo->port_state = HBA_PORTSTATE_OFFLINE;
4031 		}
4032 	}
4033 
4034 	hbainfo->pci_function_number = hba->pci_function_number;
4035 	hbainfo->pci_device_number = hba->pci_device_number;
4036 	hbainfo->pci_bus_number = hba->pci_bus_number;
4037 
4038 #ifdef FMA_SUPPORT
4039 	/* Access handle validation */
4040 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
4041 	    != DDI_FM_OK) {
4042 		EMLXS_MSGF(EMLXS_CONTEXT,
4043 		    &emlxs_invalid_access_handle_msg, NULL);
4044 		return (DFC_DRV_ERROR);
4045 	}
4046 #endif  /* FMA_SUPPORT */
4047 
4048 	return (0);
4049 
4050 } /* emlxs_dfc_get_hbainfo() */
4051 
4052 
4053 
4054 /*ARGSUSED*/
4055 static int32_t
4056 emlxs_dfc_get_hbastats(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
4057 {
4058 	emlxs_port_t	*port = &PPORT;
4059 	dfc_hbastats_t	*stats;
4060 	MAILBOX		*mb = NULL;
4061 	MAILBOXQ	*mbq = NULL;
4062 	uint32_t	rval = 0;
4063 
4064 	if (!dfc->buf1 || !dfc->buf1_size) {
4065 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4066 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
4067 
4068 		return (DFC_ARG_NULL);
4069 	}
4070 
4071 	if (dfc->buf1_size < sizeof (dfc_hbastats_t)) {
4072 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4073 		    "%s: Buffer1 too small. (size=%d)",
4074 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
4075 
4076 		return (DFC_ARG_TOOSMALL);
4077 	}
4078 
4079 	mbq =
4080 	    (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
4081 
4082 	mb = (MAILBOX *)mbq;
4083 
4084 	emlxs_mb_read_status(hba, mbq);
4085 
4086 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
4087 
4088 	if (rval == MBX_TIMEOUT) {
4089 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4090 		    "%s: Mailbox timed out. cmd=%x",
4091 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4092 
4093 		rval = DFC_TIMEOUT;
4094 		goto done;
4095 	}
4096 
4097 	if (rval) {
4098 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4099 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
4100 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
4101 
4102 		rval = DFC_IO_ERROR;
4103 		goto done;
4104 	}
4105 
4106 	stats = (dfc_hbastats_t *)dfc->buf1;
4107 	bzero((void *)stats, sizeof (dfc_hbastats_t));
4108 
4109 	stats->tx_frame_cnt = mb->un.varRdStatus.xmitFrameCnt;
4110 	stats->rx_frame_cnt = mb->un.varRdStatus.rcvFrameCnt;
4111 	stats->tx_kbyte_cnt = mb->un.varRdStatus.xmitByteCnt;
4112 	stats->rx_kbyte_cnt = mb->un.varRdStatus.rcvByteCnt;
4113 	stats->tx_seq_cnt = mb->un.varRdStatus.xmitSeqCnt;
4114 	stats->rx_seq_cnt = mb->un.varRdStatus.rcvSeqCnt;
4115 	stats->orig_exch_cnt = mb->un.varRdStatus.totalOrigExchanges;
4116 	stats->resp_exch_cnt = mb->un.varRdStatus.totalRespExchanges;
4117 	stats->pbsy_cnt = mb->un.varRdStatus.rcvPbsyCnt;
4118 	stats->fbsy_cnt = mb->un.varRdStatus.rcvFbsyCnt;
4119 
4120 	emlxs_mb_read_lnk_stat(hba, mbq);
4121 
4122 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
4123 
4124 	if (rval == MBX_TIMEOUT) {
4125 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4126 		    "%s: Mailbox timed out. cmd=%x",
4127 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4128 
4129 		rval = DFC_TIMEOUT;
4130 		goto done;
4131 	}
4132 
4133 	if (rval) {
4134 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4135 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
4136 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
4137 
4138 		rval = DFC_IO_ERROR;
4139 		goto done;
4140 	}
4141 
4142 	stats->link_failure_cnt = mb->un.varRdLnk.linkFailureCnt;
4143 	stats->loss_sync_cnt = mb->un.varRdLnk.lossSyncCnt;
4144 	stats->loss_signal_cnt = mb->un.varRdLnk.lossSignalCnt;
4145 	stats->seq_error_cnt = mb->un.varRdLnk.primSeqErrCnt;
4146 	stats->inval_tx_word_cnt = mb->un.varRdLnk.invalidXmitWord;
4147 	stats->crc_error_cnt = mb->un.varRdLnk.crcCnt;
4148 	stats->seq_timeout_cnt = mb->un.varRdLnk.primSeqTimeout;
4149 	stats->elastic_overrun_cnt = mb->un.varRdLnk.elasticOverrun;
4150 	stats->arb_timeout_cnt = mb->un.varRdLnk.arbTimeout;
4151 	stats->rx_buf_credit = mb->un.varRdLnk.rxBufCredit;
4152 	stats->rx_buf_cnt = mb->un.varRdLnk.rxBufCreditCur;
4153 	stats->tx_buf_credit = mb->un.varRdLnk.txBufCredit;
4154 	stats->tx_buf_cnt = mb->un.varRdLnk.txBufCreditCur;
4155 	stats->EOFa_cnt = mb->un.varRdLnk.EOFaCnt;
4156 	stats->EOFdti_cnt = mb->un.varRdLnk.EOFdtiCnt;
4157 	stats->EOFni_cnt = mb->un.varRdLnk.EOFniCnt;
4158 	stats->SOFf_cnt = mb->un.varRdLnk.SOFfCnt;
4159 	stats->link_event_tag = hba->link_event_tag;
4160 	stats->last_reset_time = hba->timer_tics - hba->stats.ResetTime;
4161 	stats->port_type = HBA_PORTTYPE_UNKNOWN;
4162 
4163 #ifdef MENLO_SUPPORT
4164 	if (hba->flag & FC_MENLO_MODE) {
4165 		stats->topology = LNK_MENLO_MAINTENANCE;
4166 	} else
4167 #endif /* MENLO_SUPPORT */
4168 
4169 	if (hba->state >= FC_LINK_UP) {
4170 		if (hba->topology == TOPOLOGY_LOOP) {
4171 			if (hba->flag & FC_FABRIC_ATTACHED) {
4172 				stats->port_type = HBA_PORTTYPE_NLPORT;
4173 				stats->topology = LNK_PUBLIC_LOOP;
4174 			} else {
4175 				stats->port_type = HBA_PORTTYPE_LPORT;
4176 				stats->topology = LNK_LOOP;
4177 			}
4178 		} else {
4179 			if (hba->flag & FC_PT_TO_PT) {
4180 				stats->port_type = HBA_PORTTYPE_PTP;
4181 				stats->topology = LNK_PT2PT;
4182 			} else {
4183 				stats->port_type = HBA_PORTTYPE_NPORT;
4184 				stats->topology = LNK_FABRIC;
4185 			}
4186 		}
4187 
4188 		if (hba->linkspeed == LA_2GHZ_LINK) {
4189 			stats->link_speed = HBA_PORTSPEED_2GBIT;
4190 		} else if (hba->linkspeed == LA_4GHZ_LINK) {
4191 			stats->link_speed = HBA_PORTSPEED_4GBIT;
4192 		} else if (hba->linkspeed == LA_8GHZ_LINK) {
4193 			stats->link_speed = HBA_PORTSPEED_8GBIT;
4194 		} else if (hba->linkspeed == LA_10GHZ_LINK) {
4195 			stats->link_speed = HBA_PORTSPEED_10GBIT;
4196 		} else if (hba->linkspeed == LA_16GHZ_LINK) {
4197 			stats->link_speed = HBA_PORTSPEED_16GBIT;
4198 		} else {
4199 			stats->link_speed = HBA_PORTSPEED_1GBIT;
4200 		}
4201 	}
4202 
4203 done:
4204 
4205 	/* Free allocated mbox memory */
4206 	if (mbq) {
4207 		kmem_free(mbq, sizeof (MAILBOXQ));
4208 	}
4209 
4210 	return (rval);
4211 
4212 } /* emlxs_dfc_get_hbastats() */
4213 
4214 
4215 
4216 /*ARGSUSED*/
4217 static int32_t
4218 emlxs_dfc_get_drvstats(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
4219 {
4220 	emlxs_port_t	*port = &PPORT;
4221 	dfc_drvstats_t	*stats;
4222 	uint32_t	rval = 0;
4223 
4224 	if (!dfc->buf1 || !dfc->buf1_size) {
4225 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4226 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
4227 
4228 		return (DFC_ARG_NULL);
4229 	}
4230 
4231 	stats = (dfc_drvstats_t *)dfc->buf1;
4232 	bzero((void *)stats, sizeof (dfc_drvstats_t));
4233 
4234 	stats->LinkUp = hba->stats.LinkUp;
4235 	stats->LinkDown = hba->stats.LinkDown;
4236 	stats->LinkEvent = hba->stats.LinkEvent;
4237 	stats->LinkMultiEvent = hba->stats.LinkMultiEvent;
4238 
4239 	stats->MboxIssued = hba->stats.MboxIssued;
4240 	stats->MboxCompleted = hba->stats.MboxCompleted;
4241 	stats->MboxGood = hba->stats.MboxGood;
4242 	stats->MboxError = hba->stats.MboxError;
4243 	stats->MboxBusy = hba->stats.MboxBusy;
4244 	stats->MboxInvalid = hba->stats.MboxInvalid;
4245 
4246 	stats->IocbIssued[0] = hba->stats.IocbIssued[0];
4247 	stats->IocbIssued[1] = hba->stats.IocbIssued[1];
4248 	stats->IocbIssued[2] = hba->stats.IocbIssued[2];
4249 	stats->IocbIssued[3] = hba->stats.IocbIssued[3];
4250 	stats->IocbReceived[0] = hba->stats.IocbReceived[0];
4251 	stats->IocbReceived[1] = hba->stats.IocbReceived[1];
4252 	stats->IocbReceived[2] = hba->stats.IocbReceived[2];
4253 	stats->IocbReceived[3] = hba->stats.IocbReceived[3];
4254 	stats->IocbTxPut[0] = hba->stats.IocbTxPut[0];
4255 	stats->IocbTxPut[1] = hba->stats.IocbTxPut[1];
4256 	stats->IocbTxPut[2] = hba->stats.IocbTxPut[2];
4257 	stats->IocbTxPut[3] = hba->stats.IocbTxPut[3];
4258 	stats->IocbTxGet[0] = hba->stats.IocbTxGet[0];
4259 	stats->IocbTxGet[1] = hba->stats.IocbTxGet[1];
4260 	stats->IocbTxGet[2] = hba->stats.IocbTxGet[2];
4261 	stats->IocbTxGet[3] = hba->stats.IocbTxGet[3];
4262 	stats->IocbRingFull[0] = hba->stats.IocbRingFull[0];
4263 	stats->IocbRingFull[1] = hba->stats.IocbRingFull[1];
4264 	stats->IocbRingFull[2] = hba->stats.IocbRingFull[2];
4265 	stats->IocbRingFull[3] = hba->stats.IocbRingFull[3];
4266 
4267 	stats->IntrEvent[0] = hba->stats.IntrEvent[0];
4268 	stats->IntrEvent[1] = hba->stats.IntrEvent[1];
4269 	stats->IntrEvent[2] = hba->stats.IntrEvent[2];
4270 	stats->IntrEvent[3] = hba->stats.IntrEvent[3];
4271 	stats->IntrEvent[4] = hba->stats.IntrEvent[4];
4272 	stats->IntrEvent[5] = hba->stats.IntrEvent[5];
4273 	stats->IntrEvent[6] = hba->stats.IntrEvent[6];
4274 	stats->IntrEvent[7] = hba->stats.IntrEvent[7];
4275 
4276 	stats->FcpIssued = hba->stats.FcpIssued;
4277 	stats->FcpCompleted = hba->stats.FcpCompleted;
4278 	stats->FcpGood = hba->stats.FcpGood;
4279 	stats->FcpError = hba->stats.FcpError;
4280 
4281 	stats->FcpEvent = hba->stats.FcpEvent;
4282 	stats->FcpStray = hba->stats.FcpStray;
4283 
4284 	stats->ElsEvent = hba->stats.ElsEvent;
4285 	stats->ElsStray = hba->stats.ElsStray;
4286 
4287 	stats->ElsCmdIssued = hba->stats.ElsCmdIssued;
4288 	stats->ElsCmdCompleted = hba->stats.ElsCmdCompleted;
4289 	stats->ElsCmdGood = hba->stats.ElsCmdGood;
4290 	stats->ElsCmdError = hba->stats.ElsCmdError;
4291 
4292 	stats->ElsRspIssued = hba->stats.ElsRspIssued;
4293 	stats->ElsRspCompleted = hba->stats.ElsRspCompleted;
4294 
4295 	stats->ElsRcvEvent = hba->stats.ElsRcvEvent;
4296 	stats->ElsRcvError = hba->stats.ElsRcvError;
4297 	stats->ElsRcvDropped = hba->stats.ElsRcvDropped;
4298 	stats->ElsCmdReceived = hba->stats.ElsCmdReceived;
4299 	stats->ElsRscnReceived = hba->stats.ElsRscnReceived;
4300 	stats->ElsPlogiReceived = hba->stats.ElsPlogiReceived;
4301 	stats->ElsPrliReceived = hba->stats.ElsPrliReceived;
4302 	stats->ElsPrloReceived = hba->stats.ElsPrloReceived;
4303 	stats->ElsLogoReceived = hba->stats.ElsLogoReceived;
4304 	stats->ElsAdiscReceived = hba->stats.ElsAdiscReceived;
4305 	stats->ElsGenReceived = hba->stats.ElsGenReceived;
4306 
4307 	stats->CtEvent = hba->stats.CtEvent;
4308 	stats->CtStray = hba->stats.CtStray;
4309 
4310 	stats->CtCmdIssued = hba->stats.CtCmdIssued;
4311 	stats->CtCmdCompleted = hba->stats.CtCmdCompleted;
4312 	stats->CtCmdGood = hba->stats.CtCmdGood;
4313 	stats->CtCmdError = hba->stats.CtCmdError;
4314 
4315 	stats->CtRspIssued = hba->stats.CtRspIssued;
4316 	stats->CtRspCompleted = hba->stats.CtRspCompleted;
4317 
4318 	stats->CtRcvEvent = hba->stats.CtRcvEvent;
4319 	stats->CtRcvError = hba->stats.CtRcvError;
4320 	stats->CtRcvDropped = hba->stats.CtRcvDropped;
4321 	stats->CtCmdReceived = hba->stats.CtCmdReceived;
4322 
4323 	stats->IpEvent = hba->stats.IpEvent;
4324 	stats->IpStray = hba->stats.IpStray;
4325 
4326 	stats->IpSeqIssued = hba->stats.IpSeqIssued;
4327 	stats->IpSeqCompleted = hba->stats.IpSeqCompleted;
4328 	stats->IpSeqGood = hba->stats.IpSeqGood;
4329 	stats->IpSeqError = hba->stats.IpSeqError;
4330 
4331 	stats->IpBcastIssued = hba->stats.IpBcastIssued;
4332 	stats->IpBcastCompleted = hba->stats.IpBcastCompleted;
4333 	stats->IpBcastGood = hba->stats.IpBcastGood;
4334 	stats->IpBcastError = hba->stats.IpBcastError;
4335 
4336 	stats->IpRcvEvent = hba->stats.IpRcvEvent;
4337 	stats->IpDropped = hba->stats.IpDropped;
4338 	stats->IpSeqReceived = hba->stats.IpSeqReceived;
4339 	stats->IpBcastReceived = hba->stats.IpBcastReceived;
4340 
4341 	stats->IpUbPosted = hba->stats.IpUbPosted;
4342 	stats->ElsUbPosted = hba->stats.ElsUbPosted;
4343 	stats->CtUbPosted = hba->stats.CtUbPosted;
4344 
4345 #if (DFC_REV >= 2)
4346 	stats->IocbThrottled   = hba->stats.IocbThrottled;
4347 	stats->ElsAuthReceived = hba->stats.ElsAuthReceived;
4348 #endif
4349 
4350 	return (rval);
4351 
4352 } /* emlxs_dfc_get_drvstats() */
4353 
4354 
4355 extern uint32_t
4356 emlxs_set_hba_mode(emlxs_hba_t *hba, uint32_t mode)
4357 {
4358 	emlxs_port_t	*port = &PPORT;
4359 	uint32_t	i;
4360 
4361 	mutex_enter(&EMLXS_PORT_LOCK);
4362 
4363 	/* Wait if adapter is in transition */
4364 	i = 0;
4365 	while ((hba->flag & (FC_ONLINING_MODE | FC_OFFLINING_MODE))) {
4366 		if (i++ > 30) {
4367 			break;
4368 		}
4369 
4370 		mutex_exit(&EMLXS_PORT_LOCK);
4371 		delay(drv_usectohz(1000000));
4372 		mutex_enter(&EMLXS_PORT_LOCK);
4373 	}
4374 
4375 	if (hba->sli_mode <= EMLXS_HBA_SLI3_MODE) {
4376 		switch (mode) {
4377 		case DDI_SHOW:
4378 			break;
4379 
4380 		case DDI_ONDI:
4381 			if (hba->flag & FC_OFFLINE_MODE) {
4382 				mutex_exit(&EMLXS_PORT_LOCK);
4383 				(void) emlxs_online(hba);
4384 				mutex_enter(&EMLXS_PORT_LOCK);
4385 			}
4386 			break;
4387 
4388 
4389 		/* Killed + Restart state */
4390 		case DDI_OFFDI:
4391 			if (hba->flag & FC_ONLINE_MODE) {
4392 				mutex_exit(&EMLXS_PORT_LOCK);
4393 
4394 				(void) emlxs_offline(hba, 0);
4395 
4396 				/* Reset with restart */
4397 				EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
4398 
4399 				mutex_enter(&EMLXS_PORT_LOCK);
4400 			} else if (hba->state < FC_INIT_START) {
4401 				mutex_exit(&EMLXS_PORT_LOCK);
4402 
4403 				/* Reset with restart */
4404 				EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
4405 
4406 				mutex_enter(&EMLXS_PORT_LOCK);
4407 			}
4408 
4409 			break;
4410 
4411 		/* Killed + Reset state */
4412 		case DDI_WARMDI:
4413 			if (hba->flag & FC_ONLINE_MODE) {
4414 				mutex_exit(&EMLXS_PORT_LOCK);
4415 
4416 				(void) emlxs_offline(hba, 0);
4417 
4418 				/* Reset with no restart */
4419 				EMLXS_SLI_HBA_RESET(hba, 0, 0, 0);
4420 
4421 				mutex_enter(&EMLXS_PORT_LOCK);
4422 			} else if (hba->state != FC_WARM_START) {
4423 				mutex_exit(&EMLXS_PORT_LOCK);
4424 
4425 				/* Reset with no restart */
4426 				EMLXS_SLI_HBA_RESET(hba, 0, 0, 0);
4427 
4428 				mutex_enter(&EMLXS_PORT_LOCK);
4429 			}
4430 
4431 			break;
4432 
4433 		/* Killed */
4434 		case DDI_DIAGDI:
4435 			if (hba->flag & FC_ONLINE_MODE) {
4436 				mutex_exit(&EMLXS_PORT_LOCK);
4437 
4438 				(void) emlxs_offline(hba, 0);
4439 
4440 				mutex_enter(&EMLXS_PORT_LOCK);
4441 			} else if (hba->state != FC_KILLED) {
4442 				mutex_exit(&EMLXS_PORT_LOCK);
4443 
4444 				EMLXS_SLI_HBA_KILL(hba);
4445 
4446 				mutex_enter(&EMLXS_PORT_LOCK);
4447 			}
4448 
4449 			break;
4450 
4451 		default:
4452 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4453 			    "set_hba_mode: Invalid mode. mode=%x", mode);
4454 			mutex_exit(&EMLXS_PORT_LOCK);
4455 			return (0);
4456 		}
4457 
4458 		/* Wait if adapter is in transition */
4459 		i = 0;
4460 		while ((hba->flag & (FC_ONLINING_MODE | FC_OFFLINING_MODE))) {
4461 			if (i++ > 30) {
4462 				break;
4463 			}
4464 
4465 			mutex_exit(&EMLXS_PORT_LOCK);
4466 			delay(drv_usectohz(1000000));
4467 			mutex_enter(&EMLXS_PORT_LOCK);
4468 		}
4469 
4470 		/* Return current state */
4471 		if (hba->flag & FC_ONLINE_MODE) {
4472 			mode = DDI_ONDI;
4473 		} else if (hba->state == FC_KILLED) {
4474 			mode = DDI_DIAGDI;
4475 		} else if (hba->state == FC_WARM_START) {
4476 			mode = DDI_WARMDI;
4477 		} else {
4478 			mode = DDI_OFFDI;
4479 		}
4480 
4481 		mutex_exit(&EMLXS_PORT_LOCK);
4482 
4483 		return (mode);
4484 
4485 	} else { /* SLI4 */
4486 		switch (mode) {
4487 		case DDI_SHOW:
4488 			break;
4489 
4490 		case DDI_ONDI:
4491 			if (hba->flag & FC_OFFLINE_MODE) {
4492 				mutex_exit(&EMLXS_PORT_LOCK);
4493 				(void) emlxs_online(hba);
4494 				mutex_enter(&EMLXS_PORT_LOCK);
4495 			}
4496 			break;
4497 
4498 		case DDI_OFFDI:
4499 			if (hba->flag & FC_ONLINE_MODE) {
4500 				mutex_exit(&EMLXS_PORT_LOCK);
4501 
4502 				(void) emlxs_offline(hba, 0);
4503 
4504 				/* Reset with restart */
4505 				EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
4506 
4507 				mutex_enter(&EMLXS_PORT_LOCK);
4508 			} else if (hba->state < FC_INIT_START) {
4509 				mutex_exit(&EMLXS_PORT_LOCK);
4510 
4511 				/* Reset with restart */
4512 				EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
4513 
4514 				mutex_enter(&EMLXS_PORT_LOCK);
4515 			}
4516 			break;
4517 
4518 		case DDI_DIAGDI:
4519 			if (!(hba->model_info.chip & EMLXS_LANCER_CHIP)) {
4520 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4521 				    "set_hba_mode: Invalid mode. mode=%x",
4522 				    mode);
4523 				mutex_exit(&EMLXS_PORT_LOCK);
4524 				return (0);
4525 			}
4526 
4527 			mutex_exit(&EMLXS_PORT_LOCK);
4528 			(void) emlxs_reset(port,
4529 			    EMLXS_DFC_RESET_ALL_FORCE_DUMP);
4530 
4531 			return (mode);
4532 
4533 		case DDI_WARMDI:
4534 		default:
4535 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4536 			    "set_hba_mode: Invalid mode. mode=%x", mode);
4537 			mutex_exit(&EMLXS_PORT_LOCK);
4538 			return (0);
4539 		}
4540 
4541 		/* Wait if adapter is in transition */
4542 		i = 0;
4543 		while ((hba->flag & (FC_ONLINING_MODE | FC_OFFLINING_MODE))) {
4544 			if (i++ > 30) {
4545 				break;
4546 			}
4547 
4548 			mutex_exit(&EMLXS_PORT_LOCK);
4549 			delay(drv_usectohz(1000000));
4550 			mutex_enter(&EMLXS_PORT_LOCK);
4551 		}
4552 
4553 		/* Return current state */
4554 		if (hba->flag & FC_ONLINE_MODE) {
4555 			mode = DDI_ONDI;
4556 		} else {
4557 			mode = DDI_OFFDI;
4558 		}
4559 
4560 		mutex_exit(&EMLXS_PORT_LOCK);
4561 
4562 		return (mode);
4563 	}
4564 
4565 } /* emlxs_set_hba_mode() */
4566 
4567 
4568 /*ARGSUSED*/
4569 static int32_t
4570 emlxs_dfc_set_diag(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
4571 {
4572 	emlxs_port_t	*port = &PPORT;
4573 	int32_t		rval = 0;
4574 	int32_t		flag;
4575 
4576 	if (!dfc->buf1 || !dfc->buf1_size) {
4577 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4578 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
4579 
4580 		return (DFC_ARG_NULL);
4581 	}
4582 
4583 	if (dfc->buf1_size < sizeof (uint32_t)) {
4584 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4585 		    "%s: Buffer1 too small. (size=%d)",
4586 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
4587 
4588 		return (DFC_ARG_TOOSMALL);
4589 	}
4590 
4591 	flag = emlxs_set_hba_mode(hba, dfc->flag);
4592 	bcopy((void *)&flag, (void *)dfc->buf1, sizeof (uint32_t));
4593 
4594 	return (rval);
4595 
4596 } /* emlxs_dfc_set_diag() */
4597 
4598 
4599 
4600 /*ARGSUSED*/
4601 static int32_t
4602 emlxs_dfc_send_mbox(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
4603 {
4604 	emlxs_port_t	*port  = &PPORT;
4605 	MAILBOX		*mb    = NULL;
4606 	MAILBOXQ	*mbq   = NULL;
4607 	uint32_t	size  = 0;
4608 	MATCHMAP	*rx_mp = NULL;
4609 	MATCHMAP	*tx_mp = NULL;
4610 	uintptr_t	lptr;
4611 	int32_t		rval  = 0;
4612 	int32_t		mbxstatus = 0;
4613 	NODELIST	*ndlp;
4614 	uint32_t	did;
4615 	uint32_t	extsize = 0;
4616 	uint8_t		*extbuf  = NULL;
4617 
4618 	if (hba->sli_mode > EMLXS_HBA_SLI3_MODE) {
4619 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4620 		    "%s: SLI Mode %d not supported.", emlxs_dfc_xlate(dfc->cmd),
4621 		    hba->sli_mode);
4622 
4623 		return (DFC_NOT_SUPPORTED);
4624 	}
4625 
4626 	if (!dfc->buf1 || !dfc->buf1_size) {
4627 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4628 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
4629 
4630 		return (DFC_ARG_NULL);
4631 	}
4632 
4633 	if (!dfc->buf2 || !dfc->buf2_size) {
4634 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4635 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
4636 
4637 		return (DFC_ARG_NULL);
4638 	}
4639 
4640 	if (dfc->buf1_size > MAILBOX_CMD_BSIZE) {
4641 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4642 		    "%s: Buffer1 too large. (size=%d)",
4643 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
4644 
4645 		return (DFC_ARG_TOOBIG);
4646 	}
4647 #ifdef MBOX_EXT_SUPPORT
4648 	if (dfc->buf3_size || dfc->buf4_size) {
4649 		if (dfc->buf3_size && !dfc->buf3) {
4650 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4651 			    "%s: Null buffer3 found.",
4652 			    emlxs_dfc_xlate(dfc->cmd));
4653 
4654 			return (DFC_ARG_NULL);
4655 		}
4656 
4657 		if (dfc->buf3_size > MBOX_EXTENSION_SIZE) {
4658 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4659 			    "%s: buffer3 too large. (size=%d)",
4660 			    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
4661 
4662 			return (DFC_ARG_TOOBIG);
4663 		}
4664 
4665 		if (dfc->buf4_size && !dfc->buf4) {
4666 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4667 			    "%s: Null buffer4 found.",
4668 			    emlxs_dfc_xlate(dfc->cmd));
4669 
4670 			return (DFC_ARG_NULL);
4671 		}
4672 
4673 		if (dfc->buf4_size > MBOX_EXTENSION_SIZE) {
4674 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4675 			    "%s: buffer4 too large. (size=%d)",
4676 			    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
4677 
4678 			return (DFC_ARG_TOOBIG);
4679 		}
4680 
4681 		extsize = (dfc->buf3_size > dfc->buf4_size) ?
4682 		    dfc->buf3_size : dfc->buf4_size;
4683 		extbuf = (uint8_t *)kmem_zalloc(extsize, KM_SLEEP);
4684 
4685 		if (dfc->buf3_size) {
4686 			bcopy((void *)dfc->buf3, (void *)extbuf,
4687 			    dfc->buf3_size);
4688 		}
4689 	}
4690 #endif /* MBOX_EXT_SUPPORT */
4691 
4692 	mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
4693 	mb = (MAILBOX *) mbq;
4694 	bcopy((void *)dfc->buf1, (void *)mb, dfc->buf1_size);
4695 
4696 #ifdef _LP64
4697 	if ((mb->mbxCommand == MBX_READ_SPARM) ||
4698 	    (mb->mbxCommand == MBX_READ_RPI) ||
4699 	    (mb->mbxCommand == MBX_REG_LOGIN) ||
4700 	    (mb->mbxCommand == MBX_READ_LA) ||
4701 	    (mb->mbxCommand == MBX_RUN_BIU_DIAG)) {
4702 
4703 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4704 		    "%s: Invalid mailbox command. Must use 64bit version. "
4705 		    "cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4706 
4707 		/* Must use 64 bit versions of these mbox cmds */
4708 		rval = DFC_ARG_INVALID;
4709 		goto done;
4710 	}
4711 #endif
4712 
4713 	lptr = 0;
4714 	size = 0;
4715 	switch (mb->mbxCommand) {
4716 	/* Offline only */
4717 	case MBX_CONFIG_LINK:	/* 0x07 */
4718 	case MBX_PART_SLIM:	    /* 0x08 */
4719 	case MBX_CONFIG_RING:	/* 0x09 */
4720 	case MBX_DUMP_CONTEXT:	/* 0x18 */
4721 	case MBX_RUN_DIAGS:	    /* 0x19 */
4722 	case MBX_RESTART:	    /* 0x1A */
4723 	case MBX_SET_MASK:	    /* 0x20 */
4724 	case MBX_FLASH_WR_ULA:	/* 0x98 */
4725 		if (!(hba->flag & FC_OFFLINE_MODE)) {
4726 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4727 			    "%s: Adapter not offline. cmd=%x",
4728 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4729 
4730 			rval = DFC_ONLINE_ERROR;
4731 			goto done;
4732 		}
4733 		break;
4734 
4735 	/* Online / Offline */
4736 	case MBX_UNREG_LOGIN:	/* 0x14 */
4737 		ndlp = emlxs_node_find_rpi(port, mb->un.varUnregLogin.rpi);
4738 
4739 		if (ndlp) {
4740 			did = ndlp->nlp_DID;
4741 
4742 			/* remove it */
4743 			emlxs_node_rm(port, ndlp);
4744 
4745 			/*
4746 			 * If we just unregistered the host node then
4747 			 * clear the host DID
4748 			 */
4749 			if (did == port->did) {
4750 				port->did = 0;
4751 			}
4752 		} else {
4753 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4754 			    "%s: Node not found. cmd=%x rpi=%d",
4755 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand,
4756 			    mb->un.varUnregLogin.rpi);
4757 
4758 			/* Node does not exist */
4759 			rval = DFC_ARG_INVALID;
4760 			goto done;
4761 		}
4762 
4763 		/* Send it */
4764 		break;
4765 
4766 	case MBX_UNREG_D_ID:	/* 0x23 */
4767 
4768 		did = mb->un.varRegLogin.did;
4769 
4770 		if (did == 0) {
4771 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4772 			    "%s: Node not found. cmd=%x did=%x",
4773 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand, did);
4774 
4775 			rval = DFC_ARG_INVALID;
4776 			goto done;
4777 		}
4778 
4779 		if (did == 0xffffffff) {
4780 			emlxs_node_destroy_all(port);
4781 			break;
4782 		}
4783 
4784 		/* Check for base node */
4785 		if (did == BCAST_DID) {
4786 			/* just flush base node */
4787 			(void) emlxs_tx_node_flush(port, &port->node_base,
4788 			    0, 0, 0);
4789 			(void) emlxs_chipq_node_flush(port, 0, &port->node_base,
4790 			    0);
4791 
4792 			/* Return now */
4793 			rval = 0;
4794 			goto done;
4795 		}
4796 
4797 		/* Make sure the node does already exist */
4798 		ndlp = emlxs_node_find_did(port, did, 1);
4799 
4800 		if (ndlp) {
4801 			/* remove it */
4802 			emlxs_node_rm(port, ndlp);
4803 
4804 			/*
4805 			 * If we just unregistered the host node then
4806 			 * clear the host DID
4807 			 */
4808 			if (did == port->did) {
4809 				port->did = 0;
4810 			}
4811 		} else {
4812 
4813 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4814 			    "%s: Node not found. cmd=%x did=%x",
4815 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand, did);
4816 
4817 			/* Node does not exist */
4818 			rval = DFC_ARG_INVALID;
4819 			goto done;
4820 		}
4821 
4822 		/* Send it */
4823 		break;
4824 
4825 	/* Online / Offline - with DMA */
4826 	case MBX_READ_EVENT_LOG:	/* 0x38 */
4827 		lptr =
4828 		    (uintptr_t)PADDR(mb->un.varRdEvtLog.un.sp64.addrHigh,
4829 		    mb->un.varRdEvtLog.un.sp64.addrLow);
4830 		size = (int)mb->un.varRdEvtLog.un.sp64.tus.f.bdeSize;
4831 
4832 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4833 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4834 			    "%s: Invalid BDE. cmd=%x",
4835 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4836 
4837 			rval = DFC_ARG_INVALID;
4838 			goto done;
4839 		}
4840 
4841 		/* Allocate receive buffer */
4842 		if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
4843 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4844 			    "%s: Unable to allocate receive buffer. cmd=%x",
4845 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4846 
4847 			rval = DFC_DRVRES_ERROR;
4848 			goto done;
4849 		}
4850 
4851 		mb->un.varRdEvtLog.un.sp64.addrHigh = PADDR_HI(rx_mp->phys);
4852 		mb->un.varRdEvtLog.un.sp64.addrLow = PADDR_LO(rx_mp->phys);
4853 		mb->un.varRdEvtLog.un.sp64.tus.f.bdeFlags = 0;
4854 
4855 		break;
4856 
4857 	case MBX_READ_SPARM:	/* 0x0D */
4858 	case MBX_READ_SPARM64:	/* 0x8D */
4859 		lptr =
4860 		    (uintptr_t)PADDR(mb->un.varRdSparm.un.sp64.addrHigh,
4861 		    mb->un.varRdSparm.un.sp64.addrLow);
4862 		size = (int)mb->un.varRdSparm.un.sp64.tus.f.bdeSize;
4863 
4864 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4865 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4866 			    "%s: Invalid BDE. cmd=%x",
4867 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4868 
4869 			rval = DFC_ARG_INVALID;
4870 			goto done;
4871 		}
4872 
4873 		/* Allocate receive buffer */
4874 		if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
4875 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4876 			    "%s: Unable to allocate receive buffer. cmd=%x",
4877 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4878 
4879 			rval = DFC_DRVRES_ERROR;
4880 			goto done;
4881 		}
4882 
4883 		mb->un.varRdSparm.un.sp64.addrHigh = PADDR_HI(rx_mp->phys);
4884 		mb->un.varRdSparm.un.sp64.addrLow = PADDR_LO(rx_mp->phys);
4885 		mb->un.varRdSparm.un.sp64.tus.f.bdeFlags = 0;
4886 
4887 		break;
4888 
4889 	case MBX_READ_RPI:	/* 0x0F */
4890 	case MBX_READ_RPI64:	/* 0x8F */
4891 		lptr =
4892 		    (uintptr_t)PADDR(mb->un.varRdRPI.un.sp64.addrHigh,
4893 		    mb->un.varRdRPI.un.sp64.addrLow);
4894 		size = (int)mb->un.varRdRPI.un.sp64.tus.f.bdeSize;
4895 
4896 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4897 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4898 			    "%s: Invalid BDE. cmd=%x",
4899 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4900 
4901 			rval = DFC_ARG_INVALID;
4902 			goto done;
4903 		}
4904 
4905 		/* Allocate receive buffer */
4906 		if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
4907 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4908 			    "%s: Unable to allocate receive buffer. cmd=%x",
4909 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4910 
4911 			rval = DFC_DRVRES_ERROR;
4912 			goto done;
4913 		}
4914 
4915 		mb->un.varRdRPI.un.sp64.addrHigh = PADDR_HI(rx_mp->phys);
4916 		mb->un.varRdRPI.un.sp64.addrLow = PADDR_LO(rx_mp->phys);
4917 		mb->un.varRdRPI.un.sp64.tus.f.bdeFlags = 0;
4918 
4919 		break;
4920 
4921 	case MBX_RUN_BIU_DIAG:	 /* 0x04 */
4922 	case MBX_RUN_BIU_DIAG64: /* 0x84 */
4923 		lptr =
4924 		    (uintptr_t)PADDR(mb->un.varBIUdiag.un.s2.xmit_bde64.
4925 		    addrHigh, mb->un.varBIUdiag.un.s2.xmit_bde64.addrLow);
4926 		size = (int)mb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize;
4927 
4928 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4929 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4930 			    "%s: Invalid xmit BDE. cmd=%x",
4931 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4932 
4933 			rval = DFC_ARG_INVALID;
4934 			goto done;
4935 		}
4936 
4937 		/* Allocate xmit buffer */
4938 		if ((tx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
4939 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4940 			    "%s: Unable to allocate xmit buffer. cmd=%x",
4941 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4942 
4943 			rval = DFC_DRVRES_ERROR;
4944 			goto done;
4945 		}
4946 
4947 		/* Initialize the xmit buffer */
4948 		if (ddi_copyin((void *)lptr, (void *)tx_mp->virt, size,
4949 		    mode) != 0) {
4950 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4951 			    "%s: ddi_copyin failed. cmd=%x",
4952 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4953 
4954 			rval = DFC_COPYIN_ERROR;
4955 			goto done;
4956 		}
4957 		EMLXS_MPDATA_SYNC(tx_mp->dma_handle, 0, size,
4958 		    DDI_DMA_SYNC_FORDEV);
4959 
4960 		mb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh =
4961 		    PADDR_HI(tx_mp->phys);
4962 		mb->un.varBIUdiag.un.s2.xmit_bde64.addrLow =
4963 		    PADDR_LO(tx_mp->phys);
4964 		mb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeFlags = 0;
4965 
4966 		/* Initialize the receive buffer */
4967 		lptr =
4968 		    (uintptr_t)PADDR(mb->un.varBIUdiag.un.s2.rcv_bde64.
4969 		    addrHigh, mb->un.varBIUdiag.un.s2.rcv_bde64.addrLow);
4970 		size = (int)mb->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeSize;
4971 
4972 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4973 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4974 			    "%s: Invalid rcv BDE. cmd=%x",
4975 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4976 
4977 			rval = DFC_ARG_INVALID;
4978 			goto done;
4979 		}
4980 
4981 		/* Allocate receive buffer */
4982 		if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
4983 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4984 			    "%s: Unable to allocate receive buffer. cmd=%x",
4985 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4986 
4987 			rval = DFC_DRVRES_ERROR;
4988 			goto done;
4989 		}
4990 
4991 		mb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh =
4992 		    PADDR_HI(rx_mp->phys);
4993 		mb->un.varBIUdiag.un.s2.rcv_bde64.addrLow =
4994 		    PADDR_LO(rx_mp->phys);
4995 		mb->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeFlags = 0;
4996 
4997 		break;
4998 
4999 	case MBX_REG_LOGIN:	/* 0x13 */
5000 	case MBX_REG_LOGIN64:	/* 0x93 */
5001 
5002 		did = mb->un.varRegLogin.did;
5003 
5004 		/* Check for invalid node ids to register */
5005 		if (did == 0 || (did & 0xff000000)) {
5006 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5007 			    "%s: Invalid node id. cmd=%x did=%x",
5008 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand, did);
5009 
5010 			rval = DFC_ARG_INVALID;
5011 			goto done;
5012 		}
5013 
5014 		/* Check if the node limit has been reached */
5015 		if (port->node_count >= hba->max_nodes) {
5016 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5017 			    "%s: Too many nodes. cmd=%x",
5018 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
5019 
5020 			rval = DFC_HBARES_ERROR;
5021 			goto done;
5022 		}
5023 
5024 		lptr =
5025 		    (uintptr_t)PADDR(mb->un.varRegLogin.un.sp64.addrHigh,
5026 		    mb->un.varRegLogin.un.sp64.addrLow);
5027 		size = (int)mb->un.varRegLogin.un.sp64.tus.f.bdeSize;
5028 
5029 		if (!lptr || (size > MEM_BUF_SIZE)) {
5030 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5031 			    "%s: Invalid BDE. cmd=%x",
5032 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
5033 
5034 			rval = DFC_ARG_INVALID;
5035 			goto done;
5036 		}
5037 
5038 		/* Allocate xmit buffer */
5039 		if ((tx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
5040 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5041 			    "%s: Unable to allocate xmit buffer. cmd=%x",
5042 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
5043 
5044 			rval = DFC_DRVRES_ERROR;
5045 			goto done;
5046 		}
5047 
5048 		/* Initialize the xmit buffer */
5049 		if (ddi_copyin((void *)lptr, (void *)tx_mp->virt, size,
5050 		    mode) != 0) {
5051 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5052 			    "%s: Unable to allocate xmit buffer. cmd=%x",
5053 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
5054 
5055 			rval = DFC_COPYIN_ERROR;
5056 			goto done;
5057 		}
5058 		EMLXS_MPDATA_SYNC(tx_mp->dma_handle, 0, size,
5059 		    DDI_DMA_SYNC_FORDEV);
5060 
5061 		mb->un.varRegLogin.un.sp64.addrHigh = PADDR_HI(tx_mp->phys);
5062 		mb->un.varRegLogin.un.sp64.addrLow = PADDR_LO(tx_mp->phys);
5063 		mb->un.varRegLogin.un.sp64.tus.f.bdeFlags = 0;
5064 
5065 		break;
5066 
5067 	case MBX_READ_LA:	/* 0x15 */
5068 	case MBX_READ_LA64:	/* 0x95 */
5069 		lptr =
5070 		    (uintptr_t)PADDR(mb->un.varReadLA.un.lilpBde64.
5071 		    addrHigh, mb->un.varReadLA.un.lilpBde64.addrLow);
5072 		size = (int)mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize;
5073 
5074 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
5075 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5076 			    "%s: Invalid BDE. cmd=%x",
5077 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
5078 
5079 			rval = DFC_ARG_INVALID;
5080 			goto done;
5081 		}
5082 
5083 		/* Allocate receive buffer */
5084 		if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
5085 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5086 			    "%s: Unable to allocate receive buffer. cmd=%x",
5087 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
5088 
5089 			rval = DFC_DRVRES_ERROR;
5090 			goto done;
5091 		}
5092 
5093 		mb->un.varReadLA.un.lilpBde64.addrHigh =
5094 		    PADDR_HI(rx_mp->phys);
5095 		mb->un.varReadLA.un.lilpBde64.addrLow =
5096 		    PADDR_LO(rx_mp->phys);
5097 		mb->un.varReadLA.un.lilpBde64.tus.f.bdeFlags = 0;
5098 
5099 		break;
5100 
5101 
5102 		/* Do not allow these commands */
5103 	case MBX_CONFIG_PORT:	/* 0x88 */
5104 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5105 		    "%s: Command not allowed. cmd=%x",
5106 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
5107 
5108 		rval = DFC_ARG_INVALID;
5109 		goto done;
5110 
5111 
5112 	/* Online / Offline */
5113 	default:
5114 		break;
5115 
5116 	}	/* switch() */
5117 
5118 	mb->mbxOwner = OWN_HOST;
5119 
5120 	/* Set or don't set the PASSTHRU bit. */
5121 	/* Setting will prevent the driver from processing it as its own */
5122 	switch (mb->mbxCommand) {
5123 	case MBX_REG_LOGIN:	/* 0x13 */
5124 	case MBX_REG_LOGIN64:	/* 0x93 */
5125 		break;
5126 
5127 	default:
5128 		mbq->flag |= MBQ_PASSTHRU;
5129 	}
5130 
5131 #ifdef MBOX_EXT_SUPPORT
5132 	if (extbuf) {
5133 		mbq->extbuf  = extbuf;
5134 		mbq->extsize = extsize;
5135 	}
5136 #endif /* MBOX_EXT_SUPPORT */
5137 
5138 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5139 	    "%s: %s sent.  (%x %x %x %x)", emlxs_dfc_xlate(dfc->cmd),
5140 	    emlxs_mb_cmd_xlate(mb->mbxCommand), mb->un.varWords[0],
5141 	    mb->un.varWords[1], mb->un.varWords[2], mb->un.varWords[3]);
5142 
5143 	/* issue the mbox cmd to the sli */
5144 	mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
5145 
5146 	if (mbxstatus) {
5147 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5148 		    "%s: %s failed. mbxstatus=0x%x",
5149 		    emlxs_dfc_xlate(dfc->cmd),
5150 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
5151 
5152 	}
5153 
5154 	bcopy((void *)mb, (void *)dfc->buf2, dfc->buf2_size);
5155 
5156 	if (rx_mp) {
5157 		EMLXS_MPDATA_SYNC(rx_mp->dma_handle, 0, size,
5158 		    DDI_DMA_SYNC_FORKERNEL);
5159 
5160 		if (ddi_copyout((void *)rx_mp->virt, (void *)lptr, size,
5161 		    mode) != 0) {
5162 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5163 			    "%s: ddi_copyout failed for receive buffer. cmd=%x",
5164 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
5165 
5166 			rval = DFC_COPYOUT_ERROR;
5167 			goto done;
5168 		}
5169 	}
5170 #ifdef MBOX_EXT_SUPPORT
5171 	/*  Any data needs to copy to mbox extension area */
5172 	if (dfc->buf4_size) {
5173 		bcopy((void *)extbuf, (void *)dfc->buf4, dfc->buf4_size);
5174 	}
5175 #endif /* MBOX_EXT_SUPPORT */
5176 
5177 	rval = 0;
5178 
5179 done:
5180 
5181 	/* Free allocated mbox memory */
5182 	if (extbuf) {
5183 		kmem_free(extbuf, extsize);
5184 	}
5185 
5186 	/* Free allocated mbox memory */
5187 	if (mbq) {
5188 		kmem_free(mbq, sizeof (MAILBOXQ));
5189 	}
5190 
5191 	/* Free allocated mbuf memory */
5192 	if (rx_mp) {
5193 #ifdef FMA_SUPPORT
5194 		if (!rval) {
5195 			if (emlxs_fm_check_dma_handle(hba, rx_mp->dma_handle)
5196 			    != DDI_FM_OK) {
5197 				EMLXS_MSGF(EMLXS_CONTEXT,
5198 				    &emlxs_invalid_dma_handle_msg,
5199 				    "dfc_send_mbox: hdl=%p",
5200 				    rx_mp->dma_handle);
5201 				rval = DFC_IO_ERROR;
5202 			}
5203 		}
5204 #endif  /* FMA_SUPPORT */
5205 		emlxs_mem_buf_free(hba, rx_mp);
5206 	}
5207 
5208 	if (tx_mp) {
5209 #ifdef FMA_SUPPORT
5210 		if (!rval) {
5211 			if (emlxs_fm_check_dma_handle(hba, tx_mp->dma_handle)
5212 			    != DDI_FM_OK) {
5213 				EMLXS_MSGF(EMLXS_CONTEXT,
5214 				    &emlxs_invalid_dma_handle_msg,
5215 				    "dfc_send_mbox: hdl=%p",
5216 				    tx_mp->dma_handle);
5217 				rval = DFC_IO_ERROR;
5218 			}
5219 		}
5220 #endif  /* FMA_SUPPORT */
5221 		emlxs_mem_buf_free(hba, tx_mp);
5222 	}
5223 
5224 	return (rval);
5225 
5226 } /* emlxs_dfc_send_mbox() */
5227 
5228 
5229 /*ARGSUSED*/
5230 static int32_t
5231 emlxs_dfc_read_pci(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5232 {
5233 	emlxs_port_t	*port = &PPORT;
5234 	uint32_t	offset;
5235 	uint32_t	cnt;
5236 	uint32_t	outsz;
5237 	uint32_t	i;
5238 	uint32_t	*bptr;
5239 	uint32_t	value;
5240 	uint32_t	max = 4096;
5241 
5242 	offset = dfc->data1;
5243 	cnt = dfc->data2;
5244 	outsz = dfc->buf1_size;
5245 
5246 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5247 	    "%s: offset=%x count=%d", emlxs_dfc_xlate(dfc->cmd), offset, cnt);
5248 
5249 	if (!dfc->buf1_size || !dfc->buf1) {
5250 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5251 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
5252 
5253 		return (DFC_ARG_NULL);
5254 	}
5255 
5256 	if (offset & 0x3) {
5257 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5258 		    "%s: Offset misaligned. (offset=%d)",
5259 		    emlxs_dfc_xlate(dfc->cmd), offset);
5260 
5261 		return (DFC_ARG_MISALIGNED);
5262 	}
5263 
5264 	if (cnt & 0x3) {
5265 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5266 		    "%s: Count misaligned. (count=%d)",
5267 		    emlxs_dfc_xlate(dfc->cmd), cnt);
5268 
5269 		return (DFC_ARG_MISALIGNED);
5270 	}
5271 
5272 	if (outsz & 0x3) {
5273 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5274 		    "%s: Output size misaligned. (size=%d)",
5275 		    emlxs_dfc_xlate(dfc->cmd), outsz);
5276 
5277 		return (DFC_ARG_MISALIGNED);
5278 	}
5279 
5280 	/* Get max PCI config range */
5281 	if (hba->model_info.chip <= EMLXS_HELIOS_CHIP) {
5282 		max = 256;
5283 	} else {
5284 		max = 4096;
5285 	}
5286 
5287 	if ((cnt + offset) > max) {
5288 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5289 		    "%s: Offset+Count too large. (offset=%d count=%d max=%d)",
5290 		    emlxs_dfc_xlate(dfc->cmd), offset, cnt, max);
5291 
5292 		return (DFC_ARG_TOOBIG);
5293 	}
5294 
5295 	if (outsz > max) {
5296 		outsz = max;
5297 	}
5298 
5299 	if (cnt > outsz) {
5300 		cnt = outsz;
5301 	}
5302 
5303 	bptr = (uint32_t *)dfc->buf1;
5304 	for (i = offset; i < (offset + cnt); i += 4) {
5305 		value =
5306 		    ddi_get32(hba->pci_acc_handle,
5307 		    (uint32_t *)(hba->pci_addr + i));
5308 		*bptr++ = BE_SWAP32(value);
5309 	}
5310 
5311 #ifdef FMA_SUPPORT
5312 	/* Access handle validation */
5313 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
5314 	    != DDI_FM_OK) {
5315 		EMLXS_MSGF(EMLXS_CONTEXT,
5316 		    &emlxs_invalid_access_handle_msg, NULL);
5317 		return (DFC_DRV_ERROR);
5318 	}
5319 #endif  /* FMA_SUPPORT */
5320 
5321 	return (0);
5322 
5323 } /* emlxs_dfc_read_pci() */
5324 
5325 
5326 /*ARGSUSED*/
5327 static int32_t
5328 emlxs_dfc_write_pci(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5329 {
5330 	emlxs_port_t	*port = &PPORT;
5331 	uint32_t	offset;
5332 	uint32_t	cnt;
5333 	uint32_t	value;
5334 	uint32_t	i;
5335 	uint32_t	max;
5336 	uint32_t	*bptr;
5337 	uint16_t	word0;
5338 	uint16_t	word1;
5339 
5340 	offset = dfc->data1;
5341 	cnt = dfc->data2;
5342 
5343 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5344 	    "%s: offset=%x count=%d", emlxs_dfc_xlate(dfc->cmd), offset, cnt);
5345 
5346 	if (!dfc->buf1 || !dfc->buf1_size) {
5347 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5348 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
5349 
5350 		return (DFC_ARG_NULL);
5351 	}
5352 
5353 	if (offset & 0x3) {
5354 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5355 		    "%s: Offset misaligned. (offset=%d)",
5356 		    emlxs_dfc_xlate(dfc->cmd), offset);
5357 
5358 		return (DFC_ARG_MISALIGNED);
5359 	}
5360 
5361 	if (cnt > dfc->buf1_size) {
5362 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5363 		    "%s: Count too large. (count=%d)",
5364 		    emlxs_dfc_xlate(dfc->cmd), cnt);
5365 
5366 		return (DFC_ARG_TOOBIG);
5367 	}
5368 
5369 	if (cnt & 0x3) {
5370 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5371 		    "%s: Count misaligned. (count=%d)",
5372 		    emlxs_dfc_xlate(dfc->cmd), cnt);
5373 
5374 		return (DFC_ARG_MISALIGNED);
5375 	}
5376 
5377 	/* Get max PCI config range */
5378 	if (hba->model_info.chip <= EMLXS_HELIOS_CHIP) {
5379 		max = 256;
5380 	} else {
5381 		max = 4096;
5382 	}
5383 
5384 	if ((cnt + offset) > max) {
5385 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5386 		    "%s: Count+Offset too large. (offset=%d count=%d max=%d)",
5387 		    emlxs_dfc_xlate(dfc->cmd), offset, cnt, max);
5388 
5389 		return (DFC_ARG_TOOBIG);
5390 	}
5391 
5392 	bptr = (uint32_t *)dfc->buf1;
5393 	for (i = offset; i < (offset + cnt); i += 4) {
5394 		value = *bptr++;
5395 		value = BE_SWAP32(value);
5396 
5397 		word0 = value & 0xFFFF;
5398 		word1 = value >> 16;
5399 
5400 		/*
5401 		 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
5402 		 * "%s: Writing. offset=%x cnt=%d value=%08x %04x %04x",
5403 		 * emlxs_dfc_xlate(dfc->cmd), i, value, word0, word1);
5404 		 */
5405 
5406 		/* word0 = PCIMEM_SHORT(word0); */
5407 		ddi_put16(hba->pci_acc_handle,
5408 		    (uint16_t *)(hba->pci_addr + i), (uint16_t)word0);
5409 
5410 		/* word1 = PCIMEM_SHORT(word1); */
5411 		ddi_put16(hba->pci_acc_handle,
5412 		    (uint16_t *)(hba->pci_addr + i + 2), (uint16_t)word1);
5413 	}
5414 
5415 #ifdef FMA_SUPPORT
5416 	/* Access handle validation */
5417 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
5418 	    != DDI_FM_OK) {
5419 		EMLXS_MSGF(EMLXS_CONTEXT,
5420 		    &emlxs_invalid_access_handle_msg, NULL);
5421 		return (DFC_DRV_ERROR);
5422 	}
5423 #endif  /* FMA_SUPPORT */
5424 
5425 	return (0);
5426 
5427 } /* emlxs_dfc_write_pci() */
5428 
5429 
5430 /*ARGSUSED*/
5431 static int32_t
5432 emlxs_dfc_get_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5433 {
5434 	emlxs_port_t	*port = &PPORT;
5435 	dfc_cfgparam_t	*cfgparam;
5436 	uint32_t	count;
5437 	uint32_t	i;
5438 	emlxs_config_t	*cfg;
5439 
5440 	if (!dfc->buf1 || !dfc->buf1_size) {
5441 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5442 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
5443 
5444 		return (DFC_ARG_NULL);
5445 	}
5446 
5447 	count = dfc->buf1_size / sizeof (dfc_cfgparam_t);
5448 
5449 	if (count > MAX_CFG_PARAM) {
5450 		count = MAX_CFG_PARAM;
5451 	}
5452 
5453 	cfgparam = (dfc_cfgparam_t *)dfc->buf1;
5454 	bzero(cfgparam, sizeof (dfc_cfgparam_t));
5455 
5456 	cfg = &CFG;
5457 	for (i = 0; i < count; i++) {
5458 		(void) strncpy(cfgparam[i].a_string, cfg[i].string,
5459 		    (sizeof (cfgparam[i].a_string)-1));
5460 		cfgparam[i].a_low = cfg[i].low;
5461 		cfgparam[i].a_hi = cfg[i].hi;
5462 		cfgparam[i].a_default = cfg[i].def;
5463 		cfgparam[i].a_current = cfg[i].current;
5464 
5465 		if (!(cfg[i].flags & PARM_HIDDEN)) {
5466 			cfgparam[i].a_flag |= CFG_EXPORT;
5467 		}
5468 		cfgparam[i].a_flag |= CFG_COMMON;
5469 
5470 		/* Adjust a_flag based on the hba model */
5471 		switch (i) {
5472 			case CFG_NETWORK_ON:
5473 			case CFG_TOPOLOGY:
5474 			case CFG_LINK_SPEED:
5475 			case CFG_CR_DELAY:
5476 			case CFG_CR_COUNT:
5477 			if (! ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) &&
5478 			    SLI4_FCOE_MODE)) {
5479 				cfgparam[i].a_flag |= CFG_APPLICABLE;
5480 			}
5481 			break;
5482 
5483 			case CFG_NUM_WQ:
5484 			if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) &&
5485 			    SLI4_FCOE_MODE) {
5486 				cfgparam[i].a_flag |= CFG_APPLICABLE;
5487 			}
5488 			break;
5489 
5490 			case CFG_PERSIST_LINKDOWN:
5491 			cfgparam[i].a_flag &= ~CFG_EXPORT;
5492 			break;
5493 
5494 			default:
5495 			cfgparam[i].a_flag |= CFG_APPLICABLE;
5496 			break;
5497 		}
5498 
5499 		if ((cfg[i].flags & PARM_DYNAMIC)) {
5500 			if ((cfg[i].flags & PARM_DYNAMIC_RESET) ==
5501 			    PARM_DYNAMIC_RESET) {
5502 				cfgparam[i].a_changestate = CFG_RESTART;
5503 			} else if ((cfg[i].flags & PARM_DYNAMIC_LINK) ==
5504 			    PARM_DYNAMIC_LINK) {
5505 				cfgparam[i].a_changestate = CFG_LINKRESET;
5506 			} else {
5507 				cfgparam[i].a_changestate = CFG_DYMANIC;
5508 			}
5509 		} else {
5510 			cfgparam[i].a_changestate = CFG_REBOOT;
5511 		}
5512 
5513 		(void) strncpy(cfgparam[i].a_help, cfg[i].help,
5514 		    (sizeof (cfgparam[i].a_help)-1));
5515 	}
5516 
5517 	return (0);
5518 
5519 } /* emlxs_dfc_get_cfg() */
5520 
5521 
5522 /* ARGSUSED */
5523 static int32_t
5524 emlxs_dfc_set_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5525 {
5526 	emlxs_port_t	*port = &PPORT;
5527 	uint32_t	index;
5528 	uint32_t	new_value;
5529 	uint32_t	rc;
5530 
5531 	index = dfc->data1;
5532 	new_value = dfc->data2;
5533 
5534 	rc = emlxs_set_parm(hba, index, new_value);
5535 
5536 	if (rc) {
5537 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5538 		    "%s: Unable to set parameter. code=%d",
5539 		    emlxs_dfc_xlate(dfc->cmd), rc);
5540 
5541 		switch (rc) {
5542 		case 2:
5543 			return (DFC_NPIV_ACTIVE);
5544 
5545 		default:
5546 			return (DFC_ARG_INVALID);
5547 		}
5548 	}
5549 
5550 	return (0);
5551 
5552 } /* emlxs_dfc_set_cfg() */
5553 
5554 
5555 /*ARGSUSED*/
5556 static int32_t
5557 emlxs_dfc_send_ct(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5558 {
5559 	emlxs_port_t	*port = &PPORT;
5560 	uint8_t		*rsp_buf;
5561 	uint8_t		*cmd_buf;
5562 	uint32_t	did;
5563 	uint32_t	rsp_size;
5564 	uint32_t	cmd_size;
5565 	uint32_t	timeout;
5566 	fc_packet_t	*pkt = NULL;
5567 	uint32_t	rval = 0;
5568 	dfc_destid_t	*destid;
5569 	NODELIST	*nlp;
5570 	char		buffer[128];
5571 
5572 	cmd_buf = dfc->buf1;
5573 	cmd_size = dfc->buf1_size;
5574 	rsp_buf = dfc->buf2;
5575 	rsp_size = dfc->buf2_size;
5576 	timeout = dfc->data1;
5577 
5578 	if (timeout < (2 * hba->fc_ratov)) {
5579 		timeout = 2 * hba->fc_ratov;
5580 	}
5581 
5582 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5583 	    "%s: csize=%d rsize=%d", emlxs_dfc_xlate(dfc->cmd), cmd_size,
5584 	    rsp_size);
5585 
5586 
5587 	if (!cmd_size || !cmd_buf) {
5588 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5589 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
5590 
5591 		rval = DFC_ARG_NULL;
5592 		goto done;
5593 	}
5594 
5595 	if (!rsp_size || !rsp_buf) {
5596 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5597 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
5598 
5599 		rval = DFC_ARG_NULL;
5600 		goto done;
5601 	}
5602 
5603 	if (!dfc->buf3 || !dfc->buf3_size) {
5604 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5605 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
5606 
5607 		rval = DFC_ARG_NULL;
5608 		goto done;
5609 	}
5610 
5611 	if (!dfc->buf4 || !dfc->buf4_size) {
5612 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5613 		    "%s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd));
5614 
5615 		rval = DFC_ARG_NULL;
5616 		goto done;
5617 	}
5618 
5619 	if (rsp_size > MAX_CT_PAYLOAD) {
5620 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5621 		    "%s: Buffer2 too large. size=%d",
5622 		    emlxs_dfc_xlate(dfc->cmd), rsp_size);
5623 
5624 		rval = DFC_ARG_TOOBIG;
5625 		goto done;
5626 	}
5627 
5628 	if (cmd_size > MAX_CT_PAYLOAD) {
5629 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5630 		    "%s: Buffer1 too large. size=%d",
5631 		    emlxs_dfc_xlate(dfc->cmd), cmd_size);
5632 
5633 		rval = DFC_ARG_TOOBIG;
5634 		goto done;
5635 	}
5636 
5637 	if (dfc->buf3_size < sizeof (dfc_destid_t)) {
5638 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5639 		    "%s: Buffer3 too small. (size=%d)",
5640 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
5641 
5642 		rval = DFC_ARG_TOOSMALL;
5643 		goto done;
5644 	}
5645 
5646 	if (dfc->buf4_size < sizeof (uint32_t)) {
5647 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5648 		    "%s: Buffer4 too small. (size=%d)",
5649 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf4_size);
5650 
5651 		rval = DFC_ARG_TOOSMALL;
5652 		goto done;
5653 	}
5654 
5655 	destid = (dfc_destid_t *)dfc->buf3;
5656 
5657 	if (destid->idType == 0) {
5658 		if ((nlp = emlxs_node_find_wwpn(port, destid->wwpn, 1))
5659 		    == NULL) {
5660 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5661 			    "%s: WWPN does not exists. %s",
5662 			    emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer,
5663 			    sizeof (buffer), destid->wwpn));
5664 
5665 			rval = DFC_ARG_INVALID;
5666 			goto done;
5667 		}
5668 		did = nlp->nlp_DID;
5669 	} else {
5670 		if (emlxs_node_find_did(port, destid->d_id, 1) == NULL) {
5671 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5672 			    "%s: DID does not exist. did=%x",
5673 			    emlxs_dfc_xlate(dfc->cmd), destid->d_id);
5674 
5675 			rval = DFC_ARG_INVALID;
5676 			goto done;
5677 		}
5678 		did = destid->d_id;
5679 	}
5680 
5681 	if (did == 0) {
5682 		did = port->did;
5683 	}
5684 
5685 	if (!(pkt = emlxs_pkt_alloc(port, cmd_size, rsp_size, 0, KM_NOSLEEP))) {
5686 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5687 		    "%s: Unable to allocate packet.",
5688 		    emlxs_dfc_xlate(dfc->cmd));
5689 
5690 		rval = DFC_SYSRES_ERROR;
5691 		goto done;
5692 	}
5693 
5694 	/* Make this a polled IO */
5695 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
5696 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
5697 	pkt->pkt_comp = NULL;
5698 
5699 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
5700 	pkt->pkt_timeout = (timeout) ? timeout : 30;
5701 
5702 	/* Build the fc header */
5703 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
5704 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
5705 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
5706 	pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
5707 	pkt->pkt_cmd_fhdr.f_ctl =
5708 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
5709 	pkt->pkt_cmd_fhdr.seq_id = 0;
5710 	pkt->pkt_cmd_fhdr.df_ctl = 0;
5711 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
5712 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
5713 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
5714 	pkt->pkt_cmd_fhdr.ro = 0;
5715 
5716 	/* Copy in the command buffer */
5717 	bcopy((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size);
5718 
5719 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
5720 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5721 		    "%s: Unable to send packet.", emlxs_dfc_xlate(dfc->cmd));
5722 
5723 		rval = DFC_IO_ERROR;
5724 		goto done;
5725 	}
5726 
5727 	if ((pkt->pkt_state != FC_PKT_SUCCESS) &&
5728 	    (pkt->pkt_state != FC_PKT_FS_RJT)) {
5729 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
5730 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5731 			    "Pkt Transport error. Pkt Timeout.");
5732 			rval = DFC_TIMEOUT;
5733 		} else {
5734 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5735 			    "Pkt Transport error. state=%x", pkt->pkt_state);
5736 			rval = DFC_IO_ERROR;
5737 		}
5738 		goto done;
5739 	}
5740 
5741 	bcopy((void *)pkt->pkt_resp, (void *)rsp_buf, rsp_size);
5742 
5743 	rsp_size -= pkt->pkt_resp_resid;
5744 	bcopy((void *)&rsp_size, (void *)dfc->buf4, sizeof (uint32_t));
5745 
5746 	rval = 0;
5747 
5748 done:
5749 
5750 	if (pkt) {
5751 		emlxs_pkt_free(pkt);
5752 	}
5753 
5754 	return (rval);
5755 
5756 } /* emlxs_dfc_send_ct() */
5757 
5758 
5759 /*ARGSUSED*/
5760 static int32_t
5761 emlxs_dfc_send_ct_rsp(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5762 {
5763 	emlxs_port_t	*port = &PPORT;
5764 	uint8_t		*cmd_buf;
5765 	uint32_t	rx_id;
5766 	uint32_t	cmd_size;
5767 	uint32_t	timeout;
5768 	fc_packet_t	*pkt = NULL;
5769 	uint32_t	rval = 0;
5770 
5771 	cmd_buf = dfc->buf1;
5772 	cmd_size = dfc->buf1_size;
5773 	rx_id = dfc->flag;
5774 	timeout = 2 * hba->fc_ratov;
5775 
5776 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: csize=%d",
5777 	    emlxs_dfc_xlate(dfc->cmd), cmd_size);
5778 
5779 	if (!cmd_size || !cmd_buf) {
5780 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5781 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
5782 
5783 		rval = DFC_ARG_NULL;
5784 		goto done;
5785 	}
5786 
5787 	if (!(pkt = emlxs_pkt_alloc(port, cmd_size, 0, 0, KM_NOSLEEP))) {
5788 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5789 		    "%s: Unable to allocate packet.",
5790 		    emlxs_dfc_xlate(dfc->cmd));
5791 
5792 		rval = DFC_SYSRES_ERROR;
5793 		goto done;
5794 	}
5795 
5796 	/* Make this a polled IO */
5797 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
5798 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
5799 	pkt->pkt_comp = NULL;
5800 
5801 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
5802 	pkt->pkt_timeout = (timeout) ? timeout : 30;
5803 
5804 	/* Build the fc header */
5805 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(0);
5806 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_SOLICITED_CONTROL;
5807 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
5808 	pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
5809 	pkt->pkt_cmd_fhdr.f_ctl =
5810 	    F_CTL_LAST_SEQ | F_CTL_END_SEQ | F_CTL_XCHG_CONTEXT;
5811 	pkt->pkt_cmd_fhdr.seq_id = 0;
5812 	pkt->pkt_cmd_fhdr.df_ctl = 0;
5813 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
5814 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
5815 	pkt->pkt_cmd_fhdr.rx_id = rx_id;
5816 	pkt->pkt_cmd_fhdr.ro = 0;
5817 
5818 	/* Copy in the command buffer */
5819 	bcopy((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size);
5820 
5821 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
5822 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5823 		    "%s: Unable to send packet.", emlxs_dfc_xlate(dfc->cmd));
5824 
5825 		rval = DFC_IO_ERROR;
5826 		goto done;
5827 	}
5828 
5829 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
5830 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
5831 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5832 			    "Pkt Transport error. Pkt Timeout.");
5833 			rval = DFC_TIMEOUT;
5834 		} else {
5835 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5836 			    "Pkt Transport error. state=%x", pkt->pkt_state);
5837 			rval = DFC_IO_ERROR;
5838 		}
5839 		goto done;
5840 	}
5841 
5842 	rval = 0;
5843 
5844 done:
5845 
5846 	if (pkt) {
5847 		emlxs_pkt_free(pkt);
5848 	}
5849 
5850 	return (rval);
5851 
5852 } /* emlxs_dfc_send_ct_rsp() */
5853 
5854 
5855 #ifdef MENLO_SUPPORT
5856 
5857 /*ARGSUSED*/
5858 static int32_t
5859 emlxs_dfc_send_menlo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5860 {
5861 	emlxs_port_t	*port = &PPORT;
5862 	uint8_t		*rsp_buf = NULL;
5863 	uint8_t		*cmd_buf = NULL;
5864 	uint32_t	rsp_size = 0;
5865 	uint32_t	cmd_size = 0;
5866 	uint32_t	rval = 0;
5867 
5868 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5869 	    "%s: csize=%d rsize=%d", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size,
5870 	    dfc->buf2_size);
5871 
5872 	if (hba->model_info.device_id != PCI_DEVICE_ID_HORNET) {
5873 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5874 		    "%s: Menlo device not present. device=%x,%x",
5875 		    emlxs_dfc_xlate(dfc->cmd), hba->model_info.device_id,
5876 		    hba->model_info.ssdid);
5877 
5878 		rval = DFC_INVALID_ADAPTER;
5879 		goto done;
5880 	}
5881 
5882 	if (!dfc->buf1_size || !dfc->buf1) {
5883 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5884 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
5885 
5886 		rval = DFC_ARG_NULL;
5887 		goto done;
5888 	}
5889 
5890 	if (!dfc->buf2_size || !dfc->buf2) {
5891 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5892 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
5893 
5894 		rval = DFC_ARG_NULL;
5895 		goto done;
5896 	}
5897 
5898 	if (!dfc->buf3 || !dfc->buf3_size) {
5899 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5900 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
5901 
5902 		rval = DFC_ARG_NULL;
5903 		goto done;
5904 	}
5905 
5906 	if (dfc->buf3_size < sizeof (uint32_t)) {
5907 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5908 		    "%s: Buffer3 too small. %d < %d",
5909 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size,
5910 		    sizeof (uint32_t));
5911 
5912 		rval = DFC_ARG_TOOSMALL;
5913 		goto done;
5914 	}
5915 
5916 	cmd_size  = dfc->buf1_size;
5917 	cmd_buf = (uint8_t *)dfc->buf1;
5918 
5919 	rsp_size  = dfc->buf2_size;
5920 	rsp_buf = (uint8_t *)dfc->buf2;
5921 
5922 	/* Send the command */
5923 	rval = emlxs_send_menlo_cmd(hba, cmd_buf, cmd_size,
5924 	    rsp_buf, &rsp_size);
5925 
5926 	if (rval == 0) {
5927 		/* Return the response & size */
5928 		bcopy((void *)rsp_buf, (void *)dfc->buf2, rsp_size);
5929 		bcopy((void *)&rsp_size, (void *)dfc->buf3, sizeof (uint32_t));
5930 	}
5931 
5932 done:
5933 
5934 	return (rval);
5935 
5936 } /* emlxs_dfc_send_menlo() */
5937 
5938 
5939 extern int32_t
5940 emlxs_send_menlo_cmd(emlxs_hba_t *hba, uint8_t *cmd_buf, uint32_t cmd_size,
5941     uint8_t *rsp_buf, uint32_t *rsp_size)
5942 {
5943 	emlxs_port_t		*port = &PPORT;
5944 	uint8_t			*data_buf = NULL;
5945 	uint32_t		data_size = 0;
5946 	fc_packet_t		*pkt = NULL;
5947 	int32_t			rval = 0;
5948 	menlo_set_cmd_t		set_cmd;
5949 	menlo_reset_cmd_t	reset_cmd;
5950 	uint32_t		rsp_code;
5951 	uint32_t		mm_mode = 0;
5952 	uint32_t		cmd_code;
5953 	clock_t			timeout;
5954 	MAILBOXQ		*mbq = NULL;
5955 	MAILBOX			*mb;
5956 	uint32_t		addr;
5957 	uint32_t		value;
5958 	uint32_t		mbxstatus;
5959 
5960 	cmd_code = *(uint32_t *)cmd_buf;
5961 	cmd_code = BE_SWAP32(cmd_code);
5962 
5963 	/* Look for Zephyr specific commands */
5964 	if (cmd_code & 0x80000000) {
5965 		bzero((uint8_t *)&reset_cmd, sizeof (menlo_reset_cmd_t));
5966 		bzero((uint8_t *)&set_cmd, sizeof (menlo_set_cmd_t));
5967 		bzero((uint8_t *)&rsp_code, sizeof (uint32_t));
5968 
5969 		/* Validate response buffer */
5970 		if (*rsp_size < sizeof (uint32_t)) {
5971 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5972 			    "send_menlo_cmd: Response overrun.");
5973 			rval = DFC_RSP_BUF_OVERRUN;
5974 			goto done;
5975 		}
5976 
5977 		/* All of these responses will be 4 bytes only */
5978 		*rsp_size = sizeof (uint32_t);
5979 		rsp_code = 0;
5980 
5981 		/* Validate command buffer */
5982 		switch (cmd_code) {
5983 		case MENLO_CMD_RESET:
5984 			if (cmd_size < sizeof (menlo_reset_cmd_t)) {
5985 				EMLXS_MSGF(EMLXS_CONTEXT,
5986 				    &emlxs_dfc_error_msg,
5987 				    "send_menlo_cmd: "
5988 				    "Invalid command size. %d < %d",
5989 				    cmd_size,
5990 				    sizeof (menlo_reset_cmd_t));
5991 				rval = DFC_ARG_INVALID;
5992 				goto done;
5993 			}
5994 			cmd_size = sizeof (menlo_reset_cmd_t);
5995 
5996 			/* Read the command buffer */
5997 			bcopy((void *)cmd_buf, (void *)&reset_cmd, cmd_size);
5998 
5999 			if (reset_cmd.firmware) {
6000 				/* MENLO_FW_GOLDEN */
6001 				value = 1;
6002 
6003 				EMLXS_MSGF(EMLXS_CONTEXT,
6004 				    &emlxs_dfc_detail_msg,
6005 				    "send_menlo_cmd: Reset with Golden "
6006 				    "firmware requested.");
6007 
6008 			} else {
6009 				/* MENLO_FW_OPERATIONAL */
6010 				value = 0;
6011 
6012 				EMLXS_MSGF(EMLXS_CONTEXT,
6013 				    &emlxs_dfc_detail_msg,
6014 				    "send_menlo_cmd: Reset with "
6015 				    "Operational firmware requested.");
6016 			}
6017 
6018 			addr  = 0x103007;
6019 
6020 			break;
6021 
6022 		case MENLO_CMD_SET_MODE:
6023 			if (cmd_size < sizeof (menlo_set_cmd_t)) {
6024 				EMLXS_MSGF(EMLXS_CONTEXT,
6025 				    &emlxs_dfc_error_msg,
6026 				    "send_menlo_cmd: "
6027 				    "Invalid command size. %d < %d",
6028 				    cmd_size,
6029 				    sizeof (menlo_set_cmd_t));
6030 				rval = DFC_ARG_INVALID;
6031 				goto done;
6032 			}
6033 			cmd_size = sizeof (menlo_set_cmd_t);
6034 
6035 			/* Read the command buffer */
6036 			bcopy((void *)cmd_buf, (void *)&set_cmd, cmd_size);
6037 
6038 			if (set_cmd.value1) {
6039 				EMLXS_MSGF(EMLXS_CONTEXT,
6040 				    &emlxs_dfc_detail_msg,
6041 				    "send_menlo_cmd: "
6042 				    "Maintenance mode enable requested.");
6043 
6044 				/* Make sure the mode flag is cleared */
6045 				if (hba->flag & FC_MENLO_MODE) {
6046 					mutex_enter(&EMLXS_PORT_LOCK);
6047 					hba->flag &= ~FC_MENLO_MODE;
6048 					mutex_exit(&EMLXS_PORT_LOCK);
6049 				}
6050 
6051 				mm_mode = 1;
6052 			} else {
6053 				EMLXS_MSGF(EMLXS_CONTEXT,
6054 				    &emlxs_dfc_detail_msg,
6055 				    "send_menlo_cmd: "
6056 				    "Maintenance mode disable requested.");
6057 			}
6058 
6059 			addr  = 0x103107;
6060 			value = mm_mode;
6061 
6062 			break;
6063 
6064 		default:
6065 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6066 			    "send_menlo_cmd: "
6067 			    "Invalid command. cmd=%x", cmd_code);
6068 			rval = DFC_ARG_INVALID;
6069 			goto done;
6070 		}
6071 
6072 		mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
6073 		    KM_SLEEP);
6074 
6075 		mb = (MAILBOX *) mbq;
6076 
6077 		/* Create the set_variable mailbox request */
6078 		emlxs_mb_set_var(hba, mbq, addr, value);
6079 
6080 		mbq->flag |= MBQ_PASSTHRU;
6081 
6082 		/* issue the mbox cmd to the sli */
6083 		mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
6084 
6085 		if (mbxstatus) {
6086 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6087 			    "send_menlo_cmd: %s failed. mbxstatus=0x%x",
6088 			    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
6089 
6090 			if (mbxstatus == MBX_TIMEOUT) {
6091 				rval = DFC_TIMEOUT;
6092 			} else {
6093 				rval = DFC_IO_ERROR;
6094 			}
6095 			goto done;
6096 		}
6097 
6098 		bcopy((void *)&rsp_code, (void *)rsp_buf, *rsp_size);
6099 
6100 		/* Check if we need to wait for maintenance mode */
6101 		if (mm_mode && !(hba->flag & FC_MENLO_MODE)) {
6102 			/* Wait for link to come up in maintenance mode */
6103 			mutex_enter(&EMLXS_LINKUP_LOCK);
6104 
6105 			timeout = emlxs_timeout(hba, 30);
6106 
6107 			rval = 0;
6108 			while ((rval != -1) && !(hba->flag & FC_MENLO_MODE)) {
6109 				rval =
6110 				    cv_timedwait(&EMLXS_LINKUP_CV,
6111 				    &EMLXS_LINKUP_LOCK, timeout);
6112 			}
6113 
6114 			mutex_exit(&EMLXS_LINKUP_LOCK);
6115 
6116 			if (rval == -1) {
6117 				EMLXS_MSGF(EMLXS_CONTEXT,
6118 				    &emlxs_dfc_error_msg,
6119 				    "send_menlo_cmd: "
6120 				    "Menlo maintenance mode error. Timeout.");
6121 
6122 				rval = DFC_TIMEOUT;
6123 				goto done;
6124 			}
6125 		}
6126 	} else {	/* Standard commands */
6127 
6128 		if (hba->state <= FC_LINK_DOWN) {
6129 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6130 			    "send_menlo_cmd: Adapter link down.");
6131 
6132 			rval = DFC_LINKDOWN_ERROR;
6133 			goto done;
6134 		}
6135 
6136 		if (cmd_code == MENLO_CMD_FW_DOWNLOAD) {
6137 			/* Check cmd size */
6138 			/* Must be at least 12 bytes of command */
6139 			/* plus 4 bytes of data */
6140 			if (cmd_size < (12 + 4)) {
6141 				EMLXS_MSGF(EMLXS_CONTEXT,
6142 				    &emlxs_dfc_error_msg,
6143 				    "send_menlo_cmd: "
6144 				    "Invalid command size. %d < %d",
6145 				    cmd_size,
6146 				    (12 + 4));
6147 
6148 				rval = DFC_ARG_INVALID;
6149 				goto done;
6150 			}
6151 
6152 			/* Extract data buffer from command buffer */
6153 			data_buf    = cmd_buf  + 12;
6154 			data_size   = cmd_size - 12;
6155 			cmd_size    = 12;
6156 		}
6157 
6158 		if (!(pkt = emlxs_pkt_alloc(port, cmd_size, *rsp_size, 0,
6159 		    KM_NOSLEEP))) {
6160 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6161 			    "send_menlo_cmd: Unable to allocate packet.");
6162 
6163 			rval = DFC_SYSRES_ERROR;
6164 			goto done;
6165 		}
6166 
6167 		/* Make this a polled IO */
6168 		pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
6169 		pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
6170 		pkt->pkt_comp = NULL;
6171 		pkt->pkt_tran_type = FC_PKT_EXCHANGE;
6172 		pkt->pkt_timeout = 30;
6173 
6174 		/* Build the fc header */
6175 		pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(EMLXS_MENLO_DID);
6176 		pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
6177 		pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
6178 		pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
6179 		pkt->pkt_cmd_fhdr.f_ctl =
6180 		    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
6181 		pkt->pkt_cmd_fhdr.seq_id = 0;
6182 		pkt->pkt_cmd_fhdr.df_ctl = 0;
6183 		pkt->pkt_cmd_fhdr.seq_cnt = 0;
6184 		pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
6185 		pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
6186 		pkt->pkt_cmd_fhdr.ro = 0;
6187 
6188 		/* Copy in the command buffer */
6189 		bcopy((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size);
6190 
6191 		if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
6192 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6193 			    "send_menlo_cmd: Unable to send packet.");
6194 
6195 			rval = DFC_IO_ERROR;
6196 			goto done;
6197 		}
6198 
6199 		if (pkt->pkt_state != FC_PKT_SUCCESS) {
6200 			if (pkt->pkt_state == FC_PKT_TIMEOUT) {
6201 				EMLXS_MSGF(EMLXS_CONTEXT,
6202 				    &emlxs_dfc_error_msg,
6203 				    "send_menlo_cmd: "
6204 				    "Pkt Transport error. Pkt Timeout.");
6205 				rval = DFC_TIMEOUT;
6206 			} else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) &&
6207 			    (pkt->pkt_reason == FC_REASON_OVERRUN)) {
6208 				EMLXS_MSGF(EMLXS_CONTEXT,
6209 				    &emlxs_dfc_error_msg,
6210 				    "send_menlo_cmd: "
6211 				    "Pkt Transport error. Response overrun.");
6212 				rval = DFC_RSP_BUF_OVERRUN;
6213 			} else {
6214 				EMLXS_MSGF(EMLXS_CONTEXT,
6215 				    &emlxs_dfc_error_msg,
6216 				    "send_menlo_cmd: "
6217 				    "Pkt Transport error. state=%x",
6218 				    pkt->pkt_state);
6219 				rval = DFC_IO_ERROR;
6220 			}
6221 			goto done;
6222 		}
6223 
6224 		if (cmd_code == MENLO_CMD_FW_DOWNLOAD) {
6225 			uint32_t *rsp;
6226 
6227 			/* Check response code */
6228 			rsp = (uint32_t *)pkt->pkt_resp;
6229 			rsp_code = *rsp;
6230 			rsp_code = BE_SWAP32(rsp_code);
6231 
6232 			if (rsp_code == MENLO_RSP_SUCCESS) {
6233 				/* Now transmit the data phase */
6234 
6235 				/* Save last rx_id */
6236 				uint32_t rx_id = pkt->pkt_cmd_fhdr.rx_id;
6237 
6238 				/* Free old pkt */
6239 				emlxs_pkt_free(pkt);
6240 
6241 				/* Allocate data pkt */
6242 				if (!(pkt = emlxs_pkt_alloc(port, data_size,
6243 				    *rsp_size, 0, KM_NOSLEEP))) {
6244 					EMLXS_MSGF(EMLXS_CONTEXT,
6245 					    &emlxs_dfc_error_msg,
6246 					    "send_menlo_cmd: "
6247 					    "Unable to allocate data "
6248 					    "packet.");
6249 
6250 					rval = DFC_SYSRES_ERROR;
6251 					goto done;
6252 				}
6253 
6254 				/* Make this a polled IO */
6255 				pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
6256 				pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
6257 				pkt->pkt_comp = NULL;
6258 				pkt->pkt_tran_type = FC_PKT_OUTBOUND;
6259 				pkt->pkt_timeout = 30;
6260 
6261 				/* Build the fc header */
6262 				pkt->pkt_cmd_fhdr.d_id =
6263 				    LE_SWAP24_LO(EMLXS_MENLO_DID);
6264 				pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
6265 				pkt->pkt_cmd_fhdr.s_id =
6266 				    LE_SWAP24_LO(port->did);
6267 				pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
6268 				pkt->pkt_cmd_fhdr.f_ctl =
6269 				    F_CTL_FIRST_SEQ | F_CTL_END_SEQ |
6270 				    F_CTL_SEQ_INITIATIVE;
6271 				pkt->pkt_cmd_fhdr.seq_id = 0;
6272 				pkt->pkt_cmd_fhdr.df_ctl = 0;
6273 				pkt->pkt_cmd_fhdr.seq_cnt = 0;
6274 				pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
6275 				pkt->pkt_cmd_fhdr.rx_id = rx_id;
6276 				pkt->pkt_cmd_fhdr.ro = 0;
6277 
6278 				/* Copy in the data buffer */
6279 				bcopy((void *)data_buf, (void *)pkt->pkt_cmd,
6280 				    data_size);
6281 
6282 				if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
6283 					EMLXS_MSGF(EMLXS_CONTEXT,
6284 					    &emlxs_dfc_error_msg,
6285 					    "send_menlo_cmd: "
6286 					    "Unable to send data packet.");
6287 
6288 					rval = DFC_IO_ERROR;
6289 					goto done;
6290 				}
6291 
6292 				if (pkt->pkt_state != FC_PKT_SUCCESS) {
6293 					if (pkt->pkt_state == FC_PKT_TIMEOUT) {
6294 						EMLXS_MSGF(EMLXS_CONTEXT,
6295 						    &emlxs_dfc_error_msg,
6296 						    "send_menlo_cmd: "
6297 						    "Data Pkt Transport "
6298 						    "error. Pkt Timeout.");
6299 						rval = DFC_TIMEOUT;
6300 					} else if ((pkt->pkt_state ==
6301 					    FC_PKT_LOCAL_RJT) &&
6302 					    (pkt->pkt_reason ==
6303 					    FC_REASON_OVERRUN)) {
6304 						EMLXS_MSGF(EMLXS_CONTEXT,
6305 						    &emlxs_dfc_error_msg,
6306 						    "send_menlo_cmd: "
6307 						    "Data Pkt Transport "
6308 						    "error. Response overrun.");
6309 						rval = DFC_RSP_BUF_OVERRUN;
6310 					} else {
6311 						EMLXS_MSGF(EMLXS_CONTEXT,
6312 						    &emlxs_dfc_error_msg,
6313 						    "send_menlo_cmd: "
6314 						    "Data Pkt Transport "
6315 						    "error. state=%x",
6316 						    pkt->pkt_state);
6317 						rval = DFC_IO_ERROR;
6318 					}
6319 					goto done;
6320 				}
6321 			}
6322 		}
6323 
6324 		bcopy((void *)pkt->pkt_resp, (void *)rsp_buf, *rsp_size);
6325 		*rsp_size = *rsp_size - pkt->pkt_resp_resid;
6326 	}
6327 
6328 	rval = 0;
6329 
6330 done:
6331 
6332 	if (pkt) {
6333 		emlxs_pkt_free(pkt);
6334 	}
6335 
6336 	if (mbq) {
6337 		kmem_free(mbq, sizeof (MAILBOXQ));
6338 	}
6339 
6340 	return (rval);
6341 
6342 } /* emlxs_send_menlo_cmd() */
6343 
6344 
6345 /* ARGSUSED */
6346 extern void
6347 emlxs_fcoe_attention_thread(emlxs_hba_t *hba,
6348     void *arg1, void *arg2)
6349 {
6350 	emlxs_port_t		*port = &PPORT;
6351 	menlo_init_rsp_t	*rsp;
6352 	menlo_get_cmd_t		*cmd;
6353 	fc_packet_t		*pkt = NULL;
6354 
6355 	if (!(pkt = emlxs_pkt_alloc(port, sizeof (menlo_get_cmd_t),
6356 	    sizeof (menlo_init_rsp_t), 0, KM_NOSLEEP))) {
6357 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6358 		    "FCoE attention: Unable to allocate packet.");
6359 
6360 		return;
6361 	}
6362 
6363 	/* Make this a polled IO */
6364 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
6365 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
6366 	pkt->pkt_comp = NULL;
6367 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
6368 	pkt->pkt_timeout = 30;
6369 
6370 	/* Build the fc header */
6371 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(EMLXS_MENLO_DID);
6372 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
6373 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
6374 	pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
6375 	pkt->pkt_cmd_fhdr.f_ctl =
6376 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
6377 	pkt->pkt_cmd_fhdr.seq_id = 0;
6378 	pkt->pkt_cmd_fhdr.df_ctl = 0;
6379 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
6380 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
6381 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
6382 	pkt->pkt_cmd_fhdr.ro = 0;
6383 
6384 	cmd = (menlo_get_cmd_t *)pkt->pkt_cmd;
6385 	cmd->code = MENLO_CMD_GET_INIT;
6386 	cmd->context = 0;
6387 	cmd->length = sizeof (menlo_init_rsp_t);
6388 
6389 	/* Little Endian Swap */
6390 	cmd->code = BE_SWAP32(cmd->code);
6391 	cmd->length = BE_SWAP32(cmd->length);
6392 
6393 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
6394 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6395 		    "FCoE attention: Unable to send packet.");
6396 
6397 		goto done;
6398 	}
6399 
6400 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
6401 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6402 		    "FCoE attention: Pkt Transport error. state=%x",
6403 		    pkt->pkt_state);
6404 
6405 		goto done;
6406 	}
6407 
6408 	/* Check response code */
6409 	rsp = (menlo_init_rsp_t *)pkt->pkt_resp;
6410 	rsp->code = BE_SWAP32(rsp->code);
6411 
6412 	if (rsp->code != MENLO_RSP_SUCCESS) {
6413 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6414 		    "FCoE attention: FCOE Response error =%x", rsp->code);
6415 
6416 		goto done;
6417 	}
6418 
6419 	/* Little Endian Swap */
6420 	rsp->bb_credit = BE_SWAP32(rsp->bb_credit);
6421 	rsp->frame_size = BE_SWAP32(rsp->frame_size);
6422 	rsp->fw_version = BE_SWAP32(rsp->fw_version);
6423 	rsp->reset_status = BE_SWAP32(rsp->reset_status);
6424 	rsp->maint_status = BE_SWAP32(rsp->maint_status);
6425 	rsp->fw_type = BE_SWAP32(rsp->fw_type);
6426 	rsp->fru_data_valid = BE_SWAP32(rsp->fru_data_valid);
6427 
6428 	/* Log the event */
6429 	emlxs_log_fcoe_event(port, rsp);
6430 
6431 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6432 	    "MENLO_INIT: bb_credit      = 0x%x", rsp->bb_credit);
6433 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6434 	    "MENLO_INIT: frame_size     = 0x%x", rsp->frame_size);
6435 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6436 	    "MENLO_INIT: fw_version     = 0x%x", rsp->fw_version);
6437 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6438 	    "MENLO_INIT: reset_status   = 0x%x", rsp->reset_status);
6439 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6440 	    "MENLO_INIT: maint_status   = 0x%x", rsp->maint_status);
6441 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6442 	    "MENLO_INIT: fw_type        = 0x%x", rsp->fw_type);
6443 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6444 	    "MENLO_INIT: fru_data_valid = 0x%x", rsp->fru_data_valid);
6445 
6446 	/* Perform attention checks */
6447 	if (rsp->fru_data_valid == 0) {
6448 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_error_msg,
6449 		    "Invalid FRU data found on adapter. "
6450 		    "Return adapter to Emulex for repair.");
6451 	}
6452 
6453 	switch (rsp->fw_type) {
6454 	case MENLO_FW_TYPE_GOLDEN:
6455 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_warning_msg,
6456 		    "FCoE chip is running Golden firmware. "
6457 		    "Update FCoE firmware immediately.");
6458 		break;
6459 
6460 	case MENLO_FW_TYPE_DIAG:
6461 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_notice_msg,
6462 		    "FCoE chip is running Diagnostic firmware. "
6463 		    "Operational use of the adapter is suspended.");
6464 		break;
6465 	}
6466 
6467 done:
6468 
6469 	if (pkt) {
6470 		emlxs_pkt_free(pkt);
6471 	}
6472 
6473 	return;
6474 
6475 } /* emlxs_fcoe_attention_thread() */
6476 
6477 #endif /* MENLO_SUPPORT */
6478 
6479 
6480 /*ARGSUSED*/
6481 static int32_t
6482 emlxs_dfc_write_flash(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6483 {
6484 	emlxs_port_t	*port = &PPORT;
6485 	uint32_t	offset;
6486 	uint32_t	cnt;
6487 	uint8_t		*bptr;
6488 	uint32_t	i;
6489 
6490 	if (hba->bus_type != SBUS_FC) {
6491 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6492 		    "%s: Invalid bus_type. (bus_type=%x)",
6493 		    emlxs_dfc_xlate(dfc->cmd), hba->bus_type);
6494 
6495 		return (DFC_ARG_INVALID);
6496 	}
6497 
6498 	if (!(hba->flag & FC_OFFLINE_MODE)) {
6499 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6500 		    "%s: Adapter not offline.", emlxs_dfc_xlate(dfc->cmd));
6501 
6502 		return (DFC_ONLINE_ERROR);
6503 	}
6504 
6505 	if (!dfc->buf1 || !dfc->buf1_size) {
6506 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6507 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6508 
6509 		return (DFC_ARG_NULL);
6510 	}
6511 
6512 	offset = dfc->data1;
6513 	cnt = dfc->data2;
6514 
6515 	if (offset > (64 * 1024)) {
6516 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6517 		    "%s: Offset too large. (offset=%d)",
6518 		    emlxs_dfc_xlate(dfc->cmd), offset);
6519 
6520 		return (DFC_ARG_TOOBIG);
6521 	}
6522 
6523 	if (cnt > dfc->buf1_size) {
6524 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6525 		    "%s: Count too large. (count=%d)",
6526 		    emlxs_dfc_xlate(dfc->cmd), cnt);
6527 
6528 		return (DFC_ARG_TOOBIG);
6529 	}
6530 
6531 	if ((cnt + offset) > (64 * 1024)) {
6532 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6533 		    "%s: Count+Offset too large. (count=%d offset=%d)",
6534 		    emlxs_dfc_xlate(dfc->cmd), cnt, offset);
6535 
6536 		return (DFC_ARG_TOOBIG);
6537 	}
6538 
6539 	if (cnt == 0) {
6540 		return (0);
6541 	}
6542 
6543 	bptr = (uint8_t *)dfc->buf1;
6544 	for (i = 0; i < cnt; i++) {
6545 		SBUS_WRITE_FLASH_COPY(hba, offset, *bptr);
6546 		offset++;
6547 		bptr++;
6548 	}
6549 
6550 #ifdef FMA_SUPPORT
6551 	/* Access handle validation */
6552 	if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.sbus_flash_acc_handle)
6553 	    != DDI_FM_OK) {
6554 		EMLXS_MSGF(EMLXS_CONTEXT,
6555 		    &emlxs_invalid_access_handle_msg, NULL);
6556 		return (DFC_DRV_ERROR);
6557 	}
6558 #endif  /* FMA_SUPPORT */
6559 
6560 	return (0);
6561 
6562 } /* emlxs_dfc_write_flash() */
6563 
6564 
6565 /*ARGSUSED*/
6566 static int32_t
6567 emlxs_dfc_read_flash(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6568 {
6569 	emlxs_port_t	*port = &PPORT;
6570 	uint32_t	offset;
6571 	uint32_t	count;
6572 	uint32_t	outsz;
6573 	uint8_t		*bptr;
6574 	uint32_t	i;
6575 
6576 	if (hba->bus_type != SBUS_FC) {
6577 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6578 		    "%s: Invalid bus_type. (bus_type=%x)",
6579 		    emlxs_dfc_xlate(dfc->cmd), hba->bus_type);
6580 
6581 		return (DFC_ARG_INVALID);
6582 	}
6583 
6584 	if (!(hba->flag & FC_OFFLINE_MODE)) {
6585 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6586 		    "%s: Adapter not offline.", emlxs_dfc_xlate(dfc->cmd));
6587 
6588 		return (DFC_ONLINE_ERROR);
6589 	}
6590 
6591 	if (!dfc->buf1 || !dfc->buf1_size) {
6592 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6593 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6594 
6595 		return (DFC_ARG_NULL);
6596 	}
6597 
6598 	offset = dfc->data1;
6599 	count = dfc->data2;
6600 	outsz = dfc->buf1_size;
6601 
6602 	if (offset > (64 * 1024)) {
6603 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6604 		    "%s: Offset too large. (offset=%d)",
6605 		    emlxs_dfc_xlate(dfc->cmd), offset);
6606 
6607 		return (DFC_ARG_TOOBIG);
6608 	}
6609 
6610 	if ((count + offset) > (64 * 1024)) {
6611 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6612 		    "%s: Count+Offset too large. (count=%d offset=%d)",
6613 		    emlxs_dfc_xlate(dfc->cmd), count, offset);
6614 
6615 		return (DFC_ARG_TOOBIG);
6616 	}
6617 
6618 	if (count < outsz) {
6619 		outsz = count;
6620 	}
6621 
6622 	bptr = (uint8_t *)dfc->buf1;
6623 	for (i = 0; i < outsz; i++) {
6624 		*bptr++ = SBUS_READ_FLASH_COPY(hba, offset++);
6625 	}
6626 
6627 #ifdef FMA_SUPPORT
6628 	/* Access handle validation */
6629 	if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.sbus_flash_acc_handle)
6630 	    != DDI_FM_OK) {
6631 		EMLXS_MSGF(EMLXS_CONTEXT,
6632 		    &emlxs_invalid_access_handle_msg, NULL);
6633 		return (DFC_DRV_ERROR);
6634 	}
6635 #endif  /* FMA_SUPPORT */
6636 
6637 	return (0);
6638 
6639 } /* emlxs_dfc_read_flash() */
6640 
6641 
6642 /*ARGSUSED*/
6643 static int32_t
6644 emlxs_dfc_send_els(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6645 {
6646 	emlxs_port_t	*port = &PPORT;
6647 	uint8_t		*rsp_buf;
6648 	uint8_t		*cmd_buf;
6649 	dfc_destid_t	*destid;
6650 	uint32_t	rsp_size;
6651 	uint32_t	cmd_size;
6652 	uint32_t	timeout;
6653 	fc_packet_t	*pkt = NULL;
6654 	NODELIST	*ndlp;
6655 	uint32_t	did;
6656 	uint32_t	rval = 0;
6657 	char		buffer[128];
6658 
6659 	cmd_buf = dfc->buf1;
6660 	cmd_size = dfc->buf1_size;
6661 	rsp_buf = dfc->buf2;
6662 	rsp_size = dfc->buf2_size;
6663 
6664 	timeout = 2 * hba->fc_ratov;
6665 
6666 	if (!cmd_size || !cmd_buf) {
6667 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6668 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6669 
6670 		rval = DFC_ARG_NULL;
6671 		goto done;
6672 	}
6673 
6674 	if (!rsp_buf || !rsp_size) {
6675 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6676 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
6677 
6678 		rval = DFC_ARG_NULL;
6679 		goto done;
6680 	}
6681 
6682 	if (!dfc->buf3 || !dfc->buf3_size) {
6683 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6684 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
6685 
6686 		rval = DFC_ARG_NULL;
6687 		goto done;
6688 	}
6689 
6690 	if (dfc->buf3_size < sizeof (dfc_destid_t)) {
6691 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6692 		    "%s: Buffer3 too small. (size=%d)",
6693 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
6694 
6695 		rval = DFC_ARG_TOOSMALL;
6696 		goto done;
6697 	}
6698 
6699 	if (!dfc->buf4 || !dfc->buf4_size) {
6700 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6701 		    "%s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd));
6702 
6703 		rval = DFC_ARG_NULL;
6704 		goto done;
6705 	}
6706 
6707 	if (dfc->buf4_size < sizeof (uint32_t)) {
6708 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6709 		    "%s: Buffer4 too small. (size=%d)",
6710 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf4_size);
6711 
6712 		rval = DFC_ARG_TOOSMALL;
6713 		goto done;
6714 	}
6715 
6716 	destid = (dfc_destid_t *)dfc->buf3;
6717 
6718 	if (destid->idType == 0) {
6719 		if ((ndlp = emlxs_node_find_wwpn(port, destid->wwpn, 1))
6720 		    == NULL) {
6721 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6722 			    "%s: WWPN does not exists. %s",
6723 			    emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer,
6724 			    sizeof (buffer), destid->wwpn));
6725 
6726 			rval = DFC_ARG_INVALID;
6727 			goto done;
6728 		}
6729 		did = ndlp->nlp_DID;
6730 	} else {
6731 		if (emlxs_node_find_did(port, destid->d_id, 1) == NULL) {
6732 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6733 			    "%s: DID does not exist. did=%x",
6734 			    emlxs_dfc_xlate(dfc->cmd), destid->d_id);
6735 
6736 			rval = DFC_ARG_INVALID;
6737 			goto done;
6738 		}
6739 		did = destid->d_id;
6740 	}
6741 
6742 	if (did == 0) {
6743 		did = port->did;
6744 	}
6745 
6746 	if (!(pkt = emlxs_pkt_alloc(port, cmd_size, rsp_size, 0, KM_NOSLEEP))) {
6747 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6748 		    "%s: Unable to allocate packet.",
6749 		    emlxs_dfc_xlate(dfc->cmd));
6750 
6751 		rval = DFC_SYSRES_ERROR;
6752 		goto done;
6753 	}
6754 
6755 	/* Make this a polled IO */
6756 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
6757 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
6758 	pkt->pkt_comp = NULL;
6759 
6760 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
6761 	pkt->pkt_timeout = (timeout) ? timeout : 30;
6762 
6763 	/* Build the fc header */
6764 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
6765 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
6766 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
6767 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
6768 	pkt->pkt_cmd_fhdr.f_ctl =
6769 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
6770 	pkt->pkt_cmd_fhdr.seq_id = 0;
6771 	pkt->pkt_cmd_fhdr.df_ctl = 0;
6772 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
6773 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
6774 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
6775 	pkt->pkt_cmd_fhdr.ro = 0;
6776 
6777 	/* Copy in the command buffer */
6778 	bcopy((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size);
6779 
6780 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
6781 		rval = DFC_IO_ERROR;
6782 		bzero((void *)rsp_buf, rsp_size);
6783 		bzero((void *)dfc->buf4, sizeof (uint32_t));
6784 		goto done;
6785 	}
6786 
6787 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
6788 		if (pkt->pkt_state == FC_PKT_LS_RJT) {
6789 			LS_RJT *ls_rjt;
6790 			uint32_t *word;
6791 
6792 			word = (uint32_t *)rsp_buf;
6793 			word[0] = ELS_CMD_LS_RJT;
6794 
6795 			word[1] = 0;
6796 			ls_rjt = (LS_RJT *)&word[1];
6797 			ls_rjt->un.b.lsRjtRsnCode = pkt->pkt_reason;
6798 			ls_rjt->un.b.lsRjtRsnCodeExp = pkt->pkt_expln;
6799 
6800 			rsp_size = 8;
6801 			bcopy((void *)&rsp_size, (void *)dfc->buf4,
6802 			    sizeof (uint32_t));
6803 
6804 			goto done;
6805 
6806 		} else if (pkt->pkt_state == FC_PKT_TIMEOUT) {
6807 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6808 			    "Pkt Transport error. Pkt Timeout.");
6809 			rval = DFC_TIMEOUT;
6810 		} else {
6811 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6812 			    "Pkt Transport error. state=%x", pkt->pkt_state);
6813 			rval = DFC_IO_ERROR;
6814 		}
6815 
6816 		bzero((void *)rsp_buf, rsp_size);
6817 		bzero((void *)dfc->buf4, sizeof (uint32_t));
6818 		goto done;
6819 	}
6820 
6821 	rsp_size -= pkt->pkt_resp_resid;
6822 	bcopy((void *)pkt->pkt_resp, (void *)rsp_buf, rsp_size);
6823 	bcopy((void *)&rsp_size, (void *)dfc->buf4, sizeof (uint32_t));
6824 
6825 	rval = 0;
6826 
6827 done:
6828 	if (pkt) {
6829 		emlxs_pkt_free(pkt);
6830 	}
6831 
6832 	return (rval);
6833 
6834 } /* emlxs_dfc_send_els() */
6835 
6836 
6837 /*ARGSUSED*/
6838 static int32_t
6839 emlxs_dfc_get_ioinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6840 {
6841 	emlxs_port_t	*port = &PPORT;
6842 	dfc_ioinfo_t	*ioinfo;
6843 	uint32_t	i;
6844 
6845 	if (!dfc->buf1 || !dfc->buf1_size) {
6846 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6847 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6848 
6849 		return (DFC_ARG_NULL);
6850 	}
6851 
6852 	if (dfc->buf1_size < sizeof (dfc_ioinfo_t)) {
6853 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6854 		    "%s: Buffer1 too small. (size=%d)",
6855 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
6856 
6857 		return (DFC_ARG_TOOSMALL);
6858 	}
6859 
6860 	ioinfo = (dfc_ioinfo_t *)dfc->buf1;
6861 	bzero(ioinfo, sizeof (dfc_ioinfo_t));
6862 
6863 	ioinfo->a_mboxCmd = HBASTATS.MboxIssued;
6864 	ioinfo->a_mboxCmpl = HBASTATS.MboxCompleted;
6865 	ioinfo->a_mboxErr = HBASTATS.MboxError;
6866 
6867 	for (i = 0; i < hba->chan_count; i++) {
6868 		ioinfo->a_iocbCmd += HBASTATS.IocbIssued[i];
6869 		ioinfo->a_iocbRsp += HBASTATS.IocbReceived[i];
6870 	}
6871 
6872 	ioinfo->a_adapterIntr = HBASTATS.IntrEvent[0] + HBASTATS.IntrEvent[1] +
6873 	    HBASTATS.IntrEvent[2] + HBASTATS.IntrEvent[3] +
6874 	    HBASTATS.IntrEvent[4] + HBASTATS.IntrEvent[5] +
6875 	    HBASTATS.IntrEvent[6] + HBASTATS.IntrEvent[7];
6876 
6877 	ioinfo->a_fcpCmd = HBASTATS.FcpIssued;
6878 	ioinfo->a_fcpCmpl = HBASTATS.FcpCompleted;
6879 	ioinfo->a_fcpErr = HBASTATS.FcpCompleted - HBASTATS.FcpGood;
6880 
6881 	ioinfo->a_seqXmit = HBASTATS.IpSeqIssued;
6882 	ioinfo->a_seqRcv = HBASTATS.IpSeqReceived;
6883 	ioinfo->a_seqXmitErr = HBASTATS.IpSeqCompleted - HBASTATS.IpSeqGood;
6884 
6885 	ioinfo->a_bcastXmit = HBASTATS.IpBcastIssued;
6886 	ioinfo->a_bcastRcv = HBASTATS.IpBcastReceived;
6887 
6888 	ioinfo->a_elsXmit = HBASTATS.ElsCmdIssued;
6889 	ioinfo->a_elsRcv = HBASTATS.ElsCmdReceived;
6890 	ioinfo->a_elsXmitErr = HBASTATS.ElsCmdCompleted - HBASTATS.ElsCmdGood;
6891 
6892 	ioinfo->a_RSCNRcv = HBASTATS.ElsRscnReceived;
6893 
6894 	ioinfo->a_elsBufPost = HBASTATS.ElsUbPosted;
6895 	ioinfo->a_ipBufPost = HBASTATS.IpUbPosted;
6896 
6897 	ioinfo->a_cnt1 = 0;
6898 	ioinfo->a_cnt2 = 0;
6899 	ioinfo->a_cnt3 = 0;
6900 	ioinfo->a_cnt4 = 0;
6901 
6902 	return (0);
6903 
6904 } /* emlxs_dfc_get_ioinfo() */
6905 
6906 
6907 /*ARGSUSED*/
6908 static int32_t
6909 emlxs_dfc_get_linkinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6910 {
6911 	emlxs_port_t	*port = &PPORT;
6912 	dfc_linkinfo_t	*linkinfo;
6913 
6914 	if (!dfc->buf1 || !dfc->buf1_size) {
6915 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6916 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6917 
6918 		return (DFC_ARG_NULL);
6919 	}
6920 
6921 	if (dfc->buf1_size < sizeof (dfc_linkinfo_t)) {
6922 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6923 		    "%s: Buffer1 too small. (size=%d)",
6924 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
6925 
6926 		return (DFC_ARG_TOOSMALL);
6927 	}
6928 
6929 	linkinfo = (dfc_linkinfo_t *)dfc->buf1;
6930 	bzero(linkinfo, sizeof (dfc_linkinfo_t));
6931 
6932 	linkinfo->a_linkEventTag = hba->link_event_tag;
6933 	linkinfo->a_linkUp = HBASTATS.LinkUp;
6934 	linkinfo->a_linkDown = HBASTATS.LinkDown;
6935 	linkinfo->a_linkMulti = HBASTATS.LinkMultiEvent;
6936 	linkinfo->a_DID = port->did;
6937 	linkinfo->a_topology = 0;
6938 
6939 	if (hba->state <= FC_LINK_DOWN) {
6940 		linkinfo->a_linkState = LNK_DOWN;
6941 	}
6942 #ifdef MENLO_SUPPORT
6943 	else if (hba->flag & FC_MENLO_MODE) {
6944 		linkinfo->a_linkState = LNK_DOWN;
6945 		linkinfo->a_topology  = LNK_MENLO_MAINTENANCE;
6946 
6947 	}
6948 #endif /* MENLO_SUPPORT */
6949 	else if (hba->state == FC_LINK_DOWN_PERSIST) {
6950 		linkinfo->a_linkState = LNK_DOWN_PERSIST;
6951 	} else if (hba->state < FC_READY) {
6952 		linkinfo->a_linkState = LNK_DISCOVERY;
6953 	} else {
6954 		linkinfo->a_linkState = LNK_READY;
6955 	}
6956 
6957 	if (linkinfo->a_linkState != LNK_DOWN) {
6958 		if (hba->topology == TOPOLOGY_LOOP) {
6959 			if (hba->flag & FC_FABRIC_ATTACHED) {
6960 				linkinfo->a_topology = LNK_PUBLIC_LOOP;
6961 			} else {
6962 				linkinfo->a_topology = LNK_LOOP;
6963 			}
6964 
6965 			linkinfo->a_alpa = port->did & 0xff;
6966 			linkinfo->a_alpaCnt = port->alpa_map[0];
6967 
6968 			if (linkinfo->a_alpaCnt > 127) {
6969 				linkinfo->a_alpaCnt = 127;
6970 			}
6971 
6972 			bcopy((void *)&port->alpa_map[0], linkinfo->a_alpaMap,
6973 			    linkinfo->a_alpaCnt+1);
6974 		} else {
6975 			if (hba->flag & FC_FABRIC_ATTACHED) {
6976 				linkinfo->a_topology = LNK_FABRIC;
6977 			} else {
6978 				linkinfo->a_topology = LNK_PT2PT;
6979 			}
6980 		}
6981 	}
6982 
6983 	bcopy(&hba->wwpn, linkinfo->a_wwpName, 8);
6984 	bcopy(&hba->wwnn, linkinfo->a_wwnName, 8);
6985 
6986 	return (0);
6987 
6988 } /* emlxs_dfc_get_linkinfo() */
6989 
6990 #ifdef SFCT_SUPPORT
6991 /*ARGSUSED*/
6992 static int32_t
6993 emlxs_dfc_get_fctstat(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6994 {
6995 	emlxs_port_t		*port = &PPORT;
6996 	emlxs_tgtport_stat_t	*statp = &TGTPORTSTAT;
6997 	dfc_tgtport_stat_t	*dfcstat;
6998 
6999 	if (!dfc->buf1 || !dfc->buf1_size) {
7000 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7001 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
7002 
7003 		return (DFC_ARG_NULL);
7004 	}
7005 
7006 	if (dfc->buf1_size < sizeof (emlxs_tgtport_stat_t)) {
7007 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7008 		    "%s: Buffer1 too small. (size=%d)",
7009 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
7010 
7011 		return (DFC_ARG_TOOSMALL);
7012 	}
7013 
7014 	dfcstat = (dfc_tgtport_stat_t *)dfc->buf1;
7015 	bzero(dfcstat, sizeof (dfc_tgtport_stat_t));
7016 
7017 	dfcstat->Version = DFC_TGTPORT_STAT_VERSION;
7018 
7019 	dfcstat->FctRcvDropped = statp->FctRcvDropped;
7020 	dfcstat->FctOverQDepth = statp->FctOverQDepth;
7021 	dfcstat->FctOutstandingIO = statp->FctOutstandingIO;
7022 	dfcstat->FctFailedPortRegister = statp->FctFailedPortRegister;
7023 	dfcstat->FctPortRegister = statp->FctPortRegister;
7024 	dfcstat->FctPortDeregister = statp->FctPortDeregister;
7025 
7026 	dfcstat->FctAbortSent = statp->FctAbortSent;
7027 	dfcstat->FctNoBuffer = statp->FctNoBuffer;
7028 	dfcstat->FctScsiStatusErr = statp->FctScsiStatusErr;
7029 	dfcstat->FctScsiQfullErr = statp->FctScsiQfullErr;
7030 	dfcstat->FctScsiResidOver = statp->FctScsiResidOver;
7031 	dfcstat->FctScsiResidUnder = statp->FctScsiResidUnder;
7032 	dfcstat->FctScsiSenseErr = statp->FctScsiSenseErr;
7033 
7034 	dfcstat->FctEvent = statp->FctEvent;
7035 	dfcstat->FctCompleted = statp->FctCompleted;
7036 	dfcstat->FctCmplGood = statp->FctCmplGood;
7037 	dfcstat->FctCmplError = statp->FctCmplError;
7038 	dfcstat->FctStray = statp->FctStray;
7039 
7040 	bcopy(&statp->FctP2IOWcnt[0], &dfcstat->FctP2IOWcnt[0],
7041 	    (sizeof (uint64_t) * MAX_TGTPORT_IOCNT));
7042 	bcopy(&statp->FctP2IORcnt[0], &dfcstat->FctP2IORcnt[0],
7043 	    (sizeof (uint64_t) * MAX_TGTPORT_IOCNT));
7044 	dfcstat->FctIOCmdCnt = statp->FctIOCmdCnt;
7045 	dfcstat->FctReadBytes = statp->FctReadBytes;
7046 	dfcstat->FctWriteBytes = statp->FctWriteBytes;
7047 	dfcstat->FctCmdReceived = statp->FctCmdReceived;
7048 
7049 	if (dfc->flag) {	/* Clear counters after read */
7050 		bzero(&statp->FctP2IOWcnt[0],
7051 		    (sizeof (uint64_t) * MAX_TGTPORT_IOCNT));
7052 		bzero(&statp->FctP2IORcnt[0],
7053 		    (sizeof (uint64_t) * MAX_TGTPORT_IOCNT));
7054 		statp->FctIOCmdCnt = 0;
7055 		statp->FctReadBytes = 0;
7056 		statp->FctWriteBytes = 0;
7057 		statp->FctCmdReceived = 0;
7058 	}
7059 	if (hba->state <= FC_LINK_DOWN) {
7060 		dfcstat->FctLinkState = LNK_DOWN;
7061 	}
7062 #ifdef MENLO_SUPPORT
7063 	else if (hba->flag & FC_MENLO_MODE) {
7064 		dfcstat->FctLinkState = LNK_DOWN;
7065 	}
7066 #endif /* MENLO_SUPPORT */
7067 	else if (hba->state < FC_READY) {
7068 		dfcstat->FctLinkState = LNK_DISCOVERY;
7069 	} else {
7070 		dfcstat->FctLinkState = LNK_READY;
7071 	}
7072 
7073 	return (0);
7074 
7075 } /* emlxs_dfc_get_fctstat() */
7076 #endif /* SFCT_SUPPORT */
7077 
7078 /*ARGSUSED*/
7079 static int32_t
7080 emlxs_dfc_get_nodeinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7081 {
7082 	emlxs_port_t	*port;
7083 	emlxs_config_t	*cfg = &CFG;
7084 	dfc_node_t	*dnp;
7085 	uint32_t	node_count;
7086 	NODELIST	*nlp;
7087 	uint32_t	i;
7088 
7089 	port = &VPORT(dfc->data1);
7090 
7091 	if (!dfc->buf1 || !dfc->buf1_size) {
7092 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7093 		    "%s: NULL buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
7094 
7095 		return (DFC_ARG_NULL);
7096 	}
7097 
7098 	if (dfc->buf1_size < (sizeof (dfc_node_t) * MAX_NODES)) {
7099 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7100 		    "%s: Buffer1 too small. (size=%d)",
7101 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
7102 
7103 		return (DFC_ARG_TOOSMALL);
7104 	}
7105 
7106 	if (!dfc->buf2 || !dfc->buf2_size) {
7107 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7108 		    "%s: NULL buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
7109 
7110 		return (DFC_ARG_NULL);
7111 	}
7112 
7113 	if (dfc->buf2_size < sizeof (uint32_t)) {
7114 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7115 		    "%s: Buffer2 too small. (size=%d)",
7116 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
7117 
7118 		return (DFC_ARG_TOOSMALL);
7119 	}
7120 
7121 	node_count = port->node_count;
7122 
7123 	if (node_count == 0) {
7124 		return (0);
7125 	}
7126 
7127 	dnp = (dfc_node_t *)dfc->buf1;
7128 
7129 	node_count = 0;
7130 	rw_enter(&port->node_rwlock, RW_READER);
7131 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
7132 		nlp = port->node_table[i];
7133 		while (nlp && nlp->nlp_active &&
7134 		    *((uint64_t *)&nlp->nlp_portname)) {
7135 			dnp->port_id = nlp->nlp_DID;
7136 			dnp->rpi = nlp->nlp_Rpi;
7137 			dnp->xri = nlp->nlp_Xri;
7138 
7139 			bcopy((char *)&nlp->sparm, (char *)&dnp->sparm,
7140 			    sizeof (dnp->sparm));
7141 
7142 			if (nlp->nlp_fcp_info & NLP_FCP_TGT_DEVICE) {
7143 				dnp->flags |= PORT_FLAG_FCP_TARGET;
7144 			}
7145 			if (nlp->nlp_fcp_info & NLP_FCP_INI_DEVICE) {
7146 				dnp->flags |= PORT_FLAG_FCP_INI;
7147 
7148 			}
7149 			if (nlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
7150 				dnp->flags |= PORT_FLAG_FCP2;
7151 			}
7152 			if (cfg[CFG_NETWORK_ON].current && nlp->nlp_Xri) {
7153 				dnp->flags |= PORT_FLAG_IP;
7154 			}
7155 			if (nlp->nlp_fcp_info & NLP_EMLX_VPORT) {
7156 				dnp->flags |= PORT_FLAG_VPORT;
7157 			}
7158 
7159 			/* Copy our dfc_state */
7160 			dnp->flags |= ((nlp->dfc_state & 0xF) << 28);
7161 			dnp->flags |= PORT_FLAG_DFC_STATE_VALID;
7162 
7163 			dnp++;
7164 			node_count++;
7165 			nlp = (NODELIST *) nlp->nlp_list_next;
7166 		}
7167 	}
7168 	rw_exit(&port->node_rwlock);
7169 
7170 	bcopy((void *)&node_count, (void *)dfc->buf2, sizeof (uint32_t));
7171 	return (0);
7172 
7173 } /* emlxs_dfc_get_nodeinfo() */
7174 
7175 
7176 /*ARGSUSED*/
7177 static int32_t
7178 emlxs_dfc_read_mem(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7179 {
7180 	emlxs_port_t	*port = &PPORT;
7181 	uint32_t	offset;
7182 	uint32_t	size;
7183 	uint32_t	max_size;
7184 	uint8_t		*slim;
7185 
7186 	offset = dfc->data1;
7187 	size = dfc->data2;
7188 
7189 	if (!dfc->buf1 || !dfc->buf1_size) {
7190 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7191 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
7192 
7193 		return (DFC_ARG_NULL);
7194 	}
7195 
7196 	if (size > dfc->buf1_size) {
7197 		size = dfc->buf1_size;
7198 	}
7199 
7200 	if (offset % 4) {
7201 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7202 		    "%s: Offset misaligned. (offset=%d)",
7203 		    emlxs_dfc_xlate(dfc->cmd), offset);
7204 
7205 		return (DFC_ARG_MISALIGNED);
7206 	}
7207 
7208 	if (size % 4) {
7209 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7210 		    "%s: Size misaligned. (size=%d)",
7211 		    emlxs_dfc_xlate(dfc->cmd), size);
7212 
7213 		return (DFC_ARG_MISALIGNED);
7214 	}
7215 
7216 	if (hba->flag & FC_SLIM2_MODE) {
7217 		max_size = SLI2_SLIM2_SIZE;
7218 	} else {
7219 		max_size = 4096;
7220 	}
7221 
7222 	if (offset >= max_size) {
7223 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7224 		    "%s: Offset too large. (offset=%d)",
7225 		    emlxs_dfc_xlate(dfc->cmd), offset);
7226 
7227 		return (DFC_ARG_TOOBIG);
7228 	}
7229 
7230 	if ((size + offset) > max_size) {
7231 		size = (max_size - offset);
7232 	}
7233 
7234 	if (hba->flag & FC_SLIM2_MODE) {
7235 		slim = (uint8_t *)hba->sli.sli3.slim2.virt + offset;
7236 		BE_SWAP32_BCOPY((uint8_t *)slim, (uint8_t *)dfc->buf1, size);
7237 	} else {
7238 		slim = (uint8_t *)hba->sli.sli3.slim_addr + offset;
7239 		READ_SLIM_COPY(hba, (uint32_t *)dfc->buf1, (uint32_t *)slim,
7240 		    (size / 4));
7241 	}
7242 
7243 #ifdef FMA_SUPPORT
7244 	/* Access handle validation */
7245 	if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.slim_acc_handle)
7246 	    != DDI_FM_OK) {
7247 		EMLXS_MSGF(EMLXS_CONTEXT,
7248 		    &emlxs_invalid_access_handle_msg, NULL);
7249 		return (DFC_DRV_ERROR);
7250 	}
7251 #endif  /* FMA_SUPPORT */
7252 
7253 	return (0);
7254 
7255 } /* emlxs_dfc_read_mem() */
7256 
7257 
7258 /*ARGSUSED*/
7259 static int32_t
7260 emlxs_dfc_write_mem(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7261 {
7262 	emlxs_port_t	*port = &PPORT;
7263 	uint32_t	offset;
7264 	uint32_t	size;
7265 	uint32_t	max_size;
7266 	uint8_t		*slim;
7267 
7268 	offset = dfc->data1;
7269 	size = dfc->data2;
7270 
7271 	if (!dfc->buf1 || !dfc->buf1_size) {
7272 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7273 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
7274 
7275 		return (DFC_ARG_NULL);
7276 	}
7277 
7278 	if (size > dfc->buf1_size) {
7279 		size = dfc->buf1_size;
7280 	}
7281 
7282 	if (offset % 4) {
7283 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7284 		    "%s: Offset misaligned. (offset=%d)",
7285 		    emlxs_dfc_xlate(dfc->cmd), offset);
7286 
7287 		return (DFC_ARG_MISALIGNED);
7288 	}
7289 
7290 	if (size % 4) {
7291 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7292 		    "%s: Size misaligned. (szie=%d)",
7293 		    emlxs_dfc_xlate(dfc->cmd), size);
7294 
7295 		return (DFC_ARG_MISALIGNED);
7296 	}
7297 
7298 	if (hba->flag & FC_SLIM2_MODE) {
7299 		max_size = SLI2_SLIM2_SIZE;
7300 	} else {
7301 		max_size = 4096;
7302 	}
7303 
7304 	if (offset >= max_size) {
7305 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7306 		    "%s: Offset too large. (offset=%d)",
7307 		    emlxs_dfc_xlate(dfc->cmd), offset);
7308 
7309 		return (DFC_ARG_TOOBIG);
7310 	}
7311 
7312 	if ((size + offset) > max_size) {
7313 		size = (max_size - offset);
7314 	}
7315 
7316 	if (hba->flag & FC_SLIM2_MODE) {
7317 		slim = (uint8_t *)hba->sli.sli3.slim2.virt + offset;
7318 		BE_SWAP32_BCOPY((uint8_t *)dfc->buf1, (uint8_t *)slim, size);
7319 	} else {
7320 		slim = (uint8_t *)hba->sli.sli3.slim_addr + offset;
7321 		WRITE_SLIM_COPY(hba, (uint32_t *)dfc->buf1, (uint32_t *)slim,
7322 		    (size / 4));
7323 	}
7324 
7325 #ifdef FMA_SUPPORT
7326 	/* Access handle validation */
7327 	if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.slim_acc_handle)
7328 	    != DDI_FM_OK) {
7329 		EMLXS_MSGF(EMLXS_CONTEXT,
7330 		    &emlxs_invalid_access_handle_msg, NULL);
7331 		return (DFC_DRV_ERROR);
7332 	}
7333 #endif  /* FMA_SUPPORT */
7334 
7335 	return (0);
7336 
7337 } /* emlxs_dfc_write_mem() */
7338 
7339 
7340 /* ARGSUSED */
7341 static int32_t
7342 emlxs_dfc_write_ctlreg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7343 {
7344 	emlxs_port_t	*port = &PPORT;
7345 	uint32_t	offset;
7346 	uint32_t	value;
7347 
7348 	offset = dfc->data1;
7349 	value = dfc->data2;
7350 
7351 	if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE) {
7352 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7353 		    "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd));
7354 
7355 		return (DFC_NOT_SUPPORTED);
7356 	}
7357 
7358 	if (!(hba->flag & FC_OFFLINE_MODE)) {
7359 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7360 		    "%s: Adapter not offline.", emlxs_dfc_xlate(dfc->cmd));
7361 
7362 		return (DFC_ONLINE_ERROR);
7363 	}
7364 
7365 	if (offset % 4) {
7366 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7367 		    "%s: Offset misaligned. (offset=%d)",
7368 		    emlxs_dfc_xlate(dfc->cmd), offset);
7369 
7370 		return (DFC_ARG_MISALIGNED);
7371 	}
7372 
7373 	if (offset > 255) {
7374 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7375 		    "%s: Offset too large. (offset=%d)",
7376 		    emlxs_dfc_xlate(dfc->cmd), offset);
7377 
7378 		return (DFC_ARG_TOOBIG);
7379 	}
7380 
7381 	WRITE_CSR_REG(hba, (hba->sli.sli3.csr_addr + offset), value);
7382 
7383 #ifdef FMA_SUPPORT
7384 	/* Access handle validation */
7385 	if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.csr_acc_handle)
7386 	    != DDI_FM_OK) {
7387 		EMLXS_MSGF(EMLXS_CONTEXT,
7388 		    &emlxs_invalid_access_handle_msg, NULL);
7389 		return (DFC_DRV_ERROR);
7390 	}
7391 #endif  /* FMA_SUPPORT */
7392 
7393 	return (0);
7394 
7395 } /* emlxs_dfc_write_ctlreg() */
7396 
7397 
7398 /*ARGSUSED*/
7399 static int32_t
7400 emlxs_dfc_read_ctlreg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7401 {
7402 	emlxs_port_t	*port = &PPORT;
7403 	uint32_t	offset;
7404 	uint32_t	value;
7405 
7406 	offset = dfc->data1;
7407 
7408 	if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE) {
7409 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7410 		    "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd));
7411 
7412 		return (DFC_NOT_SUPPORTED);
7413 	}
7414 
7415 	if (offset % 4) {
7416 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7417 		    "%s: Offset misaligned. (offset=%d)",
7418 		    emlxs_dfc_xlate(dfc->cmd), offset);
7419 
7420 		return (DFC_ARG_MISALIGNED);
7421 	}
7422 
7423 	if (offset > 255) {
7424 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7425 		    "%s: Offset too large. (offset=%d)",
7426 		    emlxs_dfc_xlate(dfc->cmd), offset);
7427 
7428 		return (DFC_ARG_TOOBIG);
7429 	}
7430 
7431 	if (!dfc->buf1 || !dfc->buf1_size) {
7432 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7433 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
7434 
7435 		return (DFC_ARG_NULL);
7436 	}
7437 
7438 	if (dfc->buf1_size < sizeof (uint32_t)) {
7439 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7440 		    "%s: Buffer1 too small. (size=%d)",
7441 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
7442 
7443 		return (DFC_ARG_TOOSMALL);
7444 	}
7445 
7446 	value = READ_CSR_REG(hba, (hba->sli.sli3.csr_addr + offset));
7447 	bcopy((void *)&value, (void *)dfc->buf1, sizeof (uint32_t));
7448 
7449 #ifdef FMA_SUPPORT
7450 	/* Access handle validation */
7451 	if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.csr_acc_handle)
7452 	    != DDI_FM_OK) {
7453 		EMLXS_MSGF(EMLXS_CONTEXT,
7454 		    &emlxs_invalid_access_handle_msg, NULL);
7455 		return (DFC_DRV_ERROR);
7456 	}
7457 #endif  /* FMA_SUPPORT */
7458 
7459 	return (0);
7460 
7461 } /* emlxs_dfc_read_ctlreg() */
7462 
7463 
7464 /*ARGSUSED*/
7465 static int32_t
7466 emlxs_dfc_set_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7467 {
7468 	emlxs_port_t		*port = &PPORT;
7469 	uint32_t		event;
7470 	uint32_t		enable;
7471 	uint32_t		pid;
7472 	uint32_t		count;
7473 	uint32_t		i;
7474 	emlxs_dfc_event_t	*dfc_event;
7475 
7476 	event = dfc->data1;
7477 	pid = dfc->data2;
7478 	enable = dfc->flag;
7479 
7480 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
7481 	    "%s: %s. pid=%d enable=%d", emlxs_dfc_xlate(dfc->cmd),
7482 	    emlxs_dfc_event_xlate(event), pid, enable);
7483 
7484 	switch (event) {
7485 	case FC_REG_LINK_EVENT:
7486 	case FC_REG_RSCN_EVENT:
7487 	case FC_REG_CT_EVENT:
7488 	case FC_REG_DUMP_EVENT:
7489 	case FC_REG_TEMP_EVENT:
7490 	case FC_REG_VPORTRSCN_EVENT:
7491 	case FC_REG_FCOE_EVENT:
7492 		break;
7493 
7494 	case FC_REG_MULTIPULSE_EVENT:
7495 	default:
7496 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7497 		    "%s: %s. Invalid event. pid=%d enable=%d",
7498 		    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event),
7499 		    pid, enable);
7500 
7501 		return (DFC_ARG_INVALID);
7502 	}
7503 
7504 	if (enable) {
7505 		if (dfc->buf1_size < sizeof (uint32_t)) {
7506 			dfc->buf1 = NULL;
7507 		} else if (!dfc->buf1) {
7508 			dfc->buf1_size = 0;
7509 		}
7510 
7511 		/* Make sure this pid/event is not already registered */
7512 		dfc_event = NULL;
7513 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
7514 			dfc_event = &hba->dfc_event[i];
7515 
7516 			if (dfc_event->pid == pid &&
7517 			    dfc_event->event == event) {
7518 				break;
7519 			}
7520 		}
7521 
7522 		if (i == MAX_DFC_EVENTS) {
7523 			/* Find next available event object */
7524 			for (i = 0; i < MAX_DFC_EVENTS; i++) {
7525 				dfc_event = &hba->dfc_event[i];
7526 
7527 				if (!dfc_event->pid && !dfc_event->event) {
7528 					break;
7529 				}
7530 			}
7531 
7532 			/* Return if all event objects are busy */
7533 			if (i == MAX_DFC_EVENTS) {
7534 				EMLXS_MSGF(EMLXS_CONTEXT,
7535 				    &emlxs_dfc_error_msg,
7536 				    "%s: %s. Too many events registered. "
7537 				    "pid=%d enable=%d",
7538 				    emlxs_dfc_xlate(dfc->cmd),
7539 				    emlxs_dfc_event_xlate(event), pid,
7540 				    enable);
7541 
7542 				return (DFC_DRVRES_ERROR);
7543 			}
7544 		}
7545 
7546 		/* Initialize */
7547 		dfc_event->pid = pid;
7548 		dfc_event->event = event;
7549 		dfc_event->last_id = (uint32_t)-1;
7550 		dfc_event->dataout = NULL;
7551 		dfc_event->size = 0;
7552 		dfc_event->mode = 0;
7553 
7554 		emlxs_get_dfc_event(port, dfc_event, 0);
7555 
7556 		if (dfc->buf1) {
7557 			bcopy((void *)&dfc_event->last_id, dfc->buf1,
7558 			    sizeof (uint32_t));
7559 		}
7560 
7561 		/*
7562 		 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
7563 		 * "%s: %s. Enabled. pid=%d id=%d", emlxs_dfc_xlate(dfc->cmd),
7564 		 * emlxs_dfc_event_xlate(event), pid, dfc_event->last_id);
7565 		 */
7566 
7567 		hba->event_mask |= event;
7568 
7569 	} else {	/* Disable */
7570 
7571 		/* Find the event entry */
7572 		dfc_event = NULL;
7573 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
7574 			dfc_event = &hba->dfc_event[i];
7575 
7576 			if (dfc_event->pid == pid &&
7577 			    dfc_event->event == event) {
7578 				break;
7579 			}
7580 		}
7581 
7582 		if (i == MAX_DFC_EVENTS) {
7583 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7584 			    "%s: %s. Event not registered. pid=%d enable=%d",
7585 			    emlxs_dfc_xlate(dfc->cmd),
7586 			    emlxs_dfc_event_xlate(event), pid, enable);
7587 
7588 			return (DFC_ARG_INVALID);
7589 		}
7590 
7591 		/* Kill the event thread if it is sleeping */
7592 		(void) emlxs_kill_dfc_event(port, dfc_event);
7593 
7594 		/* Count the number of pids still registered for this event */
7595 		count = 0;
7596 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
7597 			dfc_event = &hba->dfc_event[i];
7598 
7599 			if (dfc_event->event == event) {
7600 				count++;
7601 			}
7602 		}
7603 
7604 		/* If no more pids need this event, */
7605 		/* then disable logging for this event */
7606 		if (count == 0) {
7607 			hba->event_mask &= ~event;
7608 		}
7609 	}
7610 
7611 	return (0);
7612 
7613 } /* emlxs_dfc_set_event() */
7614 
7615 
7616 /*ARGSUSED*/
7617 static int32_t
7618 emlxs_dfc_get_eventinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7619 {
7620 	emlxs_port_t	*port = &PPORT;
7621 	uint32_t	size;
7622 	int32_t		rval = 0;
7623 	HBA_EVENTINFO 	*event_buffer = NULL;
7624 	uint32_t	event_count = 0;
7625 	uint32_t	missed = 0;
7626 
7627 	if (!dfc->buf1 || !dfc->buf1_size) {
7628 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7629 		    "%s: Null buffer1 buffer.", emlxs_dfc_xlate(dfc->cmd));
7630 
7631 		return (DFC_ARG_NULL);
7632 	}
7633 
7634 	event_count = dfc->buf1_size / sizeof (HBA_EVENTINFO);
7635 
7636 	if (!event_count) {
7637 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7638 		    "%s: Buffer1 too small. (size=%d)",
7639 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
7640 
7641 		return (DFC_ARG_TOOSMALL);
7642 	}
7643 
7644 	if (!dfc->buf2 || !dfc->buf2_size) {
7645 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7646 		    "%s: Null buffer2 buffer.", emlxs_dfc_xlate(dfc->cmd));
7647 
7648 		return (DFC_ARG_NULL);
7649 	}
7650 
7651 	if (dfc->buf2_size < sizeof (uint32_t)) {
7652 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7653 		    "%s: Buffer2 too small. (size=%d)",
7654 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
7655 
7656 		return (DFC_ARG_TOOSMALL);
7657 	}
7658 
7659 	if (!dfc->buf3 || !dfc->buf3_size) {
7660 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7661 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
7662 
7663 		return (DFC_ARG_NULL);
7664 	}
7665 
7666 	if (dfc->buf3_size < sizeof (uint32_t)) {
7667 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7668 		    "%s: Buffer3 too small. (size=%d)",
7669 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
7670 
7671 		return (DFC_ARG_TOOSMALL);
7672 	}
7673 
7674 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s called. max=%d",
7675 	    emlxs_dfc_xlate(dfc->cmd), event_count);
7676 
7677 	size = (event_count * sizeof (HBA_EVENTINFO));
7678 	event_buffer = (HBA_EVENTINFO *)kmem_zalloc(size, KM_SLEEP);
7679 
7680 	if (emlxs_get_dfc_eventinfo(port, event_buffer, &event_count,
7681 	    &missed) != 0) {
7682 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7683 		    "%s: get_dfc_eventinfo failed.",
7684 		    emlxs_dfc_xlate(dfc->cmd));
7685 
7686 		rval = DFC_DRV_ERROR;
7687 		goto done;
7688 	}
7689 
7690 	if (event_count) {
7691 		bcopy((void *)event_buffer, dfc->buf1,
7692 		    (event_count * sizeof (HBA_EVENTINFO)));
7693 	}
7694 
7695 	bcopy((void *)&event_count, dfc->buf2, sizeof (uint32_t));
7696 	bcopy((void *)&missed, dfc->buf3, sizeof (uint32_t));
7697 
7698 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
7699 	    "%s: events=%d missed=%d new=%d last_id=%d",
7700 	    emlxs_dfc_xlate(dfc->cmd), event_count, hba->hba_event.missed,
7701 	    hba->hba_event.new, hba->hba_event.last_id);
7702 
7703 done:
7704 
7705 	if (event_buffer) {
7706 		kmem_free(event_buffer, size);
7707 	}
7708 
7709 	return (rval);
7710 
7711 } /* emlxs_dfc_get_eventinfo() */
7712 
7713 
7714 /*ARGSUSED*/
7715 static int32_t
7716 emlxs_dfc_get_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7717 {
7718 	emlxs_port_t		*port = &PPORT;
7719 	uint32_t		event;
7720 	uint32_t		pid;
7721 	uint32_t		sleep;
7722 	uint32_t		i;
7723 	int32_t			rval = DFC_SUCCESS;
7724 	emlxs_dfc_event_t	*dfc_event;
7725 
7726 	event = dfc->data1;
7727 	pid = dfc->data2;
7728 
7729 	if (!dfc->buf1_size) {
7730 		dfc->buf1 = NULL;
7731 	} else if (!dfc->buf1) {
7732 		dfc->buf1_size = 0;
7733 	}
7734 
7735 	if (dfc->buf2_size < sizeof (uint32_t)) {
7736 		dfc->buf2 = NULL;
7737 	} else if (!dfc->buf2) {
7738 		dfc->buf2_size = 0;
7739 	}
7740 
7741 	if (dfc->buf3_size < sizeof (uint32_t)) {
7742 		dfc->buf3 = NULL;
7743 	} else if (!dfc->buf3) {
7744 		dfc->buf3_size = 0;
7745 	}
7746 
7747 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
7748 	    "%s: %s. pid=%d size=%d,%p rcv_size=%d,%p id=%d",
7749 	    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid,
7750 	    dfc->buf1_size, dfc->buf1, dfc->buf2_size, dfc->buf2, dfc->data3);
7751 
7752 	/* Find the event entry */
7753 	dfc_event = NULL;
7754 	for (i = 0; i < MAX_DFC_EVENTS; i++) {
7755 		dfc_event = &hba->dfc_event[i];
7756 
7757 		if (dfc_event->pid == pid && dfc_event->event == event) {
7758 			break;
7759 		}
7760 	}
7761 
7762 	if (i == MAX_DFC_EVENTS) {
7763 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7764 		    "%s: %s. Event not registered. pid=%d",
7765 		    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event),
7766 		    pid);
7767 
7768 		return (DFC_ARG_INVALID);
7769 	}
7770 
7771 	if (!(hba->event_mask & dfc_event->event)) {
7772 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7773 		    "%s: %s. Event not registered. pid=%d",
7774 		    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event),
7775 		    pid);
7776 
7777 		return (DFC_ARG_INVALID);
7778 	}
7779 
7780 	/* Initialize event buffer pointers */
7781 	dfc_event->dataout = dfc->buf1;
7782 	dfc_event->size = dfc->buf1_size;
7783 	dfc_event->last_id = dfc->data3;
7784 	dfc_event->mode = mode;
7785 
7786 	sleep = (dfc->flag & 0x01) ? 1 : 0;
7787 
7788 	emlxs_get_dfc_event(port, dfc_event, sleep);
7789 
7790 	if (dfc->buf2) {
7791 		bcopy((void *)&dfc_event->size, dfc->buf2, sizeof (uint32_t));
7792 	}
7793 
7794 	if (dfc->buf3) {
7795 		bcopy((void *)&dfc_event->last_id, dfc->buf3,
7796 		    sizeof (uint32_t));
7797 	}
7798 
7799 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
7800 	    "%s: %s. Completed. pid=%d rsize=%d id=%d",
7801 	    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid,
7802 	    dfc_event->size, dfc_event->last_id);
7803 
7804 	return (rval);
7805 
7806 } /* emlxs_dfc_get_event() */
7807 
7808 
7809 extern uint32_t
7810 emlxs_get_dump_region(emlxs_hba_t *hba, uint32_t region,
7811     uint8_t *buffer, uint32_t *psize)
7812 {
7813 	emlxs_port_t	*port = &PPORT;
7814 	uint32_t	size;
7815 	uint32_t	size_only;
7816 	uint32_t	rval = 0;
7817 	uint8_t		*memptr;
7818 	uint32_t	*wptr;
7819 
7820 	if (!buffer || !(*psize)) {
7821 		size_only = 1;
7822 		size = 0xffffffff;
7823 	} else {
7824 		size_only = 0;
7825 		size = *psize;
7826 	}
7827 
7828 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
7829 		if (region != 7) {
7830 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7831 			    "get_dump_region: Invalid sli4 region. "
7832 			    "(id=%d)", region);
7833 
7834 			rval = DFC_ARG_INVALID;
7835 			goto done;
7836 		}
7837 	}
7838 
7839 	switch (region) {
7840 	case 0:	/* SLI Registers */
7841 
7842 		if (size < (4 * sizeof (uint32_t))) {
7843 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7844 			    "get_dump_region: Buffer too small. "
7845 			    "(SLI Registers: size=%d)", size);
7846 
7847 			rval = DFC_ARG_TOOSMALL;
7848 			goto done;
7849 		}
7850 
7851 		size = (4 * sizeof (uint32_t));
7852 
7853 		if (size_only) {
7854 			break;
7855 		}
7856 
7857 		wptr = (uint32_t *)buffer;
7858 		wptr[0] = READ_CSR_REG(hba, FC_HA_REG(hba));
7859 		wptr[1] = READ_CSR_REG(hba, FC_CA_REG(hba));
7860 		wptr[2] = READ_CSR_REG(hba, FC_HS_REG(hba));
7861 		wptr[3] = READ_CSR_REG(hba, FC_HC_REG(hba));
7862 
7863 #ifdef FMA_SUPPORT
7864 		/* Access handle validation */
7865 		if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.csr_acc_handle)
7866 		    != DDI_FM_OK) {
7867 			EMLXS_MSGF(EMLXS_CONTEXT,
7868 			    &emlxs_invalid_access_handle_msg, NULL);
7869 			rval = DFC_DRV_ERROR;
7870 		}
7871 #endif  /* FMA_SUPPORT */
7872 
7873 		break;
7874 
7875 	case 1:	/* SLIM */
7876 
7877 		if (hba->flag & FC_SLIM2_MODE) {
7878 			size = MIN(SLI2_SLIM2_SIZE, size);
7879 		} else {
7880 			size = MIN(4096, size);
7881 		}
7882 
7883 		if (size_only) {
7884 			break;
7885 		}
7886 
7887 		if (hba->flag & FC_SLIM2_MODE) {
7888 			memptr = (uint8_t *)hba->sli.sli3.slim2.virt;
7889 			BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer,
7890 			    size);
7891 		} else {
7892 			memptr = (uint8_t *)hba->sli.sli3.slim_addr;
7893 			READ_SLIM_COPY(hba, (uint32_t *)buffer,
7894 			    (uint32_t *)memptr, (size / 4));
7895 #ifdef FMA_SUPPORT
7896 			/* Access handle validation */
7897 			if (emlxs_fm_check_acc_handle(hba,
7898 			    hba->sli.sli3.slim_acc_handle) != DDI_FM_OK) {
7899 				EMLXS_MSGF(EMLXS_CONTEXT,
7900 				    &emlxs_invalid_access_handle_msg, NULL);
7901 				rval = DFC_DRV_ERROR;
7902 			}
7903 #endif  /* FMA_SUPPORT */
7904 		}
7905 
7906 		break;
7907 
7908 	case 2:	/* Port Control Block */
7909 
7910 		if (size < sizeof (PCB)) {
7911 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7912 			    "get_dump_region: Buffer too small. "
7913 			    "(PCB: size=%d)", size);
7914 
7915 			rval = DFC_ARG_TOOSMALL;
7916 			goto done;
7917 		}
7918 
7919 		size = sizeof (PCB);
7920 
7921 		if (size_only) {
7922 			break;
7923 		}
7924 
7925 		memptr = (uint8_t *)&(((SLIM2 *)hba->sli.sli3.slim2.virt)->pcb);
7926 		BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer, size);
7927 		break;
7928 
7929 	case 3:	/* MailBox */
7930 
7931 		if (size < MAILBOX_CMD_BSIZE) {
7932 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7933 			    "get_dump_region: Buffer too small. "
7934 			    "(Mailbox: size=%d)", size);
7935 
7936 			rval = DFC_ARG_TOOSMALL;
7937 			goto done;
7938 		}
7939 
7940 		size = MAILBOX_CMD_BSIZE;
7941 
7942 		if (size_only) {
7943 			break;
7944 		}
7945 
7946 		if (hba->flag & FC_SLIM2_MODE) {
7947 			memptr = (uint8_t *)hba->sli.sli3.slim2.virt;
7948 			BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer,
7949 			    size);
7950 		} else {
7951 			memptr = (uint8_t *)hba->sli.sli3.slim_addr;
7952 			READ_SLIM_COPY(hba, (uint32_t *)buffer,
7953 			    (uint32_t *)memptr, (size / 4));
7954 #ifdef FMA_SUPPORT
7955 			/* Access handle validation */
7956 			if (emlxs_fm_check_acc_handle(hba,
7957 			    hba->sli.sli3.slim_acc_handle) != DDI_FM_OK) {
7958 				EMLXS_MSGF(EMLXS_CONTEXT,
7959 				    &emlxs_invalid_access_handle_msg, NULL);
7960 				rval = DFC_DRV_ERROR;
7961 			}
7962 #endif  /* FMA_SUPPORT */
7963 		}
7964 
7965 		break;
7966 
7967 	case 4:	/* Host Put/Get pointer array */
7968 
7969 		if (size < MAX_RINGS * sizeof (HGP)) {
7970 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7971 			    "get_dump_region: Buffer too small. "
7972 			    "(HGP: size=%d)", size);
7973 
7974 			rval = DFC_ARG_TOOSMALL;
7975 			goto done;
7976 		}
7977 
7978 		size = MAX_RINGS * sizeof (HGP);
7979 
7980 		if (size_only) {
7981 			break;
7982 		}
7983 
7984 		{
7985 			memptr = (uint8_t *)hba->sli.sli3.slim_addr +
7986 			    hba->sli.sli3.hgp_ring_offset;
7987 
7988 			READ_SLIM_COPY(hba, (uint32_t *)buffer,
7989 			    (uint32_t *)memptr, (size / 4));
7990 #ifdef FMA_SUPPORT
7991 			/* Access handle validation */
7992 			if (emlxs_fm_check_acc_handle(hba,
7993 			    hba->sli.sli3.slim_acc_handle) != DDI_FM_OK) {
7994 				EMLXS_MSGF(EMLXS_CONTEXT,
7995 				    &emlxs_invalid_access_handle_msg, NULL);
7996 				rval = DFC_DRV_ERROR;
7997 			}
7998 #endif  /* FMA_SUPPORT */
7999 		}
8000 
8001 		break;
8002 
8003 	case 5:	/* Port  Get/Put pointer array */
8004 
8005 		if (size < MAX_RINGS * sizeof (PGP)) {
8006 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8007 			    "get_dump_region: Buffer too small. "
8008 			    "(PGP: size=%d)", size);
8009 
8010 			rval = DFC_ARG_TOOSMALL;
8011 			goto done;
8012 		}
8013 
8014 		size = MAX_RINGS * sizeof (PGP);
8015 
8016 		if (size_only) {
8017 			break;
8018 		}
8019 
8020 		memptr = (uint8_t *)
8021 		    ((SLIM2 *)hba->sli.sli3.slim2.virt)->mbx.us.s2.port;
8022 		BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer, size);
8023 		break;
8024 
8025 	case 6:	/* Command/Response Ring */
8026 
8027 		if (size < SLI_IOCB_MAX_SIZE) {
8028 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8029 			    "get_dump_region: Buffer too small. "
8030 			    "(Rings: size=%d)", size);
8031 
8032 			rval = DFC_ARG_TOOSMALL;
8033 			goto done;
8034 		}
8035 
8036 		size = SLI_IOCB_MAX_SIZE;
8037 
8038 		if (size_only) {
8039 			break;
8040 		}
8041 
8042 		memptr = (uint8_t *)((SLIM2 *)hba->sli.sli3.slim2.virt)->IOCBs;
8043 		BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer, size);
8044 		break;
8045 
8046 	case 7:	/* All driver specific structures */
8047 
8048 		if (size < sizeof (emlxs_hba_t)) {
8049 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8050 			    "get_dump_region: Buffer too small. "
8051 			    "(Driver: size=%d)", size);
8052 
8053 			rval = DFC_ARG_TOOSMALL;
8054 			goto done;
8055 		}
8056 
8057 		size = sizeof (emlxs_hba_t);
8058 
8059 		if (size_only) {
8060 			break;
8061 		}
8062 
8063 		memptr = (uint8_t *)hba;
8064 		bcopy((void *)memptr, (void *)buffer, size);
8065 
8066 		break;
8067 
8068 	default:
8069 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8070 		    "get_dump_region: Invalid region. (id=%d)", region);
8071 
8072 		rval = DFC_ARG_INVALID;
8073 	}
8074 
8075 done:
8076 
8077 	*psize = size;
8078 
8079 	return (rval);
8080 
8081 } /* emlxs_get_dump_region() */
8082 
8083 
8084 
8085 /*ARGSUSED*/
8086 static int32_t
8087 emlxs_dfc_get_dump_region(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8088 {
8089 	emlxs_port_t	*port = &PPORT;
8090 	uint32_t	size;
8091 	uint32_t	size_only = 0;
8092 	uint32_t	rval = 0;
8093 
8094 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
8095 	    "%s: region=%d size=%d",
8096 	    emlxs_dfc_xlate(dfc->cmd), dfc->data1, dfc->buf1_size);
8097 
8098 	if (!dfc->buf1 || !dfc->buf1_size) {
8099 		size_only = 1;
8100 	}
8101 
8102 	if (!dfc->buf2 || !dfc->buf2_size) {
8103 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8104 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
8105 
8106 		return (DFC_ARG_NULL);
8107 	}
8108 
8109 	if (dfc->buf2_size < sizeof (uint32_t)) {
8110 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8111 		    "%s: Buffer2 too small. (size=%d)",
8112 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
8113 
8114 		return (DFC_ARG_TOOSMALL);
8115 	}
8116 
8117 	/* First get region size only */
8118 	size = 0;
8119 	rval = emlxs_get_dump_region(hba, dfc->data1, NULL, &size);
8120 
8121 	if (rval != 0) {
8122 		goto done;
8123 	}
8124 
8125 	if (!size_only) {
8126 		if (dfc->buf1_size < size) {
8127 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8128 			    "%s: Buffer1 too small. (size: %d < %d)",
8129 			    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size, size);
8130 
8131 			rval = DFC_ARG_TOOSMALL;
8132 			goto done;
8133 		}
8134 
8135 		/* Get the region data */
8136 		rval = emlxs_get_dump_region(hba, dfc->data1, dfc->buf1, &size);
8137 
8138 		if (rval != 0) {
8139 			goto done;
8140 		}
8141 	}
8142 
8143 	/* Return the region size */
8144 	bcopy((void *) &size, (void *) dfc->buf2, sizeof (uint32_t));
8145 
8146 done:
8147 	return (rval);
8148 
8149 } /* emlxs_dfc_get_dump_region() */
8150 
8151 
8152 
8153 #ifdef MENLO_SUPPORT
8154 /*ARGSUSED*/
8155 static int32_t
8156 emlxs_dfc_menlo_port_offset(emlxs_hba_t *hba)
8157 {
8158 	uint32_t	cnt;
8159 	char		pathname[256];
8160 
8161 	(void) ddi_pathname(hba->dip, pathname);
8162 	cnt = strlen(pathname);
8163 	if ((cnt < 4) || (strcmp(&pathname[cnt-3], "0,1") != 0))
8164 		return (0);
8165 	return (1);
8166 }
8167 
8168 /*ARGSUSED*/
8169 static int32_t
8170 emlxs_dfc_set_menlo_loopback(emlxs_hba_t *hba)
8171 {
8172 	emlxs_port_t *port = &PPORT;
8173 	MAILBOXQ *mbq = NULL;
8174 	MAILBOX *mb = NULL;
8175 	fc_packet_t *pkt = NULL;
8176 	uint32_t mbxstatus;
8177 	uint32_t i;
8178 	uint32_t offset;
8179 	uint32_t rval = 0;
8180 	menlo_cmd_t *cmd;
8181 
8182 	mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
8183 	    KM_SLEEP);
8184 
8185 	mb = (MAILBOX *)mbq;
8186 
8187 	/* SET MENLO maint mode */
8188 	/* Create the set_variable mailbox request */
8189 	emlxs_mb_set_var(hba, mbq, 0x103107, 1);
8190 
8191 	mbq->flag |= MBQ_PASSTHRU;
8192 
8193 	/* issue the mbox cmd to the sli */
8194 	mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
8195 
8196 	if (mbxstatus) {
8197 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8198 		    "%s: %s failed. mbxstatus=0x%x",
8199 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
8200 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
8201 
8202 		rval = DFC_IO_ERROR;
8203 		if (mbxstatus == MBX_TIMEOUT)
8204 			rval = DFC_TIMEOUT;
8205 		goto done;
8206 	}
8207 
8208 
8209 	/* Wait 30 sec for maint mode */
8210 	i = 0;
8211 	do {
8212 		if (i++ > 300) {
8213 			break;
8214 		}
8215 
8216 		delay(drv_usectohz(100000));
8217 
8218 	} while (!(hba->flag & FC_MENLO_MODE));
8219 
8220 	if (!(hba->flag & FC_MENLO_MODE)) {
8221 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8222 		    "%s: Unable to enter maint mode.",
8223 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8224 
8225 		rval = DFC_DRV_ERROR;
8226 		goto done;
8227 	}
8228 
8229 	offset = emlxs_dfc_menlo_port_offset(hba);
8230 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8231 	    "%s: Entered maint mode. Port offset: %d",
8232 	    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE), offset);
8233 
8234 
8235 	/* Issue Menlo loopback command */
8236 	if (!(pkt = emlxs_pkt_alloc(port, sizeof (menlo_cmd_t),
8237 	    sizeof (uint32_t), 0, KM_NOSLEEP))) {
8238 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8239 		    "%s: Unable to allocate packet.",
8240 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8241 
8242 		rval = DFC_SYSRES_ERROR;
8243 		goto done;
8244 	}
8245 
8246 	/* Make this a polled IO */
8247 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
8248 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
8249 	pkt->pkt_comp = NULL;
8250 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
8251 	pkt->pkt_timeout = 30;
8252 
8253 	/* Build the fc header */
8254 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(EMLXS_MENLO_DID);
8255 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
8256 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
8257 	pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
8258 	pkt->pkt_cmd_fhdr.f_ctl =
8259 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
8260 	pkt->pkt_cmd_fhdr.seq_id = 0;
8261 	pkt->pkt_cmd_fhdr.df_ctl = 0;
8262 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
8263 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
8264 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
8265 	pkt->pkt_cmd_fhdr.ro = 0;
8266 
8267 	cmd = (menlo_cmd_t *)pkt->pkt_cmd;
8268 	cmd->code = BE_SWAP32(MENLO_CMD_LOOPBACK);
8269 	cmd->lb.context = BE_SWAP32(offset);
8270 	cmd->lb.type = BE_SWAP32(MENLO_LOOPBACK_ENABLE);
8271 
8272 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
8273 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8274 		    "%s: Unable to send packet.",
8275 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8276 
8277 		rval = DFC_IO_ERROR;
8278 		goto done;
8279 	}
8280 
8281 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
8282 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
8283 			EMLXS_MSGF(EMLXS_CONTEXT,
8284 			    &emlxs_dfc_error_msg,
8285 			    "%s: Pkt Transport error. Pkt Timeout.",
8286 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8287 			rval = DFC_TIMEOUT;
8288 		} else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) &&
8289 		    (pkt->pkt_reason == FC_REASON_OVERRUN)) {
8290 			EMLXS_MSGF(EMLXS_CONTEXT,
8291 			    &emlxs_dfc_error_msg,
8292 			    "%s: Pkt Transport error. Rsp overrun.",
8293 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8294 			rval = DFC_RSP_BUF_OVERRUN;
8295 		} else {
8296 			EMLXS_MSGF(EMLXS_CONTEXT,
8297 			    &emlxs_dfc_error_msg,
8298 			    "%s: Pkt Transport error. state=%x",
8299 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
8300 			    pkt->pkt_state);
8301 			rval = DFC_IO_ERROR;
8302 		}
8303 		goto done;
8304 	}
8305 
8306 
8307 	/* CLEAR MENLO maint mode */
8308 	/* Create the set_variable mailbox request */
8309 	emlxs_mb_set_var(hba, mbq, 0x103107, 0);
8310 
8311 	mbq->flag |= MBQ_PASSTHRU;
8312 
8313 	/* issue the mbox cmd to the sli */
8314 	mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
8315 
8316 	if (mbxstatus) {
8317 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8318 		    "%s: %s failed. mbxstatus=0x%x",
8319 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
8320 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
8321 
8322 		rval = DFC_IO_ERROR;
8323 		if (mbxstatus == MBX_TIMEOUT)
8324 			rval = DFC_TIMEOUT;
8325 	}
8326 
8327 	delay(drv_usectohz(1000000));
8328 	i = 0;
8329 	while ((hba->state < FC_LINK_UP) && (hba->state != FC_ERROR)) {
8330 		delay(drv_usectohz(100000));
8331 		i++;
8332 
8333 		if (i == 300) {
8334 			rval = DFC_TIMEOUT;
8335 
8336 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8337 			    "%s: Linkup timeout.",
8338 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8339 
8340 			goto done;
8341 		}
8342 	}
8343 
8344 done:
8345 	/* Free allocated mbox memory */
8346 	if (mbq) {
8347 		kmem_free(mbq, sizeof (MAILBOXQ));
8348 	}
8349 	if (pkt) {
8350 		emlxs_pkt_free(pkt);
8351 	}
8352 	return (rval);
8353 }
8354 
8355 /*ARGSUSED*/
8356 static int32_t
8357 emlxs_dfc_set_menlo_fte(emlxs_hba_t *hba)
8358 {
8359 	emlxs_port_t *port = &PPORT;
8360 	fc_packet_t *pkt = NULL;
8361 	uint32_t rval = 0;
8362 	menlo_cmd_t *cmd;
8363 
8364 
8365 	/* Issue Menlo loopback command */
8366 	if (!(pkt = emlxs_pkt_alloc(port, sizeof (menlo_cmd_t),
8367 	    sizeof (uint32_t), 0, KM_NOSLEEP))) {
8368 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8369 		    "%s: Unable to allocate packet.",
8370 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8371 
8372 		rval = DFC_SYSRES_ERROR;
8373 		goto done;
8374 	}
8375 
8376 	/* Make this a polled IO */
8377 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
8378 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
8379 	pkt->pkt_comp = NULL;
8380 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
8381 	pkt->pkt_timeout = 30;
8382 
8383 	/* Build the fc header */
8384 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(EMLXS_MENLO_DID);
8385 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
8386 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
8387 	pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
8388 	pkt->pkt_cmd_fhdr.f_ctl =
8389 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
8390 	pkt->pkt_cmd_fhdr.seq_id = 0;
8391 	pkt->pkt_cmd_fhdr.df_ctl = 0;
8392 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
8393 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
8394 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
8395 	pkt->pkt_cmd_fhdr.ro = 0;
8396 
8397 	cmd = (menlo_cmd_t *)pkt->pkt_cmd;
8398 	cmd->code = BE_SWAP32(MENLO_CMD_FTE_INSERT);
8399 	cmd->fte_insert.fcid = BE_SWAP32(0);
8400 	bcopy((caddr_t)&port->wwpn, (caddr_t)cmd->fte_insert.wwpn, 8);
8401 
8402 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
8403 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8404 		    "%s: Unable to send packet.",
8405 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8406 
8407 		rval = DFC_IO_ERROR;
8408 		goto done;
8409 	}
8410 
8411 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
8412 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
8413 			EMLXS_MSGF(EMLXS_CONTEXT,
8414 			    &emlxs_dfc_error_msg,
8415 			    "%s: Pkt Transport error. Pkt Timeout.",
8416 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8417 			rval = DFC_TIMEOUT;
8418 		} else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) &&
8419 		    (pkt->pkt_reason == FC_REASON_OVERRUN)) {
8420 			EMLXS_MSGF(EMLXS_CONTEXT,
8421 			    &emlxs_dfc_error_msg,
8422 			    "%s: Pkt Transport error. Rsp overrun.",
8423 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8424 			rval = DFC_RSP_BUF_OVERRUN;
8425 		} else {
8426 			EMLXS_MSGF(EMLXS_CONTEXT,
8427 			    &emlxs_dfc_error_msg,
8428 			    "%s: Pkt Transport error. state=%x",
8429 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
8430 			    pkt->pkt_state);
8431 			rval = DFC_IO_ERROR;
8432 		}
8433 		goto done;
8434 	}
8435 
8436 
8437 done:
8438 	if (pkt) {
8439 		emlxs_pkt_free(pkt);
8440 	}
8441 	return (rval);
8442 }
8443 
8444 /*ARGSUSED*/
8445 static int32_t
8446 emlxs_dfc_reset_menlo(emlxs_hba_t *hba)
8447 {
8448 	emlxs_port_t *port = &PPORT;
8449 	MAILBOXQ *mbq = NULL;
8450 	MAILBOX *mb = NULL;
8451 	uint32_t mbxstatus;
8452 	uint32_t rval = 0;
8453 
8454 	mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
8455 	    KM_SLEEP);
8456 
8457 	mb = (MAILBOX *)mbq;
8458 
8459 	/* RESET MENLO */
8460 	/* Create the set_variable mailbox request */
8461 	emlxs_mb_set_var(hba, mbq, 0x103007, 0);
8462 
8463 	mbq->flag |= MBQ_PASSTHRU;
8464 
8465 	/* issue the mbox cmd to the sli */
8466 	mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
8467 
8468 	if (mbxstatus) {
8469 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8470 		    "%s: %s failed. mbxstatus=0x%x",
8471 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
8472 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
8473 
8474 		rval = DFC_IO_ERROR;
8475 		if (mbxstatus == MBX_TIMEOUT)
8476 			rval = DFC_TIMEOUT;
8477 		goto done;
8478 	}
8479 done:
8480 	/* Free allocated mbox memory */
8481 	if (mbq) {
8482 		kmem_free(mbq, sizeof (MAILBOXQ));
8483 	}
8484 	return (rval);
8485 }
8486 
8487 #endif /* MENLO_SUPPORT */
8488 
8489 /* ARGSUSED */
8490 static int32_t
8491 emlxs_dfc_loopback_mode(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8492 {
8493 	emlxs_port_t	*port = &PPORT;
8494 	emlxs_config_t	*cfg = &CFG;
8495 	MAILBOXQ	*mbq = NULL;
8496 	MAILBOX		*mb = NULL;
8497 	uint32_t	rval = DFC_SUCCESS;
8498 	uint32_t	i;
8499 	uint32_t	timeout;
8500 	uint32_t	topology;
8501 	uint32_t	speed;
8502 	uint32_t	new_mode;
8503 	NODELIST	*ndlp;
8504 	XRIobj_t	*xrip;
8505 
8506 	if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE) {
8507 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8508 		    "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd));
8509 
8510 		return (DFC_NOT_SUPPORTED);
8511 	}
8512 
8513 	/* Reinitialize the link */
8514 	switch (dfc->flag) {
8515 	case 0:	/* Disable */
8516 
8517 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8518 		    "%s: Disabling Loopback.", emlxs_dfc_xlate(dfc->cmd));
8519 
8520 		if (!(hba->flag & FC_LOOPBACK_MODE)) {
8521 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8522 			    "%s: Loopback already disabled.",
8523 			    emlxs_dfc_xlate(dfc->cmd));
8524 
8525 			return (rval);
8526 		}
8527 		goto resetdone;
8528 
8529 	case 1:	/* Internal loopback */
8530 		new_mode = FC_ILB_MODE;
8531 		topology = FLAGS_LOCAL_LB;
8532 		speed = 0;
8533 
8534 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8535 		    "%s: Enabling ILB.", emlxs_dfc_xlate(dfc->cmd));
8536 
8537 		/* Check if mode already set */
8538 		if ((hba->flag & FC_ILB_MODE)) {
8539 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8540 			    "%s: ILB mode already enabled.",
8541 			    emlxs_dfc_xlate(dfc->cmd));
8542 
8543 			return (rval);
8544 		}
8545 
8546 		break;
8547 
8548 	case 2:	/* External loopback */
8549 		new_mode = FC_ELB_MODE;
8550 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
8551 			topology = FLAGS_TOPOLOGY_MODE_LOOP_PT;
8552 		} else {
8553 			topology = FLAGS_TOPOLOGY_MODE_LOOP;
8554 		}
8555 		speed = cfg[CFG_LINK_SPEED].current;
8556 
8557 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8558 		    "%s: Enabling ELB.", emlxs_dfc_xlate(dfc->cmd));
8559 
8560 		/* Check if mode already set */
8561 		if ((hba->flag & FC_ELB_MODE)) {
8562 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8563 			    "%s: ELB mode already enabled.",
8564 			    emlxs_dfc_xlate(dfc->cmd));
8565 
8566 			return (rval);
8567 		}
8568 
8569 		break;
8570 
8571 	default:
8572 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8573 		    "%s: Invalid loopback mode. (mode=%x)",
8574 		    emlxs_dfc_xlate(dfc->cmd), dfc->flag);
8575 
8576 		return (DFC_ARG_INVALID);
8577 	}
8578 
8579 	/* Make sure adapter is online */
8580 	if (emlxs_online(hba)) {
8581 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8582 		    "%s: Unable to bring adapter online.",
8583 		    emlxs_dfc_xlate(dfc->cmd));
8584 
8585 		return (DFC_OFFLINE_ERROR);
8586 	}
8587 
8588 #ifdef MENLO_SUPPORT
8589 	if (hba->model_info.device_id == PCI_DEVICE_ID_HORNET) {
8590 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8591 		    "%s: Menlo support detected: mode:x%x",
8592 		    emlxs_dfc_xlate(dfc->cmd), new_mode);
8593 
8594 		if (new_mode == FC_ILB_MODE) {
8595 			rval = emlxs_dfc_set_menlo_loopback(hba);
8596 			if (rval)
8597 				goto done;
8598 		}
8599 	}
8600 #endif /* MENLO_SUPPORT */
8601 
8602 	mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
8603 	    KM_SLEEP);
8604 
8605 	mb = (MAILBOX *) mbq;
8606 
8607 	/* Take the link down */
8608 	emlxs_mb_down_link(hba, mbq);
8609 
8610 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
8611 
8612 	if (rval == MBX_TIMEOUT) {
8613 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8614 		    "%s: Mailbox timed out. cmd=%x",
8615 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
8616 
8617 		rval = DFC_TIMEOUT;
8618 		goto done;
8619 	}
8620 
8621 	if (rval) {
8622 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8623 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
8624 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
8625 
8626 		rval = DFC_IO_ERROR;
8627 		goto done;
8628 	}
8629 
8630 	/*
8631 	 * Need *2 since we wait 1/2 sec in while loop.
8632 	 */
8633 	timeout = dfc->data1;
8634 	if (!timeout) {
8635 		timeout = 60 * 2;
8636 	} else {
8637 		timeout = timeout * 2;
8638 	}
8639 
8640 	i = 0;
8641 	while ((hba->state >= FC_LINK_UP) && (hba->state != FC_ERROR)) {
8642 		delay(drv_usectohz(500000));
8643 		i++;
8644 
8645 		if (i == timeout) {
8646 			rval = DFC_TIMEOUT;
8647 
8648 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8649 			    "%s: Linkdown timeout.", emlxs_dfc_xlate(dfc->cmd));
8650 
8651 			goto done;
8652 		}
8653 	}
8654 
8655 	/* Reinitialize the link */
8656 	emlxs_mb_init_link(hba, mbq, topology, speed);
8657 
8658 	/* Set the loopback mode and timer */
8659 	mutex_enter(&EMLXS_PORT_LOCK);
8660 	hba->flag |= new_mode;
8661 	hba->loopback_tics = hba->timer_tics + emlxs_loopback_tmo;
8662 	mutex_exit(&EMLXS_PORT_LOCK);
8663 
8664 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
8665 
8666 	if (rval == MBX_TIMEOUT) {
8667 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8668 		    "%s: Mailbox timed out. cmd=%x",
8669 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
8670 
8671 		rval = DFC_TIMEOUT;
8672 		goto done;
8673 	}
8674 
8675 	if (rval) {
8676 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8677 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
8678 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
8679 
8680 		rval = DFC_IO_ERROR;
8681 		goto done;
8682 	}
8683 
8684 	i = 0;
8685 	while ((hba->state < FC_LINK_UP) && (hba->state != FC_ERROR)) {
8686 		delay(drv_usectohz(500000));
8687 		i++;
8688 
8689 		if (i == timeout) {
8690 			rval = DFC_TIMEOUT;
8691 
8692 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8693 			    "%s: Linkup timeout.", emlxs_dfc_xlate(dfc->cmd));
8694 
8695 			goto done;
8696 		}
8697 	}
8698 
8699 	/* Create host node */
8700 	if (EMLXS_SLI_REG_DID(port, port->did, (SERV_PARM *)&hba->sparam,
8701 	    NULL, NULL, NULL)) {
8702 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8703 		    "%s: Unable to register host node.",
8704 		    emlxs_dfc_xlate(dfc->cmd));
8705 
8706 		rval = DFC_DRV_ERROR;
8707 		goto done;
8708 	}
8709 
8710 	i = 0;
8711 	do {
8712 		if (i++ > 300) {
8713 			break;
8714 		}
8715 
8716 		delay(drv_usectohz(100000));
8717 
8718 	} while (!(ndlp = emlxs_node_find_did(port, port->did, 1)));
8719 
8720 	if (!ndlp) {
8721 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8722 		    "%s: Unable to create host node.",
8723 		    emlxs_dfc_xlate(dfc->cmd));
8724 
8725 		rval = DFC_DRV_ERROR;
8726 		goto done;
8727 	}
8728 
8729 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8730 	    "%s: Node created. node=%p", emlxs_dfc_xlate(dfc->cmd), ndlp);
8731 
8732 #ifdef MENLO_SUPPORT
8733 	if (hba->model_info.device_id == PCI_DEVICE_ID_HORNET) {
8734 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8735 		    "%s: Menlo support detected: mode:x%x",
8736 		    emlxs_dfc_xlate(dfc->cmd), new_mode);
8737 
8738 		rval = emlxs_dfc_set_menlo_fte(hba);
8739 		if (rval)
8740 			goto done;
8741 	}
8742 #endif /* MENLO_SUPPORT */
8743 
8744 	if (hba->sli_mode < EMLXS_HBA_SLI4_MODE) {
8745 		/* Create host XRI */
8746 		(void) emlxs_create_xri(port, &hba->chan[hba->channel_ct],
8747 		    ndlp);
8748 
8749 		i = 0;
8750 		do {
8751 			if (i++ > 300) {
8752 				break;
8753 			}
8754 
8755 			delay(drv_usectohz(100000));
8756 
8757 		} while (!ndlp->nlp_Xri);
8758 
8759 		if (!ndlp->nlp_Xri) {
8760 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8761 			    "%s: Unable to create XRI.",
8762 			    emlxs_dfc_xlate(dfc->cmd));
8763 
8764 			rval = DFC_DRV_ERROR;
8765 			goto done;
8766 		}
8767 
8768 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8769 		    "%s: XRI created. xri=%d", emlxs_dfc_xlate(dfc->cmd),
8770 		    ndlp->nlp_Xri);
8771 	} else {
8772 		xrip = emlxs_sli4_reserve_xri(port,
8773 		    EMLXS_NODE_TO_RPI(port, ndlp),
8774 		    EMLXS_XRI_SOL_CT_TYPE, 0xffff);
8775 
8776 		if (xrip == NULL) {
8777 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8778 			    "%s: Unable to reserve XRI.",
8779 			    emlxs_dfc_xlate(dfc->cmd));
8780 
8781 			rval = DFC_DRV_ERROR;
8782 			goto done;
8783 		}
8784 
8785 		ndlp->nlp_Xri = xrip->XRI;
8786 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8787 		    "%s: XRI reserved. xri=%d", emlxs_dfc_xlate(dfc->cmd),
8788 		    ndlp->nlp_Xri);
8789 	}
8790 
8791 done:
8792 	/* Free allocated mbox memory */
8793 	if (mbq) {
8794 		kmem_free(mbq, sizeof (MAILBOXQ));
8795 	}
8796 
8797 	if (rval) {
8798 resetdone:
8799 		/* Reset the adapter */
8800 #ifdef MENLO_SUPPORT
8801 		if (hba->model_info.device_id == PCI_DEVICE_ID_HORNET) {
8802 
8803 			rval = emlxs_dfc_reset_menlo(hba);
8804 
8805 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8806 			    "%s: Menlo reset: rval:x%x",
8807 			    emlxs_dfc_xlate(dfc->cmd), rval);
8808 	}
8809 #endif /* MENLO_SUPPORT */
8810 
8811 		/* Reset link whether we are bound to ULP or not */
8812 		(void) emlxs_reset_link(hba, 1, 1);
8813 	}
8814 
8815 	return (rval);
8816 } /* emlxs_dfc_loopback_mode() */
8817 
8818 
8819 /*ARGSUSED*/
8820 static int32_t
8821 emlxs_dfc_loopback_test(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8822 {
8823 	emlxs_port_t	*port = &PPORT;
8824 	int32_t		rval = 0;
8825 	NODELIST	*ndlp;
8826 	clock_t		timeout;
8827 	fc_packet_t	*pkt = NULL;
8828 	SLI_CT_REQUEST	*CtCmd;
8829 	uint16_t	CtRsp;
8830 
8831 	if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE) {
8832 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8833 		    "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd));
8834 
8835 		return (DFC_NOT_SUPPORTED);
8836 	}
8837 
8838 	mutex_enter(&EMLXS_PORT_LOCK);
8839 	if (!(hba->flag & FC_LOOPBACK_MODE)) {
8840 		mutex_exit(&EMLXS_PORT_LOCK);
8841 
8842 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8843 		    "%s: Adapter not in loopback mode.",
8844 		    emlxs_dfc_xlate(dfc->cmd));
8845 
8846 		rval = DFC_DRV_ERROR;
8847 		goto done;
8848 	}
8849 	hba->loopback_tics = hba->timer_tics + emlxs_loopback_tmo;
8850 	mutex_exit(&EMLXS_PORT_LOCK);
8851 
8852 	if (!(hba->flag & FC_ONLINE_MODE)) {
8853 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8854 		    "%s: Adapter offline.", emlxs_dfc_xlate(dfc->cmd));
8855 
8856 		rval = DFC_OFFLINE_ERROR;
8857 		goto done;
8858 	}
8859 
8860 	if (hba->state < FC_LINK_UP) {
8861 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8862 		    "%s: Link not up.", emlxs_dfc_xlate(dfc->cmd));
8863 
8864 		rval = DFC_OFFLINE_ERROR;
8865 		goto done;
8866 	}
8867 
8868 	if (!dfc->buf1 || !dfc->buf1_size) {
8869 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8870 		    "%s: NULL buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
8871 
8872 		rval = DFC_ARG_NULL;
8873 		goto done;
8874 	}
8875 
8876 	if (!dfc->buf2 || !dfc->buf2_size) {
8877 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8878 		    "%s: NULL buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
8879 
8880 		rval = DFC_ARG_NULL;
8881 		goto done;
8882 	}
8883 
8884 	if (dfc->buf1_size > MAX_CT_PAYLOAD) {
8885 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8886 		    "%s: Buffer1 too large. (size=%d)",
8887 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
8888 
8889 		rval = DFC_ARG_TOOBIG;
8890 		goto done;
8891 	}
8892 
8893 	/* Check if we have a node for ourselves */
8894 	ndlp = emlxs_node_find_did(port, port->did, 1);
8895 
8896 	if (!ndlp) {
8897 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8898 		    "%s: Host node not found.", emlxs_dfc_xlate(dfc->cmd));
8899 
8900 		rval = DFC_ARG_INVALID;
8901 		goto done;
8902 	}
8903 
8904 	if (!ndlp->nlp_Xri) {
8905 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8906 		    "%s: Host XRI not found.", emlxs_dfc_xlate(dfc->cmd));
8907 
8908 		rval = DFC_DRV_ERROR;
8909 		goto done;
8910 	}
8911 
8912 	pkt = emlxs_pkt_alloc(port, dfc->buf1_size + 16,
8913 	    dfc->buf2_size + 16, 0, KM_SLEEP);
8914 
8915 	if (pkt == NULL) {
8916 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8917 		    "%s: Unable to allocate pkt.", emlxs_dfc_xlate(dfc->cmd));
8918 		rval = DFC_SYSRES_ERROR;
8919 		goto done;
8920 	}
8921 
8922 	CtCmd = (SLI_CT_REQUEST*)pkt->pkt_cmd;
8923 	CtRsp = SLI_CT_LOOPBACK;
8924 	CtCmd->CommandResponse.bits.CmdRsp = LE_SWAP16(CtRsp);
8925 
8926 	bcopy((void *)dfc->buf1, (void *)&CtCmd->un.data, dfc->buf1_size);
8927 
8928 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
8929 	pkt->pkt_timeout = 2 * hba->fc_ratov;
8930 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
8931 	pkt->pkt_comp = NULL;
8932 
8933 	pkt->pkt_cmd_fhdr.d_id = port->did;
8934 	pkt->pkt_cmd_fhdr.r_ctl = FC_SOL_CTL;
8935 	pkt->pkt_cmd_fhdr.s_id = port->did;
8936 	pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
8937 	pkt->pkt_cmd_fhdr.f_ctl = 0;
8938 	pkt->pkt_cmd_fhdr.seq_id = 0;
8939 	pkt->pkt_cmd_fhdr.df_ctl = 0;
8940 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
8941 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
8942 	pkt->pkt_cmd_fhdr.rx_id = ndlp->nlp_Xri;
8943 	pkt->pkt_cmd_fhdr.ro = 0;
8944 
8945 	mutex_enter(&EMLXS_PKT_LOCK);
8946 	timeout = emlxs_timeout(hba, (pkt->pkt_timeout + 15));
8947 
8948 	if (hba->loopback_pkt) {
8949 		rval = 0;
8950 		while ((rval != -1) && hba->loopback_pkt) {
8951 			rval =
8952 			    cv_timedwait(&EMLXS_PKT_CV, &EMLXS_PKT_LOCK,
8953 			    timeout);
8954 		}
8955 
8956 		if (rval == -1) {
8957 			mutex_exit(&EMLXS_PKT_LOCK);
8958 
8959 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8960 			    "Loopback busy timeout.");
8961 			rval = DFC_TIMEOUT;
8962 			goto done;
8963 		}
8964 	}
8965 	hba->loopback_pkt = (void *) pkt;
8966 	mutex_exit(&EMLXS_PKT_LOCK);
8967 
8968 	/* Send polled command */
8969 	if ((rval = emlxs_pkt_send(pkt, 1)) != FC_SUCCESS) {
8970 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8971 		    "Pkt Transport error. ret=%x state=%x", rval,
8972 		    pkt->pkt_state);
8973 
8974 		rval = DFC_IO_ERROR;
8975 		goto done;
8976 	}
8977 
8978 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
8979 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
8980 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8981 			    "Pkt Transport error. Pkt Timeout.");
8982 			rval = DFC_TIMEOUT;
8983 		} else {
8984 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8985 			    "Pkt Transport error. state=%x", pkt->pkt_state);
8986 			rval = DFC_IO_ERROR;
8987 		}
8988 		goto done;
8989 	}
8990 
8991 	/* Wait for sequence completion */
8992 	mutex_enter(&EMLXS_PKT_LOCK);
8993 	rval = 0;
8994 	while ((rval != -1) && !(pkt->pkt_tran_flags & FC_TRAN_COMPLETED)) {
8995 		rval = cv_timedwait(&EMLXS_PKT_CV, &EMLXS_PKT_LOCK, timeout);
8996 	}
8997 	mutex_exit(&EMLXS_PKT_LOCK);
8998 
8999 	if (rval == -1) {
9000 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9001 		    "Loopback sequence timeout.");
9002 
9003 		rval = DFC_TIMEOUT;
9004 		goto done;
9005 	}
9006 
9007 	CtCmd = (SLI_CT_REQUEST*)pkt->pkt_resp;
9008 	bcopy((void *)&CtCmd->un.data, (void *)dfc->buf2, dfc->buf2_size);
9009 
9010 	rval = 0;
9011 
9012 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: Test completed.",
9013 	    emlxs_dfc_xlate(dfc->cmd));
9014 
9015 done:
9016 
9017 	if (rval) {
9018 		mutex_enter(&EMLXS_PKT_LOCK);
9019 		if (pkt && (hba->loopback_pkt == pkt)) {
9020 			hba->loopback_pkt = NULL;
9021 		}
9022 		mutex_exit(&EMLXS_PKT_LOCK);
9023 
9024 		/* Reset the adapter */
9025 		(void) emlxs_reset(port, FC_FCA_LINK_RESET);
9026 	}
9027 
9028 	if (pkt) {
9029 		emlxs_pkt_free(pkt);
9030 	}
9031 
9032 	return (rval);
9033 
9034 } /* emlxs_dfc_loopback_test() */
9035 
9036 
9037 /*ARGSUSED*/
9038 static int32_t
9039 emlxs_dfc_reset_port(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9040 {
9041 	emlxs_port_t	*port = &PPORT;
9042 	int32_t		rval = 0;
9043 
9044 	switch (dfc->flag) {
9045 	case 1:
9046 	case 2:
9047 		rval = emlxs_reset(port, FC_FCA_RESET);
9048 		break;
9049 	case 3:
9050 		if ((hba->sli_mode < EMLXS_HBA_SLI4_MODE) ||
9051 		    ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) &&
9052 		    (hba->model_info.chip & EMLXS_BE_CHIPS))) {
9053 			rval = emlxs_reset(port, FC_FCA_RESET);
9054 		} else {
9055 			/* Perform All Firmware Reset */
9056 			rval = emlxs_reset(port, EMLXS_DFC_RESET_ALL);
9057 		}
9058 
9059 		break;
9060 
9061 	default:
9062 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9063 		    "%s: Invalid reset type. (mode=%x)",
9064 		    emlxs_dfc_xlate(dfc->cmd), dfc->flag);
9065 
9066 		return (DFC_ARG_INVALID);
9067 	}
9068 
9069 	if (rval) {
9070 		rval = DFC_HBA_ERROR;
9071 	}
9072 	return (rval);
9073 
9074 } /* emlxs_dfc_reset_port() */
9075 
9076 
9077 extern int32_t
9078 emlxs_dfc_handle_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
9079 {
9080 	emlxs_port_t	*port = &PPORT;
9081 	IOCB		*cmd;
9082 	emlxs_buf_t	*sbp;
9083 
9084 	cmd = &iocbq->iocb;
9085 
9086 	HBASTATS.CtEvent++;
9087 
9088 	sbp = (emlxs_buf_t *)iocbq->sbp;
9089 
9090 	if (!sbp) {
9091 		HBASTATS.CtStray++;
9092 
9093 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9094 		    "Stray interrupt. cmd=0x%x iotag=0x%x status=0x%x "
9095 		    "perr=0x%x", (uint32_t)cmd->ULPCOMMAND,
9096 		    (uint32_t)cmd->ULPIOTAG, cmd->ULPSTATUS,
9097 		    cmd->un.ulpWord[4]);
9098 
9099 		return (DFC_ARG_INVALID);
9100 	}
9101 
9102 	if (cp->channelno != hba->channel_ct) {
9103 		HBASTATS.CtStray++;
9104 
9105 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9106 		    "CT Event: Invalid IO Channel:%d iocbq=%p", cp->channelno,
9107 		    iocbq);
9108 
9109 		return (DFC_ARG_INVALID);
9110 	}
9111 
9112 	switch (cmd->ULPCOMMAND) {
9113 	case CMD_XMIT_SEQUENCE_CR:
9114 	case CMD_XMIT_SEQUENCE64_CR:
9115 	case CMD_XMIT_SEQUENCE_CX:
9116 	case CMD_XMIT_SEQUENCE64_CX:
9117 
9118 		HBASTATS.CtCmdCompleted++;
9119 
9120 		if (cmd->ULPSTATUS == 0) {
9121 			HBASTATS.CtCmdGood++;
9122 
9123 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
9124 			    "XMIT_SEQUENCE comp: status=0x%x",
9125 			    cmd->ULPSTATUS);
9126 		} else {
9127 			HBASTATS.CtCmdError++;
9128 
9129 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9130 			    "XMIT_SEQUENCE comp: status=0x%x [%08x,%08x]",
9131 			    cmd->ULPSTATUS, cmd->un.ulpWord[4],
9132 			    cmd->un.ulpWord[5]);
9133 		}
9134 
9135 		emlxs_pkt_complete(sbp, cmd->ULPSTATUS,
9136 		    cmd->un.grsp.perr.statLocalError, 1);
9137 
9138 		break;
9139 
9140 	default:
9141 
9142 		HBASTATS.CtStray++;
9143 
9144 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9145 		    "Invalid iocb: cmd=0x%x", cmd->ULPCOMMAND);
9146 
9147 		emlxs_pkt_complete(sbp, cmd->ULPSTATUS,
9148 		    cmd->un.grsp.perr.statLocalError, 1);
9149 
9150 		break;
9151 
9152 	}	/* switch(cmd->ULPCOMMAND) */
9153 
9154 	return (0);
9155 
9156 } /* emlxs_dfc_handle_event() */
9157 
9158 
9159 /* ARGSUSED */
9160 extern int
9161 emlxs_dfc_handle_unsol_req(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
9162     MATCHMAP *mp, uint32_t size)
9163 {
9164 	emlxs_hba_t	*hba = HBA;
9165 	IOCB		*iocb;
9166 	uint8_t		*bp;
9167 	fc_packet_t	*pkt;
9168 
9169 	iocb = &iocbq->iocb;
9170 	bp = (uint8_t *)mp->virt;
9171 
9172 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
9173 	    "CT Receive: cmd=%x status=0x%x ",
9174 	    iocb->ULPCOMMAND, iocb->ULPSTATUS);
9175 
9176 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
9177 		/*
9178 		 * No response sent on loopback; free the exchange now
9179 		 */
9180 		emlxs_abort_ct_exchange(hba, port, iocb->ULPCONTEXT);
9181 	}
9182 
9183 	/*
9184 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
9185 	 * "CT Receive: payload=%p size=%d [%02x,%02x, %02x, %02x]", bp,
9186 	 * size, bp[0], bp[1], bp[2],bp[3]);
9187 	 */
9188 
9189 	/* Return payload */
9190 	mutex_enter(&EMLXS_PKT_LOCK);
9191 	if (hba->loopback_pkt) {
9192 		pkt = (fc_packet_t *)hba->loopback_pkt;
9193 		hba->loopback_pkt = NULL;
9194 
9195 		size = MIN(size, pkt->pkt_rsplen);
9196 		bcopy(bp, pkt->pkt_resp, size);
9197 		pkt->pkt_tran_flags |= FC_TRAN_COMPLETED;
9198 
9199 		cv_broadcast(&EMLXS_PKT_CV);
9200 	}
9201 	mutex_exit(&EMLXS_PKT_LOCK);
9202 
9203 	return (0);
9204 
9205 } /* emlxs_dfc_handle_unsol_req() */
9206 
9207 
9208 #ifdef DHCHAP_SUPPORT
9209 
9210 /*ARGSUSED*/
9211 static int32_t
9212 emlxs_dfc_init_auth(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9213 {
9214 	emlxs_port_t	*port = &PPORT;
9215 	uint8_t		*lwwpn;
9216 	uint8_t		*rwwpn;
9217 	int32_t		rval = 0;
9218 
9219 	if (!dfc->buf1 || !dfc->buf1_size) {
9220 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9221 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
9222 
9223 		return (DFC_ARG_NULL);
9224 	}
9225 
9226 	if (dfc->buf1_size < 8) {
9227 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9228 		    "%s: Buffer1 too small. (size=%d)",
9229 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9230 
9231 		return (DFC_ARG_TOOSMALL);
9232 	}
9233 
9234 	if (!dfc->buf2 || !dfc->buf2_size) {
9235 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9236 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
9237 
9238 		return (DFC_ARG_NULL);
9239 	}
9240 
9241 	if (dfc->buf2_size < 8) {
9242 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9243 		    "%s: Buffer2 too small. (size=%d)",
9244 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9245 
9246 		return (DFC_ARG_TOOSMALL);
9247 	}
9248 
9249 	lwwpn = (uint8_t *)dfc->buf1;
9250 	rwwpn = (uint8_t *)dfc->buf2;
9251 
9252 	/* Initiate authentication here */
9253 	rval = emlxs_dhc_init_auth(hba, lwwpn, rwwpn);
9254 
9255 	return (rval);
9256 
9257 } /* emlxs_dfc_init_auth() */
9258 
9259 
9260 /*ARGSUSED*/
9261 static int32_t
9262 emlxs_dfc_get_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9263 {
9264 	emlxs_port_t		*port = &PPORT;
9265 	dfc_fcsp_config_t	*fcsp_config;
9266 	uint32_t		rval = DFC_SUCCESS;
9267 
9268 	if (!dfc->buf1 || !dfc->buf1_size) {
9269 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9270 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
9271 
9272 		return (DFC_ARG_NULL);
9273 	}
9274 
9275 	if (dfc->buf1_size < sizeof (dfc_fcsp_config_t)) {
9276 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9277 		    "%s: Buffer1 too small. (size=%d)",
9278 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9279 
9280 		return (DFC_ARG_TOOSMALL);
9281 	}
9282 
9283 	fcsp_config = (dfc_fcsp_config_t *)dfc->buf1;
9284 
9285 	if ((rval = emlxs_dhc_get_auth_cfg(hba, fcsp_config)) != 0) {
9286 		return (rval);
9287 	}
9288 
9289 	return (0);
9290 
9291 } /* emlxs_dfc_get_auth_cfg() */
9292 
9293 
9294 
9295 /*ARGSUSED*/
9296 static int32_t
9297 emlxs_dfc_set_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9298 {
9299 	emlxs_port_t		*port = &PPORT;
9300 	dfc_fcsp_config_t	*fcsp_config;
9301 	dfc_password_t		*dfc_pwd;
9302 	uint32_t		rval = DFC_SUCCESS;
9303 
9304 	if (!dfc->buf1 || !dfc->buf1_size) {
9305 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9306 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
9307 
9308 		return (DFC_ARG_NULL);
9309 	}
9310 
9311 	if (dfc->buf1_size < sizeof (dfc_fcsp_config_t)) {
9312 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9313 		    "%s: Buffer1 too small. (size=%d)",
9314 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9315 
9316 		return (DFC_ARG_TOOSMALL);
9317 	}
9318 
9319 	if (!dfc->buf2 || !dfc->buf2_size) {
9320 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9321 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
9322 
9323 		return (DFC_ARG_NULL);
9324 	}
9325 
9326 	if (dfc->buf2_size < sizeof (dfc_password_t)) {
9327 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9328 		    "%s: Buffer2 too small. (size=%d)",
9329 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9330 
9331 		return (DFC_ARG_TOOSMALL);
9332 	}
9333 
9334 	fcsp_config = (dfc_fcsp_config_t *)dfc->buf1;
9335 	dfc_pwd = (dfc_password_t *)dfc->buf2;
9336 
9337 	switch (dfc->flag) {
9338 	case EMLXS_AUTH_CFG_ADD:
9339 		rval = emlxs_dhc_add_auth_cfg(hba, fcsp_config, dfc_pwd);
9340 		break;
9341 
9342 	case EMLXS_AUTH_CFG_DELETE:
9343 		rval = emlxs_dhc_delete_auth_cfg(hba, fcsp_config, dfc_pwd);
9344 		break;
9345 	}
9346 
9347 	if (rval) {
9348 		return (rval);
9349 	}
9350 
9351 	return (0);
9352 
9353 } /* emlxs_dfc_set_auth_cfg() */
9354 
9355 
9356 
9357 /*ARGSUSED*/
9358 static int32_t
9359 emlxs_dfc_get_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9360 {
9361 	emlxs_port_t		*port = &PPORT;
9362 	dfc_auth_password_t	*dfc_pwd;
9363 	uint32_t		rval = DFC_SUCCESS;
9364 
9365 	if (!dfc->buf1 || !dfc->buf1_size) {
9366 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9367 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
9368 
9369 		return (DFC_ARG_NULL);
9370 	}
9371 
9372 	if (dfc->buf1_size < sizeof (dfc_auth_password_t)) {
9373 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9374 		    "%s: Buffer1 too small. (size=%d)",
9375 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9376 
9377 		return (DFC_ARG_TOOSMALL);
9378 	}
9379 
9380 	/* Read the auth password */
9381 	dfc_pwd = (dfc_auth_password_t *)dfc->buf1;
9382 
9383 	if ((rval = emlxs_dhc_get_auth_key(hba, dfc_pwd)) != 0) {
9384 		return (rval);
9385 	}
9386 
9387 	return (0);
9388 
9389 } /* emlxs_dfc_get_auth_pwd() */
9390 
9391 
9392 /*ARGSUSED*/
9393 static int32_t
9394 emlxs_dfc_set_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9395 {
9396 	emlxs_port_t		*port = &PPORT;
9397 	dfc_auth_password_t	*dfc_pwd;
9398 	uint32_t		rval = DFC_SUCCESS;
9399 
9400 	if (!dfc->buf1 || !dfc->buf1_size) {
9401 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9402 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
9403 
9404 		return (DFC_ARG_NULL);
9405 	}
9406 
9407 	if (dfc->buf1_size < sizeof (dfc_auth_password_t)) {
9408 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9409 		    "%s: Buffer1 too small. (size=%d)",
9410 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9411 
9412 		return (DFC_ARG_TOOSMALL);
9413 	}
9414 
9415 	dfc_pwd = (dfc_auth_password_t *)dfc->buf1;
9416 
9417 	if ((rval = emlxs_dhc_set_auth_key(hba, dfc_pwd))) {
9418 		return (rval);
9419 	}
9420 
9421 	return (0);
9422 
9423 } /* emlxs_dfc_set_auth_pwd() */
9424 
9425 
9426 /*ARGSUSED*/
9427 static int32_t
9428 emlxs_dfc_get_auth_status(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9429 {
9430 	emlxs_port_t		*port = &PPORT;
9431 	dfc_auth_status_t	*fcsp_status;
9432 	uint32_t		rval = DFC_SUCCESS;
9433 
9434 	if (!dfc->buf1 || !dfc->buf1_size) {
9435 		EMLXS_MSGF(EMLXS_CONTEXT,
9436 		    &emlxs_dfc_error_msg, "%s: Null buffer1 found.",
9437 		    emlxs_dfc_xlate(dfc->cmd));
9438 
9439 		return (DFC_ARG_NULL);
9440 	}
9441 
9442 	if (dfc->buf1_size < sizeof (dfc_auth_status_t)) {
9443 		EMLXS_MSGF(EMLXS_CONTEXT,
9444 		    &emlxs_dfc_error_msg, "%s: Buffer too small. (size=%d)",
9445 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9446 
9447 		return (DFC_ARG_TOOSMALL);
9448 	}
9449 
9450 	fcsp_status = (dfc_auth_status_t *)dfc->buf1;
9451 
9452 	if ((rval = emlxs_dhc_get_auth_status(hba, fcsp_status)) != 0) {
9453 		return (rval);
9454 	}
9455 
9456 	return (0);
9457 
9458 } /* emlxs_dfc_get_auth_status() */
9459 
9460 
9461 /*ARGSUSED*/
9462 static int32_t
9463 emlxs_dfc_get_auth_cfg_table(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9464 {
9465 	emlxs_port_t		*port = &PPORT;
9466 	uint32_t		count;
9467 	uint32_t		rval = DFC_SUCCESS;
9468 
9469 	/* Lock cfg table while we do this */
9470 	/* This prevents the table from changing while we get a copy */
9471 	mutex_enter(&hba->auth_lock);
9472 
9473 	if (!dfc->buf2 || !dfc->buf2_size) {
9474 		EMLXS_MSGF(EMLXS_CONTEXT,
9475 		    &emlxs_dfc_error_msg, "%s: Null buffer2 found.",
9476 		    emlxs_dfc_xlate(dfc->cmd));
9477 
9478 		mutex_exit(&hba->auth_lock);
9479 		return (DFC_ARG_NULL);
9480 	}
9481 
9482 	if (dfc->buf2_size < sizeof (uint32_t)) {
9483 		EMLXS_MSGF(EMLXS_CONTEXT,
9484 		    &emlxs_dfc_error_msg, "%s: Buffer2 too small. (size=%d)",
9485 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
9486 
9487 		mutex_exit(&hba->auth_lock);
9488 		return (DFC_ARG_TOOSMALL);
9489 	}
9490 
9491 	bcopy((void *)&hba->auth_cfg_count, (void *)dfc->buf2,
9492 	    sizeof (uint32_t));
9493 
9494 	if (!dfc->buf1 || !dfc->buf1_size) {
9495 		mutex_exit(&hba->auth_lock);
9496 		return (DFC_SUCCESS);
9497 	}
9498 
9499 	/* Check table size */
9500 	count = dfc->buf1_size / sizeof (dfc_fcsp_config_t);
9501 	if (count < hba->auth_cfg_count) {
9502 		EMLXS_MSGF(EMLXS_CONTEXT,
9503 		    &emlxs_dfc_error_msg, "%s: Buffer1 too small. (%d < %d)",
9504 		    emlxs_dfc_xlate(dfc->cmd), count, hba->auth_cfg_count);
9505 
9506 		mutex_exit(&hba->auth_lock);
9507 		return (DFC_ARG_TOOSMALL);
9508 	}
9509 
9510 	rval = emlxs_dhc_get_auth_cfg_table(hba,
9511 	    (dfc_fcsp_config_t *)dfc->buf1);
9512 	mutex_exit(&hba->auth_lock);
9513 	return (rval);
9514 
9515 } /* emlxs_dfc_get_auth_cfg_table() */
9516 
9517 
9518 /*ARGSUSED*/
9519 static int32_t
9520 emlxs_dfc_get_auth_key_table(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9521 {
9522 	emlxs_port_t		*port = &PPORT;
9523 	uint32_t		count;
9524 	uint32_t		rval = DFC_SUCCESS;
9525 
9526 	/* Lock cfg table while we do this */
9527 	/* This prevents the table from changing while we get a copy */
9528 	mutex_enter(&hba->auth_lock);
9529 
9530 	if (!dfc->buf2 || !dfc->buf2_size) {
9531 		EMLXS_MSGF(EMLXS_CONTEXT,
9532 		    &emlxs_dfc_error_msg, "%s: Null buffer2 found.",
9533 		    emlxs_dfc_xlate(dfc->cmd));
9534 
9535 		mutex_exit(&hba->auth_lock);
9536 		return (DFC_ARG_NULL);
9537 	}
9538 
9539 	if (dfc->buf2_size < sizeof (uint32_t)) {
9540 		EMLXS_MSGF(EMLXS_CONTEXT,
9541 		    &emlxs_dfc_error_msg, "%s: Buffer2 too small. (size=%d)",
9542 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
9543 
9544 		mutex_exit(&hba->auth_lock);
9545 		return (DFC_ARG_TOOSMALL);
9546 	}
9547 
9548 	bcopy((void *)&hba->auth_key_count, (void *)dfc->buf2,
9549 	    sizeof (uint32_t));
9550 
9551 	if (!dfc->buf1 || !dfc->buf1_size) {
9552 		mutex_exit(&hba->auth_lock);
9553 		return (DFC_SUCCESS);
9554 	}
9555 
9556 	/* Check table size */
9557 	count = dfc->buf1_size / sizeof (dfc_auth_password_t);
9558 	if (count < hba->auth_key_count) {
9559 		EMLXS_MSGF(EMLXS_CONTEXT,
9560 		    &emlxs_dfc_error_msg, "%s: Buffer1 too small. (%d < %d)",
9561 		    emlxs_dfc_xlate(dfc->cmd), count, hba->auth_key_count);
9562 
9563 		mutex_exit(&hba->auth_lock);
9564 		return (DFC_ARG_TOOSMALL);
9565 	}
9566 
9567 	rval = emlxs_dhc_get_auth_key_table(hba,
9568 	    (dfc_auth_password_t *)dfc->buf1);
9569 	mutex_exit(&hba->auth_lock);
9570 	return (rval);
9571 
9572 } /* emlxs_dfc_get_auth_key_table() */
9573 
9574 
9575 
9576 #endif	/* DHCHAP_SUPPORT */
9577 
9578 #ifdef SAN_DIAG_SUPPORT
9579 /*ARGSUSED*/
9580 static int32_t
9581 emlxs_dfc_sd_set_bucket(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9582 {
9583 	uint32_t	type, search_type;
9584 	uint16_t	state;
9585 	int32_t		rval = DFC_SD_OK;
9586 
9587 	type = dfc->data1;
9588 	search_type = dfc->data2;
9589 
9590 	mutex_enter(&emlxs_sd_bucket_mutex);
9591 	state = emlxs_sd_bucket.state;
9592 
9593 	if (state == SD_COLLECTING)
9594 		rval = DFC_SD_ERROR_DATA_COLLECTION_ACTIVE;
9595 	else if ((search_type < SD_SEARCH_LINEAR) ||
9596 	    (search_type > SD_SEARCH_POWER_2))
9597 		rval = DFC_SD_ERROR_INVALID_ARG;
9598 	else if (type != SD_SCSI_IO_LATENCY_TYPE)
9599 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9600 	else {
9601 		bcopy(dfc->buf3, (void *) &emlxs_sd_bucket,
9602 		    sizeof (sd_bucket_info_t));
9603 		emlxs_sd_bucket.state = SD_STOPPED;
9604 	}
9605 
9606 	mutex_exit(&emlxs_sd_bucket_mutex);
9607 	return (rval);
9608 }
9609 
9610 /*ARGSUSED*/
9611 static int32_t
9612 emlxs_dfc_sd_destroy_bucket(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9613 {
9614 	uint32_t	type;
9615 	int32_t 	rval = DFC_SD_OK;
9616 
9617 	type = dfc->data1;
9618 
9619 	mutex_enter(&emlxs_sd_bucket_mutex);
9620 
9621 	if (emlxs_sd_bucket.search_type == 0) {
9622 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9623 	} else if (emlxs_sd_bucket.state == SD_COLLECTING) {
9624 		rval = DFC_SD_ERROR_DATA_COLLECTION_ACTIVE;
9625 	} else if (type != SD_SCSI_IO_LATENCY_TYPE) {
9626 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9627 	} else {
9628 		bzero((uint8_t *)&emlxs_sd_bucket, sizeof (sd_bucket_info_t));
9629 	}
9630 
9631 	mutex_exit(&emlxs_sd_bucket_mutex);
9632 	return (rval);
9633 
9634 } /* emlxs_dfc_sd_destroy_bucket() */
9635 
9636 
9637 /*ARGSUSED*/
9638 static int32_t
9639 emlxs_dfc_sd_get_bucket(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9640 {
9641 	uint32_t	type;
9642 	int32_t		rval = DFC_SD_OK;
9643 
9644 	type = dfc->data1;
9645 
9646 	mutex_enter(&emlxs_sd_bucket_mutex);
9647 
9648 	if (emlxs_sd_bucket.search_type == 0) {
9649 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9650 	} else if (type != SD_SCSI_IO_LATENCY_TYPE) {
9651 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9652 	} else {
9653 		bcopy(&emlxs_sd_bucket, dfc->buf3,
9654 		    sizeof (sd_bucket_info_t));
9655 	}
9656 
9657 	mutex_exit(&emlxs_sd_bucket_mutex);
9658 	return (rval);
9659 
9660 } /* emlxs_dfc_sd_get_bucket() */
9661 
9662 
9663 /*ARGSUSED*/
9664 static int32_t
9665 emlxs_dfc_sd_start_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9666 {
9667 	emlxs_port_t	*vport;
9668 	NODELIST	*nlp;
9669 	uint8_t		wwpn[8];
9670 	int32_t		rval = DFC_SD_OK;
9671 	int		i;
9672 
9673 	if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) {
9674 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9675 		goto start_collect_exit;
9676 	}
9677 
9678 	if (emlxs_sd_bucket.search_type == 0) {
9679 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9680 		goto start_collect_exit;
9681 	}
9682 
9683 	/* Read the wwn object */
9684 	bcopy((void *)dfc->buf3, (void *)wwpn, 8);
9685 
9686 	/* Make sure WWPN is unique */
9687 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9688 
9689 	if (!vport) {
9690 		rval = DFC_SD_ERROR_INVALID_PORT;
9691 		goto start_collect_exit;
9692 	}
9693 
9694 	/* traverse list of nodes for this vport and reset counter */
9695 	rw_enter(&vport->node_rwlock, RW_READER);
9696 	if (vport->sd_io_latency_state == SD_COLLECTING) {
9697 		rval = DFC_SD_ERROR_DATA_COLLECTION_ACTIVE;
9698 		rw_exit(&vport->node_rwlock);
9699 		goto start_collect_exit;
9700 	}
9701 
9702 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
9703 		nlp = vport->node_table[i];
9704 		while (nlp != NULL) {
9705 			bzero((void *)&nlp->sd_dev_bucket[0],
9706 			    sizeof (struct SD_time_stats_v0) *
9707 			    SD_IO_LATENCY_MAX_BUCKETS);
9708 
9709 			nlp = nlp->nlp_list_next;
9710 		}
9711 	}
9712 
9713 	vport->sd_io_latency_state = SD_COLLECTING;
9714 	rw_exit(&vport->node_rwlock);
9715 
9716 	mutex_enter(&emlxs_sd_bucket_mutex);
9717 	emlxs_sd_bucket.state = SD_COLLECTING;
9718 	mutex_exit(&emlxs_sd_bucket_mutex);
9719 
9720 start_collect_exit:
9721 	return (rval);
9722 }
9723 
9724 
9725 /*ARGSUSED*/
9726 static int32_t
9727 emlxs_dfc_sd_stop_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9728 {
9729 	emlxs_port_t	*vport;
9730 	emlxs_hba_t	*temp_hba;
9731 	uint8_t		wwpn[8];
9732 	int32_t		rval = DFC_SD_OK;
9733 	int		i, j;
9734 
9735 	if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) {
9736 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9737 		goto stop_collect_exit;
9738 	}
9739 
9740 	if (emlxs_sd_bucket.search_type == 0) {
9741 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9742 		goto stop_collect_exit;
9743 	}
9744 
9745 	/* Read the wwn object */
9746 	bcopy((void *)dfc->buf3, (void *)wwpn, 8);
9747 
9748 	/* Make sure WWPN is unique */
9749 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9750 
9751 	if (!vport) {
9752 		rval = DFC_SD_ERROR_INVALID_PORT;
9753 		goto stop_collect_exit;
9754 	}
9755 
9756 	rw_enter(&vport->node_rwlock, RW_READER);
9757 	if (vport->sd_io_latency_state != SD_COLLECTING) {
9758 		rval = DFC_SD_ERROR_DATA_COLLECTION_NOT_ACTIVE;
9759 		rw_exit(&vport->node_rwlock);
9760 		goto stop_collect_exit;
9761 	}
9762 	vport->sd_io_latency_state = SD_STOPPED;
9763 	rw_exit(&vport->node_rwlock);
9764 
9765 	/* see if any other port is collecting io latency */
9766 	for (i = 0; i < emlxs_device.hba_count; i++) {
9767 		temp_hba = emlxs_device.hba[i];
9768 		for (j = 0; j < temp_hba->num_of_ports; j++) {
9769 			vport = &temp_hba->port[j];
9770 			if (vport->sd_io_latency_state == SD_COLLECTING)
9771 				goto stop_collect_exit;
9772 		}
9773 	}
9774 
9775 	/*
9776 	 * if we get here, that means no one else is collecting
9777 	 * io latency data.
9778 	 */
9779 	mutex_enter(&emlxs_sd_bucket_mutex);
9780 	emlxs_sd_bucket.state = SD_STOPPED;
9781 	mutex_exit(&emlxs_sd_bucket_mutex);
9782 
9783 stop_collect_exit:
9784 	return (rval);
9785 }
9786 
9787 
9788 /*ARGSUSED*/
9789 static int32_t
9790 emlxs_dfc_sd_reset_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9791 {
9792 	emlxs_port_t   *vport;
9793 	NODELIST	*nlp;
9794 	uint8_t		wwpn[8];
9795 	int32_t 	rval = DFC_SD_OK;
9796 	int		i;
9797 
9798 	if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) {
9799 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9800 		goto reset_collect_exit;
9801 	}
9802 
9803 	if (emlxs_sd_bucket.search_type == 0) {
9804 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9805 		goto reset_collect_exit;
9806 	}
9807 
9808 	/* Read the wwn object */
9809 	bcopy((void *)dfc->buf3, (void *)wwpn, 8);
9810 
9811 	/* Make sure WWPN is unique */
9812 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9813 
9814 	if (!vport) {
9815 		rval = DFC_SD_ERROR_INVALID_PORT;
9816 		goto reset_collect_exit;
9817 	}
9818 
9819 	/* traverse list of nodes for this vport and reset counter */
9820 	rw_enter(&vport->node_rwlock, RW_READER);
9821 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
9822 		nlp = vport->node_table[i];
9823 		while (nlp != NULL) {
9824 			bzero((void *)&nlp->sd_dev_bucket[0],
9825 			    sizeof (struct SD_time_stats_v0) *
9826 			    SD_IO_LATENCY_MAX_BUCKETS);
9827 
9828 			nlp = nlp->nlp_list_next;
9829 		}
9830 	}
9831 	rw_exit(&vport->node_rwlock);
9832 
9833 reset_collect_exit:
9834 	return (rval);
9835 }
9836 
9837 
9838 /*ARGSUSED*/
9839 static int32_t
9840 emlxs_dfc_sd_get_data(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9841 {
9842 	emlxs_port_t   *vport;
9843 	uint8_t		wwpn[8];
9844 	int		i, skip_bytes;
9845 	uint16_t	count;
9846 	uint32_t	bufsize, size_needed;
9847 	NODELIST	*nlp;
9848 	int32_t 	rval = DFC_SD_OK;
9849 
9850 	if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) {
9851 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9852 		goto get_data_exit;
9853 	}
9854 
9855 	if (emlxs_sd_bucket.search_type == 0) {
9856 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9857 		goto get_data_exit;
9858 	}
9859 
9860 	/* Read the wwn object */
9861 	bcopy((void *)dfc->buf3, (void *)wwpn, 8);
9862 
9863 	/* Make sure WWPN is unique */
9864 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9865 
9866 	if (!vport) {
9867 		rval = DFC_SD_ERROR_INVALID_PORT;
9868 		goto get_data_exit;
9869 	}
9870 
9871 	bufsize = dfc->buf4_size;
9872 
9873 	/*
9874 	 * count # of targets to see if buffer is big enough
9875 	 */
9876 	count = 0;
9877 	rw_enter(&vport->node_rwlock, RW_READER);
9878 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
9879 		nlp = vport->node_table[i];
9880 		while (nlp != NULL) {
9881 			count++;
9882 			nlp = nlp->nlp_list_next;
9883 		}
9884 	}
9885 	rw_exit(&vport->node_rwlock);
9886 
9887 	size_needed = count * (sizeof (HBA_WWN) +
9888 	    sizeof (struct SD_time_stats_v0) * SD_IO_LATENCY_MAX_BUCKETS);
9889 
9890 	if (bufsize < size_needed) {
9891 		rval = DFC_SD_ERROR_MORE_DATA_AVAIL;
9892 		goto update_count;	/* not enough space, return */
9893 	}
9894 
9895 	/*
9896 	 * return data collected, reset counter.
9897 	 */
9898 	count = 0;
9899 	skip_bytes = 0;
9900 	rw_enter(&vport->node_rwlock, RW_READER);
9901 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
9902 		nlp = vport->node_table[i];
9903 		while (nlp != NULL) {
9904 			/* copy port name */
9905 			bcopy((void *)&nlp->nlp_portname,
9906 			    (void *)((char *)dfc->buf4 + skip_bytes),
9907 			    sizeof (HBA_WWN));
9908 			skip_bytes += sizeof (HBA_WWN);
9909 
9910 			/* copy bucket data */
9911 			bcopy((void *)&nlp->sd_dev_bucket[0],
9912 			    (void *)((char *)dfc->buf4 + skip_bytes),
9913 			    sizeof (struct SD_time_stats_v0) *
9914 			    SD_IO_LATENCY_MAX_BUCKETS);
9915 			skip_bytes += sizeof (struct SD_time_stats_v0) *
9916 			    SD_IO_LATENCY_MAX_BUCKETS;
9917 
9918 			bzero((void *)&nlp->sd_dev_bucket[0],
9919 			    sizeof (struct SD_time_stats_v0) *
9920 			    SD_IO_LATENCY_MAX_BUCKETS);
9921 
9922 			count++;
9923 			bufsize -= sizeof (struct SD_IO_Latency_Response);
9924 
9925 			nlp = nlp->nlp_list_next;
9926 		}
9927 	}
9928 	rw_exit(&vport->node_rwlock);
9929 
9930 update_count:
9931 	bcopy((void *)&count, (void *)dfc->buf2, sizeof (uint16_t));
9932 
9933 get_data_exit:
9934 	return (rval);
9935 
9936 } /* emlxs_dfc_sd_get_data() */
9937 
9938 
9939 /*ARGSUSED*/
9940 static int32_t
9941 emlxs_dfc_sd_set_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9942 {
9943 	emlxs_port_t		*vport;
9944 	uint8_t			wwpn[8];
9945 	uint32_t		event, pid, enable;
9946 	int32_t 		rval = DFC_SD_OK;
9947 	int			i, count;
9948 	emlxs_dfc_event_t	*dfc_event;
9949 
9950 	/*
9951 	 * The value of "event" has been shifted left based on
9952 	 * the category that the application gave to libdfc.
9953 	 *
9954 	 * This is so the old Event handling code won't mistakenly
9955 	 * grab an SD Event.
9956 	 */
9957 	event = dfc->data1;
9958 	pid = dfc->data3;
9959 	enable = dfc->flag;
9960 
9961 	/* Read the wwn object */
9962 	bcopy((void *)dfc->buf3, (void *)wwpn, 8);
9963 
9964 	/* Make sure WWPN is unique */
9965 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9966 
9967 	if (!vport) {
9968 		rval = DFC_SD_ERROR_INVALID_PORT;
9969 		goto set_sd_event_exit;
9970 	}
9971 
9972 	if (enable) {
9973 		/* Find next available event object */
9974 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
9975 			dfc_event = &vport->sd_events[i];
9976 
9977 			if (!dfc_event->pid && !dfc_event->event)
9978 				break;
9979 		}
9980 
9981 		/* Return if all event objects are busy */
9982 		if (i == MAX_DFC_EVENTS) {
9983 			rval = DFC_SD_ERROR_OUT_OF_HANDLES;
9984 			goto set_sd_event_exit;
9985 		}
9986 
9987 		/* Initialize */
9988 		/* TODO: Should we add SUBCAT in dfc_event ??? */
9989 		dfc_event->pid = pid;
9990 		dfc_event->event = event;
9991 		dfc_event->last_id = (uint32_t)-1;
9992 		dfc_event->dataout = NULL;
9993 		dfc_event->size = 0;
9994 		dfc_event->mode = 0;
9995 
9996 		emlxs_get_sd_event(vport, dfc_event, 0);
9997 
9998 		if (dfc->buf1) {
9999 			bcopy((void *) &dfc_event->last_id, dfc->buf1,
10000 			    sizeof (uint32_t));
10001 		}
10002 
10003 		vport->sd_event_mask |= event;
10004 	} else { /* Disable */
10005 		/* find event entry */
10006 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
10007 			dfc_event = &vport->sd_events[i];
10008 
10009 			if (dfc_event->pid  == pid && dfc_event->event == event)
10010 				break;
10011 		}
10012 
10013 		/* Return if not found */
10014 		if (i == MAX_DFC_EVENTS) {
10015 			rval = DFC_SD_ERROR_INVALID_ARG;
10016 			goto set_sd_event_exit;
10017 		}
10018 
10019 		/* Kill the event thread if it is sleeping */
10020 		(void) emlxs_kill_dfc_event(vport, dfc_event);
10021 
10022 		/* Count the number of pids still registered for this event */
10023 		count = 0;
10024 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
10025 			dfc_event = &vport->sd_events[i];
10026 
10027 			if (dfc_event->event == event)
10028 				count++;
10029 		}
10030 
10031 		/*
10032 		 * If no more pids need this event,
10033 		 * then disable logging for this event
10034 		 */
10035 		if (count == 0)
10036 			vport->sd_event_mask &= ~event;
10037 	}
10038 
10039 set_sd_event_exit:
10040 	return (rval);
10041 } /* emlxs_dfc_sd_set_event */
10042 
10043 
10044 /*ARGSUSED*/
10045 static int32_t
10046 emlxs_dfc_sd_get_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10047 {
10048 	emlxs_port_t   *vport;
10049 	uint8_t		wwpn[8];
10050 	uint32_t	event, pid, sleep, i;
10051 	int32_t		rval = DFC_SD_OK;
10052 	emlxs_dfc_event_t *dfc_event;
10053 
10054 	event = dfc->data1;
10055 	pid = dfc->data2;
10056 
10057 	/* Read the wwn object */
10058 	bcopy((void *)dfc->buf4, (void *)wwpn, 8);
10059 
10060 	/* Make sure WWPN is unique */
10061 	vport = emlxs_vport_find_wwpn(hba, wwpn);
10062 
10063 	if (!vport) {
10064 		rval = DFC_SD_ERROR_INVALID_PORT;
10065 		goto get_sd_event_exit;
10066 	}
10067 
10068 	/* Find the event entry */
10069 	dfc_event = NULL;
10070 	for (i = 0; i < MAX_DFC_EVENTS; i++) {
10071 		dfc_event = &vport->sd_events[i];
10072 
10073 		if (dfc_event->pid == pid && dfc_event->event == event)
10074 			break;
10075 	}
10076 
10077 	if (i == MAX_DFC_EVENTS) {
10078 		rval = DFC_SD_ERROR_GENERIC;
10079 		goto get_sd_event_exit;
10080 	}
10081 
10082 	if (!(vport->sd_event_mask & dfc_event->event)) {
10083 		rval = DFC_SD_ERROR_GENERIC;
10084 		goto get_sd_event_exit;
10085 	}
10086 
10087 	/* Initialize event buffer pointers */
10088 	dfc_event->dataout = dfc->buf1;
10089 	dfc_event->size = dfc->buf1_size;
10090 	dfc_event->last_id = dfc->data3;
10091 	dfc_event->mode = mode;
10092 
10093 	sleep = (dfc->flag & 0x01) ? 1 : 0;
10094 
10095 	emlxs_get_sd_event(vport, dfc_event, sleep);
10096 
10097 	/*
10098 	 * update rcv_size.
10099 	 */
10100 	if (dfc->buf2) {
10101 		bcopy((void *) &dfc_event->size, dfc->buf2,
10102 		    sizeof (uint32_t));
10103 	}
10104 
10105 	/*
10106 	 * update index
10107 	 */
10108 	if (dfc->buf3) {
10109 		bcopy((void *) &dfc_event->last_id, dfc->buf3,
10110 		    sizeof (uint32_t));
10111 	}
10112 
10113 get_sd_event_exit:
10114 	return (rval);
10115 } /* emlxs_dfc_sd_get_event */
10116 #endif
10117 
10118 /*ARGSUSED*/
10119 static int32_t
10120 emlxs_dfc_send_scsi_fcp(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10121 {
10122 	emlxs_port_t			*port = &PPORT;
10123 	fc_packet_t			*pkt = NULL;
10124 	NODELIST			*ndlp;
10125 	FCP_CMND			*fcp_cmd;
10126 	FCP_RSP				*fcp_rsp;
10127 	void				*ptr;
10128 	char				buffer[64];
10129 	dfc_send_scsi_fcp_cmd_info_t	*cmdinfo;
10130 	uint32_t			rval = 0;
10131 
10132 	/* cmd info */
10133 	if (!dfc->buf1 ||
10134 	    (dfc->buf1_size != sizeof (dfc_send_scsi_fcp_cmd_info_t))) {
10135 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10136 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
10137 
10138 		rval = DFC_ARG_NULL;
10139 		goto done;
10140 	}
10141 
10142 	/* reqBuffer info */
10143 	if (!dfc->buf2 || (dfc->buf2_size != sizeof (FCP_CMND))) {
10144 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10145 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
10146 
10147 		rval = DFC_ARG_NULL;
10148 		goto done;
10149 	}
10150 
10151 	/* rspBuffer info, could be 0 for SCSI commands like TUR */
10152 	if (!dfc->buf3 && dfc->buf3_size) {
10153 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10154 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
10155 
10156 		rval = DFC_ARG_NULL;
10157 		goto done;
10158 	}
10159 
10160 	/* senseBuffer info */
10161 	if (!dfc->buf4 || !dfc->buf4_size) {
10162 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10163 		    "%s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd));
10164 
10165 		rval = DFC_ARG_NULL;
10166 		goto done;
10167 	}
10168 
10169 	cmdinfo = (dfc_send_scsi_fcp_cmd_info_t *)dfc->buf1;
10170 
10171 	if (cmdinfo->ver == DFC_SEND_SCSI_FCP_V2) {
10172 		port =
10173 		    emlxs_vport_find_wwpn(hba, (uint8_t *)&cmdinfo->src_wwn);
10174 		if (port == NULL) {
10175 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10176 			    "%s: WWPN does not exists. %s",
10177 			    emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer,
10178 			    sizeof (buffer), (uint8_t *)&cmdinfo->src_wwn));
10179 
10180 			rval = DFC_ARG_INVALID;
10181 			goto done;
10182 		}
10183 	}
10184 
10185 	if ((ndlp = emlxs_node_find_wwpn(port,
10186 	    (uint8_t *)&cmdinfo->dst_wwn, 1)) == NULL) {
10187 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10188 		    "%s: WWPN does not exists. %s", emlxs_dfc_xlate(dfc->cmd),
10189 		    emlxs_wwn_xlate(buffer, sizeof (buffer),
10190 		    (uint8_t *)&cmdinfo->dst_wwn));
10191 
10192 		rval = DFC_ARG_INVALID;
10193 		goto done;
10194 	}
10195 
10196 	if (!(pkt = emlxs_pkt_alloc(port, sizeof (FCP_CMND), sizeof (FCP_RSP),
10197 	    dfc->buf3_size, KM_NOSLEEP))) {
10198 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10199 		    "%s: Unable to allocate packet.",
10200 		    emlxs_dfc_xlate(dfc->cmd));
10201 
10202 		rval = DFC_SYSRES_ERROR;
10203 		goto done;
10204 	}
10205 	fcp_cmd = (FCP_CMND *) pkt->pkt_cmd;
10206 
10207 	/* Copy in the command buffer */
10208 	bcopy((void *)dfc->buf2, (void *)fcp_cmd, sizeof (FCP_CMND));
10209 
10210 	/* Make this a polled IO */
10211 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
10212 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
10213 	pkt->pkt_comp = NULL;
10214 
10215 	/* Build the fc header */
10216 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(ndlp->nlp_DID);
10217 	pkt->pkt_cmd_fhdr.r_ctl = FC_FCP_CMND;
10218 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
10219 	pkt->pkt_cmd_fhdr.type = FC_TYPE_SCSI_FCP;
10220 	pkt->pkt_cmd_fhdr.seq_id = 0;
10221 	pkt->pkt_cmd_fhdr.df_ctl = 0;
10222 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
10223 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
10224 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
10225 	pkt->pkt_cmd_fhdr.ro = 0;
10226 
10227 	pkt->pkt_timeout = 30;
10228 
10229 	if ((fcp_cmd->fcpCntl3 == WRITE_DATA) && dfc->buf3_size) {
10230 		pkt->pkt_tran_type = FC_PKT_FCP_WRITE;
10231 		bcopy((void *)dfc->buf3, (void *)pkt->pkt_data, dfc->buf3_size);
10232 	} else {
10233 		pkt->pkt_tran_type = FC_PKT_FCP_READ;
10234 	}
10235 
10236 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
10237 		rval = DFC_IO_ERROR;
10238 		goto done;
10239 	}
10240 
10241 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
10242 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
10243 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10244 			    "Pkt Transport error. Pkt Timeout.");
10245 			rval = DFC_TIMEOUT;
10246 		} else {
10247 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10248 			    "Pkt Transport error. state=%x", pkt->pkt_state);
10249 			rval = DFC_IO_ERROR;
10250 		}
10251 		goto done;
10252 	}
10253 
10254 	if (pkt->pkt_data_resid) {
10255 		if (pkt->pkt_data_resid < dfc->buf3_size)
10256 			dfc->buf3_size -= pkt->pkt_data_resid;
10257 		else
10258 			dfc->buf3_size = 0;
10259 	}
10260 
10261 	SCSI_RSP_CNT(cmdinfo) = dfc->buf3_size;
10262 
10263 	fcp_rsp = (FCP_RSP *) pkt->pkt_resp;
10264 	/*
10265 	 * This is sense count for flag = 0.
10266 	 * It is fcp response size for flag = 1.
10267 	 */
10268 	if (dfc->flag) {
10269 		SCSI_SNS_CNT(cmdinfo) = 24 + LE_SWAP32(fcp_rsp->rspSnsLen) +
10270 		    LE_SWAP32(fcp_rsp->rspRspLen);
10271 		ptr = (void *)fcp_rsp;
10272 	} else {
10273 		SCSI_SNS_CNT(cmdinfo) = LE_SWAP32(fcp_rsp->rspSnsLen);
10274 		ptr = (void *)&fcp_rsp->rspSnsInfo[0];
10275 	}
10276 
10277 	if (SCSI_SNS_CNT(cmdinfo)) {
10278 		bcopy(ptr, (void *)dfc->buf4, SCSI_SNS_CNT(cmdinfo));
10279 	}
10280 
10281 	if (SCSI_RSP_CNT(cmdinfo)) {
10282 		bcopy((void *)pkt->pkt_data, (void *)dfc->buf3,
10283 		    SCSI_RSP_CNT(cmdinfo));
10284 	}
10285 
10286 	rval = 0;
10287 
10288 done:
10289 	if (pkt) {
10290 		emlxs_pkt_free(pkt);
10291 	}
10292 
10293 	return (rval);
10294 
10295 } /* emlxs_dfc_send_scsi_fcp() */
10296 
10297 
10298 /*ARGSUSED*/
10299 static int32_t
10300 emlxs_dfc_get_persist_linkdown(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10301 {
10302 	emlxs_port_t		*port = &PPORT;
10303 	emlxs_config_t		*cfg = &CFG;
10304 	uint16_t		linkdown = 0;
10305 	uint32_t		rval = 0;
10306 
10307 	if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE) {
10308 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10309 		    "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd));
10310 
10311 		return (DFC_NOT_SUPPORTED);
10312 	}
10313 
10314 	if (!dfc->buf1 || !dfc->buf1_size) {
10315 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10316 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
10317 
10318 		return (DFC_ARG_NULL);
10319 	}
10320 
10321 	linkdown = (uint16_t)cfg[CFG_PERSIST_LINKDOWN].current;
10322 	bcopy((void *)&linkdown, dfc->buf1, sizeof (uint16_t));
10323 
10324 	return (rval);
10325 
10326 } /* emlxs_dfc_get_persist_linkdown() */
10327 
10328 
10329 /*ARGSUSED*/
10330 static int32_t
10331 emlxs_dfc_set_persist_linkdown(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10332 {
10333 	emlxs_port_t		*port = &PPORT;
10334 	emlxs_config_t		*cfg = &CFG;
10335 	uint32_t		rval = 0;
10336 
10337 	if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE) {
10338 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10339 		    "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd));
10340 
10341 		return (DFC_NOT_SUPPORTED);
10342 	}
10343 
10344 	if (dfc->data1) {
10345 		cfg[CFG_PERSIST_LINKDOWN].current = 1;
10346 	} else {
10347 		cfg[CFG_PERSIST_LINKDOWN].current = 0;
10348 	}
10349 
10350 	return (rval);
10351 
10352 } /* emlxs_dfc_set_persist_linkdown() */
10353 
10354 
10355 /*ARGSUSED*/
10356 static int32_t
10357 emlxs_dfc_get_fcflist(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10358 {
10359 	emlxs_port_t		*port = &PPORT;
10360 	DFC_FCoEFCFInfo_t	*fcflistentry;
10361 	DFC_FCoEFCFList_t	*fcflist;
10362 	FCFIobj_t		*fcfp;
10363 	uint32_t		size;
10364 	uint32_t		i;
10365 	uint32_t		count = 0;
10366 	uint32_t		rval = 0;
10367 
10368 	if (!dfc->buf1 || !dfc->buf1_size) {
10369 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10370 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
10371 
10372 		return (DFC_ARG_NULL);
10373 	}
10374 
10375 	if (dfc->buf1_size < sizeof (DFC_FCoEFCFList_t)) {
10376 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10377 		    "%s: Buffer1 too small. (size=%d)",
10378 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
10379 
10380 		return (DFC_ARG_TOOSMALL);
10381 	}
10382 
10383 	if (! ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE)) {
10384 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10385 		    "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd));
10386 
10387 		return (DFC_NOT_SUPPORTED);
10388 	}
10389 
10390 	if (hba->state != FC_READY) {
10391 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10392 		    "%s: HBA not ready.", emlxs_dfc_xlate(dfc->cmd));
10393 
10394 		return (DFC_DRV_ERROR);
10395 	}
10396 
10397 	size = sizeof (DFC_FCoEFCFList_t) +
10398 	    hba->sli.sli4.fcftab.table_count * sizeof (DFC_FCoEFCFInfo_t);
10399 	fcflist = (DFC_FCoEFCFList_t *)kmem_zalloc(size, KM_SLEEP);
10400 
10401 	bcopy(dfc->buf1, (void *)fcflist, sizeof (DFC_FCoEFCFList_t));
10402 
10403 	fcflistentry = fcflist->entries;
10404 	mutex_enter(&EMLXS_FCF_LOCK);
10405 	fcfp = hba->sli.sli4.fcftab.table;
10406 	for (i = 0; i < hba->sli.sli4.fcftab.table_count; i++, fcfp++) {
10407 		if ((fcfp->state != FCFI_STATE_FREE) &&
10408 		    (fcfp->fcf_rec.fcf_valid)) {
10409 			fcflistentry->Priority = fcfp->fcf_rec.fip_priority;
10410 			if (fcfp->fcf_rec.fcf_available) {
10411 				fcflistentry->State = FCF_AVAILABLE_STATE;
10412 			}
10413 			fcflistentry->LKA_Period = fcfp->fcf_rec.fka_adv_period;
10414 
10415 			bcopy((void *)fcfp->fcf_rec.vlan_bitmap,
10416 			    (void *)fcflistentry->VLanBitMap, 512);
10417 			bcopy((void *)fcfp->fcf_rec.fc_map,
10418 			    (void *)fcflistentry->FC_Map, 3);
10419 			bcopy((void *)fcfp->fcf_rec.fabric_name_identifier,
10420 			    (void *)fcflistentry->FabricName, 8);
10421 			bcopy((void *)fcfp->fcf_rec.switch_name_identifier,
10422 			    (void *)fcflistentry->SwitchName, 8);
10423 			bcopy((void *)&fcfp->fcf_rec.fcf_mac_address_hi,
10424 			    (void *)fcflistentry->Mac, 6);
10425 
10426 			count++;
10427 			fcflistentry++;
10428 		}
10429 	}
10430 	mutex_exit(&EMLXS_FCF_LOCK);
10431 
10432 	fcflist->nActiveFCFs = hba->sli.sli4.fcftab.fcfi_count;
10433 
10434 	if (count > fcflist->numberOfEntries) {
10435 		rval = DFC_ARG_TOOSMALL;
10436 	}
10437 
10438 	i = sizeof (DFC_FCoEFCFList_t) +
10439 	    (fcflist->numberOfEntries - 1) * sizeof (DFC_FCoEFCFInfo_t);
10440 	fcflist->numberOfEntries = (uint16_t)count;
10441 
10442 	bcopy((void *)fcflist, dfc->buf1, i);
10443 
10444 done:
10445 	kmem_free(fcflist, size);
10446 	return (rval);
10447 
10448 } /* emlxs_dfc_get_fcflist() */
10449 
10450 
10451 /*ARGSUSED*/
10452 static int32_t
10453 emlxs_dfc_send_mbox4(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10454 {
10455 	emlxs_port_t	*port = &PPORT;
10456 	MAILBOX4	*mb4 = NULL;
10457 	MAILBOXQ	*mbq = NULL;
10458 	mbox_req_hdr_t	*hdr_req;
10459 	IOCTL_COMMON_WRITE_OBJECT *write_obj;
10460 	MATCHMAP	*mp = NULL, *tx_mp = NULL, *rx_mp = NULL;
10461 	uintptr_t	addr;	/* Was uint64_t in Emulex drop... */
10462 	uint32_t	size;
10463 	int32_t		mbxstatus = 0;
10464 	uint32_t	rval = 0;
10465 
10466 	if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) {
10467 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10468 		    "%s: SLI Mode %d not supported.", emlxs_dfc_xlate(dfc->cmd),
10469 		    hba->sli_mode);
10470 
10471 		return (DFC_NOT_SUPPORTED);
10472 	}
10473 
10474 	if (!dfc->buf1 || !dfc->buf1_size) {
10475 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10476 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
10477 
10478 		return (DFC_ARG_NULL);
10479 	}
10480 
10481 	if (!dfc->buf2 || !dfc->buf2_size) {
10482 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10483 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
10484 
10485 		return (DFC_ARG_NULL);
10486 	}
10487 
10488 	if ((dfc->buf1_size != dfc->buf2_size) ||
10489 	    (dfc->buf1_size < sizeof (MAILBOX4))) {
10490 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10491 		    "%s: Invalid buffer size. (size=%d)",
10492 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
10493 
10494 		return (DFC_ARG_INVALID);
10495 	}
10496 
10497 	mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
10498 	mb4 = (MAILBOX4 *) mbq;
10499 	bcopy(dfc->buf1, (void *)mb4, sizeof (MAILBOX4));
10500 
10501 	/*
10502 	 * Now snoop the mailbox command
10503 	 */
10504 	switch (mb4->mbxCommand) {
10505 		case MBX_SLI_CONFIG:
10506 		if (! mb4->un.varSLIConfig.be.embedded) {
10507 			if (mb4->un.varSLIConfig.be.sge_cnt > 1) {
10508 				/*
10509 				 * Allow only one buffer descriptor
10510 				 * for non-embedded commands
10511 				 */
10512 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10513 				    "%s: Only one buffer descriptor allowed.",
10514 				    emlxs_dfc_xlate(dfc->cmd));
10515 
10516 				rval = DFC_ARG_INVALID;
10517 				break;
10518 			}
10519 
10520 			if ((!mb4->un.varSLIConfig.be.payload_length) ||
10521 			    (mb4->un.varSLIConfig.be.payload_length !=
10522 			    (dfc->buf1_size - sizeof (MAILBOX4)))) {
10523 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10524 				    "%s: Invalid buffer size. (size=%d)",
10525 				    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
10526 
10527 				rval = DFC_ARG_INVALID;
10528 				break;
10529 			}
10530 
10531 			mp = emlxs_mem_buf_alloc(hba,
10532 			    mb4->un.varSLIConfig.be.payload_length);
10533 
10534 			if (mp == NULL) {
10535 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10536 				    "%s: Unable to allocate buffer.",
10537 				    emlxs_dfc_xlate(dfc->cmd));
10538 
10539 				rval = DFC_SYSRES_ERROR;
10540 				break;
10541 			}
10542 
10543 			bcopy((uint8_t *)dfc->buf1 + sizeof (MAILBOX4),
10544 			    mp->virt, mp->size);
10545 			EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size,
10546 			    DDI_DMA_SYNC_FORDEV);
10547 
10548 			mbq->nonembed = (void *) mp;
10549 			break;
10550 		}
10551 
10552 		hdr_req = (mbox_req_hdr_t *)
10553 		    &mb4->un.varSLIConfig.be.un_hdr.hdr_req;
10554 
10555 		/*
10556 		 * WRITE_OBJECT, READ_OBJECT and READ_OBJECT_LIST are
10557 		 * special because they use buffer descriptors
10558 		 */
10559 		if ((hdr_req->subsystem == IOCTL_SUBSYSTEM_COMMON) &&
10560 		    ((hdr_req->opcode == COMMON_OPCODE_WRITE_OBJ) ||
10561 		    (hdr_req->opcode == COMMON_OPCODE_READ_OBJ_LIST) ||
10562 		    (hdr_req->opcode == COMMON_OPCODE_READ_OBJ))) {
10563 			write_obj =
10564 			    (IOCTL_COMMON_WRITE_OBJECT *)(hdr_req + 1);
10565 
10566 			if (write_obj->params.request.buffer_desc_count
10567 			    > 1) {
10568 				/*
10569 				 * Allow only one buffer descriptor
10570 				 * for embedded commands
10571 				 */
10572 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10573 				    "%s: Only one buffer descriptor allowed.",
10574 				    emlxs_dfc_xlate(dfc->cmd));
10575 
10576 				rval = DFC_ARG_INVALID;
10577 				break;
10578 			}
10579 
10580 			if (write_obj->params.request.buffer_length !=
10581 			    (dfc->buf1_size - sizeof (MAILBOX4))) {
10582 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10583 				    "%s: Invalid buffer size. (size=%d)",
10584 				    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
10585 
10586 				rval = DFC_ARG_INVALID;
10587 				break;
10588 			}
10589 
10590 			if (write_obj->params.request.buffer_length) {
10591 				mp = emlxs_mem_buf_alloc(hba,
10592 				    write_obj->params.request.buffer_length);
10593 
10594 				if (mp == NULL) {
10595 					EMLXS_MSGF(EMLXS_CONTEXT,
10596 					    &emlxs_dfc_error_msg,
10597 					    "%s: Unable to allocate buffer.",
10598 					    emlxs_dfc_xlate(dfc->cmd));
10599 
10600 					rval = DFC_SYSRES_ERROR;
10601 					break;
10602 				}
10603 
10604 				bcopy((uint8_t *)dfc->buf1 + sizeof (MAILBOX4),
10605 				    mp->virt, mp->size);
10606 				EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size,
10607 				    DDI_DMA_SYNC_FORDEV);
10608 				write_obj->params.request.buffer_addrlo =
10609 				    PADDR_LO(mp->phys);
10610 				write_obj->params.request.buffer_addrhi =
10611 				    PADDR_HI(mp->phys);
10612 			}
10613 			break;
10614 		}
10615 		break;
10616 
10617 		case MBX_DUMP_MEMORY:
10618 		if (mb4->un.varDmp4.available_cnt == 0)
10619 			break;
10620 
10621 		if (mb4->un.varDmp4.available_cnt !=
10622 		    (dfc->buf1_size - sizeof (MAILBOX4))) {
10623 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10624 			    "%s: Invalid buffer size. (size=%d)",
10625 			    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
10626 
10627 			rval = DFC_ARG_INVALID;
10628 			break;
10629 		}
10630 
10631 		mp = emlxs_mem_buf_alloc(hba,
10632 		    mb4->un.varDmp4.available_cnt);
10633 
10634 		if (mp == NULL) {
10635 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10636 			    "%s: Unable to allocate buffer.",
10637 			    emlxs_dfc_xlate(dfc->cmd));
10638 
10639 			rval = DFC_SYSRES_ERROR;
10640 			break;
10641 		}
10642 
10643 		bcopy((uint8_t *)dfc->buf1 + sizeof (MAILBOX4),
10644 		    mp->virt, mp->size);
10645 		EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size,
10646 		    DDI_DMA_SYNC_FORDEV);
10647 
10648 		mb4->un.varDmp4.addrLow = PADDR_LO(mp->phys);
10649 		mb4->un.varDmp4.addrHigh = PADDR_HI(mp->phys);
10650 		break;
10651 
10652 		case MBX_UPDATE_CFG:
10653 		if (mb4->un.varUpdateCfg.Obit == 0)
10654 			break;
10655 
10656 		if (mb4->un.varUpdateCfg.byte_len !=
10657 		    (dfc->buf1_size - sizeof (MAILBOX4))) {
10658 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10659 			    "%s: Invalid buffer size. (size=%d)",
10660 			    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
10661 
10662 			rval = DFC_ARG_INVALID;
10663 			break;
10664 		}
10665 
10666 		mp = emlxs_mem_buf_alloc(hba,
10667 		    mb4->un.varUpdateCfg.byte_len);
10668 
10669 		if (mp == NULL) {
10670 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10671 			    "%s: Unable to allocate buffer.",
10672 			    emlxs_dfc_xlate(dfc->cmd));
10673 
10674 			rval = DFC_SYSRES_ERROR;
10675 			break;
10676 		}
10677 
10678 		bcopy((uint8_t *)dfc->buf1 + sizeof (MAILBOX4),
10679 		    mp->virt, mp->size);
10680 		EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size,
10681 		    DDI_DMA_SYNC_FORDEV);
10682 
10683 		mb4->un.varWords[5] = PADDR_LO(mp->phys);
10684 		mb4->un.varWords[6] = PADDR_HI(mp->phys);
10685 		break;
10686 
10687 		case MBX_RUN_BIU_DIAG64:
10688 		size = mb4->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize;
10689 		addr = PADDR(mb4->un.varBIUdiag.un.s2.xmit_bde64.addrHigh,
10690 		    mb4->un.varBIUdiag.un.s2.xmit_bde64.addrLow);
10691 
10692 		if (!addr || !size) {
10693 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10694 			    "%s: Invalid xmit BDE. cmd=%x",
10695 			    emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand);
10696 
10697 			rval = DFC_ARG_INVALID;
10698 			break;
10699 		}
10700 
10701 		/* Allocate xmit buffer */
10702 		if ((tx_mp = emlxs_mem_buf_alloc(hba, size)) == 0) {
10703 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10704 			    "%s: Unable to allocate xmit buffer. cmd=%x",
10705 			    emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand);
10706 
10707 			rval = DFC_DRVRES_ERROR;
10708 			break;
10709 		}
10710 
10711 		/* Initialize the xmit buffer */
10712 		if (ddi_copyin((void *)addr, (void *)tx_mp->virt, size,
10713 		    mode) != 0) {
10714 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10715 			    "%s: ddi_copyin failed. cmd=%x",
10716 			    emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand);
10717 
10718 			rval = DFC_COPYIN_ERROR;
10719 			break;
10720 		}
10721 		EMLXS_MPDATA_SYNC(tx_mp->dma_handle, 0, size,
10722 		    DDI_DMA_SYNC_FORDEV);
10723 
10724 		mb4->un.varBIUdiag.un.s2.xmit_bde64.addrHigh =
10725 		    PADDR_HI(tx_mp->phys);
10726 		mb4->un.varBIUdiag.un.s2.xmit_bde64.addrLow =
10727 		    PADDR_LO(tx_mp->phys);
10728 		mb4->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeFlags = 0;
10729 
10730 		size = mb4->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeSize;
10731 		addr = PADDR(mb4->un.varBIUdiag.un.s2.rcv_bde64.addrHigh,
10732 		    mb4->un.varBIUdiag.un.s2.rcv_bde64.addrLow);
10733 
10734 		if (!addr || !size) {
10735 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10736 			    "%s: Invalid xmit BDE. cmd=%x",
10737 			    emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand);
10738 
10739 			rval = DFC_ARG_INVALID;
10740 			break;
10741 		}
10742 
10743 		/* Allocate receive buffer */
10744 		if ((rx_mp = emlxs_mem_buf_alloc(hba, size)) == 0) {
10745 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10746 			    "%s: Unable to allocate receive buffer. cmd=%x",
10747 			    emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand);
10748 
10749 			rval = DFC_DRVRES_ERROR;
10750 			break;
10751 		}
10752 
10753 		mb4->un.varBIUdiag.un.s2.rcv_bde64.addrHigh =
10754 		    PADDR_HI(rx_mp->phys);
10755 		mb4->un.varBIUdiag.un.s2.rcv_bde64.addrLow =
10756 		    PADDR_LO(rx_mp->phys);
10757 		mb4->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeFlags = 0;
10758 		break;
10759 
10760 		default:
10761 		break;
10762 	}
10763 
10764 	if (rval)
10765 		goto done;
10766 
10767 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
10768 	    "%s: %s sent.  (%x %x %x %x)", emlxs_dfc_xlate(dfc->cmd),
10769 	    emlxs_mb_cmd_xlate(mb4->mbxCommand), mb4->un.varWords[0],
10770 	    mb4->un.varWords[1], mb4->un.varWords[2], mb4->un.varWords[3]);
10771 
10772 	/* issue the mbox cmd to the sli */
10773 	mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
10774 
10775 	if (mbxstatus) {
10776 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
10777 		    "%s: %s failed. mbxstatus=0x%x",
10778 		    emlxs_dfc_xlate(dfc->cmd),
10779 		    emlxs_mb_cmd_xlate(mb4->mbxCommand), mbxstatus);
10780 	}
10781 
10782 	bcopy((void *)mb4, dfc->buf2, sizeof (MAILBOX4));
10783 	if (mp) {
10784 		bcopy(mp->virt, (uint8_t *)dfc->buf2 + sizeof (MAILBOX4),
10785 		    mp->size);
10786 	}
10787 
10788 	if (rx_mp) {
10789 		EMLXS_MPDATA_SYNC(rx_mp->dma_handle, 0, size,
10790 		    DDI_DMA_SYNC_FORKERNEL);
10791 
10792 		if (ddi_copyout((void *)rx_mp->virt, (void *)addr, size,
10793 		    mode) != 0) {
10794 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10795 			    "%s: ddi_copyout failed for receive buffer. cmd=%x",
10796 			    emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand);
10797 
10798 			rval = DFC_COPYOUT_ERROR;
10799 			goto done;
10800 		}
10801 	}
10802 
10803 done:
10804 	/* Free allocated memory */
10805 	if (mp) {
10806 		emlxs_mem_buf_free(hba, mp);
10807 	}
10808 
10809 	if (tx_mp) {
10810 		emlxs_mem_buf_free(hba, tx_mp);
10811 	}
10812 
10813 	if (rx_mp) {
10814 		emlxs_mem_buf_free(hba, rx_mp);
10815 	}
10816 
10817 	if (mbq) {
10818 		kmem_free(mbq, sizeof (MAILBOXQ));
10819 	}
10820 
10821 	return (rval);
10822 } /* emlxs_dfc_send_mbox4() */
10823 
10824 
10825 /* ARGSUSED */
10826 static int
10827 emlxs_dfc_rd_be_fcf(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10828 {
10829 	emlxs_port_t			*port = &PPORT;
10830 	MATCHMAP			*mp;
10831 	MAILBOX4			*mb  = NULL;
10832 	MAILBOXQ			*mbq = NULL;
10833 	IOCTL_FCOE_READ_FCF_TABLE	*fcf;
10834 	mbox_req_hdr_t			*hdr_req;
10835 	mbox_rsp_hdr_t			*hdr_rsp;
10836 	FCF_RECORD_t			*fcfrec;
10837 	uint32_t			rc = 0;
10838 	uint32_t			rval = 0;
10839 	uint16_t			index;
10840 
10841 	if (!dfc->buf1 || !dfc->buf1_size) {
10842 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10843 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
10844 
10845 		return (DFC_ARG_NULL);
10846 	}
10847 
10848 	mbq =
10849 	    (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
10850 
10851 	index = dfc->data1;
10852 	mb = (MAILBOX4 *)mbq;
10853 
10854 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
10855 
10856 	if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF)) == 0) {
10857 		rval = DFC_SYSRES_ERROR;
10858 		goto done;
10859 	}
10860 	bzero(mp->virt, mp->size);
10861 
10862 	/*
10863 	 * Signifies a non-embedded command
10864 	 */
10865 	mb->un.varSLIConfig.be.embedded = 0;
10866 	mbq->nonembed = (void *)mp;
10867 	mbq->mbox_cmpl = NULL;
10868 
10869 	mb->mbxCommand = MBX_SLI_CONFIG;
10870 	mb->mbxOwner = OWN_HOST;
10871 
10872 	hdr_req = (mbox_req_hdr_t *)mp->virt;
10873 	hdr_rsp = (mbox_rsp_hdr_t *)mp->virt;
10874 
10875 	hdr_req->subsystem = IOCTL_SUBSYSTEM_FCOE;
10876 	hdr_req->opcode = FCOE_OPCODE_READ_FCF_TABLE;
10877 	hdr_req->timeout = 0;
10878 	hdr_req->req_length = sizeof (IOCTL_FCOE_READ_FCF_TABLE);
10879 	fcf = (IOCTL_FCOE_READ_FCF_TABLE *)(hdr_req + 1);
10880 	fcf->params.request.fcf_index = index;
10881 
10882 	rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
10883 	if (rc == MBX_SUCCESS) {
10884 		fcfrec = &fcf->params.response.fcf_entry[0];
10885 
10886 		bcopy((void *)fcfrec, (void *)dfc->buf1, dfc->buf1_size);
10887 		bcopy((void *)&fcf->params.response.next_valid_fcf_index,
10888 		    (void *)dfc->buf2, dfc->buf2_size);
10889 	} else {
10890 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
10891 		    "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(dfc->cmd),
10892 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rc);
10893 
10894 		if ((rc == MBX_NONEMBED_ERROR) &&
10895 		    (hdr_rsp->status == MBX_RSP_STATUS_NO_FCF)) {
10896 			rval = DFC_NO_DATA;
10897 		} else {
10898 			rval = DFC_IO_ERROR;
10899 		}
10900 	}
10901 
10902 done:
10903 	if (mp) {
10904 		emlxs_mem_put(hba, MEM_BUF, (void *)mp);
10905 	}
10906 
10907 	if (mbq) {
10908 		kmem_free(mbq, sizeof (MAILBOXQ));
10909 	}
10910 
10911 	return (rval);
10912 
10913 } /* emlxs_dfc_rd_be_fcf() */
10914 
10915 
10916 /*ARGSUSED*/
10917 static int
10918 emlxs_dfc_set_be_dcbx(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10919 {
10920 	emlxs_port_t				*port = &PPORT;
10921 	MAILBOXQ				*mbq = NULL;
10922 	MAILBOX4				*mb;
10923 	IOCTL_DCBX_SET_DCBX_MODE		*dcbx_mode;
10924 	uint32_t				port_num = 0;
10925 	uint32_t				rval = 0;
10926 
10927 	mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
10928 	mb = (MAILBOX4 *)mbq;
10929 
10930 	/*
10931 	 * Signifies an embedded command
10932 	 */
10933 	mb->un.varSLIConfig.be.embedded = 1;
10934 	mbq->mbox_cmpl = NULL;
10935 
10936 	mb->mbxCommand = MBX_SLI_CONFIG;
10937 	mb->mbxOwner = OWN_HOST;
10938 	mb->un.varSLIConfig.be.payload_length = IOCTL_HEADER_SZ;
10939 	mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem =
10940 	    IOCTL_SUBSYSTEM_DCBX;
10941 	mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode =
10942 	    DCBX_OPCODE_SET_DCBX_MODE;
10943 	mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0;
10944 	mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length =
10945 	    sizeof (IOCTL_DCBX_SET_DCBX_MODE);
10946 	dcbx_mode = (IOCTL_DCBX_SET_DCBX_MODE *)&mb->un.varSLIConfig.payload;
10947 	dcbx_mode->params.request.port_num = (uint8_t)port_num;
10948 	dcbx_mode->params.request.dcbx_mode = dfc->data1;
10949 
10950 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
10951 	    "%s requested on port %d.", emlxs_dfc_xlate(dfc->cmd), port_num);
10952 
10953 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
10954 	if (rval != MBX_SUCCESS) {
10955 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
10956 		    "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(dfc->cmd),
10957 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
10958 
10959 		rval = DFC_DRV_ERROR;
10960 	}
10961 
10962 done:
10963 	if (mbq) {
10964 		kmem_free(mbq, sizeof (MAILBOXQ));
10965 	}
10966 
10967 	return (rval);
10968 
10969 } /* emlxs_dfc_set_be_dcbx() */
10970 
10971 
10972 /* ARGSUSED */
10973 static int
10974 emlxs_dfc_get_be_dcbx(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10975 {
10976 	emlxs_port_t				*port = &PPORT;
10977 	MAILBOXQ				*mbq = NULL;
10978 	MAILBOX4				*mb;
10979 	IOCTL_DCBX_GET_DCBX_MODE		*dcbx_mode;
10980 	uint32_t				port_num = 0;
10981 	uint32_t				rval = 0;
10982 
10983 	mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
10984 	mb = (MAILBOX4 *)mbq;
10985 
10986 	/*
10987 	 * Signifies an embedded command
10988 	 */
10989 	mb->un.varSLIConfig.be.embedded = 1;
10990 	mbq->mbox_cmpl = NULL;
10991 
10992 	mb->mbxCommand = MBX_SLI_CONFIG;
10993 	mb->mbxOwner = OWN_HOST;
10994 	mb->un.varSLIConfig.be.payload_length = IOCTL_HEADER_SZ;
10995 	mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem =
10996 	    IOCTL_SUBSYSTEM_DCBX;
10997 	mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode =
10998 	    DCBX_OPCODE_GET_DCBX_MODE;
10999 	mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0;
11000 	mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length =
11001 	    sizeof (IOCTL_DCBX_SET_DCBX_MODE);
11002 	dcbx_mode = (IOCTL_DCBX_GET_DCBX_MODE *)&mb->un.varSLIConfig.payload;
11003 	dcbx_mode->params.request.port_num = (uint8_t)port_num;
11004 
11005 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
11006 	    "%s requested on port %d.", emlxs_dfc_xlate(dfc->cmd), port_num);
11007 
11008 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
11009 	if (rval != MBX_SUCCESS) {
11010 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
11011 		    "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(dfc->cmd),
11012 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
11013 
11014 		rval = DFC_DRV_ERROR;
11015 		goto done;
11016 	}
11017 
11018 	bcopy((void *)&dcbx_mode->params.response.dcbx_mode,
11019 	    (void *)dfc->buf1, dfc->buf1_size);
11020 
11021 done:
11022 	if (mbq) {
11023 		kmem_free(mbq, sizeof (MAILBOXQ));
11024 	}
11025 
11026 	return (rval);
11027 
11028 } /* emlxs_dfc_get_be_dcbx() */
11029 
11030 
11031 /* ARGSUSED */
11032 static int
11033 emlxs_dfc_get_qos(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
11034 {
11035 	emlxs_port_t	*port = &PPORT;
11036 	uint32_t	rval = 0;
11037 
11038 	if (! ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && SLI4_FCOE_MODE)) {
11039 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
11040 		    "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd));
11041 
11042 		return (DFC_NOT_SUPPORTED);
11043 	}
11044 
11045 	if (dfc->buf1_size) {
11046 		bcopy((void *)&hba->qos_linkspeed, (void *)dfc->buf1,
11047 		    dfc->buf1_size);
11048 	}
11049 
11050 	return (rval);
11051 
11052 } /* emlxs_dfc_get_qos() */
11053