1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Emulex.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <emlxs.h>
29 
30 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
31 EMLXS_MSG_DEF(EMLXS_MBOX_C);
32 
33 static void	emlxs_mb_part_slim(emlxs_hba_t *hba, MAILBOXQ *mbq,
34 			uint32_t hbainit);
35 static void	emlxs_mb_set_mask(emlxs_hba_t *hba, MAILBOXQ *mbq,
36 			uint32_t mask, uint32_t ringno);
37 static void	emlxs_mb_set_debug(emlxs_hba_t *hba, MAILBOXQ *mbq,
38 			uint32_t word0, uint32_t word1, uint32_t word2);
39 static void	emlxs_mb_write_nv(emlxs_hba_t *hba, MAILBOXQ *mbq);
40 
41 
42 emlxs_table_t emlxs_mb_cmd_table[] = {
43 	{MBX_SHUTDOWN, "SHUTDOWN"},
44 	{MBX_LOAD_SM, "LOAD_SM"},
45 	{MBX_READ_NV, "READ_NV"},
46 	{MBX_WRITE_NV, "WRITE_NV"},
47 	{MBX_RUN_BIU_DIAG, "RUN_BIU_DIAG"},
48 	{MBX_INIT_LINK, "INIT_LINK"},
49 	{MBX_DOWN_LINK, "DOWN_LINK"},
50 	{MBX_CONFIG_LINK, "CONFIG_LINK"},
51 	{MBX_PART_SLIM, "PART_SLIM"},
52 	{MBX_CONFIG_RING, "CONFIG_RING"},
53 	{MBX_RESET_RING, "RESET_RING"},
54 	{MBX_READ_CONFIG, "READ_CONFIG"},
55 	{MBX_READ_RCONFIG, "READ_RCONFIG"},
56 	{MBX_READ_SPARM, "READ_SPARM"},
57 	{MBX_READ_STATUS, "READ_STATUS"},
58 	{MBX_READ_RPI, "READ_RPI"},
59 	{MBX_READ_XRI, "READ_XRI"},
60 	{MBX_READ_REV, "READ_REV"},
61 	{MBX_READ_LNK_STAT, "READ_LNK_STAT"},
62 	{MBX_REG_LOGIN, "REG_LOGIN"},
63 	{MBX_UNREG_LOGIN, "UNREG_LOGIN"},
64 	{MBX_READ_LA, "READ_LA"},
65 	{MBX_CLEAR_LA, "CLEAR_LA"},
66 	{MBX_DUMP_MEMORY, "DUMP_MEMORY"},
67 	{MBX_DUMP_CONTEXT, "DUMP_CONTEXT"},
68 	{MBX_RUN_DIAGS, "RUN_DIAGS"},
69 	{MBX_RESTART, "RESTART"},
70 	{MBX_UPDATE_CFG, "UPDATE_CFG"},
71 	{MBX_DOWN_LOAD, "DOWN_LOAD"},
72 	{MBX_DEL_LD_ENTRY, "DEL_LD_ENTRY"},
73 	{MBX_RUN_PROGRAM, "RUN_PROGRAM"},
74 	{MBX_SET_MASK, "SET_MASK"},
75 	{MBX_SET_VARIABLE, "SET_VARIABLE"},
76 	{MBX_UNREG_D_ID, "UNREG_D_ID"},
77 	{MBX_KILL_BOARD, "KILL_BOARD"},
78 	{MBX_CONFIG_FARP, "CONFIG_FARP"},
79 	{MBX_LOAD_AREA, "LOAD_AREA"},
80 	{MBX_RUN_BIU_DIAG64, "RUN_BIU_DIAG64"},
81 	{MBX_CONFIG_PORT, "CONFIG_PORT"},
82 	{MBX_READ_SPARM64, "READ_SPARM64"},
83 	{MBX_READ_RPI64, "READ_RPI64"},
84 	{MBX_CONFIG_MSI, "CONFIG_MSI"},
85 	{MBX_CONFIG_MSIX, "CONFIG_MSIX"},
86 	{MBX_REG_LOGIN64, "REG_LOGIN64"},
87 	{MBX_READ_LA64, "READ_LA64"},
88 	{MBX_FLASH_WR_ULA, "FLASH_WR_ULA"},
89 	{MBX_SET_DEBUG, "SET_DEBUG"},
90 	{MBX_GET_DEBUG, "GET_DEBUG"},
91 	{MBX_LOAD_EXP_ROM, "LOAD_EXP_ROM"},
92 	{MBX_BEACON, "BEACON"},
93 	{MBX_CONFIG_HBQ, "CONFIG_HBQ"},	/* SLI3 */
94 	{MBX_REG_VPI, "REG_VPI"},	/* NPIV */
95 	{MBX_UNREG_VPI, "UNREG_VPI"},	/* NPIV */
96 	{MBX_ASYNC_EVENT, "ASYNC_EVENT"},
97 	{MBX_HEARTBEAT, "HEARTBEAT"},
98 	{MBX_READ_EVENT_LOG_STATUS, "READ_EVENT_LOG_STATUS"},
99 	{MBX_READ_EVENT_LOG, "READ_EVENT_LOG"},
100 	{MBX_WRITE_EVENT_LOG, "WRITE_EVENT_LOG"},
101 	{MBX_NV_LOG, "NV_LOG"},
102 	{MBX_PORT_CAPABILITIES, "PORT_CAPABILITIES"},
103 	{MBX_IOV_CONTROL, "IOV_CONTROL"},
104 	{MBX_IOV_MBX, "IOV_MBX"},
105 	{MBX_SLI_CONFIG, "SLI_CONFIG"},
106 	{MBX_REQUEST_FEATURES, "REQUEST_FEATURES"},
107 	{MBX_RESUME_RPI, "RESUME_RPI"},
108 	{MBX_REG_VFI, "REG_VFI"},
109 	{MBX_REG_FCFI, "REG_FCFI"},
110 	{MBX_UNREG_VFI, "UNREG_VFI"},
111 	{MBX_UNREG_FCFI, "UNREG_FCFI"},
112 	{MBX_INIT_VFI, "INIT_VFI"},
113 	{MBX_INIT_VPI, "INIT_VPI"}
114 };	/* emlxs_mb_cmd_table */
115 
116 
117 /*
118  * emlxs_mb_resetport  Issue a Port Reset mailbox command
119  */
120 /*ARGSUSED*/
121 extern void
122 emlxs_mb_resetport(emlxs_hba_t *hba, MAILBOXQ *mbq)
123 {
124 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
125 
126 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
127 	mbq->nonembed = NULL;
128 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
129 
130 	/*
131 	 * Signifies an embedded command
132 	 */
133 	mb->un.varSLIConfig.be.embedded = 1;
134 
135 	mb->mbxCommand = MBX_SLI_CONFIG;
136 	mb->mbxOwner = OWN_HOST;
137 	mb->un.varSLIConfig.be.payload_length = IOCTL_HEADER_SZ;
138 	mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem =
139 	    IOCTL_SUBSYSTEM_COMMON;
140 	mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode = COMMON_OPCODE_RESET;
141 	mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0;
142 	mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length = 0;
143 
144 	return;
145 
146 } /* emlxs_mb_resetport() */
147 
148 
149 /*
150  * emlxs_mb_request_features  Issue a REQUEST FEATURES mailbox command
151  */
152 /*ARGSUSED*/
153 extern void
154 emlxs_mb_request_features(emlxs_hba_t *hba, MAILBOXQ *mbq)
155 {
156 	emlxs_config_t	*cfg = &CFG;
157 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
158 
159 	hba->flag &= ~FC_NPIV_ENABLED;
160 
161 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
162 	mbq->nonembed = NULL;
163 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
164 
165 	mb->mbxCommand = MBX_REQUEST_FEATURES;
166 	mb->mbxOwner = OWN_HOST;
167 	mb->un.varReqFeatures.featuresRequested |=
168 	    SLI4_FEATURE_FCP_INITIATOR;
169 
170 	if (cfg[CFG_NPIV_ENABLE].current) {
171 		mb->un.varReqFeatures.featuresRequested |=
172 		    SLI4_FEATURE_NPIV;
173 	}
174 
175 } /* emlxs_mb_request_features() */
176 
177 
178 /*
179  * emlxs_mb_resume_rpi  Issue a RESUME_RPI mailbox command
180  */
181 /*ARGSUSED*/
182 extern int
183 emlxs_mb_resume_rpi(emlxs_hba_t *hba, emlxs_buf_t *sbp, uint16_t rpi)
184 {
185 	MAILBOX4 *mb;
186 	MAILBOXQ *mbq;
187 	uint32_t rval;
188 
189 	(void) emlxs_sli4_find_rpi(hba, rpi);
190 
191 	if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))) {
192 		return (1);
193 	}
194 	mb = (MAILBOX4 *)mbq;
195 
196 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
197 	mbq->nonembed = NULL;
198 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
199 	mbq->sbp = (uint8_t *)sbp;
200 
201 	mb->mbxCommand = MBX_RESUME_RPI;
202 	mb->mbxOwner = OWN_HOST;
203 	mb->un.varResumeRPI.EventTag = hba->link_event_tag;
204 	mb->un.varResumeRPI.RPI = rpi;
205 
206 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0);
207 	if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) {
208 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
209 	}
210 	return (rval);
211 
212 } /* emlxs_mb_resume_rpi() */
213 
214 
215 /*ARGSUSED*/
216 extern void
217 emlxs_mb_noop(emlxs_hba_t *hba, MAILBOXQ *mbq)
218 {
219 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
220 	IOCTL_COMMON_NOP *nop;
221 
222 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
223 	mbq->nonembed = NULL;
224 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
225 
226 	/*
227 	 * Signifies an embedded command
228 	 */
229 	mb->un.varSLIConfig.be.embedded = 1;
230 
231 	mb->mbxCommand = MBX_SLI_CONFIG;
232 	mb->mbxOwner = OWN_HOST;
233 	mb->un.varSLIConfig.be.payload_length = sizeof (IOCTL_COMMON_NOP) +
234 	    IOCTL_HEADER_SZ;
235 	mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem =
236 	    IOCTL_SUBSYSTEM_COMMON;
237 	mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode = COMMON_OPCODE_NOP;
238 	mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0;
239 	mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length =
240 	    sizeof (IOCTL_COMMON_NOP);
241 	nop = (IOCTL_COMMON_NOP *)&mb->un.varSLIConfig.payload;
242 	nop->params.request.context = -1;
243 
244 	return;
245 
246 } /* emlxs_mb_noop() */
247 
248 
249 /*ARGSUSED*/
250 extern int
251 emlxs_mbext_noop(emlxs_hba_t *hba, MAILBOXQ *mbq)
252 {
253 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
254 	IOCTL_COMMON_NOP *nop;
255 	MATCHMAP *mp;
256 	mbox_req_hdr_t	*hdr_req;
257 
258 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
259 
260 	if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF, 1)) == 0) {
261 		return (1);
262 	}
263 	/*
264 	 * Save address for completion
265 	 * Signifies a non-embedded command
266 	 */
267 	mb->un.varSLIConfig.be.embedded = 0;
268 	mbq->nonembed = (uint8_t *)mp;
269 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
270 
271 	mb->mbxCommand = MBX_SLI_CONFIG;
272 	mb->mbxOwner = OWN_HOST;
273 
274 	hdr_req = (mbox_req_hdr_t *)mp->virt;
275 	hdr_req->subsystem = IOCTL_SUBSYSTEM_COMMON;
276 	hdr_req->opcode = COMMON_OPCODE_NOP;
277 	hdr_req->timeout = 0;
278 	hdr_req->req_length = sizeof (IOCTL_COMMON_NOP);
279 	nop = (IOCTL_COMMON_NOP *)(hdr_req + 1);
280 	nop->params.request.context = -1;
281 
282 	return (0);
283 
284 } /* emlxs_mbext_noop() */
285 
286 
287 int
288 emlxs_cmpl_read_fcf_table(void *arg1, MAILBOXQ *mbq)
289 {
290 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
291 	emlxs_port_t *port = &PPORT;
292 	mbox_rsp_hdr_t	*hdr_rsp;
293 	IOCTL_FCOE_READ_FCF_TABLE *fcf;
294 	FCF_RECORD_t *fcfrec;
295 	FCFIobj_t *fcfp;
296 	MAILBOX4 *mb;
297 	MATCHMAP *mp;
298 	MAILBOXQ *fcfmbq;
299 	uint32_t i, *iptr;
300 	uint16_t s, *sptr;
301 	int rc;
302 
303 	mb = (MAILBOX4 *)mbq;
304 	mp = (MATCHMAP *)mbq->nonembed;
305 	hdr_rsp = (mbox_rsp_hdr_t *)mp->virt;
306 
307 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
308 	    "CMPL read fcf: stats: %x %x %x",
309 	    mb->mbxStatus, hdr_rsp->status, hdr_rsp->extra_status);
310 
311 	if (mb->mbxStatus || hdr_rsp->status) {
312 		/* Wait for FCF found async event */
313 		return (0);
314 	}
315 
316 	/*
317 	 * Only support 1 FCF for now, so we don't need to walk
318 	 * thru the FCF table.
319 	 */
320 	fcf = (IOCTL_FCOE_READ_FCF_TABLE *)(hdr_rsp + 1);
321 	fcfrec = &fcf->params.response.fcf_entry[0];
322 
323 	/* Fix up data in FCF record */
324 	BE_SWAP32_BUFFER(&fcfrec->fabric_name_identifier[0], 8);
325 	BE_SWAP32_BUFFER(&fcfrec->switch_name_identifier[0], 8);
326 	BE_SWAP32_BUFFER(&fcfrec->vlan_bitmap[0], 512);
327 	iptr = (uint32_t *)&fcfrec->fcf_mac_address_hi[0];
328 	i = *iptr;
329 	*iptr = BE_SWAP32(i);
330 	sptr = (uint16_t *)&fcfrec->fcf_mac_address_low[0];
331 	s = *sptr;
332 	*sptr = BE_SWAP16(s);
333 #ifdef EMLXS_BIG_ENDIAN
334 	i = fcfrec->fc_map[0];
335 	fcfrec->fc_map[0] = fcfrec->fc_map[2];
336 	fcfrec->fc_map[2] = i;
337 #endif
338 
339 	/* Assign a FCFI object for the fcf_index */
340 	fcfp = emlxs_sli4_assign_fcfi(hba, fcfrec);
341 	if (!fcfp) {
342 		return (0);
343 	}
344 	fcfp->EventTag = fcf->params.response.event_tag;
345 
346 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
347 	    "CMPL read fcf: info: x%x x%x",
348 	    fcfp->EventTag, fcf->params.response.next_valid_fcf_index);
349 
350 	if (emlxs_sli4_bind_fcfi(hba)) {
351 		/*
352 		 * In this phase, if we successfully bind to just
353 		 * 1 FCFI we are done.
354 		 */
355 		return (0);
356 	}
357 
358 	if (fcf->params.response.next_valid_fcf_index == 0xffff) {
359 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
360 		    "Waiting for a valid FCF to be discovered");
361 		return (0);
362 	}
363 
364 	/* Get the next one */
365 	if (!(fcfmbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))) {
366 		return (0);
367 	}
368 	rc =  emlxs_mbext_read_fcf_table(hba, fcfmbq,
369 	    fcf->params.response.next_valid_fcf_index);
370 	if (rc == 0) {
371 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)fcfmbq);
372 		return (0);
373 	}
374 
375 	rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, fcfmbq, MBX_NOWAIT, 0);
376 	if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
377 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)fcfmbq);
378 	}
379 	return (0);
380 } /* emlxs_cmpl_read_fcf_table() */
381 
382 
383 extern int
384 emlxs_mbext_read_fcf_table(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t index)
385 {
386 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
387 	IOCTL_FCOE_READ_FCF_TABLE *fcf;
388 	MATCHMAP *mp;
389 	mbox_req_hdr_t	*hdr_req;
390 
391 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
392 
393 	if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF, 1)) == 0) {
394 		return (0);
395 	}
396 	/*
397 	 * Save address for completion
398 	 * Signifies a non-embedded command
399 	 */
400 	mb->un.varSLIConfig.be.embedded = 0;
401 	mbq->nonembed = (uint8_t *)mp;
402 	mbq->mbox_cmpl = emlxs_cmpl_read_fcf_table;
403 
404 	mb->mbxCommand = MBX_SLI_CONFIG;
405 	mb->mbxOwner = OWN_HOST;
406 
407 	hdr_req = (mbox_req_hdr_t *)mp->virt;
408 	hdr_req->subsystem = IOCTL_SUBSYSTEM_FCOE;
409 	hdr_req->opcode = FCOE_OPCODE_READ_FCF_TABLE;
410 	hdr_req->timeout = 0;
411 	hdr_req->req_length = sizeof (IOCTL_FCOE_READ_FCF_TABLE);
412 	fcf = (IOCTL_FCOE_READ_FCF_TABLE *)(hdr_req + 1);
413 	fcf->params.request.fcf_index = index;
414 
415 	return (1);
416 
417 } /* emlxs_mbext_read_fcf_table() */
418 
419 
420 int
421 emlxs_cmpl_add_fcf_table(void *arg1, MAILBOXQ *mbq)
422 {
423 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
424 	emlxs_port_t *port = &PPORT;
425 	MAILBOX4 *mb;
426 	MAILBOXQ *mq;
427 	MATCHMAP *mp;
428 	mbox_rsp_hdr_t *hdr_rsp;
429 	uint32_t rc;
430 
431 	mb = (MAILBOX4 *)mbq;
432 	mp = (MATCHMAP *)mbq->nonembed;
433 
434 	hdr_rsp = (mbox_rsp_hdr_t *)mp->virt;
435 
436 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
437 	    "CMPL add fcf: stats: %x %x %x",
438 	    mb->mbxStatus, hdr_rsp->status, hdr_rsp->extra_status);
439 
440 	if (mbq->nonembed) {
441 		(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mbq->nonembed);
442 		mbq->nonembed = 0;
443 	}
444 
445 	if (mb->mbxStatus) {
446 		/* In nonFIP mode, FCF Entries are persistent */
447 		if (!hdr_rsp->status ||
448 		    (hdr_rsp->status != MGMT_STATUS_FCF_IN_USE)) {
449 			return (0);
450 		}
451 	}
452 
453 	/*
454 	 * Now that we have a fcf table entry, read it back
455 	 * to fall into the normal link up processing.
456 	 */
457 	if (!(mq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))) {
458 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
459 		    "CMPL add fcf: Cannot alloc mbox");
460 		return (0);
461 	}
462 	rc =  emlxs_mbext_read_fcf_table(hba, mq, -1);
463 
464 	if (rc == 0) {
465 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
466 		    "CMPL add fcf: Cannot build read fcf mbox");
467 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mq);
468 		return (0);
469 	}
470 
471 	rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mq, MBX_NOWAIT, 0);
472 	if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
473 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
474 		    "CMPL add fcf: Cannot issue read fcf mbox");
475 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mq);
476 	}
477 	return (0);
478 } /* emlxs_cmpl_add_fcf_table() */
479 
480 
481 extern int
482 emlxs_mbext_add_fcf_table(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t index)
483 {
484 	emlxs_port_t *port = &PPORT;
485 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
486 	IOCTL_FCOE_ADD_FCF_TABLE *fcf;
487 	FCF_RECORD_t *fcfrec;
488 	MATCHMAP *mp;
489 	mbox_req_hdr_t	*hdr_req;
490 
491 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
492 
493 	if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF, 1)) == 0) {
494 		return (0);
495 	}
496 	/*
497 	 * Save address for completion
498 	 * Signifies a non-embedded command
499 	 */
500 	mb->un.varSLIConfig.be.embedded = 0;
501 	mbq->nonembed = (uint8_t *)mp;
502 	mbq->mbox_cmpl = emlxs_cmpl_add_fcf_table;
503 
504 	mb->mbxCommand = MBX_SLI_CONFIG;
505 	mb->mbxOwner = OWN_HOST;
506 
507 	hdr_req = (mbox_req_hdr_t *)mp->virt;
508 	hdr_req->subsystem = IOCTL_SUBSYSTEM_FCOE;
509 	hdr_req->opcode = FCOE_OPCODE_ADD_FCF_TABLE;
510 	hdr_req->timeout = 0;
511 	hdr_req->req_length = sizeof (IOCTL_FCOE_ADD_FCF_TABLE);
512 	fcf = (IOCTL_FCOE_ADD_FCF_TABLE *)(hdr_req + 1);
513 	fcf->params.request.fcf_index = index;
514 
515 	fcfrec = &fcf->params.request.fcf_entry;
516 	fcfrec->max_recv_size = EMLXS_FCOE_MAX_RCV_SZ;
517 	fcfrec->fka_adv_period = 0;
518 	fcfrec->fip_priority = 128;
519 #ifdef EMLXS_BIG_ENDIAN
520 	fcfrec->fcf_mac_address_hi[0] = FCOE_FCF_MAC3;
521 	fcfrec->fcf_mac_address_hi[1] = FCOE_FCF_MAC2;
522 	fcfrec->fcf_mac_address_hi[2] = FCOE_FCF_MAC1;
523 	fcfrec->fcf_mac_address_hi[3] = FCOE_FCF_MAC0;
524 	fcfrec->fcf_mac_address_low[0] = FCOE_FCF_MAC5;
525 	fcfrec->fcf_mac_address_low[1] = FCOE_FCF_MAC4;
526 	fcfrec->fc_map[0] = hba->sli.sli4.cfgFCOE.FCMap[2];
527 	fcfrec->fc_map[1] = hba->sli.sli4.cfgFCOE.FCMap[1];
528 	fcfrec->fc_map[2] = hba->sli.sli4.cfgFCOE.FCMap[0];
529 #endif
530 #ifdef EMLXS_LITTLE_ENDIAN
531 	fcfrec->fcf_mac_address_hi[0] = FCOE_FCF_MAC0;
532 	fcfrec->fcf_mac_address_hi[1] = FCOE_FCF_MAC1;
533 	fcfrec->fcf_mac_address_hi[2] = FCOE_FCF_MAC2;
534 	fcfrec->fcf_mac_address_hi[3] = FCOE_FCF_MAC3;
535 	fcfrec->fcf_mac_address_low[0] = FCOE_FCF_MAC4;
536 	fcfrec->fcf_mac_address_low[1] = FCOE_FCF_MAC5;
537 	fcfrec->fc_map[0] = hba->sli.sli4.cfgFCOE.FCMap[0];
538 	fcfrec->fc_map[1] = hba->sli.sli4.cfgFCOE.FCMap[1];
539 	fcfrec->fc_map[2] = hba->sli.sli4.cfgFCOE.FCMap[2];
540 #endif
541 
542 	if (hba->sli.sli4.cfgFCOE.fip_flags & TLV_FCOE_VLAN) {
543 		uint16_t i;
544 		uint8_t bitmap[512];
545 
546 		bzero((void *) bitmap, 512);
547 		i = hba->sli.sli4.cfgFCOE.VLanId;
548 		bitmap[i / 8] = (1 << (i % 8));
549 		BE_SWAP32_BCOPY(bitmap, fcfrec->vlan_bitmap, 512);
550 	}
551 
552 	fcfrec->fcf_valid = 1;
553 	fcfrec->fcf_available = 1;
554 
555 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
556 	    "ADD FCF %d: av: %x %x ste %x macp %x "
557 	    "addr: %02x:%02x:%02x:%02x:%02x:%02x",
558 	    fcfrec->fcf_index,
559 	    fcfrec->fcf_available,
560 	    fcfrec->fcf_valid,
561 	    fcfrec->fcf_state,
562 	    fcfrec->mac_address_provider,
563 	    fcfrec->fcf_mac_address_hi[0],
564 	    fcfrec->fcf_mac_address_hi[1],
565 	    fcfrec->fcf_mac_address_hi[2],
566 	    fcfrec->fcf_mac_address_hi[3],
567 	    fcfrec->fcf_mac_address_low[0],
568 	    fcfrec->fcf_mac_address_low[1]);
569 	return (1);
570 
571 } /* emlxs_mbext_add_fcf_table() */
572 
573 
574 /*ARGSUSED*/
575 extern void
576 emlxs_mb_eq_create(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t num)
577 {
578 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
579 	IOCTL_COMMON_EQ_CREATE *qp;
580 	uint64_t	addr;
581 
582 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
583 	mbq->nonembed = NULL;
584 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
585 
586 	/*
587 	 * Signifies an embedded command
588 	 */
589 	mb->un.varSLIConfig.be.embedded = 1;
590 
591 	mb->mbxCommand = MBX_SLI_CONFIG;
592 	mb->mbxOwner = OWN_HOST;
593 	mb->un.varSLIConfig.be.payload_length =
594 	    sizeof (IOCTL_COMMON_EQ_CREATE) + IOCTL_HEADER_SZ;
595 	mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem =
596 	    IOCTL_SUBSYSTEM_COMMON;
597 	mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode = COMMON_OPCODE_EQ_CREATE;
598 	mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0;
599 	mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length =
600 	    sizeof (IOCTL_COMMON_EQ_CREATE);
601 	qp = (IOCTL_COMMON_EQ_CREATE *)&mb->un.varSLIConfig.payload;
602 
603 	/* 1024 * 4 bytes = 4K */
604 	qp->params.request.EQContext.Count = EQ_ELEMENT_COUNT_1024;
605 	qp->params.request.EQContext.Valid = 1;
606 	qp->params.request.EQContext.NoDelay = 0;
607 	qp->params.request.EQContext.DelayMult = EQ_DELAY_MULT;
608 
609 	addr = hba->sli.sli4.eq[num].addr.phys;
610 	qp->params.request.NumPages = 1;
611 	qp->params.request.Pages[0].addrLow = PADDR_LO(addr);
612 	qp->params.request.Pages[0].addrHigh = PADDR_HI(addr);
613 
614 	return;
615 
616 } /* emlxs_mb_eq_create() */
617 
618 
619 /*ARGSUSED*/
620 extern void
621 emlxs_mb_cq_create(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t num)
622 {
623 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
624 	IOCTL_COMMON_CQ_CREATE *qp;
625 	uint64_t	addr;
626 
627 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
628 	mbq->nonembed = NULL;
629 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
630 
631 	/*
632 	 * Signifies an embedded command
633 	 */
634 	mb->un.varSLIConfig.be.embedded = 1;
635 
636 	mb->mbxCommand = MBX_SLI_CONFIG;
637 	mb->mbxOwner = OWN_HOST;
638 	mb->un.varSLIConfig.be.payload_length =
639 	    sizeof (IOCTL_COMMON_CQ_CREATE) + IOCTL_HEADER_SZ;
640 	mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem =
641 	    IOCTL_SUBSYSTEM_COMMON;
642 	mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode = COMMON_OPCODE_CQ_CREATE;
643 	mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0;
644 	mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length =
645 	    sizeof (IOCTL_COMMON_CQ_CREATE);
646 	qp = (IOCTL_COMMON_CQ_CREATE *)&mb->un.varSLIConfig.payload;
647 
648 	/* 256 * 16 bytes = 4K */
649 	qp->params.request.CQContext.Count = CQ_ELEMENT_COUNT_256;
650 	qp->params.request.CQContext.EQId = hba->sli.sli4.cq[num].eqid;
651 	qp->params.request.CQContext.Valid = 1;
652 	qp->params.request.CQContext.Eventable = 1;
653 	qp->params.request.CQContext.NoDelay = 0;
654 
655 	addr = hba->sli.sli4.cq[num].addr.phys;
656 	qp->params.request.NumPages = 1;
657 	qp->params.request.Pages[0].addrLow = PADDR_LO(addr);
658 	qp->params.request.Pages[0].addrHigh = PADDR_HI(addr);
659 
660 	return;
661 
662 } /* emlxs_mb_cq_create() */
663 
664 
665 /*ARGSUSED*/
666 extern void
667 emlxs_mb_wq_create(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t num)
668 {
669 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
670 	IOCTL_FCOE_WQ_CREATE *qp;
671 	uint64_t addr;
672 	int i;
673 
674 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
675 	mbq->nonembed = NULL;
676 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
677 
678 	/*
679 	 * Signifies an embedded command
680 	 */
681 	mb->un.varSLIConfig.be.embedded = 1;
682 
683 	mb->mbxCommand = MBX_SLI_CONFIG;
684 	mb->mbxOwner = OWN_HOST;
685 	mb->un.varSLIConfig.be.payload_length =
686 	    sizeof (IOCTL_FCOE_WQ_CREATE) + IOCTL_HEADER_SZ;
687 	mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem =
688 	    IOCTL_SUBSYSTEM_FCOE;
689 	mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode = FCOE_OPCODE_WQ_CREATE;
690 	mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0;
691 	mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length =
692 	    sizeof (IOCTL_FCOE_WQ_CREATE);
693 
694 	addr = hba->sli.sli4.wq[num].addr.phys;
695 	qp = (IOCTL_FCOE_WQ_CREATE *)&mb->un.varSLIConfig.payload;
696 
697 	qp->params.request.CQId = hba->sli.sli4.wq[num].cqid;
698 
699 	qp->params.request.NumPages = EMLXS_NUM_WQ_PAGES;
700 	for (i = 0; i < EMLXS_NUM_WQ_PAGES; i++) {
701 		qp->params.request.Pages[i].addrLow = PADDR_LO(addr);
702 		qp->params.request.Pages[i].addrHigh = PADDR_HI(addr);
703 		addr += 4096;
704 	}
705 
706 	return;
707 
708 } /* emlxs_mb_wq_create() */
709 
710 
711 /*ARGSUSED*/
712 extern void
713 emlxs_mb_rq_create(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t num)
714 {
715 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
716 	IOCTL_FCOE_RQ_CREATE *qp;
717 	uint64_t	addr;
718 
719 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
720 	mbq->nonembed = NULL;
721 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
722 
723 	/*
724 	 * Signifies an embedded command
725 	 */
726 	mb->un.varSLIConfig.be.embedded = 1;
727 
728 	mb->mbxCommand = MBX_SLI_CONFIG;
729 	mb->mbxOwner = OWN_HOST;
730 	mb->un.varSLIConfig.be.payload_length =
731 	    sizeof (IOCTL_FCOE_RQ_CREATE) + IOCTL_HEADER_SZ;
732 	mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem =
733 	    IOCTL_SUBSYSTEM_FCOE;
734 	mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode = FCOE_OPCODE_RQ_CREATE;
735 	mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0;
736 	mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length =
737 	    sizeof (IOCTL_FCOE_RQ_CREATE);
738 	addr = hba->sli.sli4.rq[num].addr.phys;
739 
740 	qp = (IOCTL_FCOE_RQ_CREATE *)&mb->un.varSLIConfig.payload;
741 
742 	qp->params.request.RQContext.RQSize	= RQ_DEPTH_EXPONENT;
743 	qp->params.request.RQContext.BufferSize	= RQB_DATA_SIZE;
744 	qp->params.request.RQContext.CQIdRecv	= hba->sli.sli4.rq[num].cqid;
745 
746 	qp->params.request.NumPages = 1;
747 	qp->params.request.Pages[0].addrLow = PADDR_LO(addr);
748 	qp->params.request.Pages[0].addrHigh = PADDR_HI(addr);
749 
750 	return;
751 
752 } /* emlxs_mb_rq_create() */
753 
754 
755 /*ARGSUSED*/
756 extern void
757 emlxs_mb_mq_create(emlxs_hba_t *hba, MAILBOXQ *mbq)
758 {
759 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
760 	IOCTL_COMMON_MQ_CREATE *qp;
761 	uint64_t	addr;
762 
763 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
764 	mbq->nonembed = NULL;
765 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
766 
767 	/*
768 	 * Signifies an embedded command
769 	 */
770 	mb->un.varSLIConfig.be.embedded = 1;
771 
772 	mb->mbxCommand = MBX_SLI_CONFIG;
773 	mb->mbxOwner = OWN_HOST;
774 	mb->un.varSLIConfig.be.payload_length =
775 	    sizeof (IOCTL_COMMON_MQ_CREATE) + IOCTL_HEADER_SZ;
776 	mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem =
777 	    IOCTL_SUBSYSTEM_COMMON;
778 	mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode = COMMON_OPCODE_MQ_CREATE;
779 	mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0;
780 	mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length =
781 	    sizeof (IOCTL_COMMON_MQ_CREATE);
782 
783 	addr = hba->sli.sli4.mq.addr.phys;
784 	qp = (IOCTL_COMMON_MQ_CREATE *)&mb->un.varSLIConfig.payload;
785 
786 	qp->params.request.MQContext.Size = MQ_ELEMENT_COUNT_16;
787 	qp->params.request.MQContext.Valid = 1;
788 	qp->params.request.MQContext.CQId = hba->sli.sli4.mq.cqid;
789 
790 	qp->params.request.NumPages = 1;
791 	qp->params.request.Pages[0].addrLow = PADDR_LO(addr);
792 	qp->params.request.Pages[0].addrHigh = PADDR_HI(addr);
793 
794 	return;
795 
796 } /* emlxs_mb_mq_create() */
797 
798 
799 static int
800 emlxs_cmpl_reg_fcfi(void *arg1, MAILBOXQ *mbq)
801 {
802 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
803 	emlxs_port_t *port = &PPORT;
804 	FCFIobj_t *fcfp;
805 	VFIobj_t *vfip;
806 	RPIobj_t *rpip;
807 	MAILBOX4 *mb;
808 
809 	mb = (MAILBOX4 *)mbq;
810 	fcfp = (FCFIobj_t *)mbq->context;
811 
812 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
813 	    "CMPL reg fcfi: status: %x", mb->mbxStatus);
814 
815 	if (mb->mbxStatus) {
816 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
817 		    "Unable to register FCFI for FCFI %d index %d",
818 		    mb->un.varRegFCFI.FCFI, mb->un.varRegFCFI.InfoIndex);
819 		(void) emlxs_sli4_free_fcfi(hba, fcfp);
820 		return (0);
821 	}
822 
823 	fcfp->state |= RESOURCE_FCFI_REG;
824 
825 	if (!fcfp->fcf_vfi) {
826 		vfip = emlxs_sli4_alloc_vfi(hba, fcfp);
827 		if (!vfip) {
828 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
829 			    "Unable to alloc VFI for Fabric, fcf index %d",
830 			    fcfp->FCF_index);
831 			(void) emlxs_sli4_free_fcfi(hba, fcfp);
832 			return (0);
833 		}
834 		fcfp->fcf_vfi = vfip;
835 	}
836 
837 	if (!fcfp->fcf_vpi) {
838 		fcfp->fcf_vpi = port;
839 		port->VFIp = fcfp->fcf_vfi;
840 		port->VFIp->outstandingVPIs++;
841 	}
842 
843 	rpip = &fcfp->scratch_rpi;
844 	rpip->state = RESOURCE_ALLOCATED;
845 	rpip->VPIp = fcfp->fcf_vpi;
846 	rpip->RPI = 0xffff;
847 	rpip->index = 0xffff;
848 
849 	fcfp->FCFI = mb->un.varRegFCFI.FCFI;
850 
851 	/* Declare the linkup here */
852 	if (!(fcfp->state & RESOURCE_FCFI_DISC)) {
853 		fcfp->state |= RESOURCE_FCFI_DISC;
854 		emlxs_linkup(hba);
855 	}
856 	return (0);
857 
858 } /* emlxs_cmpl_reg_fcfi() */
859 
860 
861 /*ARGSUSED*/
862 extern void
863 emlxs_mb_reg_fcfi(emlxs_hba_t *hba, MAILBOXQ *mbq, FCFIobj_t *fcfp)
864 {
865 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
866 
867 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
868 
869 	mb->mbxCommand = MBX_REG_FCFI;
870 	mb->mbxOwner = OWN_HOST;
871 	mb->un.varRegFCFI.FCFI = 0; /* FCFI will be returned by firmware */
872 	mb->un.varRegFCFI.InfoIndex = fcfp->FCF_index;
873 
874 	mb->un.varRegFCFI.RQId0 = hba->sli.sli4.rq[EMLXS_FCFI_RQ0_INDEX].qid;
875 	mb->un.varRegFCFI.Id0_rctl_mask = EMLXS_FCFI_RQ0_RMASK;
876 	mb->un.varRegFCFI.Id0_rctl = EMLXS_FCFI_RQ0_RCTL;
877 	mb->un.varRegFCFI.Id0_type_mask = EMLXS_FCFI_RQ0_TMASK;
878 	mb->un.varRegFCFI.Id0_type = EMLXS_FCFI_RQ0_TYPE;
879 
880 	mb->un.varRegFCFI.RQId1 = 0xffff;
881 	mb->un.varRegFCFI.RQId2 = 0xffff;
882 	mb->un.varRegFCFI.RQId3 = 0xffff;
883 
884 	if (fcfp->state & RESOURCE_FCFI_VLAN_ID) {
885 		mb->un.varRegFCFI.vv = 1;
886 		mb->un.varRegFCFI.vlanTag = fcfp->vlan_id;
887 	}
888 
889 	/* Ignore the fcf record and force FPMA */
890 	mb->un.varRegFCFI.mam = EMLXS_REG_FCFI_MAM_FPMA;
891 
892 	mbq->mbox_cmpl = emlxs_cmpl_reg_fcfi;
893 	mbq->context = (uint8_t *)fcfp;
894 	return;
895 
896 } /* emlxs_mb_reg_fcfi() */
897 
898 
899 /* SLI4 */
900 static int
901 emlxs_cmpl_unreg_fcfi(void *arg1, MAILBOXQ *mbq)
902 {
903 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
904 	emlxs_port_t *port = &PPORT;
905 	FCFIobj_t *fcfp;
906 	MAILBOX4 *mb;
907 
908 	mb = (MAILBOX4 *)mbq;
909 	fcfp = (FCFIobj_t *)mbq->context;
910 
911 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
912 	    "CMPL unreg fcfi: status: %x", mb->mbxStatus);
913 
914 	if (mb->mbxStatus) {
915 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
916 		    "Unable to unregister FCFI %d index %d",
917 		    fcfp->FCFI, fcfp->FCF_index);
918 	}
919 
920 	(void) emlxs_sli4_free_fcfi(hba, fcfp);
921 
922 	/* Make sure link is declared down */
923 	emlxs_linkdown(hba);
924 
925 	return (0);
926 
927 } /* emlxs_cmpl_unreg_fcfi() */
928 
929 
930 /* ARGSUSED */
931 extern int
932 emlxs_mb_unreg_fcfi(emlxs_hba_t *hba, FCFIobj_t *fcfp)
933 {
934 	MAILBOXQ *mbq;
935 	MAILBOX4 *mb;
936 	uint32_t rval;
937 
938 	mutex_enter(&EMLXS_PORT_LOCK);
939 
940 	if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))) {
941 		mutex_exit(&EMLXS_PORT_LOCK);
942 		return (1);
943 	}
944 	mb = (MAILBOX4 *)mbq;
945 	mutex_exit(&EMLXS_PORT_LOCK);
946 
947 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
948 
949 	mb->mbxCommand = MBX_UNREG_FCFI;
950 	mb->mbxOwner = OWN_HOST;
951 	mb->un.varUnRegFCFI.FCFI = fcfp->FCFI;
952 
953 	mbq->mbox_cmpl = emlxs_cmpl_unreg_fcfi;
954 	mbq->context = (uint8_t *)fcfp;
955 	fcfp->fcf_vfi = NULL;
956 	fcfp->fcf_vpi = NULL;
957 
958 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0);
959 	if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) {
960 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
961 	}
962 
963 	return (0);
964 
965 } /* emlxs_mb_unreg_fcfi() */
966 
967 
968 int
969 emlxs_mb_cmpl_reg_vfi(void *arg1, MAILBOXQ *mbq)
970 {
971 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
972 	emlxs_port_t *port = &PPORT;
973 	MAILBOX4 *mb;
974 	MAILBOXQ *mbox;
975 	MATCHMAP *mp;
976 	NODELIST *ndlp;
977 	emlxs_port_t *vport;
978 	VFIobj_t *vfip;
979 	uint8_t *wwn;
980 	volatile SERV_PARM *sp;
981 	int32_t i;
982 	uint32_t ldid;
983 	emlxs_vvl_fmt_t vvl;
984 
985 	mb = (MAILBOX4 *)mbq;
986 	if (mb->mbxStatus) {
987 		EMLXS_MSGF(EMLXS_CONTEXT,
988 		    &emlxs_sli_detail_msg,
989 		    "REG_VFI failed. status=x%x", mb->mbxStatus);
990 		return (0);
991 	}
992 
993 	vport = (emlxs_port_t *)mbq->context;
994 	vfip = vport->VFIp;
995 	vfip->state |= RESOURCE_VFI_REG;
996 
997 	if (mb->un.varRegVFI4.vp) {
998 		vport->flag |= EMLXS_PORT_REGISTERED;
999 	}
1000 
1001 	mp = (MATCHMAP *)mbq->bp;
1002 	if (!mp) {
1003 		return (0);
1004 	}
1005 	sp = (volatile SERV_PARM *)mp->virt;
1006 
1007 	ldid = FABRIC_DID;
1008 	ndlp = emlxs_node_find_did(port, ldid);
1009 
1010 	if (!ndlp) {
1011 		/* Attempt to create a node */
1012 		if ((ndlp = (NODELIST *)emlxs_mem_get(hba, MEM_NLP, 0))) {
1013 			ndlp->nlp_Rpi = 0xffff;
1014 			ndlp->nlp_DID = ldid;
1015 
1016 			bcopy((uint8_t *)sp, (uint8_t *)&ndlp->sparm,
1017 			    sizeof (SERV_PARM));
1018 
1019 			bcopy((uint8_t *)&sp->nodeName,
1020 			    (uint8_t *)&ndlp->nlp_nodename,
1021 			    sizeof (NAME_TYPE));
1022 
1023 			bcopy((uint8_t *)&sp->portName,
1024 			    (uint8_t *)&ndlp->nlp_portname,
1025 			    sizeof (NAME_TYPE));
1026 
1027 			ndlp->nlp_active = 1;
1028 			ndlp->nlp_flag[hba->channel_ct]  |= NLP_CLOSED;
1029 			ndlp->nlp_flag[hba->channel_els] |= NLP_CLOSED;
1030 			ndlp->nlp_flag[hba->channel_fcp] |= NLP_CLOSED;
1031 			ndlp->nlp_flag[hba->channel_ip]  |= NLP_CLOSED;
1032 
1033 			/* Add the node */
1034 			emlxs_node_add(port, ndlp);
1035 
1036 			/* Open the node */
1037 			emlxs_node_open(port, ndlp, hba->channel_ct);
1038 			emlxs_node_open(port, ndlp, hba->channel_els);
1039 			emlxs_node_open(port, ndlp, hba->channel_ip);
1040 			emlxs_node_open(port, ndlp, hba->channel_fcp);
1041 		} else {
1042 			wwn = (uint8_t *)&sp->portName;
1043 			EMLXS_MSGF(EMLXS_CONTEXT,
1044 			    &emlxs_node_create_failed_msg,
1045 			    "Unable to allocate node. did=%06x "
1046 			    "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x",
1047 			    ldid, wwn[0], wwn[1], wwn[2],
1048 			    wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
1049 
1050 			return (0);
1051 		}
1052 	} else {
1053 		mutex_enter(&EMLXS_PORT_LOCK);
1054 
1055 		ndlp->nlp_Rpi = 0xffff;
1056 		ndlp->nlp_DID = ldid;
1057 
1058 		bcopy((uint8_t *)sp,
1059 		    (uint8_t *)&ndlp->sparm, sizeof (SERV_PARM));
1060 
1061 		bcopy((uint8_t *)&sp->nodeName,
1062 		    (uint8_t *)&ndlp->nlp_nodename, sizeof (NAME_TYPE));
1063 
1064 		bcopy((uint8_t *)&sp->portName,
1065 		    (uint8_t *)&ndlp->nlp_portname, sizeof (NAME_TYPE));
1066 
1067 		wwn = (uint8_t *)&ndlp->nlp_portname;
1068 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_update_msg,
1069 		    "node=%p did=%06x rpi=%x "
1070 		    "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x",
1071 		    ndlp, ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0],
1072 		    wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
1073 
1074 		mutex_exit(&EMLXS_PORT_LOCK);
1075 
1076 		/* Open the node */
1077 		emlxs_node_open(port, ndlp, hba->channel_ct);
1078 		emlxs_node_open(port, ndlp, hba->channel_els);
1079 		emlxs_node_open(port, ndlp, hba->channel_ip);
1080 		emlxs_node_open(port, ndlp, hba->channel_fcp);
1081 	}
1082 
1083 	bzero((char *)&vvl, sizeof (emlxs_vvl_fmt_t));
1084 
1085 	if (sp->VALID_VENDOR_VERSION) {
1086 
1087 		bcopy((caddr_t *)&sp->vendorVersion[0],
1088 		    (caddr_t *)&vvl, sizeof (emlxs_vvl_fmt_t));
1089 
1090 		vvl.un0.word0 = LE_SWAP32(vvl.un0.word0);
1091 		vvl.un1.word1 = LE_SWAP32(vvl.un1.word1);
1092 
1093 		if ((vvl.un0.w0.oui == 0x0000C9) &&
1094 		    (vvl.un1.w1.vport)) {
1095 			ndlp->nlp_fcp_info |= NLP_EMLX_VPORT;
1096 		}
1097 	}
1098 
1099 	if ((mbox = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))) {
1100 		/* If link not already down then */
1101 		/* declare it down now */
1102 		if (emlxs_mb_read_sparam(hba, mbox) == 0) {
1103 			emlxs_mb_put(hba, mbox);
1104 		} else {
1105 			(void) emlxs_mem_put(hba, MEM_MBOX,
1106 			    (uint8_t *)mbox);
1107 		}
1108 	}
1109 
1110 	/* Since this is a fabric login */
1111 	/*
1112 	 * If NPIV Fabric support has just been established on
1113 	 * the physical port, then notify the vports of the
1114 	 * link up
1115 	 */
1116 	EMLXS_STATE_CHANGE_LOCKED(hba, FC_READY);
1117 	if ((hba->flag & FC_NPIV_ENABLED) &&
1118 	    (hba->flag & FC_NPIV_SUPPORTED)) {
1119 		/* Skip the physical port */
1120 		for (i = 1; i < MAX_VPORTS; i++) {
1121 			vport = &VPORT(i);
1122 
1123 			if (!(vport->flag & EMLXS_PORT_BOUND) ||
1124 			    !(vport->flag & EMLXS_PORT_ENABLE)) {
1125 				continue;
1126 			}
1127 
1128 			emlxs_port_online(vport);
1129 		}
1130 	}
1131 
1132 #ifdef SFCT_SUPPORT
1133 	if (mbq->sbp && ((emlxs_buf_t *)mbq->sbp)->fct_cmd) {
1134 		emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)mbq->sbp;
1135 
1136 		if (cmd_sbp->fct_state == EMLXS_FCT_REG_PENDING) {
1137 			mbq->sbp = NULL;
1138 
1139 			mutex_enter(&EMLXS_PKT_LOCK);
1140 			cmd_sbp->node = ndlp;
1141 			cv_broadcast(&EMLXS_PKT_CV);
1142 			mutex_exit(&EMLXS_PKT_LOCK);
1143 		}
1144 	}
1145 #endif /* SFCT_SUPPORT */
1146 	return (0);
1147 
1148 } /* emlxs_mb_cmpl_reg_vfi */
1149 
1150 
1151 /*ARGSUSED*/
1152 extern int
1153 emlxs_mb_reg_vfi(emlxs_hba_t *hba, MAILBOXQ *mbq, VFIobj_t *vfip,
1154     emlxs_port_t *port)
1155 {
1156 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
1157 	FCFIobj_t *fcfp;
1158 	MATCHMAP *mp;
1159 
1160 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
1161 
1162 	if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF, 1)) == 0) {
1163 		return (0);
1164 	}
1165 
1166 	mb->mbxCommand = MBX_REG_VFI;
1167 	mb->mbxOwner = OWN_HOST;
1168 	mb->un.varRegVFI4.vfi = vfip->VFI;
1169 	if (!(port->flag & EMLXS_PORT_REGISTERED)) {
1170 		mb->un.varRegVFI4.vp = 1;
1171 		mb->un.varRegVFI4.vpi = port->vpi + hba->vpi_base;
1172 	}
1173 	fcfp = vfip->FCFIp;
1174 	mb->un.varRegVFI4.fcfi = fcfp->FCFI;
1175 	mb->un.varRegVFI4.sid = port->did;
1176 
1177 	/* in ms */
1178 	mb->un.varRegVFI4.edtov = fcfp->fcf_sparam.cmn.e_d_tov;
1179 
1180 	/* Convert to seconds */
1181 	mb->un.varRegVFI4.ratov = (fcfp->fcf_sparam.cmn.w2.r_a_tov +
1182 	    999) / 1000;
1183 
1184 	mb->un.varRegVFI4.bde.tus.f.bdeSize = sizeof (SERV_PARM);
1185 	mb->un.varRegVFI4.bde.addrHigh = PADDR_HI(mp->phys);
1186 	mb->un.varRegVFI4.bde.addrLow = PADDR_LO(mp->phys);
1187 	bcopy((uint32_t *)&fcfp->fcf_sparam,
1188 	    (uint32_t *)mp->virt, sizeof (SERV_PARM));
1189 
1190 	mbq->mbox_cmpl = emlxs_mb_cmpl_reg_vfi;
1191 
1192 	/*
1193 	 * save address for completion
1194 	 */
1195 	mbq->bp = (uint8_t *)mp;
1196 	mbq->context = (uint8_t *)port;
1197 	return (1);
1198 
1199 } /* emlxs_mb_reg_vfi() */
1200 
1201 
1202 /*ARGSUSED*/
1203 extern int
1204 emlxs_mb_unreg_vfi(emlxs_hba_t *hba, VFIobj_t *vfip)
1205 {
1206 	FCFIobj_t *fcfp;
1207 	MAILBOX4 *mb;
1208 	MAILBOXQ *mbq;
1209 	uint32_t rval;
1210 
1211 	mutex_enter(&EMLXS_PORT_LOCK);
1212 	if (!(vfip->state & RESOURCE_VFI_REG)) {
1213 		mutex_exit(&EMLXS_PORT_LOCK);
1214 		return (1);
1215 
1216 	}
1217 	if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))) {
1218 		mutex_exit(&EMLXS_PORT_LOCK);
1219 		return (1);
1220 	}
1221 
1222 	vfip->state &= ~RESOURCE_VFI_REG;
1223 	mutex_exit(&EMLXS_PORT_LOCK);
1224 
1225 	mb = (MAILBOX4 *)mbq->mbox;
1226 
1227 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
1228 
1229 	mb->mbxCommand = MBX_UNREG_VFI;
1230 	mb->mbxOwner = OWN_HOST;
1231 
1232 	mb->un.varUnRegVFI4.vfi = vfip->VFI;
1233 
1234 	mbq->mbox_cmpl = NULL;
1235 
1236 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0);
1237 	if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) {
1238 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
1239 	}
1240 
1241 	fcfp = vfip->FCFIp;
1242 	if (vfip == fcfp->fcf_vfi) {
1243 		fcfp->fcf_vfi = NULL;
1244 	}
1245 	emlxs_sli4_free_vfi(hba, vfip);
1246 	return (1);
1247 
1248 } /* emlxs_mb_unreg_vfi() */
1249 
1250 
1251 /*ARGSUSED*/
1252 extern void
1253 emlxs_mb_async_event(emlxs_hba_t *hba, MAILBOXQ *mbq)
1254 {
1255 	MAILBOX *mb = (MAILBOX *)mbq;
1256 
1257 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
1258 
1259 	mb->mbxCommand = MBX_ASYNC_EVENT;
1260 	mb->mbxOwner = OWN_HOST;
1261 	mb->un.varWords[0] = hba->channel_els;
1262 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
1263 
1264 	return;
1265 
1266 } /* emlxs_mb_async_event() */
1267 
1268 
1269 /*ARGSUSED*/
1270 extern void
1271 emlxs_mb_heartbeat(emlxs_hba_t *hba, MAILBOXQ *mbq)
1272 {
1273 	MAILBOX *mb = (MAILBOX *)mbq;
1274 
1275 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
1276 
1277 	mb->mbxCommand = MBX_HEARTBEAT;
1278 	mb->mbxOwner = OWN_HOST;
1279 	mbq->mbox_cmpl = NULL; /* no cmpl needed for hbeat */
1280 
1281 	return;
1282 
1283 } /* emlxs_mb_heartbeat() */
1284 
1285 
1286 #ifdef MSI_SUPPORT
1287 
1288 /*ARGSUSED*/
1289 extern void
1290 emlxs_mb_config_msi(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t *intr_map,
1291     uint32_t intr_count)
1292 {
1293 	MAILBOX *mb = (MAILBOX *)mbq;
1294 	uint32_t i;
1295 	uint32_t mask;
1296 
1297 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
1298 
1299 	mb->mbxCommand = MBX_CONFIG_MSI;
1300 
1301 	/* Set the default message id to zero */
1302 	mb->un.varCfgMSI.defaultPresent = 1;
1303 	mb->un.varCfgMSI.defaultMessageNumber = 0;
1304 
1305 	for (i = 1; i < intr_count; i++) {
1306 		mask = intr_map[i];
1307 
1308 		mb->un.varCfgMSI.attConditions |= mask;
1309 
1310 #ifdef EMLXS_BIG_ENDIAN
1311 		if (mask & HA_R0ATT) {
1312 			mb->un.varCfgMSI.messageNumberByHA[3] = i;
1313 		}
1314 		if (mask & HA_R1ATT) {
1315 			mb->un.varCfgMSI.messageNumberByHA[7] = i;
1316 		}
1317 		if (mask & HA_R2ATT) {
1318 			mb->un.varCfgMSI.messageNumberByHA[11] = i;
1319 		}
1320 		if (mask & HA_R3ATT) {
1321 			mb->un.varCfgMSI.messageNumberByHA[15] = i;
1322 		}
1323 		if (mask & HA_LATT) {
1324 			mb->un.varCfgMSI.messageNumberByHA[29] = i;
1325 		}
1326 		if (mask & HA_MBATT) {
1327 			mb->un.varCfgMSI.messageNumberByHA[30] = i;
1328 		}
1329 		if (mask & HA_ERATT) {
1330 			mb->un.varCfgMSI.messageNumberByHA[31] = i;
1331 		}
1332 #endif	/* EMLXS_BIG_ENDIAN */
1333 
1334 #ifdef EMLXS_LITTLE_ENDIAN
1335 		/* Accounts for half word swap of LE architecture */
1336 		if (mask & HA_R0ATT) {
1337 			mb->un.varCfgMSI.messageNumberByHA[2] = i;
1338 		}
1339 		if (mask & HA_R1ATT) {
1340 			mb->un.varCfgMSI.messageNumberByHA[6] = i;
1341 		}
1342 		if (mask & HA_R2ATT) {
1343 			mb->un.varCfgMSI.messageNumberByHA[10] = i;
1344 		}
1345 		if (mask & HA_R3ATT) {
1346 			mb->un.varCfgMSI.messageNumberByHA[14] = i;
1347 		}
1348 		if (mask & HA_LATT) {
1349 			mb->un.varCfgMSI.messageNumberByHA[28] = i;
1350 		}
1351 		if (mask & HA_MBATT) {
1352 			mb->un.varCfgMSI.messageNumberByHA[31] = i;
1353 		}
1354 		if (mask & HA_ERATT) {
1355 			mb->un.varCfgMSI.messageNumberByHA[30] = i;
1356 		}
1357 #endif	/* EMLXS_LITTLE_ENDIAN */
1358 	}
1359 
1360 	mb->mbxOwner = OWN_HOST;
1361 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
1362 
1363 	return;
1364 
1365 } /* emlxs_mb_config_msi() */
1366 
1367 
1368 /*ARGSUSED*/
1369 extern void
1370 emlxs_mb_config_msix(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t *intr_map,
1371     uint32_t intr_count)
1372 {
1373 	MAILBOX *mb = (MAILBOX *)mbq;
1374 	uint32_t i;
1375 	uint32_t mask;
1376 
1377 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
1378 
1379 	mb->mbxCommand = MBX_CONFIG_MSIX;
1380 
1381 	/* Set the default message id to zero */
1382 	mb->un.varCfgMSIX.defaultPresent = 1;
1383 	mb->un.varCfgMSIX.defaultMessageNumber = 0;
1384 
1385 	for (i = 1; i < intr_count; i++) {
1386 		mask = intr_map[i];
1387 
1388 		mb->un.varCfgMSIX.attConditions1 |= mask;
1389 
1390 #ifdef EMLXS_BIG_ENDIAN
1391 		if (mask & HA_R0ATT) {
1392 			mb->un.varCfgMSIX.messageNumberByHA[3] = i;
1393 		}
1394 		if (mask & HA_R1ATT) {
1395 			mb->un.varCfgMSIX.messageNumberByHA[7] = i;
1396 		}
1397 		if (mask & HA_R2ATT) {
1398 			mb->un.varCfgMSIX.messageNumberByHA[11] = i;
1399 		}
1400 		if (mask & HA_R3ATT) {
1401 			mb->un.varCfgMSIX.messageNumberByHA[15] = i;
1402 		}
1403 		if (mask & HA_LATT) {
1404 			mb->un.varCfgMSIX.messageNumberByHA[29] = i;
1405 		}
1406 		if (mask & HA_MBATT) {
1407 			mb->un.varCfgMSIX.messageNumberByHA[30] = i;
1408 		}
1409 		if (mask & HA_ERATT) {
1410 			mb->un.varCfgMSIX.messageNumberByHA[31] = i;
1411 		}
1412 #endif	/* EMLXS_BIG_ENDIAN */
1413 
1414 #ifdef EMLXS_LITTLE_ENDIAN
1415 		/* Accounts for word swap of LE architecture */
1416 		if (mask & HA_R0ATT) {
1417 			mb->un.varCfgMSIX.messageNumberByHA[0] = i;
1418 		}
1419 		if (mask & HA_R1ATT) {
1420 			mb->un.varCfgMSIX.messageNumberByHA[4] = i;
1421 		}
1422 		if (mask & HA_R2ATT) {
1423 			mb->un.varCfgMSIX.messageNumberByHA[8] = i;
1424 		}
1425 		if (mask & HA_R3ATT) {
1426 			mb->un.varCfgMSIX.messageNumberByHA[12] = i;
1427 		}
1428 		if (mask & HA_LATT) {
1429 			mb->un.varCfgMSIX.messageNumberByHA[30] = i;
1430 		}
1431 		if (mask & HA_MBATT) {
1432 			mb->un.varCfgMSIX.messageNumberByHA[29] = i;
1433 		}
1434 		if (mask & HA_ERATT) {
1435 			mb->un.varCfgMSIX.messageNumberByHA[28] = i;
1436 		}
1437 #endif	/* EMLXS_LITTLE_ENDIAN */
1438 	}
1439 
1440 	mb->mbxOwner = OWN_HOST;
1441 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
1442 
1443 	return;
1444 
1445 } /* emlxs_mb_config_msix() */
1446 
1447 
1448 #endif	/* MSI_SUPPORT */
1449 
1450 
1451 /*ARGSUSED*/
1452 extern void
1453 emlxs_mb_reset_ring(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t ringno)
1454 {
1455 	MAILBOX *mb = (MAILBOX *)mbq;
1456 
1457 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
1458 
1459 	mb->mbxCommand = MBX_RESET_RING;
1460 	mb->un.varRstRing.ring_no = ringno;
1461 	mb->mbxOwner = OWN_HOST;
1462 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
1463 
1464 	return;
1465 
1466 } /* emlxs_mb_reset_ring() */
1467 
1468 
1469 /*ARGSUSED*/
1470 extern void
1471 emlxs_mb_dump_vpd(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t offset)
1472 {
1473 
1474 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1475 		MAILBOX4 *mb = (MAILBOX4 *)mbq;
1476 
1477 		/* Clear the local dump_region */
1478 		bzero(hba->sli.sli4.dump_region.virt,
1479 		    hba->sli.sli4.dump_region.size);
1480 
1481 		bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
1482 
1483 		mb->mbxCommand = MBX_DUMP_MEMORY;
1484 		mb->un.varDmp4.type = DMP_NV_PARAMS;
1485 		mb->un.varDmp4.entry_index = offset;
1486 		mb->un.varDmp4.region_id = DMP_VPD_REGION;
1487 
1488 		mb->un.varDmp4.available_cnt = hba->sli.sli4.dump_region.size;
1489 		mb->un.varDmp4.addrHigh =
1490 		    PADDR_HI(hba->sli.sli4.dump_region.phys);
1491 		mb->un.varDmp4.addrLow =
1492 		    PADDR_LO(hba->sli.sli4.dump_region.phys);
1493 		mb->un.varDmp4.rsp_cnt = 0;
1494 
1495 		mb->mbxOwner = OWN_HOST;
1496 
1497 	} else {
1498 		MAILBOX *mb = (MAILBOX *)mbq;
1499 
1500 		bzero((void *)mb, MAILBOX_CMD_BSIZE);
1501 
1502 		mb->mbxCommand = MBX_DUMP_MEMORY;
1503 		mb->un.varDmp.cv = 1;
1504 		mb->un.varDmp.type = DMP_NV_PARAMS;
1505 		mb->un.varDmp.entry_index = offset;
1506 		mb->un.varDmp.region_id = DMP_VPD_REGION;
1507 
1508 		/* limited by mailbox size */
1509 		mb->un.varDmp.word_cnt = DMP_VPD_DUMP_WCOUNT;
1510 
1511 		mb->un.varDmp.co = 0;
1512 		mb->un.varDmp.resp_offset = 0;
1513 		mb->mbxOwner = OWN_HOST;
1514 	}
1515 
1516 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
1517 
1518 } /* emlxs_mb_dump_vpd() */
1519 
1520 
1521 /*ARGSUSED*/
1522 extern void
1523 emlxs_mb_dump_fcoe(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t offset)
1524 {
1525 	MAILBOX4 *mb = (MAILBOX4 *)mbq;
1526 
1527 	if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) {
1528 		return;
1529 	}
1530 	/* Clear the local dump_region */
1531 	bzero(hba->sli.sli4.dump_region.virt,
1532 	    hba->sli.sli4.dump_region.size);
1533 
1534 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
1535 
1536 	mb->mbxCommand = MBX_DUMP_MEMORY;
1537 	mb->un.varDmp4.type = DMP_NV_PARAMS;
1538 	mb->un.varDmp4.entry_index = offset;
1539 	mb->un.varDmp4.region_id = DMP_FCOE_REGION;
1540 
1541 	mb->un.varDmp4.available_cnt = hba->sli.sli4.dump_region.size;
1542 	mb->un.varDmp4.addrHigh =
1543 	    PADDR_HI(hba->sli.sli4.dump_region.phys);
1544 	mb->un.varDmp4.addrLow =
1545 	    PADDR_LO(hba->sli.sli4.dump_region.phys);
1546 	mb->un.varDmp4.rsp_cnt = 0;
1547 
1548 	mb->mbxOwner = OWN_HOST;
1549 
1550 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
1551 
1552 } /* emlxs_mb_dump_fcoe() */
1553 
1554 
1555 /*ARGSUSED*/
1556 extern void
1557 emlxs_mb_dump(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t offset, uint32_t words)
1558 {
1559 
1560 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1561 		MAILBOX4 *mb = (MAILBOX4 *)mbq;
1562 
1563 		/* Clear the local dump_region */
1564 		bzero(hba->sli.sli4.dump_region.virt,
1565 		    hba->sli.sli4.dump_region.size);
1566 
1567 		bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
1568 
1569 		mb->mbxCommand = MBX_DUMP_MEMORY;
1570 		mb->un.varDmp4.type = DMP_MEM_REG;
1571 		mb->un.varDmp4.entry_index = offset;
1572 		mb->un.varDmp4.region_id = 0;
1573 
1574 		mb->un.varDmp4.available_cnt = min((words*4),
1575 		    hba->sli.sli4.dump_region.size);
1576 		mb->un.varDmp4.addrHigh =
1577 		    PADDR_HI(hba->sli.sli4.dump_region.phys);
1578 		mb->un.varDmp4.addrLow =
1579 		    PADDR_LO(hba->sli.sli4.dump_region.phys);
1580 		mb->un.varDmp4.rsp_cnt = 0;
1581 
1582 		mb->mbxOwner = OWN_HOST;
1583 
1584 	} else {
1585 
1586 		MAILBOX *mb = (MAILBOX *)mbq;
1587 
1588 		bzero((void *)mb, MAILBOX_CMD_BSIZE);
1589 
1590 		mb->mbxCommand = MBX_DUMP_MEMORY;
1591 		mb->un.varDmp.type = DMP_MEM_REG;
1592 		mb->un.varDmp.word_cnt = words;
1593 		mb->un.varDmp.base_adr = offset;
1594 
1595 		mb->un.varDmp.co = 0;
1596 		mb->un.varDmp.resp_offset = 0;
1597 		mb->mbxOwner = OWN_HOST;
1598 	}
1599 
1600 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
1601 
1602 	return;
1603 
1604 } /* emlxs_mb_dump() */
1605 
1606 
1607 /*
1608  *  emlxs_mb_read_nv  Issue a READ NVPARAM mailbox command
1609  */
1610 /*ARGSUSED*/
1611 extern void
1612 emlxs_mb_read_nv(emlxs_hba_t *hba, MAILBOXQ *mbq)
1613 {
1614 	MAILBOX *mb = (MAILBOX *)mbq;
1615 
1616 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
1617 
1618 	mb->mbxCommand = MBX_READ_NV;
1619 	mb->mbxOwner = OWN_HOST;
1620 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
1621 
1622 } /* emlxs_mb_read_nv() */
1623 
1624 
1625 /*
1626  * emlxs_mb_read_rev  Issue a READ REV mailbox command
1627  */
1628 /*ARGSUSED*/
1629 extern void
1630 emlxs_mb_read_rev(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t v3)
1631 {
1632 	MAILBOX *mb = (MAILBOX *)mbq;
1633 
1634 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1635 		bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
1636 		mbq->nonembed = NULL;
1637 	} else {
1638 		bzero((void *)mb, MAILBOX_CMD_BSIZE);
1639 
1640 		mb->un.varRdRev.cv = 1;
1641 
1642 		if (v3) {
1643 			mb->un.varRdRev.cv3 = 1;
1644 		}
1645 	}
1646 
1647 	mb->mbxCommand = MBX_READ_REV;
1648 	mb->mbxOwner = OWN_HOST;
1649 	mbq->mbox_cmpl = NULL;
1650 
1651 } /* emlxs_mb_read_rev() */
1652 
1653 
1654 /*
1655  * emlxs_mb_run_biu_diag  Issue a RUN_BIU_DIAG mailbox command
1656  */
1657 /*ARGSUSED*/
1658 extern uint32_t
1659 emlxs_mb_run_biu_diag(emlxs_hba_t *hba, MAILBOXQ *mbq, uint64_t out,
1660     uint64_t in)
1661 {
1662 	MAILBOX *mb = (MAILBOX *)mbq;
1663 
1664 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
1665 
1666 	mb->mbxCommand = MBX_RUN_BIU_DIAG64;
1667 	mb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize = MEM_ELSBUF_SIZE;
1668 	mb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = PADDR_HI(out);
1669 	mb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = PADDR_LO(out);
1670 	mb->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeSize = MEM_ELSBUF_SIZE;
1671 	mb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = PADDR_HI(in);
1672 	mb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = PADDR_LO(in);
1673 	mb->mbxOwner = OWN_HOST;
1674 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
1675 
1676 	return (0);
1677 } /* emlxs_mb_run_biu_diag() */
1678 
1679 
1680 /* This should only be called with active MBX_NOWAIT mailboxes */
1681 void
1682 emlxs_mb_retry(emlxs_hba_t *hba, MAILBOXQ *mbq)
1683 {
1684 	MAILBOX	*mb;
1685 	MAILBOX	*mbox;
1686 	int rc;
1687 
1688 	mbox = (MAILBOX *)emlxs_mem_get(hba, MEM_MBOX, 1);
1689 	if (!mbox) {
1690 		return;
1691 	}
1692 	mb = (MAILBOX *)mbq;
1693 	bcopy((uint8_t *)mb, (uint8_t *)mbox, MAILBOX_CMD_BSIZE);
1694 	mbox->mbxOwner = OWN_HOST;
1695 	mbox->mbxStatus = 0;
1696 
1697 	mutex_enter(&EMLXS_PORT_LOCK);
1698 
1699 	HBASTATS.MboxCompleted++;
1700 
1701 	if (mb->mbxStatus != 0) {
1702 		HBASTATS.MboxError++;
1703 	} else {
1704 		HBASTATS.MboxGood++;
1705 	}
1706 
1707 	hba->mbox_mbq = 0;
1708 	hba->mbox_queue_flag = 0;
1709 
1710 	mutex_exit(&EMLXS_PORT_LOCK);
1711 
1712 	rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_NOWAIT, 0);
1713 	if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
1714 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbox);
1715 	}
1716 	return;
1717 
1718 } /* emlxs_mb_retry() */
1719 
1720 
1721 int
1722 emlxs_cmpl_read_la(void *arg1, MAILBOXQ *mbq)
1723 {
1724 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
1725 	emlxs_port_t *port = &PPORT;
1726 	MAILBOX *mb;
1727 	MAILBOXQ *mbox;
1728 	MATCHMAP *mp;
1729 	READ_LA_VAR la;
1730 	int i;
1731 	uint32_t  control;
1732 
1733 	mb = (MAILBOX *)mbq;
1734 	if (mb->mbxStatus) {
1735 		if (mb->mbxStatus == MBXERR_NO_RESOURCES) {
1736 			control = mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize;
1737 			if (control == 0) {
1738 				(void) emlxs_mb_read_la(hba, mbq);
1739 			}
1740 			emlxs_mb_retry(hba, mbq);
1741 			return (1);
1742 		}
1743 		/* Enable Link Attention interrupts */
1744 		mutex_enter(&EMLXS_PORT_LOCK);
1745 
1746 		if (!(hba->sli.sli3.hc_copy & HC_LAINT_ENA)) {
1747 			hba->sli.sli3.hc_copy |= HC_LAINT_ENA;
1748 			WRITE_CSR_REG(hba, FC_HC_REG(hba),
1749 			    hba->sli.sli3.hc_copy);
1750 #ifdef FMA_SUPPORT
1751 			/* Access handle validation */
1752 			EMLXS_CHK_ACC_HANDLE(hba,
1753 			    hba->sli.sli3.csr_acc_handle);
1754 #endif  /* FMA_SUPPORT */
1755 		}
1756 
1757 		mutex_exit(&EMLXS_PORT_LOCK);
1758 		return (0);
1759 	}
1760 	bcopy((uint32_t *)((char *)mb + sizeof (uint32_t)),
1761 	    (uint32_t *)&la, sizeof (READ_LA_VAR));
1762 
1763 	mp = (MATCHMAP *)mbq->bp;
1764 	if (mp) {
1765 		bcopy((caddr_t)mp->virt, (caddr_t)port->alpa_map, 128);
1766 	} else {
1767 		bzero((caddr_t)port->alpa_map, 128);
1768 	}
1769 
1770 	if (la.attType == AT_LINK_UP) {
1771 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_linkup_atten_msg,
1772 		    "tag=%d -> %d  ALPA=%x",
1773 		    (uint32_t)hba->link_event_tag,
1774 		    (uint32_t)la.eventTag,
1775 		    (uint32_t)la.granted_AL_PA);
1776 	} else {
1777 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_linkdown_atten_msg,
1778 		    "tag=%d -> %d  ALPA=%x",
1779 		    (uint32_t)hba->link_event_tag,
1780 		    (uint32_t)la.eventTag,
1781 		    (uint32_t)la.granted_AL_PA);
1782 	}
1783 
1784 	if (la.pb) {
1785 		hba->flag |= FC_BYPASSED_MODE;
1786 	} else {
1787 		hba->flag &= ~FC_BYPASSED_MODE;
1788 	}
1789 
1790 	if (hba->link_event_tag == la.eventTag) {
1791 		HBASTATS.LinkMultiEvent++;
1792 	} else if (hba->link_event_tag + 1 < la.eventTag) {
1793 		HBASTATS.LinkMultiEvent++;
1794 
1795 		/* Make sure link is declared down */
1796 		emlxs_linkdown(hba);
1797 	}
1798 
1799 	hba->link_event_tag = la.eventTag;
1800 	port->lip_type = 0;
1801 
1802 	/* If link not already up then declare it up now */
1803 	if ((la.attType == AT_LINK_UP) && (hba->state < FC_LINK_UP)) {
1804 
1805 #ifdef MENLO_SUPPORT
1806 		if ((hba->model_info.device_id == PCI_DEVICE_ID_LP21000_M) &&
1807 		    (hba->flag & (FC_ILB_MODE | FC_ELB_MODE))) {
1808 			la.topology = TOPOLOGY_LOOP;
1809 			la.granted_AL_PA = 0;
1810 			port->alpa_map[0] = 1;
1811 			port->alpa_map[1] = 0;
1812 			la.lipType = LT_PORT_INIT;
1813 		}
1814 #endif /* MENLO_SUPPORT */
1815 		/* Save the linkspeed */
1816 		hba->linkspeed = la.UlnkSpeed;
1817 
1818 		/* Check for old model adapters that only */
1819 		/* supported 1Gb */
1820 		if ((hba->linkspeed == 0) &&
1821 		    (hba->model_info.chip & EMLXS_DRAGONFLY_CHIP)) {
1822 			hba->linkspeed = LA_1GHZ_LINK;
1823 		}
1824 
1825 		if ((hba->topology = la.topology) == TOPOLOGY_LOOP) {
1826 			port->did = la.granted_AL_PA;
1827 			port->lip_type = la.lipType;
1828 			if (hba->flag & FC_SLIM2_MODE) {
1829 				i = la.un.lilpBde64.tus.f.bdeSize;
1830 			} else {
1831 				i = la.un.lilpBde.bdeSize;
1832 			}
1833 
1834 			if (i == 0) {
1835 				port->alpa_map[0] = 0;
1836 			} else {
1837 				uint8_t *alpa_map;
1838 				uint32_t j;
1839 
1840 				/* Check number of devices in map */
1841 				if (port->alpa_map[0] > 127) {
1842 					port->alpa_map[0] = 127;
1843 				}
1844 
1845 				alpa_map = (uint8_t *)port->alpa_map;
1846 
1847 				EMLXS_MSGF(EMLXS_CONTEXT,
1848 				    &emlxs_link_atten_msg,
1849 				    "alpa_map: %d device(s):      "
1850 				    "%02x %02x %02x %02x %02x %02x "
1851 				    "%02x", alpa_map[0], alpa_map[1],
1852 				    alpa_map[2], alpa_map[3],
1853 				    alpa_map[4], alpa_map[5],
1854 				    alpa_map[6], alpa_map[7]);
1855 
1856 				for (j = 8; j <= alpa_map[0]; j += 8) {
1857 					EMLXS_MSGF(EMLXS_CONTEXT,
1858 					    &emlxs_link_atten_msg,
1859 					    "alpa_map:             "
1860 					    "%02x %02x %02x %02x %02x "
1861 					    "%02x %02x %02x",
1862 					    alpa_map[j],
1863 					    alpa_map[j + 1],
1864 					    alpa_map[j + 2],
1865 					    alpa_map[j + 3],
1866 					    alpa_map[j + 4],
1867 					    alpa_map[j + 5],
1868 					    alpa_map[j + 6],
1869 					    alpa_map[j + 7]);
1870 				}
1871 			}
1872 		}
1873 #ifdef MENLO_SUPPORT
1874 		/* Check if Menlo maintenance mode is enabled */
1875 		if (hba->model_info.device_id ==
1876 		    PCI_DEVICE_ID_LP21000_M) {
1877 			if (la.mm == 1) {
1878 				EMLXS_MSGF(EMLXS_CONTEXT,
1879 				    &emlxs_link_atten_msg,
1880 				    "Maintenance Mode enabled.");
1881 
1882 				mutex_enter(&EMLXS_PORT_LOCK);
1883 				hba->flag |= FC_MENLO_MODE;
1884 				mutex_exit(&EMLXS_PORT_LOCK);
1885 
1886 				mutex_enter(&EMLXS_LINKUP_LOCK);
1887 				cv_broadcast(&EMLXS_LINKUP_CV);
1888 				mutex_exit(&EMLXS_LINKUP_LOCK);
1889 			} else {
1890 				EMLXS_MSGF(EMLXS_CONTEXT,
1891 				    &emlxs_link_atten_msg,
1892 				    "Maintenance Mode disabled.");
1893 			}
1894 
1895 			/* Check FCoE attention bit */
1896 			if (la.fa == 1) {
1897 				emlxs_thread_spawn(hba,
1898 				    emlxs_fcoe_attention_thread,
1899 				    NULL, NULL);
1900 			}
1901 		}
1902 #endif /* MENLO_SUPPORT */
1903 
1904 		if ((mbox = (MAILBOXQ *)emlxs_mem_get(hba,
1905 		    MEM_MBOX, 1))) {
1906 			/* This should turn on DELAYED ABTS for */
1907 			/* ELS timeouts */
1908 			emlxs_mb_set_var(hba, mbox, 0x00052198, 0x1);
1909 
1910 			emlxs_mb_put(hba, mbox);
1911 		}
1912 
1913 		if ((mbox = (MAILBOXQ *)emlxs_mem_get(hba,
1914 		    MEM_MBOX, 1))) {
1915 			/* If link not already down then */
1916 			/* declare it down now */
1917 			if (emlxs_mb_read_sparam(hba, mbox) == 0) {
1918 				emlxs_mb_put(hba, mbox);
1919 			} else {
1920 				(void) emlxs_mem_put(hba, MEM_MBOX,
1921 				    (uint8_t *)mbox);
1922 			}
1923 		}
1924 
1925 		if ((mbox = (MAILBOXQ *)emlxs_mem_get(hba,
1926 		    MEM_MBOX, 1))) {
1927 			emlxs_mb_config_link(hba, mbox);
1928 
1929 			emlxs_mb_put(hba, mbox);
1930 		}
1931 
1932 		/* Declare the linkup here */
1933 		emlxs_linkup(hba);
1934 	}
1935 
1936 	/* If link not already down then declare it down now */
1937 	else if (la.attType == AT_LINK_DOWN) {
1938 		/* Make sure link is declared down */
1939 		emlxs_linkdown(hba);
1940 	}
1941 
1942 	/* Enable Link attention interrupt */
1943 	mutex_enter(&EMLXS_PORT_LOCK);
1944 
1945 	if (!(hba->sli.sli3.hc_copy & HC_LAINT_ENA)) {
1946 		hba->sli.sli3.hc_copy |= HC_LAINT_ENA;
1947 		WRITE_CSR_REG(hba, FC_HC_REG(hba), hba->sli.sli3.hc_copy);
1948 #ifdef FMA_SUPPORT
1949 		/* Access handle validation */
1950 		EMLXS_CHK_ACC_HANDLE(hba, hba->sli.sli3.csr_acc_handle);
1951 #endif  /* FMA_SUPPORT */
1952 	}
1953 
1954 	mutex_exit(&EMLXS_PORT_LOCK);
1955 
1956 	/* Log the link event */
1957 	emlxs_log_link_event(port);
1958 	return (0);
1959 
1960 } /* emlxs_cmpl_read_la() */
1961 
1962 
1963 /*
1964  *  emlxs_mb_read_la  Issue a READ LA mailbox command
1965  */
1966 extern uint32_t
1967 emlxs_mb_read_la(emlxs_hba_t *hba, MAILBOXQ *mbq)
1968 {
1969 	MAILBOX *mb = (MAILBOX *)mbq;
1970 	MATCHMAP *mp;
1971 
1972 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
1973 
1974 	if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF, 1)) == 0) {
1975 		mb->mbxCommand = MBX_READ_LA64;
1976 
1977 		return (1);
1978 	}
1979 
1980 	mb->mbxCommand = MBX_READ_LA64;
1981 	mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize = 128;
1982 	mb->un.varReadLA.un.lilpBde64.addrHigh = PADDR_HI(mp->phys);
1983 	mb->un.varReadLA.un.lilpBde64.addrLow = PADDR_LO(mp->phys);
1984 	mb->mbxOwner = OWN_HOST;
1985 	mbq->mbox_cmpl = emlxs_cmpl_read_la;
1986 
1987 	/*
1988 	 * save address for completion
1989 	 */
1990 	((MAILBOXQ *)mb)->bp = (uint8_t *)mp;
1991 
1992 	return (0);
1993 
1994 } /* emlxs_mb_read_la() */
1995 
1996 
1997 int
1998 emlxs_cmpl_clear_la(void *arg1, MAILBOXQ *mbq)
1999 {
2000 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
2001 	emlxs_port_t *port = &PPORT;
2002 	MAILBOX *mb;
2003 	MAILBOXQ *mbox;
2004 	emlxs_port_t *vport;
2005 	uint32_t la_enable;
2006 	int i, rc;
2007 
2008 	mb = (MAILBOX *)mbq;
2009 	if (mb->mbxStatus) {
2010 		la_enable = 1;
2011 
2012 		if (mb->mbxStatus == 0x1601) {
2013 			/* Get a buffer which will be used for */
2014 			/* mailbox commands */
2015 			if ((mbox = (MAILBOXQ *)emlxs_mem_get(hba,
2016 			    MEM_MBOX, 1))) {
2017 				/* Get link attention message */
2018 				if (emlxs_mb_read_la(hba, mbox) == 0) {
2019 					rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba,
2020 					    (MAILBOX *)mbox, MBX_NOWAIT, 0);
2021 					if ((rc != MBX_BUSY) &&
2022 					    (rc != MBX_SUCCESS)) {
2023 						(void) emlxs_mem_put(hba,
2024 						    MEM_MBOX, (uint8_t *)mbox);
2025 					}
2026 					la_enable = 0;
2027 				} else {
2028 					(void) emlxs_mem_put(hba, MEM_MBOX,
2029 					    (uint8_t *)mbox);
2030 				}
2031 			}
2032 		}
2033 
2034 		mutex_enter(&EMLXS_PORT_LOCK);
2035 		if (la_enable) {
2036 			if (!(hba->sli.sli3.hc_copy & HC_LAINT_ENA)) {
2037 				/* Enable Link Attention interrupts */
2038 				hba->sli.sli3.hc_copy |= HC_LAINT_ENA;
2039 				WRITE_CSR_REG(hba, FC_HC_REG(hba),
2040 				    hba->sli.sli3.hc_copy);
2041 #ifdef FMA_SUPPORT
2042 				/* Access handle validation */
2043 				EMLXS_CHK_ACC_HANDLE(hba,
2044 				    hba->sli.sli3.csr_acc_handle);
2045 #endif  /* FMA_SUPPORT */
2046 			}
2047 		} else {
2048 			if (hba->sli.sli3.hc_copy & HC_LAINT_ENA) {
2049 				/* Disable Link Attention interrupts */
2050 				hba->sli.sli3.hc_copy &= ~HC_LAINT_ENA;
2051 				WRITE_CSR_REG(hba, FC_HC_REG(hba),
2052 				    hba->sli.sli3.hc_copy);
2053 #ifdef FMA_SUPPORT
2054 				/* Access handle validation */
2055 				EMLXS_CHK_ACC_HANDLE(hba,
2056 				    hba->sli.sli3.csr_acc_handle);
2057 #endif  /* FMA_SUPPORT */
2058 			}
2059 		}
2060 		mutex_exit(&EMLXS_PORT_LOCK);
2061 
2062 		return (0);
2063 	}
2064 	/* Enable on Link Attention interrupts */
2065 	mutex_enter(&EMLXS_PORT_LOCK);
2066 
2067 	if (!(hba->sli.sli3.hc_copy & HC_LAINT_ENA)) {
2068 		hba->sli.sli3.hc_copy |= HC_LAINT_ENA;
2069 		WRITE_CSR_REG(hba, FC_HC_REG(hba), hba->sli.sli3.hc_copy);
2070 #ifdef FMA_SUPPORT
2071 		/* Access handle validation */
2072 		EMLXS_CHK_ACC_HANDLE(hba, hba->sli.sli3.csr_acc_handle);
2073 #endif  /* FMA_SUPPORT */
2074 	}
2075 
2076 	if (hba->state >= FC_LINK_UP) {
2077 		EMLXS_STATE_CHANGE_LOCKED(hba, FC_READY);
2078 	}
2079 
2080 	mutex_exit(&EMLXS_PORT_LOCK);
2081 
2082 	/* Adapter is now ready for FCP traffic */
2083 	if (hba->state == FC_READY) {
2084 		/* Register vpi's for all ports that have did's */
2085 		for (i = 0; i < MAX_VPORTS; i++) {
2086 			vport = &VPORT(i);
2087 
2088 			if (!(vport->flag & EMLXS_PORT_BOUND) ||
2089 			    !(vport->did)) {
2090 				continue;
2091 			}
2092 
2093 			(void) emlxs_mb_reg_vpi(vport, NULL);
2094 		}
2095 
2096 		/* Attempt to send any pending IO */
2097 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[hba->channel_fcp], 0);
2098 	}
2099 	return (0);
2100 
2101 } /* emlxs_cmpl_clear_la() */
2102 
2103 
2104 /*
2105  *  emlxs_mb_clear_la  Issue a CLEAR LA mailbox command
2106  */
2107 extern void
2108 emlxs_mb_clear_la(emlxs_hba_t *hba, MAILBOXQ *mbq)
2109 {
2110 	MAILBOX *mb = (MAILBOX *)mbq;
2111 
2112 #ifdef FC_RPI_CHECK
2113 	emlxs_rpi_check(hba);
2114 #endif	/* FC_RPI_CHECK */
2115 
2116 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
2117 
2118 	mb->un.varClearLA.eventTag = hba->link_event_tag;
2119 	mb->mbxCommand = MBX_CLEAR_LA;
2120 	mb->mbxOwner = OWN_HOST;
2121 	mbq->mbox_cmpl = emlxs_cmpl_clear_la;
2122 
2123 	return;
2124 
2125 } /* emlxs_mb_clear_la() */
2126 
2127 
2128 /*
2129  * emlxs_mb_read_status  Issue a READ STATUS mailbox command
2130  */
2131 /*ARGSUSED*/
2132 extern void
2133 emlxs_mb_read_status(emlxs_hba_t *hba, MAILBOXQ *mbq)
2134 {
2135 	MAILBOX *mb = (MAILBOX *)mbq;
2136 
2137 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
2138 
2139 	mb->mbxCommand = MBX_READ_STATUS;
2140 	mb->mbxOwner = OWN_HOST;
2141 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
2142 
2143 } /* fc_read_status() */
2144 
2145 
2146 /*
2147  * emlxs_mb_read_lnk_stat  Issue a LINK STATUS mailbox command
2148  */
2149 /*ARGSUSED*/
2150 extern void
2151 emlxs_mb_read_lnk_stat(emlxs_hba_t *hba, MAILBOXQ *mbq)
2152 {
2153 	MAILBOX *mb = (MAILBOX *)mbq;
2154 
2155 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
2156 
2157 	mb->mbxCommand = MBX_READ_LNK_STAT;
2158 	mb->mbxOwner = OWN_HOST;
2159 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
2160 
2161 } /* emlxs_mb_read_lnk_stat() */
2162 
2163 
2164 /*
2165  * emlxs_mb_write_nv  Issue a WRITE NVPARAM mailbox command
2166  */
2167 static void
2168 emlxs_emb_mb_write_nv(emlxs_hba_t *hba, MAILBOXQ *mbq)
2169 {
2170 	MAILBOX *mb = (MAILBOX *)mbq;
2171 	int32_t		i;
2172 	emlxs_config_t	*cfg = &CFG;
2173 
2174 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
2175 
2176 	bcopy((void *)&hba->wwnn,
2177 	    (void *)mb->un.varWTnvp.nodename, sizeof (NAME_TYPE));
2178 
2179 	bcopy((void *)&hba->wwpn,
2180 	    (void *)mb->un.varWTnvp.portname, sizeof (NAME_TYPE));
2181 
2182 	mb->un.varWTnvp.pref_DID = 0;
2183 	mb->un.varWTnvp.hardAL_PA = (uint8_t)cfg[CFG_ASSIGN_ALPA].current;
2184 	mb->un.varWTnvp.rsvd1[0] = 0xffffffff;
2185 	mb->un.varWTnvp.rsvd1[1] = 0xffffffff;
2186 	mb->un.varWTnvp.rsvd1[2] = 0xffffffff;
2187 	for (i = 0; i < 21; i++) {
2188 		mb->un.varWTnvp.rsvd3[i] = 0xffffffff;
2189 	}
2190 
2191 	mb->mbxCommand = MBX_WRITE_NV;
2192 	mb->mbxOwner = OWN_HOST;
2193 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
2194 
2195 } /* emlxs_mb_write_nv() */
2196 
2197 
2198 /*
2199  * emlxs_mb_part_slim  Issue a PARTITION SLIM mailbox command
2200  */
2201 static void
2202 emlxs_mb_part_slim(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t hbainit)
2203 {
2204 	MAILBOX *mb = (MAILBOX *)mbq;
2205 
2206 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
2207 
2208 
2209 	mb->un.varSlim.numRing = hba->chan_count;
2210 	mb->un.varSlim.hbainit = hbainit;
2211 	mb->mbxCommand = MBX_PART_SLIM;
2212 	mb->mbxOwner = OWN_HOST;
2213 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
2214 
2215 } /* emlxs_mb_part_slim() */
2216 
2217 
2218 /*
2219  * emlxs_mb_config_ring  Issue a CONFIG RING mailbox command
2220  */
2221 extern void
2222 emlxs_mb_config_ring(emlxs_hba_t *hba, int32_t ring, MAILBOXQ *mbq)
2223 {
2224 	MAILBOX *mb = (MAILBOX *)mbq;
2225 	int32_t i;
2226 	int32_t j;
2227 
2228 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
2229 
2230 	j = 0;
2231 	for (i = 0; i < ring; i++) {
2232 		j += hba->sli.sli3.ring_masks[i];
2233 	}
2234 
2235 	for (i = 0; i < hba->sli.sli3.ring_masks[ring]; i++) {
2236 		if ((j + i) >= 6) {
2237 			break;
2238 		}
2239 
2240 		mb->un.varCfgRing.rrRegs[i].rval  =
2241 		    hba->sli.sli3.ring_rval[j + i];
2242 		mb->un.varCfgRing.rrRegs[i].rmask =
2243 		    hba->sli.sli3.ring_rmask[j + i];
2244 		mb->un.varCfgRing.rrRegs[i].tval  =
2245 		    hba->sli.sli3.ring_tval[j + i];
2246 		mb->un.varCfgRing.rrRegs[i].tmask =
2247 		    hba->sli.sli3.ring_tmask[j + i];
2248 	}
2249 
2250 	mb->un.varCfgRing.ring = ring;
2251 	mb->un.varCfgRing.profile = 0;
2252 	mb->un.varCfgRing.maxOrigXchg = 0;
2253 	mb->un.varCfgRing.maxRespXchg = 0;
2254 	mb->un.varCfgRing.recvNotify = 1;
2255 	mb->un.varCfgRing.numMask = hba->sli.sli3.ring_masks[ring];
2256 	mb->mbxCommand = MBX_CONFIG_RING;
2257 	mb->mbxOwner = OWN_HOST;
2258 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
2259 
2260 	return;
2261 
2262 } /* emlxs_mb_config_ring() */
2263 
2264 
2265 /*
2266  *  emlxs_mb_config_link  Issue a CONFIG LINK mailbox command
2267  */
2268 extern void
2269 emlxs_mb_config_link(emlxs_hba_t *hba, MAILBOXQ *mbq)
2270 {
2271 	MAILBOX	*mb = (MAILBOX *)mbq;
2272 	emlxs_port_t   *port = &PPORT;
2273 	emlxs_config_t *cfg = &CFG;
2274 
2275 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
2276 
2277 	/*
2278 	 * NEW_FEATURE SLI-2, Coalescing Response Feature.
2279 	 */
2280 	if (cfg[CFG_CR_DELAY].current) {
2281 		mb->un.varCfgLnk.cr = 1;
2282 		mb->un.varCfgLnk.ci = 1;
2283 		mb->un.varCfgLnk.cr_delay = cfg[CFG_CR_DELAY].current;
2284 		mb->un.varCfgLnk.cr_count = cfg[CFG_CR_COUNT].current;
2285 	}
2286 
2287 	if (cfg[CFG_ACK0].current)
2288 		mb->un.varCfgLnk.ack0_enable = 1;
2289 
2290 	mb->un.varCfgLnk.myId = port->did;
2291 	mb->un.varCfgLnk.edtov = hba->fc_edtov;
2292 	mb->un.varCfgLnk.arbtov = hba->fc_arbtov;
2293 	mb->un.varCfgLnk.ratov = hba->fc_ratov;
2294 	mb->un.varCfgLnk.rttov = hba->fc_rttov;
2295 	mb->un.varCfgLnk.altov = hba->fc_altov;
2296 	mb->un.varCfgLnk.crtov = hba->fc_crtov;
2297 	mb->un.varCfgLnk.citov = hba->fc_citov;
2298 	mb->mbxCommand = MBX_CONFIG_LINK;
2299 	mb->mbxOwner = OWN_HOST;
2300 	mbq->mbox_cmpl = NULL;
2301 
2302 	return;
2303 
2304 } /* emlxs_mb_config_link() */
2305 
2306 
2307 int
2308 emlxs_cmpl_init_link(void *arg1, MAILBOXQ *mbq)
2309 {
2310 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
2311 	emlxs_port_t *port = &PPORT;
2312 	emlxs_config_t	*cfg = &CFG;
2313 	MAILBOX *mb;
2314 
2315 	mb = (MAILBOX *)mbq;
2316 	if (mb->mbxStatus) {
2317 		if ((hba->flag & FC_SLIM2_MODE) &&
2318 		    (hba->mbox_queue_flag == MBX_NOWAIT)) {
2319 			/* Retry only MBX_NOWAIT requests */
2320 
2321 			if ((cfg[CFG_LINK_SPEED].current > 0) &&
2322 			    ((mb->mbxStatus == 0x0011) ||
2323 			    (mb->mbxStatus == 0x0500))) {
2324 
2325 				EMLXS_MSGF(EMLXS_CONTEXT,
2326 				    &emlxs_mbox_event_msg,
2327 				    "Retrying.  %s: status=%x. Auto-speed set.",
2328 				    emlxs_mb_cmd_xlate(mb->mbxCommand),
2329 				    (uint32_t)mb->mbxStatus);
2330 
2331 				mb->un.varInitLnk.link_flags &=
2332 				    ~FLAGS_LINK_SPEED;
2333 				mb->un.varInitLnk.link_speed = 0;
2334 
2335 				emlxs_mb_retry(hba, mbq);
2336 				return (1);
2337 			}
2338 		}
2339 	}
2340 	return (0);
2341 
2342 } /* emlxs_cmpl_init_link() */
2343 
2344 
2345 /*
2346  *  emlxs_mb_init_link  Issue an INIT LINK mailbox command
2347  */
2348 extern void
2349 emlxs_mb_init_link(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t topology,
2350     uint32_t linkspeed)
2351 {
2352 	MAILBOX *mb = (MAILBOX *)mbq;
2353 	emlxs_vpd_t	*vpd = &VPD;
2354 	emlxs_config_t	*cfg = &CFG;
2355 
2356 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2357 		bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
2358 		mbq->nonembed = NULL;
2359 		mbq->mbox_cmpl = NULL; /* no cmpl needed */
2360 
2361 		mb->mbxCommand = (volatile uint8_t) MBX_INIT_LINK;
2362 		mb->mbxOwner = OWN_HOST;
2363 		return;
2364 	}
2365 
2366 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
2367 
2368 	switch (topology) {
2369 	case FLAGS_LOCAL_LB:
2370 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
2371 		mb->un.varInitLnk.link_flags |= FLAGS_LOCAL_LB;
2372 		break;
2373 	case FLAGS_TOPOLOGY_MODE_LOOP_PT:
2374 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
2375 		mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER;
2376 		break;
2377 	case FLAGS_TOPOLOGY_MODE_PT_PT:
2378 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT;
2379 		break;
2380 	case FLAGS_TOPOLOGY_MODE_LOOP:
2381 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
2382 		break;
2383 	case FLAGS_TOPOLOGY_MODE_PT_LOOP:
2384 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT;
2385 		mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER;
2386 		break;
2387 	}
2388 
2389 	if (cfg[CFG_LILP_ENABLE].current == 0) {
2390 		/* Disable LIRP/LILP support */
2391 		mb->un.varInitLnk.link_flags |= FLAGS_LIRP_LILP;
2392 	}
2393 
2394 	/*
2395 	 * Setting up the link speed
2396 	 */
2397 	switch (linkspeed) {
2398 	case 0:
2399 		break;
2400 
2401 	case 1:
2402 		if (!(vpd->link_speed & LMT_1GB_CAPABLE)) {
2403 			linkspeed = 0;
2404 		}
2405 		break;
2406 
2407 	case 2:
2408 		if (!(vpd->link_speed & LMT_2GB_CAPABLE)) {
2409 			linkspeed = 0;
2410 		}
2411 		break;
2412 
2413 	case 4:
2414 		if (!(vpd->link_speed & LMT_4GB_CAPABLE)) {
2415 			linkspeed = 0;
2416 		}
2417 		break;
2418 
2419 	case 8:
2420 		if (!(vpd->link_speed & LMT_8GB_CAPABLE)) {
2421 			linkspeed = 0;
2422 		}
2423 		break;
2424 
2425 	case 10:
2426 		if (!(vpd->link_speed & LMT_10GB_CAPABLE)) {
2427 			linkspeed = 0;
2428 		}
2429 		break;
2430 
2431 	default:
2432 		linkspeed = 0;
2433 		break;
2434 
2435 	}
2436 
2437 	if ((linkspeed > 0) && (vpd->feaLevelHigh >= 0x02)) {
2438 		mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
2439 		mb->un.varInitLnk.link_speed = linkspeed;
2440 	}
2441 
2442 	mb->un.varInitLnk.link_flags |= FLAGS_PREABORT_RETURN;
2443 
2444 	mb->un.varInitLnk.fabric_AL_PA =
2445 	    (uint8_t)cfg[CFG_ASSIGN_ALPA].current;
2446 	mb->mbxCommand = (volatile uint8_t) MBX_INIT_LINK;
2447 	mb->mbxOwner = OWN_HOST;
2448 	mbq->mbox_cmpl = emlxs_cmpl_init_link;
2449 
2450 
2451 	return;
2452 
2453 } /* emlxs_mb_init_link() */
2454 
2455 
2456 /*
2457  *  emlxs_mb_down_link  Issue a DOWN LINK mailbox command
2458  */
2459 /*ARGSUSED*/
2460 extern void
2461 emlxs_mb_down_link(emlxs_hba_t *hba, MAILBOXQ *mbq)
2462 {
2463 	MAILBOX *mb = (MAILBOX *)mbq;
2464 
2465 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
2466 
2467 	mb->mbxCommand = MBX_DOWN_LINK;
2468 	mb->mbxOwner = OWN_HOST;
2469 	mbq->mbox_cmpl = NULL;
2470 
2471 	return;
2472 
2473 } /* emlxs_mb_down_link() */
2474 
2475 
2476 int
2477 emlxs_cmpl_read_sparam(void *arg1, MAILBOXQ *mbq)
2478 {
2479 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
2480 	emlxs_port_t *port = &PPORT;
2481 	MAILBOX *mb;
2482 	MATCHMAP *mp;
2483 	emlxs_port_t *vport;
2484 	int32_t i;
2485 	uint32_t  control;
2486 	uint8_t null_wwn[8];
2487 
2488 	mb = (MAILBOX *)mbq;
2489 	if (mb->mbxStatus) {
2490 		if (mb->mbxStatus == MBXERR_NO_RESOURCES) {
2491 			control = mb->un.varRdSparm.un.sp64.tus.f.bdeSize;
2492 			if (control == 0) {
2493 				(void) emlxs_mb_read_sparam(hba, mbq);
2494 			}
2495 			emlxs_mb_retry(hba, mbq);
2496 			return (1);
2497 		}
2498 		return (0);
2499 	}
2500 	mp = (MATCHMAP *)mbq->bp;
2501 	if (!mp) {
2502 		return (0);
2503 	}
2504 
2505 	bcopy((caddr_t)mp->virt, (caddr_t)&hba->sparam, sizeof (SERV_PARM));
2506 
2507 	/* Initialize the node name and port name only once */
2508 	bzero(null_wwn, 8);
2509 	if ((bcmp((caddr_t)&hba->wwnn, (caddr_t)null_wwn, 8) == 0) &&
2510 	    (bcmp((caddr_t)&hba->wwpn, (caddr_t)null_wwn, 8) == 0)) {
2511 		bcopy((caddr_t)&hba->sparam.nodeName,
2512 		    (caddr_t)&hba->wwnn, sizeof (NAME_TYPE));
2513 
2514 		bcopy((caddr_t)&hba->sparam.portName,
2515 		    (caddr_t)&hba->wwpn, sizeof (NAME_TYPE));
2516 	} else {
2517 		bcopy((caddr_t)&hba->wwnn,
2518 		    (caddr_t)&hba->sparam.nodeName, sizeof (NAME_TYPE));
2519 
2520 		bcopy((caddr_t)&hba->wwpn,
2521 		    (caddr_t)&hba->sparam.portName, sizeof (NAME_TYPE));
2522 	}
2523 
2524 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
2525 	    "SPARAM: EDTOV hba=x%x mbox_csp=x%x,  BBC=x%x",
2526 	    hba->fc_edtov, hba->sparam.cmn.e_d_tov,
2527 	    hba->sparam.cmn.bbCreditlsb);
2528 
2529 	hba->sparam.cmn.e_d_tov = hba->fc_edtov;
2530 
2531 	/* Initialize the physical port */
2532 	bcopy((caddr_t)&hba->sparam,
2533 	    (caddr_t)&port->sparam, sizeof (SERV_PARM));
2534 	bcopy((caddr_t)&hba->wwpn, (caddr_t)&port->wwpn,
2535 	    sizeof (NAME_TYPE));
2536 	bcopy((caddr_t)&hba->wwnn, (caddr_t)&port->wwnn,
2537 	    sizeof (NAME_TYPE));
2538 
2539 	/* Initialize the virtual ports */
2540 	for (i = 1; i < MAX_VPORTS; i++) {
2541 		vport = &VPORT(i);
2542 		if (vport->flag & EMLXS_PORT_BOUND) {
2543 			continue;
2544 		}
2545 
2546 		bcopy((caddr_t)&hba->sparam,
2547 		    (caddr_t)&vport->sparam,
2548 		    sizeof (SERV_PARM));
2549 
2550 		bcopy((caddr_t)&vport->wwnn,
2551 		    (caddr_t)&vport->sparam.nodeName,
2552 		    sizeof (NAME_TYPE));
2553 
2554 		bcopy((caddr_t)&vport->wwpn,
2555 		    (caddr_t)&vport->sparam.portName,
2556 		    sizeof (NAME_TYPE));
2557 	}
2558 
2559 	return (0);
2560 
2561 } /* emlxs_cmpl_read_sparam() */
2562 
2563 
2564 /*
2565  * emlxs_mb_read_sparam  Issue a READ SPARAM mailbox command
2566  */
2567 extern uint32_t
2568 emlxs_mb_read_sparam(emlxs_hba_t *hba, MAILBOXQ *mbq)
2569 {
2570 	MAILBOX *mb = (MAILBOX *)mbq;
2571 	MATCHMAP *mp;
2572 
2573 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
2574 
2575 	if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF, 1)) == 0) {
2576 		mb->mbxCommand = MBX_READ_SPARM64;
2577 
2578 		return (1);
2579 	}
2580 
2581 	mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (SERV_PARM);
2582 	mb->un.varRdSparm.un.sp64.addrHigh = PADDR_HI(mp->phys);
2583 	mb->un.varRdSparm.un.sp64.addrLow = PADDR_LO(mp->phys);
2584 	mb->mbxCommand = MBX_READ_SPARM64;
2585 	mb->mbxOwner = OWN_HOST;
2586 	mbq->mbox_cmpl = emlxs_cmpl_read_sparam;
2587 
2588 	/*
2589 	 * save address for completion
2590 	 */
2591 	mbq->bp = (uint8_t *)mp;
2592 
2593 	return (0);
2594 
2595 } /* emlxs_mb_read_sparam() */
2596 
2597 
2598 /*
2599  * emlxs_mb_read_rpi    Issue a READ RPI mailbox command
2600  */
2601 /*ARGSUSED*/
2602 extern uint32_t
2603 emlxs_mb_read_rpi(emlxs_hba_t *hba, uint32_t rpi, MAILBOXQ *mbq,
2604     uint32_t flag)
2605 {
2606 	MAILBOX *mb = (MAILBOX *)mbq;
2607 
2608 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
2609 
2610 	/*
2611 	 * Set flag to issue action on cmpl
2612 	 */
2613 	mb->un.varWords[30] = flag;
2614 	mb->un.varRdRPI.reqRpi = (volatile uint16_t) rpi;
2615 	mb->mbxCommand = MBX_READ_RPI64;
2616 	mb->mbxOwner = OWN_HOST;
2617 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
2618 
2619 	return (0);
2620 } /* emlxs_mb_read_rpi() */
2621 
2622 
2623 /*
2624  * emlxs_mb_read_xri    Issue a READ XRI mailbox command
2625  */
2626 /*ARGSUSED*/
2627 extern uint32_t
2628 emlxs_mb_read_xri(emlxs_hba_t *hba, uint32_t xri, MAILBOXQ *mbq,
2629     uint32_t flag)
2630 {
2631 	MAILBOX *mb = (MAILBOX *)mbq;
2632 
2633 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
2634 
2635 	/*
2636 	 * Set flag to issue action on cmpl
2637 	 */
2638 	mb->un.varWords[30] = flag;
2639 	mb->un.varRdXRI.reqXri = (volatile uint16_t)xri;
2640 	mb->mbxCommand = MBX_READ_XRI;
2641 	mb->mbxOwner = OWN_HOST;
2642 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
2643 
2644 	return (0);
2645 } /* emlxs_mb_read_xri() */
2646 
2647 
2648 /*ARGSUSED*/
2649 extern int32_t
2650 emlxs_mb_check_sparm(emlxs_hba_t *hba, SERV_PARM *nsp)
2651 {
2652 	uint32_t nsp_value;
2653 	uint32_t *iptr;
2654 
2655 	if (nsp->cmn.fPort) {
2656 		return (0);
2657 	}
2658 
2659 	/* Validate the service parameters */
2660 	iptr = (uint32_t *)&nsp->portName;
2661 	if (iptr[0] == 0 && iptr[1] == 0) {
2662 		return (1);
2663 	}
2664 
2665 	iptr = (uint32_t *)&nsp->nodeName;
2666 	if (iptr[0] == 0 && iptr[1] == 0) {
2667 		return (2);
2668 	}
2669 
2670 	if (nsp->cls2.classValid) {
2671 		nsp_value =
2672 		    ((nsp->cls2.rcvDataSizeMsb & 0x0f) << 8) | nsp->cls2.
2673 		    rcvDataSizeLsb;
2674 
2675 		/* If the receive data length is zero then set it to */
2676 		/* the CSP value */
2677 		if (!nsp_value) {
2678 			nsp->cls2.rcvDataSizeMsb = nsp->cmn.bbRcvSizeMsb;
2679 			nsp->cls2.rcvDataSizeLsb = nsp->cmn.bbRcvSizeLsb;
2680 			return (0);
2681 		}
2682 	}
2683 
2684 	if (nsp->cls3.classValid) {
2685 		nsp_value =
2686 		    ((nsp->cls3.rcvDataSizeMsb & 0x0f) << 8) | nsp->cls3.
2687 		    rcvDataSizeLsb;
2688 
2689 		/* If the receive data length is zero then set it to */
2690 		/* the CSP value */
2691 		if (!nsp_value) {
2692 			nsp->cls3.rcvDataSizeMsb = nsp->cmn.bbRcvSizeMsb;
2693 			nsp->cls3.rcvDataSizeLsb = nsp->cmn.bbRcvSizeLsb;
2694 			return (0);
2695 		}
2696 	}
2697 
2698 	return (0);
2699 
2700 } /* emlxs_mb_check_sparm() */
2701 
2702 
2703 int
2704 emlxs_cmpl_reg_did(void *arg1, MAILBOXQ *mbq)
2705 {
2706 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
2707 	emlxs_port_t *port = &PPORT;
2708 	MAILBOX *mb;
2709 	MATCHMAP *mp;
2710 	NODELIST *ndlp;
2711 	emlxs_port_t *vport;
2712 	uint8_t *wwn;
2713 	volatile SERV_PARM *sp;
2714 	int32_t i;
2715 	uint32_t  control;
2716 	uint32_t ldata;
2717 	uint32_t ldid;
2718 	uint16_t lrpi;
2719 	uint16_t lvpi;
2720 	emlxs_vvl_fmt_t vvl;
2721 
2722 	mb = (MAILBOX *)mbq;
2723 	if (mb->mbxStatus) {
2724 		if (mb->mbxStatus == MBXERR_NO_RESOURCES) {
2725 			control = mb->un.varRegLogin.un.sp.bdeSize;
2726 			if (control == 0) {
2727 				/* Special handle for vport PLOGI */
2728 				if (mbq->iocbq == (uint8_t *)1) {
2729 					mbq->iocbq = NULL;
2730 				}
2731 				return (0);
2732 			}
2733 			emlxs_mb_retry(hba, mbq);
2734 			return (1);
2735 		}
2736 		if (mb->mbxStatus == MBXERR_RPI_FULL) {
2737 			port = &VPORT((mb->un.varRegLogin.vpi - hba->vpi_base));
2738 
2739 			EMLXS_MSGF(EMLXS_CONTEXT,
2740 			    &emlxs_node_create_failed_msg,
2741 			    "Limit reached. count=%d", port->node_count);
2742 		}
2743 
2744 		/* Special handle for vport PLOGI */
2745 		if (mbq->iocbq == (uint8_t *)1) {
2746 			mbq->iocbq = NULL;
2747 		}
2748 
2749 		return (0);
2750 	}
2751 
2752 	mp = (MATCHMAP *)mbq->bp;
2753 	if (!mp) {
2754 		return (0);
2755 	}
2756 	ldata = mb->un.varWords[5];
2757 	lvpi = (ldata & 0xffff) - hba->vpi_base;
2758 	port = &VPORT(lvpi);
2759 
2760 	/* First copy command data */
2761 	ldata = mb->un.varWords[0];	/* get rpi */
2762 	lrpi = ldata & 0xffff;
2763 
2764 	ldata = mb->un.varWords[1];	/* get did */
2765 	ldid = ldata & MASK_DID;
2766 
2767 	sp = (volatile SERV_PARM *)mp->virt;
2768 	ndlp = emlxs_node_find_did(port, ldid);
2769 
2770 	if (!ndlp) {
2771 		/* Attempt to create a node */
2772 		if ((ndlp = (NODELIST *)emlxs_mem_get(hba, MEM_NLP, 0))) {
2773 			ndlp->nlp_Rpi = lrpi;
2774 			ndlp->nlp_DID = ldid;
2775 
2776 			bcopy((uint8_t *)sp, (uint8_t *)&ndlp->sparm,
2777 			    sizeof (SERV_PARM));
2778 
2779 			bcopy((uint8_t *)&sp->nodeName,
2780 			    (uint8_t *)&ndlp->nlp_nodename,
2781 			    sizeof (NAME_TYPE));
2782 
2783 			bcopy((uint8_t *)&sp->portName,
2784 			    (uint8_t *)&ndlp->nlp_portname,
2785 			    sizeof (NAME_TYPE));
2786 
2787 			ndlp->nlp_active = 1;
2788 			ndlp->nlp_flag[hba->channel_ct]  |= NLP_CLOSED;
2789 			ndlp->nlp_flag[hba->channel_els] |= NLP_CLOSED;
2790 			ndlp->nlp_flag[hba->channel_fcp] |= NLP_CLOSED;
2791 			ndlp->nlp_flag[hba->channel_ip]  |= NLP_CLOSED;
2792 
2793 			/* Add the node */
2794 			emlxs_node_add(port, ndlp);
2795 
2796 			/* Open the node */
2797 			emlxs_node_open(port, ndlp, hba->channel_ct);
2798 			emlxs_node_open(port, ndlp, hba->channel_els);
2799 			emlxs_node_open(port, ndlp, hba->channel_ip);
2800 			emlxs_node_open(port, ndlp, hba->channel_fcp);
2801 		} else {
2802 			wwn = (uint8_t *)&sp->portName;
2803 			EMLXS_MSGF(EMLXS_CONTEXT,
2804 			    &emlxs_node_create_failed_msg,
2805 			    "Unable to allocate node. did=%06x rpi=%x "
2806 			    "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x",
2807 			    ldid, lrpi, wwn[0], wwn[1], wwn[2],
2808 			    wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
2809 
2810 			return (0);
2811 		}
2812 	} else {
2813 		mutex_enter(&EMLXS_PORT_LOCK);
2814 
2815 		ndlp->nlp_Rpi = lrpi;
2816 		ndlp->nlp_DID = ldid;
2817 
2818 		bcopy((uint8_t *)sp,
2819 		    (uint8_t *)&ndlp->sparm, sizeof (SERV_PARM));
2820 
2821 		bcopy((uint8_t *)&sp->nodeName,
2822 		    (uint8_t *)&ndlp->nlp_nodename, sizeof (NAME_TYPE));
2823 
2824 		bcopy((uint8_t *)&sp->portName,
2825 		    (uint8_t *)&ndlp->nlp_portname, sizeof (NAME_TYPE));
2826 
2827 		wwn = (uint8_t *)&ndlp->nlp_portname;
2828 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_update_msg,
2829 		    "node=%p did=%06x rpi=%x "
2830 		    "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x",
2831 		    ndlp, ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0],
2832 		    wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
2833 
2834 		mutex_exit(&EMLXS_PORT_LOCK);
2835 
2836 		/* Open the node */
2837 		emlxs_node_open(port, ndlp, hba->channel_ct);
2838 		emlxs_node_open(port, ndlp, hba->channel_els);
2839 		emlxs_node_open(port, ndlp, hba->channel_ip);
2840 		emlxs_node_open(port, ndlp, hba->channel_fcp);
2841 	}
2842 
2843 	bzero((char *)&vvl, sizeof (emlxs_vvl_fmt_t));
2844 
2845 	if (sp->VALID_VENDOR_VERSION) {
2846 
2847 		bcopy((caddr_t *)&sp->vendorVersion[0],
2848 		    (caddr_t *)&vvl, sizeof (emlxs_vvl_fmt_t));
2849 
2850 		vvl.un0.word0 = LE_SWAP32(vvl.un0.word0);
2851 		vvl.un1.word1 = LE_SWAP32(vvl.un1.word1);
2852 
2853 		if ((vvl.un0.w0.oui == 0x0000C9) &&
2854 		    (vvl.un1.w1.vport)) {
2855 			ndlp->nlp_fcp_info |= NLP_EMLX_VPORT;
2856 		}
2857 	}
2858 
2859 	if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) &&
2860 	    (ndlp->nlp_DID == NAMESERVER_DID)) {
2861 			EMLXS_STATE_CHANGE_LOCKED(hba, FC_READY);
2862 	}
2863 
2864 	/* If this was a fabric login */
2865 	if (ndlp->nlp_DID == FABRIC_DID) {
2866 		/* If CLEAR_LA has been sent, then attempt to */
2867 		/* register the vpi now */
2868 		if (hba->state == FC_READY) {
2869 			(void) emlxs_mb_reg_vpi(port, NULL);
2870 		}
2871 
2872 		/*
2873 		 * If NPIV Fabric support has just been established on
2874 		 * the physical port, then notify the vports of the
2875 		 * link up
2876 		 */
2877 		if ((lvpi == 0) &&
2878 		    (hba->flag & FC_NPIV_ENABLED) &&
2879 		    (hba->flag & FC_NPIV_SUPPORTED)) {
2880 			/* Skip the physical port */
2881 			for (i = 1; i < MAX_VPORTS; i++) {
2882 				vport = &VPORT(i);
2883 
2884 				if (!(vport->flag & EMLXS_PORT_BOUND) ||
2885 				    !(vport->flag & EMLXS_PORT_ENABLE)) {
2886 					continue;
2887 				}
2888 
2889 				emlxs_port_online(vport);
2890 			}
2891 		}
2892 	}
2893 
2894 	if (mbq->iocbq == (uint8_t *)1) {
2895 		mbq->iocbq = NULL;
2896 		(void) emlxs_mb_unreg_did(port, ldid, NULL, NULL, NULL);
2897 	}
2898 
2899 #ifdef DHCHAP_SUPPORT
2900 	if (mbq->sbp || mbq->ubp) {
2901 		if (emlxs_dhc_auth_start(port, ndlp, mbq->sbp,
2902 		    mbq->ubp) == 0) {
2903 			/* Auth started - auth completion will */
2904 			/* handle sbp and ubp now */
2905 			mbq->sbp = NULL;
2906 			mbq->ubp = NULL;
2907 		}
2908 	}
2909 #endif	/* DHCHAP_SUPPORT */
2910 
2911 #ifdef SFCT_SUPPORT
2912 	if (mbq->sbp && ((emlxs_buf_t *)mbq->sbp)->fct_cmd) {
2913 		emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)mbq->sbp;
2914 
2915 		if (cmd_sbp->fct_state == EMLXS_FCT_REG_PENDING) {
2916 			mbq->sbp = NULL;
2917 
2918 			mutex_enter(&EMLXS_PKT_LOCK);
2919 			cmd_sbp->node = ndlp;
2920 			cv_broadcast(&EMLXS_PKT_CV);
2921 			mutex_exit(&EMLXS_PKT_LOCK);
2922 		}
2923 	}
2924 #endif /* SFCT_SUPPORT */
2925 	return (0);
2926 
2927 } /* emlxs_cmpl_reg_did() */
2928 
2929 
2930 /*
2931  * emlxs_mb_reg_did  Issue a REG_LOGIN mailbox command
2932  */
2933 extern uint32_t
2934 emlxs_mb_reg_did(emlxs_port_t *port, uint32_t did, SERV_PARM *param,
2935     emlxs_buf_t *sbp, fc_unsol_buf_t *ubp, IOCBQ *iocbq)
2936 {
2937 	emlxs_hba_t	*hba = HBA;
2938 	MATCHMAP	*mp;
2939 	MAILBOXQ	*mbq;
2940 	MAILBOX		*mb;
2941 	NODELIST	*node;
2942 	RPIobj_t	*rp = NULL;
2943 	uint32_t	rval;
2944 
2945 	/* Check for invalid node ids to register */
2946 	if ((did == 0) && (!(hba->flag & FC_LOOPBACK_MODE))) {
2947 		return (1);
2948 	}
2949 
2950 	if (did & 0xff000000) {
2951 		return (1);
2952 	}
2953 
2954 	if ((rval = emlxs_mb_check_sparm(hba, param))) {
2955 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_failed_msg,
2956 		    "Invalid service parameters. did=%06x rval=%d", did,
2957 		    rval);
2958 
2959 		return (1);
2960 	}
2961 
2962 	/* Check if the node limit has been reached */
2963 	if (port->node_count >= hba->max_nodes) {
2964 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_failed_msg,
2965 		    "Limit reached. did=%06x count=%d", did,
2966 		    port->node_count);
2967 
2968 		return (1);
2969 	}
2970 
2971 	if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))) {
2972 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_failed_msg,
2973 		    "Unable to allocate mailbox. did=%x", did);
2974 
2975 		return (1);
2976 	}
2977 	mb = (MAILBOX *)mbq->mbox;
2978 
2979 	/* Build login request */
2980 	if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF, 1)) == 0) {
2981 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_failed_msg,
2982 		    "Unable to allocate buffer. did=%x", did);
2983 
2984 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
2985 		return (1);
2986 	}
2987 
2988 	/*
2989 	 * If we are SLI4, the RPI number gets assigned by the driver.
2990 	 * For SLI3, the firmware assigns the RPI number.
2991 	 */
2992 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2993 		node = emlxs_node_find_did(port, did);
2994 		rp = EMLXS_NODE_TO_RPI(hba, node);
2995 
2996 		if (!rp) {
2997 			rp = emlxs_sli4_alloc_rpi(port);
2998 		}
2999 
3000 		if (!rp) {
3001 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_failed_msg,
3002 			    "Unable to get an rpi. did=%x", did);
3003 
3004 			(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
3005 			return (1);
3006 		}
3007 		rp->state &= ~RESOURCE_RPI_PAUSED;
3008 	}
3009 
3010 	bcopy((void *)param, (void *)mp->virt, sizeof (SERV_PARM));
3011 
3012 	mb->un.varRegLogin.un.sp64.tus.f.bdeSize = sizeof (SERV_PARM);
3013 	mb->un.varRegLogin.un.sp64.addrHigh = PADDR_HI(mp->phys);
3014 	mb->un.varRegLogin.un.sp64.addrLow = PADDR_LO(mp->phys);
3015 	mb->un.varRegLogin.did = did;
3016 	mb->un.varWords[30] = 0;	/* flags */
3017 	mb->mbxCommand = MBX_REG_LOGIN64;
3018 	mb->mbxOwner = OWN_HOST;
3019 	mb->un.varRegLogin.vpi = port->vpi + hba->vpi_base;
3020 	mb->un.varRegLogin.rpi = (rp)? rp->RPI: 0;
3021 
3022 	mbq->sbp = (uint8_t *)sbp;
3023 	mbq->ubp = (uint8_t *)ubp;
3024 	mbq->iocbq = (uint8_t *)iocbq;
3025 	mbq->bp = (uint8_t *)mp;
3026 	mbq->mbox_cmpl = emlxs_cmpl_reg_did;
3027 
3028 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0);
3029 	if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) {
3030 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
3031 		if (rp) {
3032 			emlxs_sli4_free_rpi(hba, rp);
3033 		}
3034 	}
3035 
3036 	return (0);
3037 
3038 } /* emlxs_mb_reg_did() */
3039 
3040 /*
3041  * emlxs_mb_unreg_rpi  Issue a UNREG_LOGIN mailbox command
3042  */
3043 extern uint32_t
3044 emlxs_mb_unreg_rpi(emlxs_port_t *port, uint32_t rpi, emlxs_buf_t *sbp,
3045     fc_unsol_buf_t *ubp, IOCBQ *iocbq)
3046 {
3047 	emlxs_hba_t	*hba = HBA;
3048 	MAILBOXQ	*mbq;
3049 	MAILBOX		*mb;
3050 	NODELIST	*ndlp;
3051 	int rval;
3052 
3053 	if (rpi != 0xffff) {
3054 		/* Make sure the node does already exist */
3055 		ndlp = emlxs_node_find_rpi(port, rpi);
3056 
3057 
3058 		if (ndlp) {
3059 			/*
3060 			 * If we just unregistered the host node then
3061 			 * clear the host DID
3062 			 */
3063 			if (ndlp->nlp_DID == port->did) {
3064 				port->did = 0;
3065 			}
3066 
3067 			/* remove it */
3068 			emlxs_node_rm(port, ndlp);
3069 
3070 		} else {
3071 			return (1);
3072 		}
3073 	} else {	/* Unreg all */
3074 
3075 		emlxs_node_destroy_all(port);
3076 	}
3077 
3078 	if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))) {
3079 		return (1);
3080 	}
3081 
3082 	mb = (MAILBOX *)mbq->mbox;
3083 
3084 #define	INDEX_INDICATOR_VPI	1
3085 
3086 	if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) && (rpi == 0xffff)) {
3087 		mb->un.varUnregLogin.ll = INDEX_INDICATOR_VPI;
3088 		mb->un.varUnregLogin.rpi = (uint16_t)port->vpi + hba->vpi_base;
3089 	} else {
3090 		mb->un.varUnregLogin.rpi = (uint16_t)rpi;
3091 	}
3092 
3093 	mb->un.varUnregLogin.vpi = port->vpi + hba->vpi_base;
3094 	mb->mbxCommand = MBX_UNREG_LOGIN;
3095 	mb->mbxOwner = OWN_HOST;
3096 	mbq->sbp = (uint8_t *)sbp;
3097 	mbq->ubp = (uint8_t *)ubp;
3098 	mbq->iocbq = (uint8_t *)iocbq;
3099 	mbq->mbox_cmpl = NULL;
3100 
3101 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0);
3102 	if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) {
3103 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
3104 	}
3105 
3106 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3107 		port->outstandingRPIs--;
3108 		if ((port->outstandingRPIs == 0) &&
3109 		    (hba->state == FC_LINK_DOWN)) {
3110 			/* No more RPIs so unreg the VPI */
3111 			(void) emlxs_mb_unreg_vpi(port);
3112 		}
3113 	}
3114 
3115 	return (0);
3116 } /* emlxs_mb_unreg_rpi() */
3117 
3118 
3119 /*
3120  * emlxs_mb_unreg_did  Issue a UNREG_DID mailbox command
3121  */
3122 extern uint32_t
3123 emlxs_mb_unreg_did(emlxs_port_t *port, uint32_t did, emlxs_buf_t *sbp,
3124     fc_unsol_buf_t *ubp, IOCBQ *iocbq)
3125 {
3126 	emlxs_hba_t	*hba = HBA;
3127 	NODELIST	*ndlp;
3128 	MAILBOXQ	*mbq;
3129 	MAILBOX		*mb;
3130 	int rval = 0;
3131 
3132 	/*
3133 	 * Unregister all default RPIs if did == 0xffffffff
3134 	 */
3135 	if (did != 0xffffffff) {
3136 		/* Check for base node */
3137 		if (did == BCAST_DID) {
3138 			/* just flush base node */
3139 			(void) emlxs_tx_node_flush(port, &port->node_base,
3140 			    0, 0, 0);
3141 			(void) emlxs_chipq_node_flush(port, 0,
3142 			    &port->node_base, 0);
3143 
3144 			/* Return now */
3145 			return (1);
3146 		}
3147 
3148 
3149 		/*
3150 		 * A zero DID means that we are trying to unreg the host node
3151 		 * after a link bounce
3152 		 */
3153 
3154 		/*
3155 		 * If the prev_did == 0 then the adapter has been reset and
3156 		 * there is no need in unregistering
3157 		 */
3158 
3159 		/*
3160 		 * If the prev_did != 0 then we can look for the hosts
3161 		 * last known DID node
3162 		 */
3163 
3164 		if (did == 0) {
3165 			if (port->prev_did == 0) {
3166 				return (1);
3167 			}
3168 
3169 			did = port->prev_did;
3170 		}
3171 
3172 		/* Make sure the node does already exist */
3173 		ndlp = emlxs_node_find_did(port, did);
3174 
3175 		if (ndlp) {
3176 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3177 				/* Use UNREG_RPI for SLI4 */
3178 				if (ndlp->nlp_Rpi != 0xffff) {
3179 					rval = emlxs_mb_unreg_rpi(port,
3180 					    ndlp->nlp_Rpi, sbp, ubp, iocbq);
3181 				}
3182 				return (rval);
3183 			}
3184 			/* remove it */
3185 			emlxs_node_rm(port, ndlp);
3186 
3187 			/*
3188 			 * If we just unregistered the host node then
3189 			 * clear the host DID
3190 			 */
3191 			if (did == port->did) {
3192 				port->did = 0;
3193 			}
3194 
3195 		} else {
3196 			return (1);
3197 		}
3198 	} else {
3199 		/* SLI4 doesn't have dflt RPIs in SLI Port */
3200 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3201 			return (0);
3202 		}
3203 	}
3204 
3205 	if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))) {
3206 		return (1);
3207 	}
3208 
3209 	mb = (MAILBOX *)mbq->mbox;
3210 	mb->un.varUnregDID.did = did;
3211 	mb->un.varUnregDID.vpi = port->vpi + hba->vpi_base;
3212 	mb->mbxCommand = MBX_UNREG_D_ID;
3213 	mb->mbxOwner = OWN_HOST;
3214 	mbq->sbp = (uint8_t *)sbp;
3215 	mbq->ubp = (uint8_t *)ubp;
3216 	mbq->iocbq = (uint8_t *)iocbq;
3217 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
3218 
3219 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0);
3220 	if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) {
3221 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
3222 	}
3223 
3224 	return (0);
3225 
3226 } /* emlxs_mb_unreg_did() */
3227 
3228 
3229 /*
3230  * emlxs_mb_set_mask   Issue a SET MASK mailbox command
3231  */
3232 /*ARGSUSED*/
3233 static void
3234 emlxs_mb_set_mask(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t mask,
3235     uint32_t ringno)
3236 {
3237 	MAILBOX *mb = (MAILBOX *)mbq;
3238 
3239 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
3240 
3241 	mb->un.varWords[0] = 0x11223344;	/* set passwd */
3242 	mb->un.varWords[1] = mask;	/* set mask */
3243 	mb->un.varWords[2] = ringno;	/* set ringno */
3244 	mb->mbxCommand = MBX_SET_MASK;
3245 	mb->mbxOwner = OWN_HOST;
3246 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
3247 
3248 } /* emlxs_mb_set_mask() */
3249 
3250 
3251 /*
3252  * emlxs_mb_set_debug  Issue a special debug mailbox command
3253  */
3254 /*ARGSUSED*/
3255 static void
3256 emlxs_mb_set_debug(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t word0,
3257     uint32_t word1, uint32_t word2)
3258 {
3259 	MAILBOX *mb = (MAILBOX *)mbq;
3260 
3261 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
3262 
3263 	mb->un.varWords[0] = word0;
3264 	mb->un.varWords[1] = word1;
3265 	mb->un.varWords[2] = word2;
3266 	mb->mbxCommand = MBX_SET_DEBUG;
3267 	mb->mbxOwner = OWN_HOST;
3268 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
3269 
3270 } /* emlxs_mb_set_debug() */
3271 
3272 
3273 /*
3274  * emlxs_mb_set_var   Issue a special debug mbox command to write slim
3275  */
3276 /*ARGSUSED*/
3277 extern void
3278 emlxs_mb_set_var(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t addr,
3279     uint32_t value)
3280 {
3281 	MAILBOX *mb = (MAILBOX *)mbq;
3282 
3283 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
3284 
3285 	/* addr = 0x090597 is AUTO ABTS disable for ELS commands */
3286 	/* addr = 0x052198 is DELAYED ABTS enable for ELS commands */
3287 	/* addr = 0x100506 is for setting PCI MAX READ value */
3288 
3289 	/*
3290 	 * Always turn on DELAYED ABTS for ELS timeouts
3291 	 */
3292 	if ((addr == 0x052198) && (value == 0)) {
3293 		value = 1;
3294 	}
3295 
3296 	mb->un.varWords[0] = addr;
3297 	mb->un.varWords[1] = value;
3298 	mb->mbxCommand = MBX_SET_VARIABLE;
3299 	mb->mbxOwner = OWN_HOST;
3300 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
3301 
3302 } /* emlxs_mb_set_var() */
3303 
3304 
3305 /*
3306  * Disable Traffic Cop
3307  */
3308 /*ARGSUSED*/
3309 extern void
3310 emlxs_disable_tc(emlxs_hba_t *hba, MAILBOXQ *mbq)
3311 {
3312 	MAILBOX *mb = (MAILBOX *)mbq;
3313 
3314 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
3315 
3316 	mb->un.varWords[0] = 0x50797;
3317 	mb->un.varWords[1] = 0;
3318 	mb->un.varWords[2] = 0xfffffffe;
3319 	mb->mbxCommand = MBX_SET_VARIABLE;
3320 	mb->mbxOwner = OWN_HOST;
3321 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
3322 
3323 } /* emlxs_disable_tc() */
3324 
3325 
3326 extern void
3327 emlxs_mb_config_hbq(emlxs_hba_t *hba, MAILBOXQ *mbq, int hbq_id)
3328 {
3329 	HBQ_INIT_t	*hbq;
3330 	MAILBOX		*mb = (MAILBOX *)mbq;
3331 	int		i;
3332 
3333 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
3334 
3335 	hbq = &hba->sli.sli3.hbq_table[hbq_id];
3336 
3337 	mb->un.varCfgHbq.hbqId = hbq_id;
3338 	mb->un.varCfgHbq.numEntries = hbq->HBQ_numEntries;
3339 	mb->un.varCfgHbq.recvNotify = hbq->HBQ_recvNotify;
3340 	mb->un.varCfgHbq.numMask = hbq->HBQ_num_mask;
3341 	mb->un.varCfgHbq.profile = hbq->HBQ_profile;
3342 	mb->un.varCfgHbq.ringMask = hbq->HBQ_ringMask;
3343 	mb->un.varCfgHbq.headerLen = hbq->HBQ_headerLen;
3344 	mb->un.varCfgHbq.logEntry = hbq->HBQ_logEntry;
3345 	mb->un.varCfgHbq.hbqaddrLow = PADDR_LO(hbq->HBQ_host_buf.phys);
3346 	mb->un.varCfgHbq.hbqaddrHigh = PADDR_HI(hbq->HBQ_host_buf.phys);
3347 	mb->mbxCommand = MBX_CONFIG_HBQ;
3348 	mb->mbxOwner = OWN_HOST;
3349 	mbq->mbox_cmpl = NULL;
3350 
3351 	/* Copy info for profiles 2,3,5. Other profiles this area is reserved */
3352 	if ((hbq->HBQ_profile == 2) || (hbq->HBQ_profile == 3) ||
3353 	    (hbq->HBQ_profile == 5)) {
3354 		bcopy(&hbq->profiles.allprofiles,
3355 		    &mb->un.varCfgHbq.profiles.allprofiles,
3356 		    sizeof (hbq->profiles));
3357 	}
3358 
3359 	/* Return if no rctl / type masks for this HBQ */
3360 	if (!hbq->HBQ_num_mask) {
3361 		return;
3362 	}
3363 
3364 	/* Otherwise we setup specific rctl / type masks for this HBQ */
3365 	for (i = 0; i < hbq->HBQ_num_mask; i++) {
3366 		mb->un.varCfgHbq.hbqMasks[i].tmatch =
3367 		    hbq->HBQ_Masks[i].tmatch;
3368 		mb->un.varCfgHbq.hbqMasks[i].tmask = hbq->HBQ_Masks[i].tmask;
3369 		mb->un.varCfgHbq.hbqMasks[i].rctlmatch =
3370 		    hbq->HBQ_Masks[i].rctlmatch;
3371 		mb->un.varCfgHbq.hbqMasks[i].rctlmask =
3372 		    hbq->HBQ_Masks[i].rctlmask;
3373 	}
3374 
3375 	return;
3376 
3377 } /* emlxs_mb_config_hbq() */
3378 
3379 int
3380 emlxs_cmpl_init_vpi(void *arg1, MAILBOXQ *mbq)
3381 {
3382 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
3383 	emlxs_port_t *port = &PPORT;
3384 	emlxs_port_t *vport;
3385 	MAILBOX4 *mb;
3386 
3387 	mb = (MAILBOX4 *)mbq;
3388 
3389 	if (mb->mbxStatus == MBX_SUCCESS) {
3390 		vport = &VPORT((mb->un.varInitVPI4.vpi - hba->vpi_base));
3391 		vport->flag |= EMLXS_PORT_INIT_VPI_CMPL;
3392 	}
3393 
3394 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
3395 	    "CMPL init_vpi: stats: %x", mb->mbxStatus);
3396 
3397 	return (0);
3398 
3399 } /* emlxs_cmpl_init_vpi() */
3400 
3401 
3402 extern uint32_t
3403 emlxs_mb_init_vpi(emlxs_port_t *port)
3404 {
3405 	emlxs_hba_t	*hba = HBA;
3406 	emlxs_port_t    *phy_port = &PPORT;
3407 	MAILBOXQ	*mbq;
3408 	MAILBOX4	*mb;
3409 	int rval;
3410 
3411 	if (!(hba->flag & FC_NPIV_ENABLED)) {
3412 		return (0);
3413 	}
3414 
3415 	if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))) {
3416 		return (1);
3417 	}
3418 
3419 
3420 	mb = (MAILBOX4 *)mbq->mbox;
3421 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
3422 	mbq->nonembed = NULL;
3423 	mb->un.varInitVPI4.vfi = phy_port->VFIp->VFI;
3424 	mb->un.varInitVPI4.vpi = port->vpi + hba->vpi_base;
3425 	mb->mbxCommand = MBX_INIT_VPI;
3426 	mb->mbxOwner = OWN_HOST;
3427 	mbq->mbox_cmpl = emlxs_cmpl_init_vpi;
3428 
3429 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
3430 	if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) {
3431 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
3432 	}
3433 
3434 	return (0);
3435 
3436 } /* emlxs_mb_init_vpi() */
3437 
3438 
3439 /* Leadville wll start sending PLOGI right after */
3440 /* FDISC completion, we need to wait for REG_VPI */
3441 /* completion, before sending back the FDISK request */
3442 /* Also, allocate a node structure for Fabric port */
3443 int
3444 emlxs_cmpl_reg_vpi(void *arg1, MAILBOXQ *mbq)
3445 {
3446 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
3447 	emlxs_port_t *port = &PPORT;
3448 	emlxs_port_t *vport;
3449 	MAILBOX *mb;
3450 	emlxs_buf_t *sbp;
3451 	SERV_PARM *sp;
3452 	fc_packet_t *pkt;
3453 	NODELIST *ndlp;
3454 	uint32_t ldid;
3455 	uint8_t *wwn;
3456 
3457 	mb = (MAILBOX *)mbq;
3458 
3459 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
3460 	    "CMPL reg_vpi: stats: %x", mb->mbxStatus);
3461 
3462 	if (mb->mbxStatus != MBX_SUCCESS) {
3463 		return (0);
3464 	}
3465 
3466 	vport = &VPORT((mb->un.varRegVpi.vpi - hba->vpi_base));
3467 	vport->flag |= EMLXS_PORT_REG_VPI_CMPL;
3468 	sbp = (emlxs_buf_t *)mbq->sbp;
3469 
3470 	if (!sbp) {
3471 		return (0);
3472 	}
3473 
3474 	pkt = PRIV2PKT(sbp);
3475 	sp = (SERV_PARM *)((caddr_t)pkt->pkt_resp + sizeof (uint32_t));
3476 
3477 	vport->VFIp->outstandingVPIs++;
3478 
3479 	ldid = FABRIC_DID;
3480 	ndlp = emlxs_node_find_did(vport, ldid);
3481 
3482 	if (!ndlp) {
3483 		/* Attempt to create a node */
3484 		if ((ndlp = (NODELIST *)emlxs_mem_get(hba, MEM_NLP, 0))) {
3485 			ndlp->nlp_Rpi = 0xffff;
3486 			ndlp->nlp_DID = ldid;
3487 
3488 			bcopy((uint8_t *)sp, (uint8_t *)&ndlp->sparm,
3489 			    sizeof (SERV_PARM));
3490 
3491 			bcopy((uint8_t *)&sp->nodeName,
3492 			    (uint8_t *)&ndlp->nlp_nodename,
3493 			    sizeof (NAME_TYPE));
3494 
3495 			bcopy((uint8_t *)&sp->portName,
3496 			    (uint8_t *)&ndlp->nlp_portname,
3497 			    sizeof (NAME_TYPE));
3498 
3499 			ndlp->nlp_active = 1;
3500 			ndlp->nlp_flag[hba->channel_ct]  |= NLP_CLOSED;
3501 			ndlp->nlp_flag[hba->channel_els] |= NLP_CLOSED;
3502 			ndlp->nlp_flag[hba->channel_fcp] |= NLP_CLOSED;
3503 			ndlp->nlp_flag[hba->channel_ip]  |= NLP_CLOSED;
3504 
3505 			/* Add the node */
3506 			emlxs_node_add(vport, ndlp);
3507 
3508 			/* Open the node */
3509 			emlxs_node_open(vport, ndlp, hba->channel_ct);
3510 			emlxs_node_open(vport, ndlp, hba->channel_els);
3511 			emlxs_node_open(vport, ndlp, hba->channel_ip);
3512 			emlxs_node_open(vport, ndlp, hba->channel_fcp);
3513 		} else {
3514 			wwn = (uint8_t *)&sp->portName;
3515 			EMLXS_MSGF(EMLXS_CONTEXT,
3516 			    &emlxs_node_create_failed_msg,
3517 			    "Unable to allocate node. did=%06x "
3518 			    "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x",
3519 			    ldid, wwn[0], wwn[1], wwn[2],
3520 			    wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
3521 
3522 			return (0);
3523 		}
3524 	} else {
3525 		mutex_enter(&EMLXS_PORT_LOCK);
3526 
3527 		ndlp->nlp_Rpi = 0xffff;
3528 		ndlp->nlp_DID = ldid;
3529 
3530 		bcopy((uint8_t *)sp,
3531 		    (uint8_t *)&ndlp->sparm, sizeof (SERV_PARM));
3532 
3533 		bcopy((uint8_t *)&sp->nodeName,
3534 		    (uint8_t *)&ndlp->nlp_nodename, sizeof (NAME_TYPE));
3535 
3536 		bcopy((uint8_t *)&sp->portName,
3537 		    (uint8_t *)&ndlp->nlp_portname, sizeof (NAME_TYPE));
3538 
3539 		wwn = (uint8_t *)&ndlp->nlp_portname;
3540 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_update_msg,
3541 		    "node=%p did=%06x rpi=%x "
3542 		    "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x",
3543 		    ndlp, ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0],
3544 		    wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
3545 
3546 		mutex_exit(&EMLXS_PORT_LOCK);
3547 
3548 		/* Open the node */
3549 		emlxs_node_open(vport, ndlp, hba->channel_ct);
3550 		emlxs_node_open(vport, ndlp, hba->channel_els);
3551 		emlxs_node_open(vport, ndlp, hba->channel_ip);
3552 		emlxs_node_open(vport, ndlp, hba->channel_fcp);
3553 	}
3554 
3555 	return (0);
3556 } /* emlxs_cmpl_reg_vpi */
3557 
3558 
3559 extern uint32_t
3560 emlxs_mb_reg_vpi(emlxs_port_t *port, emlxs_buf_t *sbp)
3561 {
3562 	emlxs_hba_t *hba = HBA;
3563 	MAILBOXQ *mbq;
3564 	MAILBOX	*mb;
3565 	int rval;
3566 
3567 	if (!(hba->flag & FC_NPIV_ENABLED)) {
3568 		return (0);
3569 	}
3570 
3571 	mutex_enter(&EMLXS_PORT_LOCK);
3572 
3573 	/* Can't reg vpi until ClearLA is sent */
3574 	if (hba->state != FC_READY) {
3575 		mutex_exit(&EMLXS_PORT_LOCK);
3576 
3577 		return (1);
3578 	}
3579 
3580 	/* Must have port id */
3581 	if (!port->did) {
3582 		mutex_exit(&EMLXS_PORT_LOCK);
3583 
3584 		return (1);
3585 	}
3586 
3587 	if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))) {
3588 		mutex_exit(&EMLXS_PORT_LOCK);
3589 
3590 		return (1);
3591 	}
3592 
3593 	port->flag |= EMLXS_PORT_REGISTERED;
3594 
3595 	mutex_exit(&EMLXS_PORT_LOCK);
3596 
3597 	mb = (MAILBOX *)mbq->mbox;
3598 
3599 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3600 		bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
3601 		mbq->nonembed = NULL;
3602 		mb->un.varRegVpi.vfi = port->VFIp->VFI;
3603 		mbq->mbox_cmpl = emlxs_cmpl_reg_vpi;
3604 	} else {
3605 		bzero((void *)mb, MAILBOX_CMD_BSIZE);
3606 		mbq->mbox_cmpl = NULL; /* no cmpl needed */
3607 	}
3608 
3609 	if (sbp) {
3610 		mbq->sbp = (uint8_t *)sbp;
3611 	}
3612 
3613 	mb->un.varRegVpi.vpi = port->vpi + hba->vpi_base;
3614 	mb->un.varRegVpi.sid = port->did;
3615 	mb->mbxCommand = MBX_REG_VPI;
3616 	mb->mbxOwner = OWN_HOST;
3617 
3618 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0);
3619 	if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) {
3620 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
3621 	}
3622 
3623 	return (0);
3624 
3625 } /* emlxs_mb_reg_vpi() */
3626 
3627 
3628 int
3629 emlxs_cmpl_unreg_vpi(void *arg1, MAILBOXQ *mbq)
3630 {
3631 	emlxs_hba_t *hba = (emlxs_hba_t *)arg1;
3632 	emlxs_port_t *vport;
3633 	MAILBOX *mb;
3634 
3635 	mb = (MAILBOX *)mbq;
3636 	if (mb->mbxStatus == MBX_SUCCESS) {
3637 		vport = &VPORT(mb->un.varUnregVpi.vpi);
3638 		vport->flag &= ~EMLXS_PORT_INIT_VPI_CMPL;
3639 		vport->flag &= ~EMLXS_PORT_REG_VPI_CMPL;
3640 	}
3641 	return (0);
3642 
3643 } /* emlxs_cmpl_unreg_vpi() */
3644 
3645 
3646 extern uint32_t
3647 emlxs_mb_unreg_vpi(emlxs_port_t *port)
3648 {
3649 	emlxs_hba_t	*hba = HBA;
3650 	MAILBOXQ	*mbq;
3651 	MAILBOX		*mb;
3652 	MAILBOX4	*mb4;
3653 	VFIobj_t	*vfip;
3654 	FCFIobj_t	*fcfp;
3655 	int		rval;
3656 
3657 	mutex_enter(&EMLXS_PORT_LOCK);
3658 
3659 	if (!(port->flag & EMLXS_PORT_REGISTERED)) {
3660 		mutex_exit(&EMLXS_PORT_LOCK);
3661 		return (0);
3662 	}
3663 
3664 	if (!(mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))) {
3665 		mutex_exit(&EMLXS_PORT_LOCK);
3666 		return (1);
3667 	}
3668 
3669 	port->flag &= ~EMLXS_PORT_REGISTERED;
3670 
3671 	mutex_exit(&EMLXS_PORT_LOCK);
3672 
3673 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3674 		mb4 = (MAILBOX4 *)mbq->mbox;
3675 		bzero((void *)mb4, MAILBOX_CMD_SLI4_BSIZE);
3676 		mb4->un.varUnRegVPI4.ii = 0; /* index is a VPI */
3677 		mb4->un.varUnRegVPI4.index = port->vpi + hba->vpi_base;
3678 		mb4->mbxCommand = MBX_UNREG_VPI;
3679 		mb4->mbxOwner = OWN_HOST;
3680 		mbq->mbox_cmpl = emlxs_cmpl_unreg_vpi;
3681 	} else {
3682 		mb = (MAILBOX *)mbq->mbox;
3683 		bzero((void *)mb, MAILBOX_CMD_BSIZE);
3684 		mb->un.varUnregVpi.vpi = port->vpi + hba->vpi_base;
3685 		mb->mbxCommand = MBX_UNREG_VPI;
3686 		mb->mbxOwner = OWN_HOST;
3687 		mbq->mbox_cmpl = NULL; /* no cmpl needed */
3688 	}
3689 
3690 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0);
3691 	if ((rval != MBX_BUSY) && (rval != MBX_SUCCESS)) {
3692 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
3693 	}
3694 
3695 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3696 		if ((vfip = port->VFIp) != NULL) {
3697 
3698 			fcfp = vfip->FCFIp;
3699 			if (port == fcfp->fcf_vpi) {
3700 				fcfp->fcf_vpi = NULL;
3701 			}
3702 
3703 			mutex_enter(&EMLXS_PORT_LOCK);
3704 			vfip->outstandingVPIs--;
3705 			if ((vfip->outstandingVPIs == 0) &&
3706 			    (hba->state == FC_LINK_DOWN)) {
3707 				mutex_exit(&EMLXS_PORT_LOCK);
3708 
3709 				/* No more VPIs so unreg the VFI */
3710 				(void) emlxs_mb_unreg_vfi(hba, vfip);
3711 			} else {
3712 				mutex_exit(&EMLXS_PORT_LOCK);
3713 			}
3714 		}
3715 	}
3716 	return (0);
3717 
3718 } /* emlxs_mb_unreg_vpi() */
3719 
3720 
3721 /*
3722  * emlxs_mb_config_farp  Issue a CONFIG FARP mailbox command
3723  */
3724 extern void
3725 emlxs_mb_config_farp(emlxs_hba_t *hba, MAILBOXQ *mbq)
3726 {
3727 	MAILBOX *mb = (MAILBOX *)mbq;
3728 
3729 	bzero((void *)mb, MAILBOX_CMD_BSIZE);
3730 
3731 	bcopy((uint8_t *)&hba->wwpn,
3732 	    (uint8_t *)&mb->un.varCfgFarp.portname, sizeof (NAME_TYPE));
3733 
3734 	bcopy((uint8_t *)&hba->wwpn,
3735 	    (uint8_t *)&mb->un.varCfgFarp.nodename, sizeof (NAME_TYPE));
3736 
3737 	mb->un.varCfgFarp.filterEnable = 1;
3738 	mb->un.varCfgFarp.portName = 1;
3739 	mb->un.varCfgFarp.nodeName = 1;
3740 	mb->mbxCommand = MBX_CONFIG_FARP;
3741 	mb->mbxOwner = OWN_HOST;
3742 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
3743 } /* emlxs_mb_config_farp() */
3744 
3745 
3746 /*
3747  * emlxs_mb_read_nv  Issue a READ CONFIG mailbox command
3748  */
3749 /*ARGSUSED*/
3750 extern void
3751 emlxs_mb_read_config(emlxs_hba_t *hba, MAILBOXQ *mbq)
3752 {
3753 	MAILBOX *mb = (MAILBOX *)mbq;
3754 
3755 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3756 		bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
3757 		mbq->nonembed = NULL;
3758 	} else {
3759 		bzero((void *)mb, MAILBOX_CMD_BSIZE);
3760 	}
3761 
3762 	mb->mbxCommand = MBX_READ_CONFIG;
3763 	mb->mbxOwner = OWN_HOST;
3764 	mbq->mbox_cmpl = NULL; /* no cmpl needed */
3765 } /* emlxs_mb_read_config() */
3766 
3767 
3768 /*
3769  * NAME:     emlxs_mb_put
3770  *
3771  * FUNCTION: put mailbox cmd onto the mailbox queue.
3772  *
3773  * EXECUTION ENVIRONMENT: process and interrupt level.
3774  *
3775  * NOTES:
3776  *
3777  * CALLED FROM: EMLXS_SLI_ISSUE_MBOX_CMD
3778  *
3779  * INPUT: hba           - pointer to the device info area
3780  *      mbp             - pointer to mailbox queue entry of mailbox cmd
3781  *
3782  * RETURNS: NULL - command queued
3783  */
3784 extern void
3785 emlxs_mb_put(emlxs_hba_t *hba, MAILBOXQ *mbq)
3786 {
3787 
3788 	mutex_enter(&EMLXS_MBOX_LOCK);
3789 
3790 	if (hba->mbox_queue.q_first) {
3791 
3792 		/*
3793 		 * queue command to end of list
3794 		 */
3795 		((MAILBOXQ *)hba->mbox_queue.q_last)->next = mbq;
3796 		hba->mbox_queue.q_last = (uint8_t *)mbq;
3797 		hba->mbox_queue.q_cnt++;
3798 	} else {
3799 
3800 		/*
3801 		 * add command to empty list
3802 		 */
3803 		hba->mbox_queue.q_first = (uint8_t *)mbq;
3804 		hba->mbox_queue.q_last = (uint8_t *)mbq;
3805 		hba->mbox_queue.q_cnt = 1;
3806 	}
3807 
3808 	mbq->next = NULL;
3809 
3810 	mutex_exit(&EMLXS_MBOX_LOCK);
3811 } /* emlxs_mb_put() */
3812 
3813 
3814 /*
3815  * NAME:     emlxs_mb_get
3816  *
3817  * FUNCTION: get a mailbox command from mailbox command queue
3818  *
3819  * EXECUTION ENVIRONMENT: interrupt level.
3820  *
3821  * NOTES:
3822  *
3823  * CALLED FROM: emlxs_handle_mb_event
3824  *
3825  * INPUT: hba       - pointer to the device info area
3826  *
3827  * RETURNS: NULL - no match found mb pointer - pointer to a mailbox command
3828  */
3829 extern MAILBOXQ *
3830 emlxs_mb_get(emlxs_hba_t *hba)
3831 {
3832 	MAILBOXQ	*p_first = NULL;
3833 
3834 	mutex_enter(&EMLXS_MBOX_LOCK);
3835 
3836 	if (hba->mbox_queue.q_first) {
3837 		p_first = (MAILBOXQ *)hba->mbox_queue.q_first;
3838 		hba->mbox_queue.q_first = (uint8_t *)p_first->next;
3839 
3840 		if (hba->mbox_queue.q_first == NULL) {
3841 			hba->mbox_queue.q_last = NULL;
3842 			hba->mbox_queue.q_cnt = 0;
3843 		} else {
3844 			hba->mbox_queue.q_cnt--;
3845 		}
3846 
3847 		p_first->next = NULL;
3848 	}
3849 
3850 	mutex_exit(&EMLXS_MBOX_LOCK);
3851 
3852 	return (p_first);
3853 
3854 } /* emlxs_mb_get() */
3855 
3856 
3857 /* EMLXS_PORT_LOCK must be held when calling this */
3858 void
3859 emlxs_mb_init(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t flag, uint32_t tmo)
3860 {
3861 #ifdef FMA_SUPPORT
3862 	emlxs_port_t *port = &PPORT;
3863 #endif	/* FMA_SUPPORT */
3864 	MATCHMAP	*mp;
3865 
3866 	HBASTATS.MboxIssued++;
3867 	hba->mbox_queue_flag = flag;
3868 
3869 	/* Set the Mailbox timer */
3870 	hba->mbox_timer = hba->timer_tics + tmo;
3871 
3872 	/* Initialize mailbox */
3873 	mbq->flag &= MBQ_INIT_MASK;
3874 	mbq->next = 0;
3875 
3876 	mutex_enter(&EMLXS_MBOX_LOCK);
3877 	hba->mbox_mbq = (uint8_t *)mbq;
3878 	mutex_exit(&EMLXS_MBOX_LOCK);
3879 
3880 	if (mbq->nonembed) {
3881 		mp = (MATCHMAP *) mbq->nonembed;
3882 		EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size,
3883 		    DDI_DMA_SYNC_FORDEV);
3884 	}
3885 
3886 	if (mbq->bp) {
3887 		mp = (MATCHMAP *) mbq->bp;
3888 		EMLXS_MPDATA_SYNC(mp->dma_handle, 0, mp->size,
3889 		    DDI_DMA_SYNC_FORDEV);
3890 	}
3891 	return;
3892 
3893 } /* emlxs_mb_init() */
3894 
3895 
3896 extern void
3897 emlxs_mb_fini(emlxs_hba_t *hba, MAILBOX *mb, uint32_t mbxStatus)
3898 {
3899 	emlxs_port_t	*port = &PPORT;
3900 	MATCHMAP	*mbox_nonembed;
3901 	MATCHMAP	*mbox_bp;
3902 	emlxs_buf_t	*mbox_sbp;
3903 	fc_unsol_buf_t	*mbox_ubp;
3904 	IOCBQ		*mbox_iocbq;
3905 	MAILBOXQ	*mbox_mbq;
3906 	MAILBOX		*mbox;
3907 	uint32_t	mbox_queue_flag;
3908 	emlxs_ub_priv_t	*ub_priv;
3909 
3910 	mutex_enter(&EMLXS_PORT_LOCK);
3911 
3912 	if (hba->mbox_queue_flag) {
3913 		HBASTATS.MboxCompleted++;
3914 
3915 		if (mbxStatus != MBX_SUCCESS) {
3916 			HBASTATS.MboxError++;
3917 		} else {
3918 			HBASTATS.MboxGood++;
3919 		}
3920 	}
3921 
3922 	mutex_enter(&EMLXS_MBOX_LOCK);
3923 	mbox_queue_flag = hba->mbox_queue_flag;
3924 	mbox_mbq = (MAILBOXQ *)hba->mbox_mbq;
3925 
3926 	if (mbox_mbq) {
3927 		mbox_nonembed = (MATCHMAP *)mbox_mbq->nonembed;
3928 		mbox_bp = (MATCHMAP *)mbox_mbq->bp;
3929 		mbox_sbp = (emlxs_buf_t *)mbox_mbq->sbp;
3930 		mbox_ubp = (fc_unsol_buf_t *)mbox_mbq->ubp;
3931 		mbox_iocbq = (IOCBQ *)mbox_mbq->iocbq;
3932 	} else {
3933 		mbox_nonembed = NULL;
3934 		mbox_bp = NULL;
3935 		mbox_sbp = NULL;
3936 		mbox_ubp = NULL;
3937 		mbox_iocbq = NULL;
3938 	}
3939 
3940 	hba->mbox_mbq = 0;
3941 	hba->mbox_queue_flag = 0;
3942 	hba->mbox_timer = 0;
3943 	mutex_exit(&EMLXS_MBOX_LOCK);
3944 
3945 	mutex_exit(&EMLXS_PORT_LOCK);
3946 
3947 	if (mbox_queue_flag == MBX_NOWAIT) {
3948 		/* Check for deferred MBUF cleanup */
3949 		if (mbox_bp) {
3950 			(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mbox_bp);
3951 		}
3952 		if (mbox_nonembed) {
3953 			(void) emlxs_mem_put(hba, MEM_BUF,
3954 			    (uint8_t *)mbox_nonembed);
3955 		}
3956 		if (mbox_mbq) {
3957 			(void) emlxs_mem_put(hba, MEM_MBOX,
3958 			    (uint8_t *)mbox_mbq);
3959 		}
3960 	} else {  /* MBX_WAIT */
3961 		if (mbox_mbq) {
3962 			if (mb) {
3963 				/* Copy the local mailbox provided back into */
3964 				/* the original mailbox */
3965 				if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3966 					bcopy((uint32_t *)mb,
3967 					    (uint32_t *)mbox_mbq,
3968 					    MAILBOX_CMD_SLI4_BSIZE);
3969 				} else {
3970 					bcopy((uint32_t *)mb,
3971 					    (uint32_t *)mbox_mbq,
3972 					    MAILBOX_CMD_BSIZE);
3973 				}
3974 			}
3975 
3976 			mbox = (MAILBOX *)mbox_mbq;
3977 			mbox->mbxStatus = mbxStatus;
3978 
3979 			/* Mark mailbox complete */
3980 			mbox_mbq->flag |= MBQ_COMPLETED;
3981 		}
3982 
3983 		/* Wake up the sleeping thread */
3984 		if (mbox_queue_flag == MBX_SLEEP) {
3985 			mutex_enter(&EMLXS_MBOX_LOCK);
3986 			cv_broadcast(&EMLXS_MBOX_CV);
3987 			mutex_exit(&EMLXS_MBOX_LOCK);
3988 		}
3989 	}
3990 
3991 #ifdef SFCT_SUPPORT
3992 	if (mb && mbox_sbp && mbox_sbp->fct_cmd) {
3993 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3994 		    "FCT mailbox: %s: status=%x",
3995 		    emlxs_mb_cmd_xlate(mb->mbxCommand),
3996 		    (uint32_t)mb->mbxStatus);
3997 	}
3998 #endif /* SFCT_SUPPORT */
3999 
4000 	/* Check for deferred pkt completion */
4001 	if (mbox_sbp) {
4002 		if (mbxStatus != MBX_SUCCESS) {
4003 			/* Set error status */
4004 			mbox_sbp->pkt_flags &= ~PACKET_STATE_VALID;
4005 			emlxs_set_pkt_state(mbox_sbp, IOSTAT_LOCAL_REJECT,
4006 			    IOERR_NO_RESOURCES, 1);
4007 		}
4008 
4009 		emlxs_pkt_complete(mbox_sbp, -1, 0, 1);
4010 	}
4011 
4012 	/* Check for deferred ub completion */
4013 	if (mbox_ubp) {
4014 		ub_priv = mbox_ubp->ub_fca_private;
4015 		port = ub_priv->port;
4016 
4017 		emlxs_ub_callback(port, mbox_ubp);
4018 	}
4019 
4020 	/* Special handling for vport PLOGI */
4021 	if (mbox_iocbq == (IOCBQ *)1) {
4022 		mbox_iocbq = NULL;
4023 	}
4024 
4025 	/* Check for deferred iocb tx */
4026 	if (mbox_iocbq) {
4027 		/* Check for driver special codes */
4028 		/* These indicate the mailbox is being flushed */
4029 		if (mbxStatus >= MBX_DRIVER_RESERVED) {
4030 			/* Set the error status and return it */
4031 			mbox_iocbq->iocb.ULPSTATUS = IOSTAT_LOCAL_REJECT;
4032 			mbox_iocbq->iocb.un.grsp.perr.statLocalError =
4033 			    IOERR_ABORT_REQUESTED;
4034 
4035 			emlxs_proc_channel_event(hba, mbox_iocbq->channel,
4036 			    mbox_iocbq);
4037 		} else {
4038 			EMLXS_SLI_ISSUE_IOCB_CMD(hba, mbox_iocbq->channel,
4039 			    mbox_iocbq);
4040 		}
4041 	}
4042 	return;
4043 
4044 } /* emlxs_mb_fini() */
4045 
4046 
4047 extern void
4048 emlxs_mb_flush(emlxs_hba_t *hba)
4049 {
4050 	MAILBOXQ	*mbq;
4051 	uint32_t	mbxStatus;
4052 
4053 	mbxStatus = (hba->flag & FC_HARDWARE_ERROR) ?
4054 	    MBX_HARDWARE_ERROR : MBX_NOT_FINISHED;
4055 
4056 	/* Flush out the active mbox command */
4057 	emlxs_mb_fini(hba, NULL, mbxStatus);
4058 
4059 	/* Flush out the queued mbox commands */
4060 	while (mbq = (MAILBOXQ *)emlxs_mb_get(hba)) {
4061 		mutex_enter(&EMLXS_MBOX_LOCK);
4062 		hba->mbox_queue_flag = MBX_NOWAIT;
4063 		hba->mbox_mbq = (uint8_t *)mbq;
4064 		mutex_exit(&EMLXS_MBOX_LOCK);
4065 
4066 		emlxs_mb_fini(hba, NULL, mbxStatus);
4067 	}
4068 
4069 	return;
4070 
4071 } /* emlxs_mb_flush */
4072 
4073 
4074 extern char *
4075 emlxs_mb_cmd_xlate(uint8_t cmd)
4076 {
4077 	static char	buffer[32];
4078 	uint32_t	i;
4079 	uint32_t	count;
4080 
4081 	count = sizeof (emlxs_mb_cmd_table) / sizeof (emlxs_table_t);
4082 	for (i = 0; i < count; i++) {
4083 		if (cmd == emlxs_mb_cmd_table[i].code) {
4084 			return (emlxs_mb_cmd_table[i].string);
4085 		}
4086 	}
4087 
4088 	(void) sprintf(buffer, "Cmd=0x%x", cmd);
4089 	return (buffer);
4090 
4091 } /* emlxs_mb_cmd_xlate() */
4092