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 2008 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, MAILBOX *mb,
34     uint32_t hbainit);
35 static void emlxs_mb_set_mask(emlxs_hba_t *hba, MAILBOX *mb, uint32_t mask,
36     uint32_t ringno);
37 static void emlxs_mb_set_debug(emlxs_hba_t *hba, MAILBOX *mb, uint32_t word0,
38     uint32_t word1, uint32_t word2);
39 static int32_t emlxs_mb_handle_cmd(emlxs_hba_t *hba, MAILBOX *mb);
40 static void emlxs_mb_write_nv(emlxs_hba_t *hba, MAILBOX *mb);
41 
42 static void emlxs_mb_init(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t flag,
43     uint32_t tmo);
44 static void emlxs_mb_retry(emlxs_hba_t *hba, MAILBOX *mb);
45 
46 
47 emlxs_table_t emlxs_mb_cmd_table[] =
48 {
49 	{MBX_SHUTDOWN, "SHUTDOWN"},
50 	{MBX_LOAD_SM, "LOAD_SM"},
51 	{MBX_READ_NV, "READ_NV"},
52 	{MBX_WRITE_NV, "WRITE_NV"},
53 	{MBX_RUN_BIU_DIAG, "RUN_BIU_DIAG"},
54 	{MBX_INIT_LINK, "INIT_LINK"},
55 	{MBX_DOWN_LINK, "DOWN_LINK"},
56 	{MBX_CONFIG_LINK, "CONFIG_LINK"},
57 	{MBX_PART_SLIM, "PART_SLIM"},
58 	{MBX_CONFIG_RING, "CONFIG_RING"},
59 	{MBX_RESET_RING, "RESET_RING"},
60 	{MBX_READ_CONFIG, "READ_CONFIG"},
61 	{MBX_READ_RCONFIG, "READ_RCONFIG"},
62 	{MBX_READ_SPARM, "READ_SPARM"},
63 	{MBX_READ_STATUS, "READ_STATUS"},
64 	{MBX_READ_RPI, "READ_RPI"},
65 	{MBX_READ_XRI, "READ_XRI"},
66 	{MBX_READ_REV, "READ_REV"},
67 	{MBX_READ_LNK_STAT, "READ_LNK_STAT"},
68 	{MBX_REG_LOGIN, "REG_LOGIN"},
69 	{MBX_UNREG_LOGIN, "UNREG_LOGIN"},
70 	{MBX_READ_LA, "READ_LA"},
71 	{MBX_CLEAR_LA, "CLEAR_LA"},
72 	{MBX_DUMP_MEMORY, "DUMP_MEMORY"},
73 	{MBX_DUMP_CONTEXT, "DUMP_CONTEXT"},
74 	{MBX_RUN_DIAGS, "RUN_DIAGS"},
75 	{MBX_RESTART, "RESTART"},
76 	{MBX_UPDATE_CFG, "UPDATE_CFG"},
77 	{MBX_DOWN_LOAD, "DOWN_LOAD"},
78 	{MBX_DEL_LD_ENTRY, "DEL_LD_ENTRY"},
79 	{MBX_RUN_PROGRAM, "RUN_PROGRAM"},
80 	{MBX_SET_MASK, "SET_MASK"},
81 	{MBX_SET_VARIABLE, "SET_VARIABLE"},
82 	{MBX_UNREG_D_ID, "UNREG_D_ID"},
83 	{MBX_KILL_BOARD, "KILL_BOARD"},
84 	{MBX_CONFIG_FARP, "CONFIG_FARP"},
85 	{MBX_LOAD_AREA, "LOAD_AREA"},
86 	{MBX_RUN_BIU_DIAG64, "RUN_BIU_DIAG64"},
87 	{MBX_CONFIG_PORT, "CONFIG_PORT"},
88 	{MBX_READ_SPARM64, "READ_SPARM64"},
89 	{MBX_READ_RPI64, "READ_RPI64"},
90 	{MBX_CONFIG_MSI, "CONFIG_MSI"},
91 	{MBX_CONFIG_MSIX, "CONFIG_MSIX"},
92 	{MBX_REG_LOGIN64, "REG_LOGIN64"},
93 	{MBX_READ_LA64, "READ_LA64"},
94 	{MBX_FLASH_WR_ULA, "FLASH_WR_ULA"},
95 	{MBX_SET_DEBUG, "SET_DEBUG"},
96 	{MBX_GET_DEBUG, "GET_DEBUG"},
97 	{MBX_LOAD_EXP_ROM, "LOAD_EXP_ROM"},
98 	{MBX_BEACON, "BEACON"},
99 	{MBX_CONFIG_HBQ, "CONFIG_HBQ"},	/* SLI3 */
100 	{MBX_REG_VPI, "REG_VPI"},	/* NPIV */
101 	{MBX_ASYNC_EVENT, "ASYNC_EVENT"},
102 	{MBX_HEARTBEAT, "HEARTBEAT"},
103 	{MBX_READ_EVENT_LOG_STATUS, "READ_EVENT_LOG_STATUS"},
104 	{MBX_READ_EVENT_LOG, "READ_EVENT_LOG"},
105 	{MBX_WRITE_EVENT_LOG, "WRITE_EVENT_LOG"},
106 	{MBX_NV_LOG, "NV_LOG"}
107 
108 };	/* emlxs_mb_cmd_table */
109 
110 
111 /* ARGSUSED */
112 extern void
113 emlxs_mb_async_event(emlxs_hba_t *hba, MAILBOX *mb)
114 {
115 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
116 
117 	mb->mbxCommand = MBX_ASYNC_EVENT;
118 	mb->mbxOwner = OWN_HOST;
119 	mb->un.varWords[0] = FC_ELS_RING;
120 
121 	return;
122 
123 } /* emlxs_mb_async_event() */
124 
125 
126 /* ARGSUSED */
127 extern void
128 emlxs_mb_heartbeat(emlxs_hba_t *hba, MAILBOX *mb)
129 {
130 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
131 
132 	mb->mbxCommand = MBX_HEARTBEAT;
133 	mb->mbxOwner = OWN_HOST;
134 
135 	return;
136 
137 } /* emlxs_mb_heartbeat() */
138 
139 
140 #ifdef MSI_SUPPORT
141 
142 /* ARGSUSED */
143 extern void
144 emlxs_mb_config_msi(emlxs_hba_t *hba, MAILBOX *mb, uint32_t *intr_map,
145     uint32_t intr_count)
146 {
147 	uint32_t i;
148 	uint32_t mask;
149 
150 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
151 
152 	mb->mbxCommand = MBX_CONFIG_MSI;
153 
154 	/* Set the default message id to zero */
155 	mb->un.varCfgMSI.defaultPresent = 1;
156 	mb->un.varCfgMSI.defaultMessageNumber = 0;
157 
158 	for (i = 1; i < intr_count; i++) {
159 		mask = intr_map[i];
160 
161 		mb->un.varCfgMSI.attConditions |= mask;
162 
163 #ifdef EMLXS_BIG_ENDIAN
164 		if (mask & HA_R0ATT) {
165 			mb->un.varCfgMSI.messageNumberByHA[3] = i;
166 		}
167 		if (mask & HA_R1ATT) {
168 			mb->un.varCfgMSI.messageNumberByHA[7] = i;
169 		}
170 		if (mask & HA_R2ATT) {
171 			mb->un.varCfgMSI.messageNumberByHA[11] = i;
172 		}
173 		if (mask & HA_R3ATT) {
174 			mb->un.varCfgMSI.messageNumberByHA[15] = i;
175 		}
176 		if (mask & HA_LATT) {
177 			mb->un.varCfgMSI.messageNumberByHA[29] = i;
178 		}
179 		if (mask & HA_MBATT) {
180 			mb->un.varCfgMSI.messageNumberByHA[30] = i;
181 		}
182 		if (mask & HA_ERATT) {
183 			mb->un.varCfgMSI.messageNumberByHA[31] = i;
184 		}
185 #endif	/* EMLXS_BIG_ENDIAN */
186 
187 #ifdef EMLXS_LITTLE_ENDIAN
188 		/* Accounts for half word swap of LE architecture */
189 		if (mask & HA_R0ATT) {
190 			mb->un.varCfgMSI.messageNumberByHA[2] = i;
191 		}
192 		if (mask & HA_R1ATT) {
193 			mb->un.varCfgMSI.messageNumberByHA[6] = i;
194 		}
195 		if (mask & HA_R2ATT) {
196 			mb->un.varCfgMSI.messageNumberByHA[10] = i;
197 		}
198 		if (mask & HA_R3ATT) {
199 			mb->un.varCfgMSI.messageNumberByHA[14] = i;
200 		}
201 		if (mask & HA_LATT) {
202 			mb->un.varCfgMSI.messageNumberByHA[28] = i;
203 		}
204 		if (mask & HA_MBATT) {
205 			mb->un.varCfgMSI.messageNumberByHA[31] = i;
206 		}
207 		if (mask & HA_ERATT) {
208 			mb->un.varCfgMSI.messageNumberByHA[30] = i;
209 		}
210 #endif	/* EMLXS_LITTLE_ENDIAN */
211 	}
212 
213 	mb->mbxOwner = OWN_HOST;
214 
215 	return;
216 
217 } /* emlxs_mb_config_msi() */
218 
219 
220 /* ARGSUSED */
221 extern void
222 emlxs_mb_config_msix(emlxs_hba_t *hba, MAILBOX *mb, uint32_t *intr_map,
223     uint32_t intr_count)
224 {
225 	uint32_t i;
226 	uint32_t mask;
227 
228 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
229 
230 	mb->mbxCommand = MBX_CONFIG_MSIX;
231 
232 	/* Set the default message id to zero */
233 	mb->un.varCfgMSIX.defaultPresent = 1;
234 	mb->un.varCfgMSIX.defaultMessageNumber = 0;
235 
236 	for (i = 1; i < intr_count; i++) {
237 		mask = intr_map[i];
238 
239 		mb->un.varCfgMSIX.attConditions1 |= mask;
240 
241 #ifdef EMLXS_BIG_ENDIAN
242 		if (mask & HA_R0ATT) {
243 			mb->un.varCfgMSIX.messageNumberByHA[3] = i;
244 		}
245 		if (mask & HA_R1ATT) {
246 			mb->un.varCfgMSIX.messageNumberByHA[7] = i;
247 		}
248 		if (mask & HA_R2ATT) {
249 			mb->un.varCfgMSIX.messageNumberByHA[11] = i;
250 		}
251 		if (mask & HA_R3ATT) {
252 			mb->un.varCfgMSIX.messageNumberByHA[15] = i;
253 		}
254 		if (mask & HA_LATT) {
255 			mb->un.varCfgMSIX.messageNumberByHA[29] = i;
256 		}
257 		if (mask & HA_MBATT) {
258 			mb->un.varCfgMSIX.messageNumberByHA[30] = i;
259 		}
260 		if (mask & HA_ERATT) {
261 			mb->un.varCfgMSIX.messageNumberByHA[31] = i;
262 		}
263 #endif	/* EMLXS_BIG_ENDIAN */
264 
265 #ifdef EMLXS_LITTLE_ENDIAN
266 		/* Accounts for word swap of LE architecture */
267 		if (mask & HA_R0ATT) {
268 			mb->un.varCfgMSIX.messageNumberByHA[0] = i;
269 		}
270 		if (mask & HA_R1ATT) {
271 			mb->un.varCfgMSIX.messageNumberByHA[4] = i;
272 		}
273 		if (mask & HA_R2ATT) {
274 			mb->un.varCfgMSIX.messageNumberByHA[8] = i;
275 		}
276 		if (mask & HA_R3ATT) {
277 			mb->un.varCfgMSIX.messageNumberByHA[12] = i;
278 		}
279 		if (mask & HA_LATT) {
280 			mb->un.varCfgMSIX.messageNumberByHA[30] = i;
281 		}
282 		if (mask & HA_MBATT) {
283 			mb->un.varCfgMSIX.messageNumberByHA[29] = i;
284 		}
285 		if (mask & HA_ERATT) {
286 			mb->un.varCfgMSIX.messageNumberByHA[28] = i;
287 		}
288 #endif	/* EMLXS_LITTLE_ENDIAN */
289 	}
290 
291 	mb->mbxOwner = OWN_HOST;
292 
293 	return;
294 
295 } /* emlxs_mb_config_msix() */
296 
297 
298 #endif	/* MSI_SUPPORT */
299 
300 /* ARGSUSED */
301 extern void
302 emlxs_mb_reset_ring(emlxs_hba_t *hba, MAILBOX *mb, uint32_t ringno)
303 {
304 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
305 
306 	mb->mbxCommand = MBX_RESET_RING;
307 	mb->un.varRstRing.ring_no = ringno;
308 	mb->mbxOwner = OWN_HOST;
309 
310 	return;
311 
312 } /* emlxs_mb_reset_ring() */
313 
314 
315 
316 /*
317  *  emlxs_mb_dump_vpd  Issue a DUMP MEMORY
318  *                     mailbox command
319  */
320 /* ARGSUSED */
321 extern void
322 emlxs_mb_dump_vpd(emlxs_hba_t *hba, MAILBOX *mb, uint32_t offset)
323 {
324 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
325 
326 	/*
327 	 * Setup to dump VPD region
328 	 */
329 	mb->mbxCommand = MBX_DUMP_MEMORY;
330 	mb->un.varDmp.cv = 1;
331 	mb->un.varDmp.type = DMP_NV_PARAMS;
332 	mb->un.varDmp.entry_index = offset;
333 	mb->un.varDmp.region_id = DMP_VPD_REGION;
334 	mb->un.varDmp.word_cnt = DMP_VPD_DUMP_WCOUNT;	/* limited by */
335 							/*   mailbox size */
336 
337 	mb->un.varDmp.co = 0;
338 	mb->un.varDmp.resp_offset = 0;
339 	mb->mbxOwner = OWN_HOST;
340 } /* emlxs_mb_dump_vpd() */
341 
342 
343 /*
344  *  emlxs_mb_read_nv  Issue a READ NVPARAM
345  *                  mailbox command
346  */
347 /* ARGSUSED */
348 extern void
349 emlxs_mb_read_nv(emlxs_hba_t *hba, MAILBOX *mb)
350 {
351 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
352 
353 	mb->mbxCommand = MBX_READ_NV;
354 	mb->mbxOwner = OWN_HOST;
355 
356 } /* End emlxs_mb_read_nv */
357 
358 
359 /*
360  *  emlxs_mb_read_rev  Issue a READ REV
361  *                   mailbox command
362  */
363 /* ARGSUSED */
364 extern void
365 emlxs_mb_read_rev(emlxs_hba_t *hba, MAILBOX *mb, uint32_t v3)
366 {
367 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
368 
369 	mb->un.varRdRev.cv = 1;
370 
371 	if (v3) {
372 		mb->un.varRdRev.cv3 = 1;
373 	}
374 
375 	mb->mbxCommand = MBX_READ_REV;
376 	mb->mbxOwner = OWN_HOST;
377 
378 } /* End emlxs_mb_read_rev */
379 
380 
381 /*
382  *  emlxs_mb_run_biu_diag  Issue a RUN_BIU_DIAG
383  *                     mailbox command
384  */
385 /* ARGSUSED */
386 extern uint32_t
387 emlxs_mb_run_biu_diag(emlxs_hba_t *hba, MAILBOX *mb, uint64_t out,
388     uint64_t in)
389 {
390 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
391 
392 	mb->mbxCommand = MBX_RUN_BIU_DIAG64;
393 	mb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize = MEM_ELSBUF_SIZE;
394 	mb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh =
395 	    (uint32_t)putPaddrHigh(out);
396 	mb->un.varBIUdiag.un.s2.xmit_bde64.addrLow =
397 	    (uint32_t)putPaddrLow(out);
398 	mb->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeSize = MEM_ELSBUF_SIZE;
399 	mb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh =
400 	    (uint32_t)putPaddrHigh(in);
401 	mb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = (uint32_t)putPaddrLow(in);
402 	mb->mbxOwner = OWN_HOST;
403 
404 	return (0);
405 
406 } /* End emlxs_mb_run_biu_diag */
407 
408 
409 /*
410  *  emlxs_mb_read_la  Issue a READ LA
411  *                  mailbox command
412  */
413 extern uint32_t
414 emlxs_mb_read_la(emlxs_hba_t *hba, MAILBOX *mb)
415 {
416 	MATCHMAP *mp;
417 
418 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
419 
420 	if ((mp = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF)) == 0) {
421 		mb->mbxCommand = MBX_READ_LA64;
422 
423 		return (1);
424 	}
425 	mb->mbxCommand = MBX_READ_LA64;
426 	mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize = 128;
427 	mb->un.varReadLA.un.lilpBde64.addrHigh =
428 	    (uint32_t)putPaddrHigh(mp->phys);
429 	mb->un.varReadLA.un.lilpBde64.addrLow =
430 	    (uint32_t)putPaddrLow(mp->phys);
431 	mb->mbxOwner = OWN_HOST;
432 
433 	/*
434 	 * save address for completion
435 	 */
436 	((MAILBOXQ *)mb)->bp = (uint8_t *)mp;
437 
438 	return (0);
439 
440 } /* emlxs_mb_read_la() */
441 
442 
443 /*
444  *  emlxs_mb_clear_la  Issue a CLEAR LA
445  *                   mailbox command
446  */
447 extern void
448 emlxs_mb_clear_la(emlxs_hba_t *hba, MAILBOX *mb)
449 {
450 #ifdef FC_RPI_CHECK
451 	emlxs_rpi_check(hba);
452 #endif	/* FC_RPI_CHECK */
453 
454 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
455 
456 	mb->un.varClearLA.eventTag = hba->link_event_tag;
457 	mb->mbxCommand = MBX_CLEAR_LA;
458 	mb->mbxOwner = OWN_HOST;
459 
460 	return;
461 
462 } /* End emlxs_mb_clear_la */
463 
464 
465 /*
466  *  emlxs_mb_read_status  Issue a READ STATUS
467  *                      mailbox command
468  */
469 /* ARGSUSED */
470 extern void
471 emlxs_mb_read_status(emlxs_hba_t *hba, MAILBOX *mb)
472 {
473 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
474 
475 	mb->mbxCommand = MBX_READ_STATUS;
476 	mb->mbxOwner = OWN_HOST;
477 
478 } /* End fc_read_status */
479 
480 
481 /*
482  *  emlxs_mb_read_lnk_stat  Issue a LINK STATUS
483  *                        mailbox command
484  */
485 /* ARGSUSED */
486 extern void
487 emlxs_mb_read_lnk_stat(emlxs_hba_t *hba, MAILBOX *mb)
488 {
489 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
490 
491 	mb->mbxCommand = MBX_READ_LNK_STAT;
492 	mb->mbxOwner = OWN_HOST;
493 
494 } /* End emlxs_mb_read_lnk_stat */
495 
496 
497 /*
498  *  emlxs_mb_write_nv  Issue a WRITE NVPARAM
499  *                   mailbox command
500  */
501 static void
502 emlxs_emb_mb_write_nv(emlxs_hba_t *hba, MAILBOX *mb)
503 {
504 	int32_t i;
505 	emlxs_config_t *cfg = &CFG;
506 
507 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
508 
509 	bcopy((void *) &hba->wwnn,
510 	    (void *) mb->un.varWTnvp.nodename,
511 	    sizeof (NAME_TYPE));
512 
513 	bcopy((void *) &hba->wwpn,
514 	    (void *) mb->un.varWTnvp.portname,
515 	    sizeof (NAME_TYPE));
516 
517 	mb->un.varWTnvp.pref_DID = 0;
518 	mb->un.varWTnvp.hardAL_PA = (uint8_t)cfg[CFG_ASSIGN_ALPA].current;
519 	mb->un.varWTnvp.rsvd1[0] = 0xffffffff;
520 	mb->un.varWTnvp.rsvd1[1] = 0xffffffff;
521 	mb->un.varWTnvp.rsvd1[2] = 0xffffffff;
522 	for (i = 0; i < 21; i++) {
523 		mb->un.varWTnvp.rsvd3[i] = 0xffffffff;
524 	}
525 
526 	mb->mbxCommand = MBX_WRITE_NV;
527 	mb->mbxOwner = OWN_HOST;
528 } /* End emlxs_mb_write_nv */
529 
530 
531 /*
532  *  emlxs_mb_part_slim  Issue a PARTITION SLIM
533  *                    mailbox command
534  */
535 static void
536 emlxs_mb_part_slim(emlxs_hba_t *hba, MAILBOX *mb, uint32_t hbainit)
537 {
538 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
539 
540 
541 	mb->un.varSlim.numRing = hba->ring_count;
542 	mb->un.varSlim.hbainit = hbainit;
543 	mb->mbxCommand = MBX_PART_SLIM;
544 	mb->mbxOwner = OWN_HOST;
545 
546 } /* End emlxs_mb_part_slim */
547 
548 
549 /*
550  *  emlxs_mb_config_ring  Issue a CONFIG RING
551  *                      mailbox command
552  */
553 extern void
554 emlxs_mb_config_ring(emlxs_hba_t *hba, int32_t ring, MAILBOX *mb)
555 {
556 	int32_t i;
557 	int32_t j;
558 
559 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
560 
561 	j = 0;
562 	for (i = 0; i < ring; i++) {
563 		j += hba->ring_masks[i];
564 	}
565 
566 	for (i = 0; i < hba->ring_masks[ring]; i++) {
567 		if ((j + i) >= 6) {
568 			break;
569 		}
570 		mb->un.varCfgRing.rrRegs[i].rval = hba->ring_rval[j + i];
571 		mb->un.varCfgRing.rrRegs[i].rmask = hba->ring_rmask[j + i];
572 
573 		mb->un.varCfgRing.rrRegs[i].tval = hba->ring_tval[j + i];
574 		mb->un.varCfgRing.rrRegs[i].tmask = hba->ring_tmask[j + i];
575 	}
576 
577 	mb->un.varCfgRing.ring = ring;
578 	mb->un.varCfgRing.profile = 0;
579 	mb->un.varCfgRing.maxOrigXchg = 0;
580 	mb->un.varCfgRing.maxRespXchg = 0;
581 	mb->un.varCfgRing.recvNotify = 1;
582 	mb->un.varCfgRing.numMask = hba->ring_masks[ring];
583 	mb->mbxCommand = MBX_CONFIG_RING;
584 	mb->mbxOwner = OWN_HOST;
585 
586 	return;
587 
588 } /* End emlxs_mb_config_ring */
589 
590 
591 /*
592  *  emlxs_mb_config_link  Issue a CONFIG LINK
593  *                      mailbox command
594  */
595 extern void
596 emlxs_mb_config_link(emlxs_hba_t *hba, MAILBOX *mb)
597 {
598 	emlxs_port_t *port = &PPORT;
599 	emlxs_config_t *cfg = &CFG;
600 
601 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
602 
603 	/*
604 	 * NEW_FEATURE SLI-2, Coalescing Response Feature.
605 	 */
606 	if (cfg[CFG_CR_DELAY].current) {
607 		mb->un.varCfgLnk.cr = 1;
608 		mb->un.varCfgLnk.ci = 1;
609 		mb->un.varCfgLnk.cr_delay = cfg[CFG_CR_DELAY].current;
610 		mb->un.varCfgLnk.cr_count = cfg[CFG_CR_COUNT].current;
611 	}
612 	if (cfg[CFG_ACK0].current)
613 		mb->un.varCfgLnk.ack0_enable = 1;
614 
615 	mb->un.varCfgLnk.myId = port->did;
616 	mb->un.varCfgLnk.edtov = hba->fc_edtov;
617 	mb->un.varCfgLnk.arbtov = hba->fc_arbtov;
618 	mb->un.varCfgLnk.ratov = hba->fc_ratov;
619 	mb->un.varCfgLnk.rttov = hba->fc_rttov;
620 	mb->un.varCfgLnk.altov = hba->fc_altov;
621 	mb->un.varCfgLnk.crtov = hba->fc_crtov;
622 	mb->un.varCfgLnk.citov = hba->fc_citov;
623 	mb->mbxCommand = MBX_CONFIG_LINK;
624 	mb->mbxOwner = OWN_HOST;
625 
626 	return;
627 
628 } /* emlxs_mb_config_link() */
629 
630 
631 /*
632  *  emlxs_mb_init_link  Issue an INIT LINK
633  *                    mailbox command
634  */
635 extern void
636 emlxs_mb_init_link(emlxs_hba_t *hba, MAILBOX *mb, uint32_t topology,
637     uint32_t linkspeed)
638 {
639 	emlxs_vpd_t *vpd = &VPD;
640 	emlxs_config_t *cfg = &CFG;
641 
642 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
643 
644 	switch (topology) {
645 	case FLAGS_LOCAL_LB:
646 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
647 		mb->un.varInitLnk.link_flags |= FLAGS_LOCAL_LB;
648 		break;
649 	case FLAGS_TOPOLOGY_MODE_LOOP_PT:
650 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
651 		mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER;
652 		break;
653 	case FLAGS_TOPOLOGY_MODE_PT_PT:
654 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT;
655 		break;
656 	case FLAGS_TOPOLOGY_MODE_LOOP:
657 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
658 		break;
659 	case FLAGS_TOPOLOGY_MODE_PT_LOOP:
660 		mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT;
661 		mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER;
662 		break;
663 	}
664 
665 	if (cfg[CFG_LILP_ENABLE].current == 0) {
666 		/* Disable LIRP/LILP support */
667 		mb->un.varInitLnk.link_flags |= FLAGS_LIRP_LILP;
668 	}
669 	/*
670 	 * Setting up the link speed
671 	 */
672 	switch (linkspeed) {
673 	case 0:
674 		break;
675 
676 	case 1:
677 		if (!(vpd->link_speed & LMT_1GB_CAPABLE)) {
678 			linkspeed = 0;
679 		}
680 		break;
681 
682 	case 2:
683 		if (!(vpd->link_speed & LMT_2GB_CAPABLE)) {
684 			linkspeed = 0;
685 		}
686 		break;
687 
688 	case 4:
689 		if (!(vpd->link_speed & LMT_4GB_CAPABLE)) {
690 			linkspeed = 0;
691 		}
692 		break;
693 
694 	case 8:
695 		if (!(vpd->link_speed & LMT_8GB_CAPABLE)) {
696 			linkspeed = 0;
697 		}
698 		break;
699 
700 	case 10:
701 		if (!(vpd->link_speed & LMT_10GB_CAPABLE)) {
702 			linkspeed = 0;
703 		}
704 		break;
705 
706 	default:
707 		linkspeed = 0;
708 		break;
709 
710 	}
711 
712 	if ((linkspeed > 0) && (vpd->feaLevelHigh >= 0x02)) {
713 		mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
714 		mb->un.varInitLnk.link_speed = linkspeed;
715 	}
716 	mb->un.varInitLnk.link_flags |= FLAGS_PREABORT_RETURN;
717 
718 	mb->un.varInitLnk.fabric_AL_PA = (uint8_t)cfg[CFG_ASSIGN_ALPA].current;
719 	mb->mbxCommand = (volatile uint8_t) MBX_INIT_LINK;
720 	mb->mbxOwner = OWN_HOST;
721 
722 
723 	return;
724 
725 } /* emlxs_mb_init_link() */
726 
727 
728 /*
729  *  emlxs_mb_down_link  Issue a DOWN LINK
730  *                    mailbox command
731  */
732 /* ARGSUSED */
733 extern void
734 emlxs_mb_down_link(emlxs_hba_t *hba, MAILBOX *mb)
735 {
736 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
737 
738 	mb->mbxCommand = MBX_DOWN_LINK;
739 	mb->mbxOwner = OWN_HOST;
740 
741 	return;
742 
743 } /* emlxs_mb_down_link() */
744 
745 
746 /*
747  *  emlxs_mb_read_sparam  Issue a READ SPARAM
748  *                      mailbox command
749  */
750 extern uint32_t
751 emlxs_mb_read_sparam(emlxs_hba_t *hba, MAILBOX *mb)
752 {
753 	MATCHMAP *mp;
754 
755 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
756 
757 	if ((mp = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF)) == 0) {
758 		mb->mbxCommand = MBX_READ_SPARM64;
759 
760 		return (1);
761 	}
762 	mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (SERV_PARM);
763 	mb->un.varRdSparm.un.sp64.addrHigh = (uint32_t)putPaddrHigh(mp->phys);
764 	mb->un.varRdSparm.un.sp64.addrLow = (uint32_t)putPaddrLow(mp->phys);
765 	mb->mbxCommand = MBX_READ_SPARM64;
766 	mb->mbxOwner = OWN_HOST;
767 
768 	/*
769 	 * save address for completion
770 	 */
771 	((MAILBOXQ *)mb)->bp = (uint8_t *)mp;
772 
773 	return (0);
774 
775 } /* emlxs_mb_read_sparam() */
776 
777 
778 /*
779  *  emlxs_mb_read_rpi    Issue a READ RPI
780  *                     mailbox command
781  */
782 /* ARGSUSED */
783 extern uint32_t
784 emlxs_mb_read_rpi(emlxs_hba_t *hba, uint32_t rpi, MAILBOX *mb, uint32_t flag)
785 {
786 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
787 
788 	/*
789 	 * Set flag to issue action on cmpl
790 	 */
791 	mb->un.varWords[30] = flag;
792 	mb->un.varRdRPI.reqRpi = (volatile uint16_t) rpi;
793 	mb->mbxCommand = MBX_READ_RPI64;
794 	mb->mbxOwner = OWN_HOST;
795 
796 	return (0);
797 
798 } /* End emlxs_mb_read_rpi */
799 
800 
801 /*
802  *  emlxs_mb_read_xri    Issue a READ XRI
803  *                     mailbox command
804  */
805 /* ARGSUSED */
806 extern uint32_t
807 emlxs_mb_read_xri(emlxs_hba_t *hba, uint32_t xri, MAILBOX *mb, uint32_t flag)
808 {
809 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
810 
811 	/*
812 	 * Set flag to issue action on cmpl
813 	 */
814 	mb->un.varWords[30] = flag;
815 	mb->un.varRdXRI.reqXri = (volatile uint16_t) xri;
816 	mb->mbxCommand = MBX_READ_XRI;
817 	mb->mbxOwner = OWN_HOST;
818 
819 	return (0);
820 
821 } /* End emlxs_mb_read_xri */
822 
823 
824 /* ARGSUSED */
825 extern int32_t
826 emlxs_mb_check_sparm(emlxs_hba_t *hba, SERV_PARM *nsp)
827 {
828 	uint32_t nsp_value;
829 	uint32_t *iptr;
830 
831 	if (nsp->cmn.fPort) {
832 		return (0);
833 	}
834 	/* Validate the service parameters */
835 	iptr = (uint32_t *)& nsp->portName;
836 	if (iptr[0] == 0 && iptr[1] == 0) {
837 		return (1);
838 	}
839 	iptr = (uint32_t *)& nsp->nodeName;
840 	if (iptr[0] == 0 && iptr[1] == 0) {
841 		return (2);
842 	}
843 	if (nsp->cls2.classValid) {
844 		nsp_value = ((nsp->cls2.rcvDataSizeMsb & 0x0f) << 8) |
845 		    nsp->cls2.rcvDataSizeLsb;
846 
847 		/*
848 		 * If the receive data length is zero then set it to the CSP
849 		 * value
850 		 */
851 		if (!nsp_value) {
852 			nsp->cls2.rcvDataSizeMsb = nsp->cmn.bbRcvSizeMsb;
853 			nsp->cls2.rcvDataSizeLsb = nsp->cmn.bbRcvSizeLsb;
854 			return (0);
855 		}
856 	}
857 	if (nsp->cls3.classValid) {
858 		nsp_value = ((nsp->cls3.rcvDataSizeMsb & 0x0f) << 8) |
859 		    nsp->cls3.rcvDataSizeLsb;
860 
861 		/*
862 		 * If the receive data length is zero then set it to the CSP
863 		 * value
864 		 */
865 		/* This prevents a Emulex adapter bug from occurring */
866 		if (!nsp_value) {
867 			nsp->cls3.rcvDataSizeMsb = nsp->cmn.bbRcvSizeMsb;
868 			nsp->cls3.rcvDataSizeLsb = nsp->cmn.bbRcvSizeLsb;
869 			return (0);
870 		}
871 	}
872 	return (0);
873 
874 } /* emlxs_mb_check_sparm() */
875 
876 
877 /*
878  *  emlxs_mb_reg_did  Issue a REG_LOGIN
879  *                    mailbox command
880  */
881 extern uint32_t
882 emlxs_mb_reg_did(emlxs_port_t *port, uint32_t did, SERV_PARM *param,
883     emlxs_buf_t *sbp, fc_unsol_buf_t *ubp, IOCBQ *iocbq)
884 {
885 	emlxs_hba_t *hba = HBA;
886 	MATCHMAP *mp;
887 	MAILBOXQ *mbq;
888 	MAILBOX *mb;
889 	uint32_t rval;
890 
891 	/* Check for invalid node ids to register */
892 	if (did == 0 || (did & 0xff000000)) {
893 		return (1);
894 	}
895 	if ((rval = emlxs_mb_check_sparm(hba, param))) {
896 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_failed_msg,
897 		    "Invalid service parameters. did=%06x rval=%d", did, rval);
898 
899 		return (1);
900 	}
901 	/* Check if the node limit has been reached */
902 	if (port->node_count >= hba->max_nodes) {
903 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_failed_msg,
904 		    "Limit reached. did=%06x count=%d", did, port->node_count);
905 
906 		return (1);
907 	}
908 	if (!(mbq = (MAILBOXQ *) emlxs_mem_get(hba, MEM_MBOX | MEM_PRI))) {
909 		return (1);
910 	}
911 	/* Build login request */
912 	if ((mp = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF | MEM_PRI)) == 0) {
913 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
914 		return (1);
915 	}
916 	bcopy((void *) param, (void *) mp->virt, sizeof (SERV_PARM));
917 
918 	mb = (MAILBOX *) mbq->mbox;
919 	mb->un.varRegLogin.un.sp64.tus.f.bdeSize = sizeof (SERV_PARM);
920 	mb->un.varRegLogin.un.sp64.addrHigh = (uint32_t)putPaddrHigh(mp->phys);
921 	mb->un.varRegLogin.un.sp64.addrLow = (uint32_t)putPaddrLow(mp->phys);
922 	mb->un.varRegLogin.rpi = 0;
923 	mb->un.varRegLogin.did = did;
924 	mb->un.varWords[30] = 0;	/* flags */
925 	mb->mbxCommand = MBX_REG_LOGIN64;
926 	mb->mbxOwner = OWN_HOST;
927 
928 #ifdef SLI3_SUPPORT
929 	mb->un.varRegLogin.vpi =
930 	    port->vpi;
931 #endif	/* SLI3_SUPPORT */
932 
933 	mbq->sbp = (uint8_t *)sbp;
934 	mbq->ubp = (uint8_t *)ubp;
935 	mbq->iocbq = (uint8_t *)iocbq;
936 	mbq->bp = (uint8_t *)mp;
937 
938 	if (emlxs_mb_issue_cmd(hba, mb, MBX_NOWAIT, 0) != MBX_BUSY) {
939 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
940 	}
941 	return (0);
942 
943 } /* emlxs_mb_reg_did() */
944 
945 /*
946  *  emlxs_mb_unreg_rpi  Issue a UNREG_LOGIN
947  *                      mailbox command
948  */
949 extern uint32_t
950 emlxs_mb_unreg_rpi(emlxs_port_t *port, uint32_t rpi, emlxs_buf_t *sbp,
951     fc_unsol_buf_t *ubp, IOCBQ *iocbq)
952 {
953 	emlxs_hba_t *hba = HBA;
954 	MAILBOXQ *mbq;
955 	MAILBOX *mb;
956 	NODELIST *ndlp;
957 
958 	if (rpi != 0xffff) {
959 		/* Make sure the node does already exist */
960 		ndlp = emlxs_node_find_rpi(port, rpi);
961 
962 
963 		if (ndlp) {
964 			/*
965 			 * If we just unregistered the host node then clear
966 			 * the host DID
967 			 */
968 			if (ndlp->nlp_DID == port->did) {
969 				port->did = 0;
970 			}
971 			/* remove it */
972 			emlxs_node_rm(port, ndlp);
973 
974 		} else {
975 			return (1);
976 		}
977 	} else {	/* Unreg all */
978 		emlxs_node_destroy_all(port);
979 	}
980 
981 	if (!(mbq = (MAILBOXQ *) emlxs_mem_get(hba, MEM_MBOX | MEM_PRI))) {
982 		return (1);
983 	}
984 	mb = (MAILBOX *) mbq->mbox;
985 	mb->un.varUnregLogin.rpi = (uint16_t)rpi;
986 
987 #ifdef SLI3_SUPPORT
988 	mb->un.varUnregLogin.vpi = port->vpi;
989 #endif	/* SLI3_SUPPORT */
990 
991 	mb->mbxCommand = MBX_UNREG_LOGIN;
992 	mb->mbxOwner = OWN_HOST;
993 	mbq->sbp = (uint8_t *)sbp;
994 	mbq->ubp = (uint8_t *)ubp;
995 	mbq->iocbq = (uint8_t *)iocbq;
996 
997 	if (emlxs_mb_issue_cmd(hba, mb, MBX_NOWAIT, 0) != MBX_BUSY) {
998 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
999 	}
1000 	return (0);
1001 } /* emlxs_mb_unreg_rpi() */
1002 
1003 /*
1004  *  emlxs_mb_unreg_did  Issue a UNREG_DID
1005  *                      mailbox command
1006  */
1007 extern uint32_t
1008 emlxs_mb_unreg_did(emlxs_port_t *port, uint32_t did, emlxs_buf_t *sbp,
1009     fc_unsol_buf_t *ubp, IOCBQ *iocbq)
1010 {
1011 	emlxs_hba_t *hba = HBA;
1012 	NODELIST *ndlp;
1013 	MAILBOXQ *mbq;
1014 	MAILBOX *mb;
1015 
1016 	/*
1017 	 * Unregister all default RPIs if did == 0xffffffff
1018 	 */
1019 	if (did != 0xffffffff) {
1020 		/* Check for base node */
1021 		if (did == Bcast_DID) {
1022 			/* just flush base node */
1023 			(void) emlxs_tx_node_flush(port, &port->node_base,
1024 			    0, 0, 0);
1025 			(void) emlxs_chipq_node_flush(port, 0, &port->node_base,
1026 			    0);
1027 
1028 			/* Return now */
1029 			return (1);
1030 		}
1031 		/*
1032 		 * A zero DID means that we are trying to unreg the host node
1033 		 * after a link bounce
1034 		 */
1035 
1036 		/*
1037 		 * If the prev_did == 0 then the adapter has been reset and
1038 		 * there is no need in unregistering
1039 		 */
1040 
1041 		/*
1042 		 * If the prev_did != 0 then we can look for the hosts last
1043 		 * known DID node
1044 		 */
1045 
1046 		if (did == 0) {
1047 			if (port->prev_did == 0) {
1048 				return (1);
1049 			}
1050 			did = port->prev_did;
1051 		}
1052 		/* Make sure the node does already exist */
1053 		ndlp = emlxs_node_find_did(port, did);
1054 
1055 
1056 		if (ndlp) {
1057 			/* remove it */
1058 			emlxs_node_rm(port, ndlp);
1059 
1060 			/*
1061 			 * If we just unregistered the host node then clear
1062 			 * the host DID
1063 			 */
1064 			if (did == port->did) {
1065 				port->did = 0;
1066 			}
1067 		} else {
1068 			return (1);
1069 		}
1070 	}
1071 	if (!(mbq = (MAILBOXQ *) emlxs_mem_get(hba, MEM_MBOX | MEM_PRI))) {
1072 		return (1);
1073 	}
1074 	mb = (MAILBOX *) mbq->mbox;
1075 	mb->un.varUnregDID.did = did;
1076 
1077 #ifdef SLI3_SUPPORT
1078 	mb->un.varUnregDID.vpi = port->vpi;
1079 #endif	/* SLI3_SUPPORT */
1080 
1081 	mb->mbxCommand = MBX_UNREG_D_ID;
1082 	mb->mbxOwner = OWN_HOST;
1083 	mbq->sbp = (uint8_t *)sbp;
1084 	mbq->ubp = (uint8_t *)ubp;
1085 	mbq->iocbq = (uint8_t *)iocbq;
1086 
1087 	if (emlxs_mb_issue_cmd(hba, mb, MBX_NOWAIT, 0) != MBX_BUSY) {
1088 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
1089 	}
1090 	return (0);
1091 
1092 } /* End emlxs_mb_unreg_did */
1093 
1094 
1095 /*
1096  *  emlxs_mb_set_mask   Issue a SET MASK
1097  *                    mailbox command
1098  */
1099 /* ARGSUSED */
1100 static void
1101 emlxs_mb_set_mask(emlxs_hba_t *hba, MAILBOX *mb, uint32_t mask,
1102     uint32_t ringno)
1103 {
1104 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
1105 
1106 	mb->un.varWords[0] = 0x11223344;	/* set passwd */
1107 	mb->un.varWords[1] = mask;	/* set mask */
1108 	mb->un.varWords[2] = ringno;	/* set ringno */
1109 	mb->mbxCommand = MBX_SET_MASK;
1110 	mb->mbxOwner = OWN_HOST;
1111 
1112 } /* End emlxs_mb_set_mask */
1113 
1114 
1115 /*
1116  *  emlxs_mb_set_debug  Issue a special debug
1117  *                    mailbox command
1118  */
1119 /* ARGSUSED */
1120 static void
1121 emlxs_mb_set_debug(emlxs_hba_t *hba, MAILBOX *mb, uint32_t word0,
1122     uint32_t word1, uint32_t word2)
1123 {
1124 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
1125 
1126 	mb->un.varWords[0] = word0;
1127 	mb->un.varWords[1] = word1;
1128 	mb->un.varWords[2] = word2;
1129 	mb->mbxCommand = MBX_SET_DEBUG;
1130 	mb->mbxOwner = OWN_HOST;
1131 
1132 } /* End emlxs_mb_set_debug */
1133 
1134 
1135 /*
1136  *  emlxs_mb_set_var   Issue a special debug mbox
1137  *                    command to write slim
1138  */
1139 /* ARGSUSED */
1140 extern void
1141 emlxs_mb_set_var(emlxs_hba_t *hba, MAILBOX *mb, uint32_t addr, uint32_t value)
1142 {
1143 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
1144 
1145 	/* addr = 0x090597 is AUTO ABTS disable for ELS commands */
1146 	/* addr = 0x052198 is DELAYED ABTS enable for ELS commands */
1147 	/* addr = 0x100506 is for setting PCI MAX READ value */
1148 
1149 	/*
1150 	 * Always turn on DELAYED ABTS for ELS timeouts
1151 	 */
1152 	if ((addr == 0x052198) && (value == 0)) {
1153 		value = 1;
1154 	}
1155 	mb->un.varWords[0] = addr;
1156 	mb->un.varWords[1] = value;
1157 	mb->mbxCommand = MBX_SET_VARIABLE;
1158 	mb->mbxOwner = OWN_HOST;
1159 
1160 } /* End emlxs_mb_set_var */
1161 
1162 
1163 /*
1164  * Disable Traffic Cop
1165  */
1166 /* ARGSUSED */
1167 extern void
1168 emlxs_disable_tc(emlxs_hba_t *hba, MAILBOX *mb)
1169 {
1170 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
1171 
1172 	mb->un.varWords[0] = 0x50797;
1173 	mb->un.varWords[1] = 0;
1174 	mb->un.varWords[2] = 0xfffffffe;
1175 	mb->mbxCommand = MBX_SET_VARIABLE;
1176 	mb->mbxOwner = OWN_HOST;
1177 
1178 } /* End emlxs_disable_tc */
1179 
1180 
1181 /*
1182  *  emlxs_mb_config_port  Issue a CONFIG_PORT
1183  *                      mailbox command
1184  */
1185 extern uint32_t
1186 emlxs_mb_config_port(emlxs_hba_t *hba, MAILBOX *mb, uint32_t sli_mode,
1187     uint32_t hbainit)
1188 {
1189 	emlxs_vpd_t *vpd = &VPD;
1190 	emlxs_port_t *port = &PPORT;
1191 	emlxs_config_t *cfg;
1192 	RING *rp;
1193 	uint64_t pcb;
1194 	uint64_t mbx;
1195 	uint64_t hgp;
1196 	uint64_t pgp;
1197 	uint64_t rgp;
1198 	MAILBOX *mbox;
1199 	SLIM2 *slim;
1200 	SLI2_RDSC *rdsc;
1201 	uint64_t offset;
1202 	uint32_t Laddr;
1203 	uint32_t i;
1204 
1205 	cfg = &CFG;
1206 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
1207 	mbox = NULL;
1208 	slim = NULL;
1209 
1210 	mb->mbxCommand = MBX_CONFIG_PORT;
1211 	mb->mbxOwner = OWN_HOST;
1212 
1213 	mb->un.varCfgPort.pcbLen = sizeof (PCB);
1214 
1215 #ifdef SLI3_SUPPORT
1216 	mb->un.varCfgPort.hbainit[0] = hbainit;
1217 #else	/* SLI3_SUPPORT */
1218 	mb->un.varCfgPort.hbainit = hbainit;
1219 #endif	/* SLI3_SUPPORT */
1220 
1221 	pcb = hba->slim2.phys + (uint64_t)(unsigned long)& (slim->pcb);
1222 	mb->un.varCfgPort.pcbLow = (uint32_t)putPaddrLow(pcb);
1223 	mb->un.varCfgPort.pcbHigh = (uint32_t)putPaddrHigh(pcb);
1224 
1225 	/* Set Host pointers in SLIM flag */
1226 	mb->un.varCfgPort.hps = 1;
1227 
1228 	/* Initialize hba structure for assumed default SLI2 mode */
1229 	/* If config port succeeds, then we will update it then   */
1230 	hba->sli_mode = 2;
1231 	hba->vpi_max = 1;
1232 	hba->flag &= ~FC_NPIV_ENABLED;
1233 
1234 #ifdef SLI3_SUPPORT
1235 	if (sli_mode >= 3) {
1236 		mb->un.varCfgPort.sli_mode = 3;
1237 		mb->un.varCfgPort.cerbm = 1;
1238 		mb->un.varCfgPort.max_hbq = EMLXS_NUM_HBQ;
1239 
1240 #ifdef NPIV_SUPPORT
1241 		if (cfg[CFG_NPIV_ENABLE].current) {
1242 			if (vpd->feaLevelHigh >= 0x09) {
1243 				if (hba->model_info.chip >= EMLXS_SATURN_CHIP) {
1244 					mb->un.varCfgPort.vpi_max =
1245 					    MAX_VPORTS - 1;
1246 				} else {
1247 					mb->un.varCfgPort.vpi_max =
1248 					    MAX_VPORTS_LIMITED - 1;
1249 				}
1250 
1251 				mb->un.varCfgPort.cmv = 1;
1252 			} else {
1253 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
1254 				    "CFGPORT: Firmware does not support NPIV. "
1255 				    "level=%d", vpd->feaLevelHigh);
1256 			}
1257 
1258 		}
1259 #endif	/* NPIV_SUPPORT */
1260 	}
1261 #endif	/* SLI3_SUPPORT */
1262 
1263 	/*
1264 	 * Now setup pcb
1265 	 */
1266 	((SLIM2 *) hba->slim2.virt)->pcb.type = TYPE_NATIVE_SLI2;
1267 	((SLIM2 *) hba->slim2.virt)->pcb.feature = FEATURE_INITIAL_SLI2;
1268 	((SLIM2 *) hba->slim2.virt)->pcb.maxRing = (hba->ring_count - 1);
1269 	((SLIM2 *) hba->slim2.virt)->pcb.mailBoxSize = sizeof (MAILBOX) +
1270 	    MBOX_EXTENSION_SIZE;
1271 
1272 	mbx = hba->slim2.phys + (uint64_t)(unsigned long)& (slim->mbx);
1273 	((SLIM2 *)hba->slim2.virt)->pcb.mbAddrHigh =
1274 	    (uint32_t)putPaddrHigh(mbx);
1275 	((SLIM2 *)hba->slim2.virt)->pcb.mbAddrLow = (uint32_t)putPaddrLow(mbx);
1276 
1277 
1278 	/*
1279 	 * Set up HGP - Port Memory
1280 	 *
1281 	 * CR0Put    - SLI2(no HBQs) = 0xc0, With HBQs = 0x80
1282 	 * RR0Get 0xc4 0x84
1283 	 * CR1Put 0xc8 0x88
1284 	 * RR1Get 0xcc 0x8c
1285 	 * CR2Put 0xd0 0x90
1286 	 * RR2Get 0xd4 0x94
1287 	 * CR3Put 0xd8 0x98
1288 	 * RR3Get 0xdc 0x9c
1289 	 *
1290 	 * Reserved 0xa0-0xbf
1291 	 *
1292 	 * If HBQs configured:
1293 	 * HBQ 0 Put ptr  0xc0
1294 	 * HBQ 1 Put ptr  0xc4
1295 	 * HBQ 2 Put ptr  0xc8
1296 	 * ......
1297 	 * HBQ(M-1)Put Pointer 0xc0+(M-1)*4
1298 	 */
1299 
1300 #ifdef SLI3_SUPPORT
1301 	if (sli_mode >= 3) {
1302 		/* ERBM is enabled */
1303 		hba->hgp_ring_offset = 0x80;
1304 		hba->hgp_hbq_offset = 0xC0;
1305 
1306 		hba->iocb_cmd_size = SLI3_IOCB_CMD_SIZE;
1307 		hba->iocb_rsp_size = SLI3_IOCB_RSP_SIZE;
1308 
1309 	} else	/* SLI2 */
1310 #endif	/* SLI3_SUPPORT */
1311 	{
1312 		/* ERBM is disabled */
1313 		hba->hgp_ring_offset = 0xC0;
1314 		hba->hgp_hbq_offset = 0;
1315 
1316 		hba->iocb_cmd_size = SLI2_IOCB_CMD_SIZE;
1317 		hba->iocb_rsp_size = SLI2_IOCB_RSP_SIZE;
1318 	}
1319 
1320 	/* The Sbus card uses Host Memory. The PCI card uses SLIM POINTER */
1321 	if (hba->bus_type == SBUS_FC) {
1322 		hgp = hba->slim2.phys +
1323 		    (uint64_t)(unsigned long)& (mbox->us.s2.host);
1324 		((SLIM2 *)hba->slim2.virt)->pcb.hgpAddrHigh =
1325 		    (uint32_t)putPaddrHigh(hgp);
1326 		((SLIM2 *)hba->slim2.virt)->pcb.hgpAddrLow =
1327 		    (uint32_t)putPaddrLow(hgp);
1328 	} else {
1329 		((SLIM2 *)hba->slim2.virt)->pcb.hgpAddrHigh =
1330 		    (uint32_t)ddi_get32(hba->pci_acc_handle,
1331 		    (uint32_t *)(hba->pci_addr + PCI_BAR_1_REGISTER));
1332 
1333 		Laddr = ddi_get32(hba->pci_acc_handle,
1334 		    (uint32_t *)(hba->pci_addr + PCI_BAR_0_REGISTER));
1335 		Laddr &= ~0x4;
1336 		((SLIM2 *)hba->slim2.virt)->pcb.hgpAddrLow =
1337 		    (uint32_t)(Laddr + hba->hgp_ring_offset);
1338 
1339 	}
1340 
1341 	pgp = hba->slim2.phys + (uint64_t)(unsigned long)& (mbox->us.s2.port);
1342 	((SLIM2 *)hba->slim2.virt)->pcb.pgpAddrHigh =
1343 	    (uint32_t)putPaddrHigh(pgp);
1344 	((SLIM2 *)hba->slim2.virt)->pcb.pgpAddrLow = (uint32_t)putPaddrLow(pgp);
1345 
1346 	offset = 0;
1347 	for (i = 0; i < 4; i++) {
1348 		rp = &hba->ring[i];
1349 		rdsc = &((SLIM2 *) hba->slim2.virt)->pcb.rdsc[i];
1350 
1351 		/* Setup command ring */
1352 		rgp = hba->slim2.phys +
1353 		    (uint64_t)(unsigned long)& (slim->IOCBs[offset]);
1354 		rdsc->cmdAddrHigh = (uint32_t)putPaddrHigh(rgp);
1355 		rdsc->cmdAddrLow = (uint32_t)putPaddrLow(rgp);
1356 		rdsc->cmdEntries = rp->fc_numCiocb;
1357 
1358 		rp->fc_cmdringaddr = (void *) &((SLIM2 *) hba->slim2.virt)->
1359 		    IOCBs[offset];
1360 		offset += rdsc->cmdEntries * hba->iocb_cmd_size;
1361 
1362 		/* Setup response ring */
1363 		rgp = hba->slim2.phys +
1364 		    (uint64_t)(unsigned long)& (slim->IOCBs[offset]);
1365 		rdsc->rspAddrHigh = (uint32_t)putPaddrHigh(rgp);
1366 		rdsc->rspAddrLow = (uint32_t)putPaddrLow(rgp);
1367 		rdsc->rspEntries = rp->fc_numRiocb;
1368 
1369 		rp->fc_rspringaddr = (void *) &((SLIM2 *) hba->slim2.virt)->
1370 		    IOCBs[offset];
1371 		offset += rdsc->rspEntries * hba->iocb_rsp_size;
1372 	}
1373 
1374 	emlxs_pcimem_bcopy((uint32_t *)(&((SLIM2 *) hba->slim2.virt)->pcb),
1375 	    (uint32_t *)(&((SLIM2 *) hba->slim2.virt)->pcb), sizeof (PCB));
1376 
1377 	offset =
1378 	    ((uint64_t)(unsigned long)& (((SLIM2 *) hba->slim2.virt)->pcb) -
1379 	    (uint64_t)(unsigned long)hba->slim2.virt);
1380 	emlxs_mpdata_sync(hba->slim2.dma_handle, (off_t)offset, sizeof (PCB),
1381 	    DDI_DMA_SYNC_FORDEV);
1382 
1383 	return (0);
1384 
1385 } /* emlxs_mb_config_port() */
1386 
1387 
1388 #ifdef SLI3_SUPPORT
1389 extern void
1390 emlxs_mb_config_hbq(emlxs_hba_t *hba, MAILBOX *mb, int hbq_id)
1391 {
1392 	HBQ_INIT_t *hbq;
1393 	int i;
1394 
1395 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
1396 
1397 	hbq = &hba->hbq_table[hbq_id];
1398 
1399 	mb->un.varCfgHbq.hbqId = hbq_id;
1400 	mb->un.varCfgHbq.numEntries = hbq->HBQ_numEntries;
1401 	mb->un.varCfgHbq.recvNotify = hbq->HBQ_recvNotify;
1402 	mb->un.varCfgHbq.numMask = hbq->HBQ_num_mask;
1403 	mb->un.varCfgHbq.profile = hbq->HBQ_profile;
1404 	mb->un.varCfgHbq.ringMask = hbq->HBQ_ringMask;
1405 	mb->un.varCfgHbq.headerLen = hbq->HBQ_headerLen;
1406 	mb->un.varCfgHbq.logEntry = hbq->HBQ_logEntry;
1407 	mb->un.varCfgHbq.hbqaddrLow = putPaddrLow(hbq->HBQ_host_buf.phys);
1408 	mb->un.varCfgHbq.hbqaddrHigh = putPaddrHigh(hbq->HBQ_host_buf.phys);
1409 	mb->mbxCommand = MBX_CONFIG_HBQ;
1410 	mb->mbxOwner = OWN_HOST;
1411 
1412 	/* Copy info for profiles 2,3,5. Other profiles this area is reserved */
1413 	if ((hbq->HBQ_profile == 2) || (hbq->HBQ_profile == 3) ||
1414 	    (hbq->HBQ_profile == 5)) {
1415 		bcopy(&hbq->profiles.allprofiles,
1416 		    &mb->un.varCfgHbq.profiles.allprofiles,
1417 		    sizeof (hbq->profiles));
1418 	}
1419 	/* Return if no rctl / type masks for this HBQ */
1420 	if (!hbq->HBQ_num_mask) {
1421 		return;
1422 	}
1423 	/* Otherwise we setup specific rctl / type masks for this HBQ */
1424 	for (i = 0; i < hbq->HBQ_num_mask; i++) {
1425 		mb->un.varCfgHbq.hbqMasks[i].tmatch = hbq->HBQ_Masks[i].tmatch;
1426 		mb->un.varCfgHbq.hbqMasks[i].tmask = hbq->HBQ_Masks[i].tmask;
1427 		mb->un.varCfgHbq.hbqMasks[i].rctlmatch =
1428 		    hbq->HBQ_Masks[i].rctlmatch;
1429 		mb->un.varCfgHbq.hbqMasks[i].rctlmask =
1430 		    hbq->HBQ_Masks[i].rctlmask;
1431 	}
1432 
1433 	return;
1434 
1435 } /* emlxs_mb_config_hbq() */
1436 
1437 #endif	/* SLI3_SUPPORT */
1438 
1439 
1440 extern uint32_t
1441 emlxs_mb_reg_vpi(emlxs_port_t *port)
1442 {
1443 	emlxs_hba_t *hba = HBA;
1444 	MAILBOXQ *mbq;
1445 	MAILBOX *mb;
1446 
1447 	if (!(hba->flag & FC_NPIV_ENABLED)) {
1448 		return (0);
1449 	}
1450 	mutex_enter(&EMLXS_PORT_LOCK);
1451 
1452 	/* Can't reg vpi until ClearLA is sent */
1453 	if (hba->state != FC_READY) {
1454 		mutex_exit(&EMLXS_PORT_LOCK);
1455 
1456 		return (1);
1457 	}
1458 	/* Must have port id */
1459 	if (!port->did) {
1460 		mutex_exit(&EMLXS_PORT_LOCK);
1461 
1462 		return (1);
1463 	}
1464 	if (!(mbq = (MAILBOXQ *) emlxs_mem_get(hba, MEM_MBOX | MEM_PRI))) {
1465 		mutex_exit(&EMLXS_PORT_LOCK);
1466 
1467 		return (1);
1468 	}
1469 	port->flag |= EMLXS_PORT_REGISTERED;
1470 
1471 	mutex_exit(&EMLXS_PORT_LOCK);
1472 
1473 	mb = (MAILBOX *) mbq->mbox;
1474 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
1475 	mb->un.varRegVpi.vpi = port->vpi;
1476 	mb->un.varRegVpi.sid = port->did;
1477 	mb->mbxCommand = MBX_REG_VPI;
1478 	mb->mbxOwner = OWN_HOST;
1479 
1480 	if (emlxs_mb_issue_cmd(hba, mb, MBX_NOWAIT, 0) != MBX_BUSY) {
1481 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
1482 	}
1483 	return (0);
1484 
1485 } /* emlxs_mb_reg_vpi() */
1486 
1487 
1488 extern uint32_t
1489 emlxs_mb_unreg_vpi(emlxs_port_t *port)
1490 {
1491 	emlxs_hba_t *hba = HBA;
1492 	MAILBOXQ *mbq;
1493 	MAILBOX *mb;
1494 
1495 	mutex_enter(&EMLXS_PORT_LOCK);
1496 
1497 	if (!(port->flag & EMLXS_PORT_REGISTERED)) {
1498 		mutex_exit(&EMLXS_PORT_LOCK);
1499 
1500 		return (0);
1501 	}
1502 	if (!(mbq = (MAILBOXQ *) emlxs_mem_get(hba, MEM_MBOX | MEM_PRI))) {
1503 		mutex_exit(&EMLXS_PORT_LOCK);
1504 
1505 		return (1);
1506 	}
1507 	port->flag &= ~EMLXS_PORT_REGISTERED;
1508 
1509 	mutex_exit(&EMLXS_PORT_LOCK);
1510 
1511 	mb = (MAILBOX *) mbq->mbox;
1512 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
1513 	mb->un.varUnregVpi.vpi = port->vpi;
1514 	mb->mbxCommand = MBX_UNREG_VPI;
1515 	mb->mbxOwner = OWN_HOST;
1516 
1517 	if (emlxs_mb_issue_cmd(hba, mb, MBX_NOWAIT, 0) != MBX_BUSY) {
1518 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
1519 	}
1520 	return (0);
1521 
1522 } /* emlxs_mb_unreg_vpi() */
1523 
1524 
1525 /*
1526  *  emlxs_mb_config_farp  Issue a CONFIG FARP
1527  *                      mailbox command
1528  */
1529 extern void
1530 emlxs_mb_config_farp(emlxs_hba_t *hba, MAILBOX *mb)
1531 {
1532 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
1533 
1534 	bcopy((uint8_t *)& hba->wwpn,
1535 	    (uint8_t *)& mb->un.varCfgFarp.portname,
1536 	    sizeof (NAME_TYPE));
1537 
1538 	bcopy((uint8_t *)& hba->wwpn,
1539 	    (uint8_t *)& mb->un.varCfgFarp.nodename,
1540 	    sizeof (NAME_TYPE));
1541 
1542 	mb->un.varCfgFarp.filterEnable = 1;
1543 	mb->un.varCfgFarp.portName = 1;
1544 	mb->un.varCfgFarp.nodeName = 1;
1545 	mb->mbxCommand = MBX_CONFIG_FARP;
1546 	mb->mbxOwner = OWN_HOST;
1547 } /* emlxs_mb_config_farp() */
1548 
1549 
1550 /*
1551  *  emlxs_mb_read_nv  Issue a READ CONFIG
1552  *                  mailbox command
1553  */
1554 /* ARGSUSED */
1555 extern void
1556 emlxs_mb_read_config(emlxs_hba_t *hba, MAILBOX *mb)
1557 {
1558 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
1559 
1560 	mb->mbxCommand = MBX_READ_CONFIG;
1561 	mb->mbxOwner = OWN_HOST;
1562 
1563 } /* emlxs_mb_read_config() */
1564 
1565 
1566 
1567 /*
1568  * NAME:     emlxs_mb_put
1569  *
1570  * FUNCTION: put mailbox cmd onto the mailbox queue.
1571  *
1572  * EXECUTION ENVIRONMENT: process and interrupt level.
1573  *
1574  * NOTES:
1575  *
1576  * CALLED FROM: emlxs_mb_issue_cmd
1577  *
1578  * INPUT: hba           - pointer to the device info area mbp
1579  *                      - pointer to mailbox queue entry of mailbox cmd
1580  *
1581  * RETURNS: NULL - command queued
1582  */
1583 extern void
1584 emlxs_mb_put(emlxs_hba_t *hba, MAILBOXQ *mbq)
1585 {
1586 
1587 	mutex_enter(&EMLXS_MBOX_LOCK);
1588 
1589 	if (hba->mbox_queue.q_first) {
1590 
1591 		/*
1592 		 * queue command to end of list
1593 		 */
1594 		((MAILBOXQ *) hba->mbox_queue.q_last)->next = mbq;
1595 		hba->mbox_queue.q_last = (uint8_t *)mbq;
1596 		hba->mbox_queue.q_cnt++;
1597 	} else {
1598 
1599 		/*
1600 		 * add command to empty list
1601 		 */
1602 		hba->mbox_queue.q_first = (uint8_t *)mbq;
1603 		hba->mbox_queue.q_last = (uint8_t *)mbq;
1604 		hba->mbox_queue.q_cnt = 1;
1605 	}
1606 
1607 	mbq->next = NULL;
1608 
1609 	mutex_exit(&EMLXS_MBOX_LOCK);
1610 } /* emlxs_mb_put() */
1611 
1612 
1613 /*
1614  * NAME:     emlxs_mb_get
1615  *
1616  * FUNCTION: get a mailbox command from mailbox command queue
1617  *
1618  * EXECUTION ENVIRONMENT: interrupt level.
1619  *
1620  * NOTES:
1621  *
1622  * CALLED FROM: emlxs_handle_mb_event
1623  *
1624  * INPUT: hba       - pointer to the device info area
1625  *
1626  * RETURNS: NULL - no match found mb pointer - pointer to a mailbox command
1627  */
1628 extern MAILBOXQ *
1629 emlxs_mb_get(emlxs_hba_t *hba)
1630 {
1631 	MAILBOXQ *p_first = NULL;
1632 
1633 	mutex_enter(&EMLXS_MBOX_LOCK);
1634 
1635 	if (hba->mbox_queue.q_first) {
1636 		p_first = (MAILBOXQ *) hba->mbox_queue.q_first;
1637 		hba->mbox_queue.q_first = (uint8_t *)p_first->next;
1638 
1639 		if (hba->mbox_queue.q_first == NULL) {
1640 			hba->mbox_queue.q_last = NULL;
1641 			hba->mbox_queue.q_cnt = 0;
1642 		} else {
1643 			hba->mbox_queue.q_cnt--;
1644 		}
1645 
1646 		p_first->next = NULL;
1647 	}
1648 	mutex_exit(&EMLXS_MBOX_LOCK);
1649 
1650 	return (p_first);
1651 
1652 } /* emlxs_mb_get() */
1653 
1654 
1655 
1656 /* EMLXS_PORT_LOCK must be held when calling this */
1657 static void
1658 emlxs_mb_init(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t flag, uint32_t tmo)
1659 {
1660 	MATCHMAP *mp;
1661 
1662 	HBASTATS.MboxIssued++;
1663 	hba->mbox_queue_flag = flag;
1664 
1665 	/* Set the Mailbox timer */
1666 	hba->mbox_timer = hba->timer_tics + tmo;
1667 
1668 	/* Initialize mailbox */
1669 	mbq->flag &= MBQ_INIT_MASK;
1670 	hba->mbox_mbqflag = mbq->flag;
1671 
1672 	mbq->next = 0;
1673 
1674 	mutex_enter(&EMLXS_MBOX_LOCK);
1675 	if (flag == MBX_NOWAIT) {
1676 		hba->mbox_mbq = 0;
1677 	} else {
1678 		hba->mbox_mbq = (uint8_t *)mbq;
1679 	}
1680 	mutex_exit(&EMLXS_MBOX_LOCK);
1681 
1682 	if (mbq->bp) {
1683 		mp = (MATCHMAP *) mbq->bp;
1684 		emlxs_mpdata_sync(mp->dma_handle, 0, mp->size,
1685 		    DDI_DMA_SYNC_FORDEV);
1686 
1687 		hba->mbox_bp = mbq->bp;
1688 		mbq->bp = 0;
1689 	}
1690 	if (mbq->sbp) {
1691 		hba->mbox_sbp = mbq->sbp;
1692 		mbq->sbp = 0;
1693 	}
1694 	if (mbq->ubp) {
1695 		hba->mbox_ubp = mbq->ubp;
1696 		mbq->ubp = 0;
1697 	}
1698 	if (mbq->iocbq) {
1699 		hba->mbox_iocbq = mbq->iocbq;
1700 		mbq->iocbq = 0;
1701 	}
1702 #ifdef MBOX_EXT_SUPPORT
1703 	if (mbq->extbuf && mbq->extsize) {
1704 		hba->mbox_ext = mbq->extbuf;
1705 		hba->mbox_ext_size = mbq->extsize;
1706 	}
1707 #endif	/* MBOX_EXT_SUPPORT */
1708 
1709 	return;
1710 
1711 } /* emlxs_mb_init() */
1712 
1713 
1714 extern void
1715 emlxs_mb_fini(emlxs_hba_t *hba, MAILBOX *mb, uint32_t mbxStatus)
1716 {
1717 	emlxs_port_t *port = &PPORT;
1718 	MATCHMAP *mbox_bp;
1719 	emlxs_buf_t *mbox_sbp;
1720 	fc_unsol_buf_t *mbox_ubp;
1721 	IOCBQ *mbox_iocbq;
1722 	MAILBOXQ *mbox_mbq;
1723 	MAILBOX *mbox;
1724 	uint32_t mbox_queue_flag;
1725 	emlxs_ub_priv_t *ub_priv;
1726 
1727 	mutex_enter(&EMLXS_PORT_LOCK);
1728 
1729 	if (hba->mbox_queue_flag) {
1730 		HBASTATS.MboxCompleted++;
1731 
1732 		if (mbxStatus != MBX_SUCCESS) {
1733 			HBASTATS.MboxError++;
1734 		} else {
1735 			HBASTATS.MboxGood++;
1736 		}
1737 	}
1738 	mbox_bp = (MATCHMAP *) hba->mbox_bp;
1739 	mbox_sbp = (emlxs_buf_t *)hba->mbox_sbp;
1740 	mbox_ubp = (fc_unsol_buf_t *)hba->mbox_ubp;
1741 	mbox_iocbq = (IOCBQ *) hba->mbox_iocbq;
1742 	mbox_mbq = (MAILBOXQ *) hba->mbox_mbq;
1743 	mbox_queue_flag = hba->mbox_queue_flag;
1744 
1745 #ifdef MBOX_EXT_SUPPORT
1746 	hba->mbox_ext = 0;
1747 	hba->mbox_ext_size = 0;
1748 #endif	/* MBOX_EXT_SUPPORT */
1749 
1750 	hba->mbox_bp = 0;
1751 	hba->mbox_sbp = 0;
1752 	hba->mbox_ubp = 0;
1753 	hba->mbox_iocbq = 0;
1754 	hba->mbox_mbqflag = 0;
1755 	hba->mbox_mbq = 0;
1756 	hba->mbox_timer = 0;
1757 	hba->mbox_queue_flag = 0;
1758 
1759 	mutex_exit(&EMLXS_PORT_LOCK);
1760 
1761 	if (mbox_mbq) {
1762 		if (mb) {
1763 			/*
1764 			 * Copy the local mailbox provided back into the
1765 			 * original mailbox
1766 			 */
1767 			bcopy((uint32_t *)mb, (uint32_t *)mbox_mbq,
1768 			    MAILBOX_CMD_BSIZE);
1769 		}
1770 		mbox = (MAILBOX *) mbox_mbq;
1771 		mbox->mbxStatus = mbxStatus;
1772 
1773 		/* Mark mailbox complete */
1774 		mbox_mbq->flag |= MBQ_COMPLETED;
1775 
1776 		/* Wake up the sleeping thread */
1777 		if (mbox_queue_flag == MBX_SLEEP) {
1778 			mutex_enter(&EMLXS_MBOX_LOCK);
1779 			cv_broadcast(&EMLXS_MBOX_CV);
1780 			mutex_exit(&EMLXS_MBOX_LOCK);
1781 		}
1782 	}
1783 	/* Check for deferred MBUF cleanup */
1784 	if (mbox_bp && (mbox_queue_flag == MBX_NOWAIT)) {
1785 		(void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mbox_bp);
1786 	}
1787 #ifdef SFCT_SUPPORT
1788 	if (mbox_sbp && mbox_sbp->fct_cmd) {
1789 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1790 		    "FCT mailbox: %s: status=%x",
1791 		    emlxs_mb_cmd_xlate(mb->mbxCommand),
1792 		    (uint32_t)mb->mbxStatus);
1793 	}
1794 #endif	/* SFCT_SUPPORT */
1795 
1796 	/* Check for deferred pkt completion */
1797 	if (mbox_sbp) {
1798 		if (mbxStatus != MBX_SUCCESS) {
1799 			/* Set error status */
1800 			mbox_sbp->pkt_flags &= ~PACKET_STATE_VALID;
1801 			emlxs_set_pkt_state(mbox_sbp, IOSTAT_LOCAL_REJECT,
1802 			    IOERR_NO_RESOURCES, 1);
1803 		}
1804 		emlxs_pkt_complete(mbox_sbp, -1, 0, 1);
1805 	}
1806 	/* Check for deferred ub completion */
1807 	if (mbox_ubp) {
1808 		ub_priv = mbox_ubp->ub_fca_private;
1809 		port = ub_priv->port;
1810 
1811 		emlxs_ub_callback(port, mbox_ubp);
1812 	}
1813 	/* Check for deferred iocb tx */
1814 	if (mbox_iocbq) {
1815 		emlxs_issue_iocb_cmd(hba, mbox_iocbq->ring, mbox_iocbq);
1816 	}
1817 	return;
1818 
1819 } /* emlxs_mb_fini() */
1820 
1821 
1822 
1823 /* This should only be called with active MBX_NOWAIT mailboxes */
1824 static void
1825 emlxs_mb_retry(emlxs_hba_t *hba, MAILBOX *mb)
1826 {
1827 	MAILBOXQ *mbq;
1828 
1829 	mutex_enter(&EMLXS_PORT_LOCK);
1830 
1831 	HBASTATS.MboxCompleted++;
1832 
1833 	if (mb->mbxStatus != 0) {
1834 		HBASTATS.MboxError++;
1835 	} else {
1836 		HBASTATS.MboxGood++;
1837 	}
1838 
1839 	mbq = (MAILBOXQ *) mb;
1840 	mbq->bp = (uint8_t *)hba->mbox_bp;
1841 	mbq->sbp = (uint8_t *)hba->mbox_sbp;
1842 	mbq->ubp = (uint8_t *)hba->mbox_ubp;
1843 	mbq->iocbq = (uint8_t *)hba->mbox_iocbq;
1844 
1845 	hba->mbox_bp = 0;
1846 	hba->mbox_sbp = 0;
1847 	hba->mbox_ubp = 0;
1848 	hba->mbox_iocbq = 0;
1849 	hba->mbox_mbq = 0;
1850 	hba->mbox_mbqflag = 0;
1851 	hba->mbox_queue_flag = 0;
1852 
1853 	mutex_exit(&EMLXS_PORT_LOCK);
1854 
1855 	return;
1856 
1857 } /* emlxs_mb_retry() */
1858 
1859 
1860 
1861 /*
1862  *  emlxs_handle_mb_event
1863  *
1864  *  Description: Process a Mailbox Attention.
1865  *  Called from host_interrupt to process MBATT
1866  *
1867  *    Returns:
1868  *
1869  */
1870 extern uint32_t
1871 emlxs_handle_mb_event(emlxs_hba_t *hba)
1872 {
1873 	emlxs_port_t *port = &PPORT;
1874 	MAILBOX *mb;
1875 	MAILBOX *swpmb;
1876 	MAILBOX *mbox;
1877 	MAILBOXQ *mbq;
1878 	emlxs_config_t *cfg;
1879 	uint32_t control;
1880 	volatile uint32_t word0;
1881 	MATCHMAP *mbox_bp;
1882 	uint32_t la_enable;
1883 	off_t offset;
1884 	uint32_t i;
1885 	MAILBOXQ mailbox;
1886 
1887 	cfg = &CFG;
1888 	swpmb = (MAILBOX *) & word0;
1889 	mb = (MAILBOX *) & mailbox;
1890 
1891 	switch (hba->mbox_queue_flag) {
1892 	case 0:
1893 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_mbox_intr_msg,
1894 		    "No mailbox active.");
1895 		return (0);
1896 
1897 	case MBX_POLL:
1898 
1899 		/*
1900 		 * Mark mailbox complete, this should wake up any polling
1901 		 * threads
1902 		 */
1903 		/*
1904 		 * This can happen if interrupts are enabled while a polled
1905 		 * mailbox command is outstanding
1906 		 */
1907 		/*
1908 		 * If we don't set MBQ_COMPLETED here, the polling thread may
1909 		 * wait until timeout error occurs
1910 		 */
1911 
1912 		mutex_enter(&EMLXS_MBOX_LOCK);
1913 		mbq = (MAILBOXQ *) hba->mbox_mbq;
1914 		if (mbq) {
1915 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
1916 			    "Mailbox event. Completing Polled command.");
1917 			mbq->flag |= MBQ_COMPLETED;
1918 		}
1919 		mutex_exit(&EMLXS_MBOX_LOCK);
1920 
1921 		return (0);
1922 
1923 	case MBX_SLEEP:
1924 	case MBX_NOWAIT:
1925 		break;
1926 
1927 	default:
1928 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_completion_error_msg,
1929 		    "Invalid Mailbox flag (%x).");
1930 		return (0);
1931 	}
1932 
1933 	/* Get first word of mailbox */
1934 	if (hba->flag & FC_SLIM2_MODE) {
1935 		mbox = FC_SLIM2_MAILBOX(hba);
1936 		offset = (off_t)((uint64_t)(unsigned long)mbox -
1937 		    (uint64_t)(unsigned long)hba->slim2.virt);
1938 
1939 		emlxs_mpdata_sync(hba->slim2.dma_handle, offset,
1940 		    sizeof (uint32_t), DDI_DMA_SYNC_FORKERNEL);
1941 		word0 = *((volatile uint32_t *) mbox);
1942 		word0 = PCIMEM_LONG(word0);
1943 	} else {
1944 		mbox = FC_SLIM1_MAILBOX(hba);
1945 		word0 = READ_SLIM_ADDR(hba, ((volatile uint32_t *) mbox));
1946 	}
1947 
1948 	i = 0;
1949 	while (swpmb->mbxOwner == OWN_CHIP) {
1950 		if (i++ > 10000) {
1951 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_mbox_intr_msg,
1952 			    "OWN_CHIP: %s: status=%x",
1953 			    emlxs_mb_cmd_xlate(swpmb->mbxCommand),
1954 			    swpmb->mbxStatus);
1955 
1956 			return (1);
1957 		}
1958 		/* Get first word of mailbox */
1959 		if (hba->flag & FC_SLIM2_MODE) {
1960 			emlxs_mpdata_sync(hba->slim2.dma_handle, offset,
1961 			    sizeof (uint32_t), DDI_DMA_SYNC_FORKERNEL);
1962 			word0 = *((volatile uint32_t *) mbox);
1963 			word0 = PCIMEM_LONG(word0);
1964 		} else {
1965 			word0 = READ_SLIM_ADDR(hba,
1966 			    ((volatile uint32_t *) mbox));
1967 		}
1968 	}
1969 
1970 	/* Now that we are the owner, DMA Sync entire mailbox if needed */
1971 	if (hba->flag & FC_SLIM2_MODE) {
1972 		emlxs_mpdata_sync(hba->slim2.dma_handle, offset,
1973 		    MAILBOX_CMD_BSIZE, DDI_DMA_SYNC_FORKERNEL);
1974 		emlxs_pcimem_bcopy((uint32_t *)mbox, (uint32_t *)mb,
1975 		    MAILBOX_CMD_BSIZE);
1976 	} else {
1977 		READ_SLIM_COPY(hba, (uint32_t *)mb, (uint32_t *)mbox,
1978 		    MAILBOX_CMD_WSIZE);
1979 	}
1980 
1981 #ifdef MBOX_EXT_SUPPORT
1982 	if (hba->mbox_ext) {
1983 		uint32_t *mbox_ext = (uint32_t *)((uint8_t *)mbox +
1984 		    MBOX_EXTENSION_OFFSET);
1985 		off_t offset_ext = offset + MBOX_EXTENSION_OFFSET;
1986 
1987 		if (hba->flag & FC_SLIM2_MODE) {
1988 			emlxs_mpdata_sync(hba->slim2.dma_handle, offset_ext,
1989 			    hba->mbox_ext_size, DDI_DMA_SYNC_FORKERNEL);
1990 			emlxs_pcimem_bcopy(mbox_ext, (uint32_t *)hba->mbox_ext,
1991 			    hba->mbox_ext_size);
1992 		} else {
1993 			READ_SLIM_COPY(hba, (uint32_t *)hba->mbox_ext, mbox_ext,
1994 			    (hba->mbox_ext_size / 4));
1995 		}
1996 	}
1997 #endif	/* MBOX_EXT_SUPPORT */
1998 
1999 	/* Now sync the memory buffer if one was used */
2000 	if (hba->mbox_bp) {
2001 		mbox_bp = (MATCHMAP *) hba->mbox_bp;
2002 		emlxs_mpdata_sync(mbox_bp->dma_handle, 0, mbox_bp->size,
2003 		    DDI_DMA_SYNC_FORKERNEL);
2004 	}
2005 	/* Mailbox has been completely received at this point */
2006 
2007 	if (mb->mbxCommand == MBX_HEARTBEAT) {
2008 		hba->heartbeat_active = 0;
2009 		goto done;
2010 	}
2011 	if (hba->mbox_queue_flag == MBX_SLEEP) {
2012 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
2013 		    "Received.  %s: status=%x Sleep.",
2014 		    emlxs_mb_cmd_xlate(swpmb->mbxCommand), swpmb->mbxStatus);
2015 	} else {
2016 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
2017 		    "Completed. %s: status=%x",
2018 		    emlxs_mb_cmd_xlate(swpmb->mbxCommand), swpmb->mbxStatus);
2019 	}
2020 
2021 	/* Filter out passthru mailbox */
2022 	if (hba->mbox_mbqflag & MBQ_PASSTHRU) {
2023 		goto done;
2024 	}
2025 	/* If succesful, process the result */
2026 	if (mb->mbxStatus == 0) {
2027 		(void) emlxs_mb_handle_cmd(hba, mb);
2028 		goto done;
2029 	}
2030 	/* ERROR RETURNED */
2031 
2032 	/* Check for no resources */
2033 	if ((mb->mbxStatus == MBXERR_NO_RESOURCES) &&
2034 	    (hba->mbox_queue_flag == MBX_NOWAIT)) {
2035 		/* Retry only MBX_NOWAIT requests */
2036 
2037 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_event_msg,
2038 		    "Retrying.  %s: status=%x",
2039 		    emlxs_mb_cmd_xlate(mb->mbxCommand),
2040 		    (uint32_t)mb->mbxStatus);
2041 
2042 		if ((mbox = (MAILBOX *) emlxs_mem_get(hba, MEM_MBOX))) {
2043 			bcopy((uint8_t *)mb, (uint8_t *)mbox,
2044 			    MAILBOX_CMD_BSIZE);
2045 
2046 			switch (mbox->mbxCommand) {
2047 			case MBX_READ_SPARM:
2048 				control = mbox->un.varRdSparm.un.sp.bdeSize;
2049 				if (control == 0) {
2050 					(void) emlxs_mb_read_sparam(hba, mbox);
2051 				}
2052 				break;
2053 
2054 			case MBX_READ_SPARM64:
2055 				control = mbox->un.varRdSparm.un.sp64.tus.f.
2056 				    bdeSize;
2057 				if (control == 0) {
2058 					(void) emlxs_mb_read_sparam(hba, mbox);
2059 				}
2060 				break;
2061 
2062 			case MBX_REG_LOGIN:
2063 				control = mbox->un.varRegLogin.un.sp.bdeSize;
2064 				if (control == 0) {
2065 					goto done;
2066 				}
2067 				break;
2068 
2069 			case MBX_REG_LOGIN64:
2070 				control = mbox->un.varRegLogin.un.sp64.tus.f.
2071 				    bdeSize;
2072 				if (control == 0) {
2073 					goto done;
2074 				}
2075 				break;
2076 
2077 			case MBX_READ_LA:
2078 				control = mbox->un.varReadLA.un.lilpBde.bdeSize;
2079 				if (control == 0) {
2080 					(void) emlxs_mb_read_la(hba, mbox);
2081 				}
2082 				break;
2083 
2084 			case MBX_READ_LA64:
2085 				control = mbox->un.varReadLA.un.lilpBde64.tus.f.
2086 				    bdeSize;
2087 				if (control == 0) {
2088 					(void) emlxs_mb_read_la(hba, mbox);
2089 				}
2090 				break;
2091 			}
2092 
2093 			mbox->mbxOwner = OWN_HOST;
2094 			mbox->mbxStatus = 0;
2095 
2096 			/* Refresh the mailbox area */
2097 			emlxs_mb_retry(hba, mbox);
2098 
2099 			if (emlxs_mb_issue_cmd(hba, mbox, MBX_NOWAIT, 0) !=
2100 			    MBX_BUSY) {
2101 				(void) emlxs_mem_put(hba, MEM_MBOX,
2102 				    (uint8_t *)mbox);
2103 			}
2104 			return (0);
2105 		}
2106 	}
2107 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_completion_error_msg,
2108 	    "%s: status=0x%x", emlxs_mb_cmd_xlate(mb->mbxCommand),
2109 	    (uint32_t)mb->mbxStatus);
2110 
2111 	/*
2112 	 * ERROR: process mailbox command error
2113 	 */
2114 	switch (mb->mbxCommand) {
2115 	case MBX_REG_LOGIN:
2116 	case MBX_REG_LOGIN64:
2117 
2118 		if (mb->mbxStatus == MBXERR_RPI_FULL) {
2119 #ifdef SLI3_SUPPORT
2120 			port = &VPORT(mb->un.varRegLogin.vpi);
2121 #endif	/* SLI3_SUPPORT */
2122 
2123 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_create_failed_msg,
2124 			    "Limit reached. count=%d", port->node_count);
2125 		}
2126 		break;
2127 
2128 	case MBX_READ_LA:
2129 	case MBX_READ_LA64:
2130 
2131 		/* Enable Link Attention interrupts */
2132 		mutex_enter(&EMLXS_PORT_LOCK);
2133 
2134 		if (!(hba->hc_copy & HC_LAINT_ENA)) {
2135 			/*
2136 			 * hba->hc_copy  = READ_CSR_REG(hba, FC_HC_REG(hba,
2137 			 * hba->csr_addr));
2138 			 */
2139 			hba->hc_copy |= HC_LAINT_ENA;
2140 			WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr),
2141 			    hba->hc_copy);
2142 		}
2143 		mutex_exit(&EMLXS_PORT_LOCK);
2144 
2145 		break;
2146 
2147 
2148 	case MBX_CLEAR_LA:
2149 
2150 		la_enable = 1;
2151 
2152 		if (mb->mbxStatus == 0x1601) {
2153 			/*
2154 			 * Get a buffer which will be used for mailbox
2155 			 * commands
2156 			 */
2157 			if ((mbox = (MAILBOX *) emlxs_mem_get(hba, MEM_MBOX |
2158 			    MEM_PRI))) {
2159 				/* Get link attention message */
2160 				if (emlxs_mb_read_la(hba, mbox) == 0) {
2161 					if (emlxs_mb_issue_cmd(hba, mbox,
2162 					    MBX_NOWAIT, 0) != MBX_BUSY) {
2163 						(void) emlxs_mem_put(hba,
2164 						    MEM_MBOX, (uint8_t *)mbox);
2165 					}
2166 					la_enable = 0;
2167 				} else {
2168 					(void) emlxs_mem_put(hba, MEM_MBOX,
2169 					    (uint8_t *)mbox);
2170 				}
2171 			}
2172 		}
2173 		mutex_enter(&EMLXS_PORT_LOCK);
2174 		if (la_enable) {
2175 			if (!(hba->hc_copy & HC_LAINT_ENA)) {
2176 				/* Enable Link Attention interrupts */
2177 				/*
2178 				 * hba->hc_copy  = READ_CSR_REG(hba,
2179 				 * FC_HC_REG(hba, hba->csr_addr));
2180 				 */
2181 				hba->hc_copy |= HC_LAINT_ENA;
2182 				WRITE_CSR_REG(hba,
2183 				    FC_HC_REG(hba, hba->csr_addr),
2184 				    hba->hc_copy);
2185 			}
2186 		} else {
2187 			if (hba->hc_copy & HC_LAINT_ENA) {
2188 				/* Disable Link Attention interrupts */
2189 				/*
2190 				 * hba->hc_copy  = READ_CSR_REG(hba,
2191 				 * FC_HC_REG(hba, hba->csr_addr));
2192 				 */
2193 				hba->hc_copy &= ~HC_LAINT_ENA;
2194 				WRITE_CSR_REG(hba,
2195 				    FC_HC_REG(hba, hba->csr_addr),
2196 				    hba->hc_copy);
2197 			}
2198 		}
2199 		mutex_exit(&EMLXS_PORT_LOCK);
2200 
2201 		break;
2202 
2203 	case MBX_INIT_LINK:
2204 		if ((hba->flag & FC_SLIM2_MODE) &&
2205 		    (hba->mbox_queue_flag == MBX_NOWAIT)) {
2206 			/* Retry only MBX_NOWAIT requests */
2207 
2208 			if ((cfg[CFG_LINK_SPEED].current > 0) &&
2209 			    ((mb->mbxStatus == 0x0011) ||
2210 			    (mb->mbxStatus == 0x0500))) {
2211 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_event_msg,
2212 				    "Retrying.  %s: status=%x. Auto-speed set.",
2213 				    emlxs_mb_cmd_xlate(mb->mbxCommand),
2214 				    (uint32_t)mb->mbxStatus);
2215 
2216 				if ((mbox = (MAILBOX *) emlxs_mem_get(hba,
2217 				    MEM_MBOX))) {
2218 					bcopy((uint8_t *)mb, (uint8_t *)mbox,
2219 					    MAILBOX_CMD_BSIZE);
2220 
2221 					mbox->un.varInitLnk.link_flags &=
2222 					    ~FLAGS_LINK_SPEED;
2223 					mbox->un.varInitLnk.link_speed = 0;
2224 					mbox->mbxOwner = OWN_HOST;
2225 					mbox->mbxStatus = 0;
2226 
2227 					/* Refresh the mailbox area */
2228 					emlxs_mb_retry(hba, mbox);
2229 
2230 					if (emlxs_mb_issue_cmd(hba, mbox,
2231 					    MBX_NOWAIT, 0) != MBX_BUSY) {
2232 						(void) emlxs_mem_put(hba,
2233 						    MEM_MBOX, (uint8_t *)mbox);
2234 					}
2235 					return (0);
2236 				}
2237 			}
2238 		}
2239 		break;
2240 	}
2241 
2242 done:
2243 
2244 	/* Clean up the mailbox area */
2245 	emlxs_mb_fini(hba, mb, mb->mbxStatus);
2246 
2247 	/* Attempt to send pending mailboxes */
2248 	if ((mbox = (MAILBOX *) emlxs_mb_get(hba))) {
2249 		if (emlxs_mb_issue_cmd(hba, mbox, MBX_NOWAIT, 0) != MBX_BUSY) {
2250 			(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbox);
2251 		}
2252 	}
2253 	return (0);
2254 
2255 } /* emlxs_handle_mb_event() */
2256 
2257 
2258 
2259 /*
2260  *  emlxs_mb_handle_cmd
2261  *
2262  *  Description: Process a Mailbox Command.
2263  *  Called from host_interrupt to process MBATT
2264  *
2265  *    Returns:
2266  *
2267  */
2268 static int
2269 emlxs_mb_handle_cmd(emlxs_hba_t *hba, MAILBOX *mb)
2270 {
2271 	emlxs_port_t *port = &PPORT;
2272 	emlxs_port_t *vport;
2273 	MAILBOXQ *mbox;
2274 	NODELIST *ndlp;
2275 	volatile SERV_PARM *sp;
2276 	int32_t i;
2277 	uint32_t ldata;
2278 	uint32_t ldid;
2279 	uint16_t lrpi;
2280 	uint16_t lvpi;
2281 	MATCHMAP *mp;
2282 	uint8_t *wwn;
2283 	READ_LA_VAR la;
2284 
2285 	if (mb->mbxStatus != 0) {
2286 		return (1);
2287 	}
2288 	mp = (MATCHMAP *) hba->mbox_bp;
2289 
2290 	/*
2291 	 * Mailbox command completed successfully, process completion
2292 	 */
2293 	switch (mb->mbxCommand) {
2294 	case MBX_SHUTDOWN:
2295 	case MBX_LOAD_SM:
2296 	case MBX_READ_NV:
2297 	case MBX_WRITE_NV:
2298 	case MBX_RUN_BIU_DIAG:
2299 	case MBX_RUN_BIU_DIAG64:
2300 	case MBX_INIT_LINK:
2301 	case MBX_DOWN_LINK:
2302 	case MBX_CONFIG_LINK:
2303 	case MBX_PART_SLIM:
2304 	case MBX_CONFIG_RING:
2305 	case MBX_RESET_RING:
2306 	case MBX_READ_CONFIG:
2307 	case MBX_READ_RCONFIG:
2308 	case MBX_READ_STATUS:
2309 	case MBX_READ_XRI:
2310 	case MBX_READ_REV:
2311 	case MBX_READ_LNK_STAT:
2312 	case MBX_UNREG_LOGIN:
2313 	case MBX_DUMP_MEMORY:
2314 	case MBX_DUMP_CONTEXT:
2315 	case MBX_RUN_DIAGS:
2316 	case MBX_RESTART:
2317 	case MBX_UPDATE_CFG:
2318 	case MBX_DOWN_LOAD:
2319 	case MBX_DEL_LD_ENTRY:
2320 	case MBX_RUN_PROGRAM:
2321 	case MBX_SET_MASK:
2322 	case MBX_SET_VARIABLE:
2323 	case MBX_UNREG_D_ID:
2324 	case MBX_KILL_BOARD:
2325 	case MBX_CONFIG_FARP:
2326 	case MBX_LOAD_AREA:
2327 	case MBX_CONFIG_PORT:
2328 	case MBX_CONFIG_MSI:
2329 	case MBX_FLASH_WR_ULA:
2330 	case MBX_SET_DEBUG:
2331 	case MBX_GET_DEBUG:
2332 	case MBX_LOAD_EXP_ROM:
2333 	case MBX_BEACON:
2334 	case MBX_READ_RPI:
2335 	case MBX_READ_RPI64:
2336 	case MBX_REG_VPI:
2337 	case MBX_UNREG_VPI:
2338 	case MBX_CONFIG_HBQ:
2339 	case MBX_ASYNC_EVENT:
2340 	case MBX_HEARTBEAT:
2341 		break;
2342 
2343 	case MBX_CONFIG_MSIX:
2344 		break;
2345 
2346 	case MBX_READ_SPARM:	/* a READ SPARAM command completed */
2347 	case MBX_READ_SPARM64:	/* a READ SPARAM command completed */
2348 		{
2349 			if (mp) {
2350 				bcopy((caddr_t)mp->virt, (caddr_t)& hba->sparam,
2351 				    sizeof (SERV_PARM));
2352 
2353 				bcopy((caddr_t)& hba->sparam.nodeName,
2354 				    (caddr_t)& hba->wwnn,
2355 				    sizeof (NAME_TYPE));
2356 
2357 				bcopy((caddr_t)& hba->sparam.portName,
2358 				    (caddr_t)& hba->wwpn,
2359 				    sizeof (NAME_TYPE));
2360 
2361 				/* Initialize the physical port */
2362 				bcopy((caddr_t)& hba->sparam,
2363 				    (caddr_t)& port->sparam,
2364 				    sizeof (SERV_PARM));
2365 				bcopy((caddr_t)& hba->wwpn,
2366 				    (caddr_t)& port->wwpn, sizeof (NAME_TYPE));
2367 				bcopy((caddr_t)& hba->wwnn,
2368 				    (caddr_t)& port->wwnn, sizeof (NAME_TYPE));
2369 
2370 				/* Initialize the virtual ports */
2371 				for (i = 1; i < MAX_VPORTS; i++) {
2372 					vport = &VPORT(i);
2373 					if (vport->flag & EMLXS_PORT_BOUND) {
2374 						continue;
2375 					}
2376 					bcopy((caddr_t)& hba->sparam,
2377 					    (caddr_t)& vport->sparam,
2378 					    sizeof (SERV_PARM));
2379 
2380 					bcopy((caddr_t)& vport->wwnn,
2381 					    (caddr_t)& vport->sparam.nodeName,
2382 					    sizeof (NAME_TYPE));
2383 
2384 					bcopy((caddr_t)& vport->wwpn,
2385 					    (caddr_t)& vport->sparam.portName,
2386 					    sizeof (NAME_TYPE));
2387 				}
2388 
2389 			}
2390 			break;
2391 		}
2392 
2393 
2394 	case MBX_REG_LOGIN:
2395 	case MBX_REG_LOGIN64:
2396 
2397 		if (!mp) {
2398 			break;
2399 		}
2400 #ifdef SLI3_SUPPORT
2401 		ldata = mb->un.varWords[5];
2402 		lvpi = ldata & 0xffff;
2403 		port = &VPORT(lvpi);
2404 #endif	/* SLI3_SUPPORT */
2405 
2406 		/* First copy command data */
2407 		ldata = mb->un.varWords[0];	/* get rpi */
2408 		lrpi = ldata & 0xffff;
2409 
2410 		ldata = mb->un.varWords[1];	/* get did */
2411 		ldid = ldata & Mask_DID;
2412 
2413 		sp = (volatile SERV_PARM *) mp->virt;
2414 		ndlp = emlxs_node_find_did(port, ldid);
2415 
2416 		if (!ndlp) {
2417 			/* Attempt to create a node */
2418 			if ((ndlp = (NODELIST *) emlxs_mem_get(hba, MEM_NLP))) {
2419 				ndlp->nlp_Rpi = lrpi;
2420 				ndlp->nlp_DID = ldid;
2421 
2422 				bcopy((uint8_t *)sp,
2423 				    (uint8_t *)& ndlp->sparm,
2424 				    sizeof (SERV_PARM));
2425 
2426 				bcopy((uint8_t *)& sp->nodeName,
2427 				    (uint8_t *)& ndlp->nlp_nodename,
2428 				    sizeof (NAME_TYPE));
2429 
2430 				bcopy((uint8_t *)& sp->portName,
2431 				    (uint8_t *)& ndlp->nlp_portname,
2432 				    sizeof (NAME_TYPE));
2433 
2434 				ndlp->nlp_active = 1;
2435 				ndlp->nlp_flag[FC_CT_RING] |= NLP_CLOSED;
2436 				ndlp->nlp_flag[FC_ELS_RING] |= NLP_CLOSED;
2437 				ndlp->nlp_flag[FC_FCP_RING] |= NLP_CLOSED;
2438 				ndlp->nlp_flag[FC_IP_RING] |= NLP_CLOSED;
2439 
2440 				/* Add the node */
2441 				emlxs_node_add(port, ndlp);
2442 
2443 				/* Open the node */
2444 				emlxs_node_open(port, ndlp, FC_CT_RING);
2445 				emlxs_node_open(port, ndlp, FC_ELS_RING);
2446 				emlxs_node_open(port, ndlp, FC_IP_RING);
2447 				emlxs_node_open(port, ndlp, FC_FCP_RING);
2448 			} else {
2449 				wwn = (uint8_t *)& sp->portName;
2450 				EMLXS_MSGF(EMLXS_CONTEXT,
2451 				    &emlxs_node_create_failed_msg,
2452 				    "Unable to allocate node. did=%06x rpi=%x "
2453 				    "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x",
2454 				    ldid, lrpi, wwn[0], wwn[1], wwn[2], wwn[3],
2455 				    wwn[4], wwn[5], wwn[6], wwn[7]);
2456 
2457 				break;
2458 			}
2459 		} else {
2460 			mutex_enter(&EMLXS_PORT_LOCK);
2461 
2462 			ndlp->nlp_Rpi = lrpi;
2463 			ndlp->nlp_DID = ldid;
2464 
2465 			bcopy((uint8_t *)sp,
2466 			    (uint8_t *)& ndlp->sparm,
2467 			    sizeof (SERV_PARM));
2468 
2469 			bcopy((uint8_t *)& sp->nodeName,
2470 			    (uint8_t *)& ndlp->nlp_nodename,
2471 			    sizeof (NAME_TYPE));
2472 
2473 			bcopy((uint8_t *)& sp->portName,
2474 			    (uint8_t *)& ndlp->nlp_portname,
2475 			    sizeof (NAME_TYPE));
2476 
2477 			wwn = (uint8_t *)& ndlp->nlp_portname;
2478 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_update_msg,
2479 			    "node=%p did=%06x rpi=%x wwpn="
2480 			    "%02x%02x%02x%02x%02x%02x%02x%02x",
2481 			    ndlp, ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0], wwn[1],
2482 			    wwn[2], wwn[3], wwn[4], wwn[5], wwn[6], wwn[7]);
2483 
2484 			mutex_exit(&EMLXS_PORT_LOCK);
2485 
2486 			/* Open the node */
2487 			emlxs_node_open(port, ndlp, FC_CT_RING);
2488 			emlxs_node_open(port, ndlp, FC_ELS_RING);
2489 			emlxs_node_open(port, ndlp, FC_IP_RING);
2490 			emlxs_node_open(port, ndlp, FC_FCP_RING);
2491 		}
2492 
2493 		/* If this was a fabric login */
2494 		if (ndlp->nlp_DID == Fabric_DID) {
2495 			/*
2496 			 * If CLEAR_LA has been sent, then attempt to
2497 			 * register the vpi now
2498 			 */
2499 			if (hba->state == FC_READY) {
2500 				(void) emlxs_mb_reg_vpi(port);
2501 			}
2502 #ifdef SLI3_SUPPORT
2503 			/*
2504 			 * If NPIV Fabric support has just been established
2505 			 * on the physical port, then notify the vports of
2506 			 * the link up
2507 			 */
2508 			if ((lvpi == 0) &&
2509 			    (hba->flag & FC_NPIV_ENABLED) &&
2510 			    (hba->flag & FC_NPIV_SUPPORTED)) {
2511 				/* Skip the physical port */
2512 				for (i = 1; i < MAX_VPORTS; i++) {
2513 					vport = &VPORT(i);
2514 
2515 					if (!(vport->flag & EMLXS_PORT_BOUND) ||
2516 					    !(vport->flag &
2517 					    EMLXS_PORT_ENABLE)) {
2518 						continue;
2519 					}
2520 					emlxs_port_online(vport);
2521 				}
2522 			}
2523 #endif	/* SLI3_SUPPORT */
2524 
2525 		}
2526 #ifdef NPIV_SUPPORT
2527 		if (hba->mbox_iocbq == (uint8_t *)1) {
2528 			hba->mbox_iocbq = NULL;
2529 			(void) emlxs_mb_unreg_did(port, ldid, NULL, NULL, NULL);
2530 		}
2531 #endif	/* NPIV_SUPPORT */
2532 
2533 #ifdef DHCHAP_SUPPORT
2534 		if (hba->mbox_sbp || hba->mbox_ubp) {
2535 			if (emlxs_dhc_auth_start(port, ndlp, hba->mbox_sbp,
2536 			    hba->mbox_ubp) == 0) {
2537 				/*
2538 				 * Auth started - auth completion will handle
2539 				 * sbp and ubp now
2540 				 */
2541 				hba->mbox_sbp = NULL;
2542 				hba->mbox_ubp = NULL;
2543 			}
2544 		}
2545 #endif	/* DHCHAP_SUPPORT */
2546 
2547 #ifdef SFCT_SUPPORT
2548 		if (hba->mbox_sbp && ((emlxs_buf_t *)hba->mbox_sbp)->fct_cmd) {
2549 			emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)hba->mbox_sbp;
2550 
2551 			if (cmd_sbp->fct_state == EMLXS_FCT_REG_PENDING) {
2552 				hba->mbox_sbp = NULL;
2553 
2554 				mutex_enter(&EMLXS_PKT_LOCK);
2555 				cmd_sbp->node = ndlp;
2556 				cmd_sbp->fct_state = EMLXS_FCT_REG_COMPLETE;
2557 				cv_broadcast(&EMLXS_PKT_CV);
2558 				mutex_exit(&EMLXS_PKT_LOCK);
2559 			}
2560 		}
2561 #endif	/* SFCT_SUPPORT */
2562 
2563 		break;
2564 
2565 	case MBX_READ_LA:
2566 	case MBX_READ_LA64:
2567 		bcopy((uint32_t *)((char *)mb + sizeof (uint32_t)),
2568 		    (uint32_t *)& la, sizeof (READ_LA_VAR));
2569 
2570 		if (mp) {
2571 			bcopy((caddr_t)mp->virt,
2572 			    (caddr_t)port->alpa_map, 128);
2573 		} else {
2574 			bzero((caddr_t)port->alpa_map, 128);
2575 		}
2576 
2577 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_atten_msg,
2578 		    "type=%s tag=%d -> %d  ALPA=%x",
2579 		    ((la.attType == AT_LINK_UP) ?
2580 		    "LinkUp" : "LinkDown"),
2581 		    (uint32_t)hba->link_event_tag,
2582 		    (uint32_t)la.eventTag, (uint32_t)la.granted_AL_PA);
2583 
2584 		if (la.pb) {
2585 			hba->flag |= FC_BYPASSED_MODE;
2586 		} else {
2587 			hba->flag &= ~FC_BYPASSED_MODE;
2588 		}
2589 
2590 		if (hba->link_event_tag == la.eventTag) {
2591 			HBASTATS.LinkMultiEvent++;
2592 		} else if (hba->link_event_tag + 1 < la.eventTag) {
2593 			HBASTATS.LinkMultiEvent++;
2594 
2595 			if (hba->state > FC_LINK_DOWN) {
2596 				/* Declare link down here */
2597 				emlxs_linkdown(hba);
2598 			}
2599 		}
2600 		hba->link_event_tag = la.eventTag;
2601 		port->lip_type = 0;
2602 
2603 		/* If link not already up then declare it up now */
2604 		if ((la.attType == AT_LINK_UP) &&
2605 		    (hba->state < FC_LINK_UP)) {
2606 
2607 			/* Save the linkspeed */
2608 			hba->linkspeed = la.UlnkSpeed;
2609 
2610 			/*
2611 			 * Check for old model adapters that only
2612 			 * supported 1Gb
2613 			 */
2614 			if ((hba->linkspeed == 0) &&
2615 			    (hba->model_info.chip &
2616 			    EMLXS_DRAGONFLY_CHIP)) {
2617 				hba->linkspeed = LA_1GHZ_LINK;
2618 			}
2619 			if ((hba->topology = la.topology) ==
2620 			    TOPOLOGY_LOOP) {
2621 				port->did = la.granted_AL_PA;
2622 				port->lip_type = la.lipType;
2623 
2624 				if (hba->flag & FC_SLIM2_MODE) {
2625 					i = la.un.lilpBde64.tus.f.
2626 					    bdeSize;
2627 				} else {
2628 					i = la.un.lilpBde.bdeSize;
2629 				}
2630 
2631 				if (i == 0) {
2632 					port->alpa_map[0] = 0;
2633 				} else {
2634 					uint8_t *alpa_map;
2635 					uint32_t j;
2636 
2637 					/*
2638 					 * Check number of devices in
2639 					 * map
2640 					 */
2641 					if (port->alpa_map[0] > 127) {
2642 						port->alpa_map[0] = 127;
2643 					}
2644 					alpa_map = (uint8_t *)port->alpa_map;
2645 
2646 					EMLXS_MSGF(EMLXS_CONTEXT,
2647 					    &emlxs_link_atten_msg,
2648 					    "alpa_map: %d device(s):  %02x "
2649 					    "%02x %02x %02x %02x %02x %02x",
2650 					    alpa_map[0], alpa_map[1],
2651 					    alpa_map[2], alpa_map[3],
2652 					    alpa_map[4], alpa_map[5],
2653 					    alpa_map[6], alpa_map[7]);
2654 
2655 					for (j = 8; j <= alpa_map[0]; j += 8) {
2656 						EMLXS_MSGF(EMLXS_CONTEXT,
2657 						    &emlxs_link_atten_msg,
2658 						    "alpa_map: %02x %02x %02x "
2659 						    "%02x %02x %02x %02x %02x",
2660 						    alpa_map[j],
2661 						    alpa_map[j + 1],
2662 						    alpa_map[j + 2],
2663 						    alpa_map[j + 3],
2664 						    alpa_map[j + 4],
2665 						    alpa_map[j + 5],
2666 						    alpa_map[j + 6],
2667 						    alpa_map[j + 7]);
2668 					}
2669 				}
2670 			}
2671 #ifdef MENLO_SUPPORT
2672 			/* Check if Menlo maintenance mode is enabled */
2673 			if (hba->model_info.device_id ==
2674 			    PCI_DEVICE_ID_LP21000_M) {
2675 				if (la.mm == 1) {
2676 					EMLXS_MSGF(EMLXS_CONTEXT,
2677 					    &emlxs_link_atten_msg,
2678 					    "Maintenance Mode enabled.");
2679 
2680 					mutex_enter(&EMLXS_PORT_LOCK);
2681 					hba->flag |= FC_MENLO_MODE;
2682 					mutex_exit(&EMLXS_PORT_LOCK);
2683 
2684 					mutex_enter(&EMLXS_LINKUP_LOCK);
2685 					cv_broadcast(&EMLXS_LINKUP_CV);
2686 					mutex_exit(&EMLXS_LINKUP_LOCK);
2687 				} else {
2688 					EMLXS_MSGF(EMLXS_CONTEXT,
2689 					    &emlxs_link_atten_msg,
2690 					    "Maintenance Mode disabled.");
2691 				}
2692 
2693 				/* Check FCoE attention bit */
2694 				if (la.fa == 1) {
2695 					(void) thread_create(NULL, 0,
2696 					    emlxs_fcoe_attention_thread,
2697 					    (char *)hba, 0,
2698 					    &p0, TS_RUN,
2699 					    v.v_maxsyspri - 2);
2700 				}
2701 			}
2702 #endif	/* MENLO_SUPPORT */
2703 
2704 			if ((mbox = (MAILBOXQ *) emlxs_mem_get(hba,
2705 			    MEM_MBOX | MEM_PRI))) {
2706 				/*
2707 				 * This should turn on DELAYED ABTS
2708 				 * for ELS timeouts
2709 				 */
2710 				emlxs_mb_set_var(hba, (MAILBOX *) mbox,
2711 				    0x00052198, 0x1);
2712 
2713 				emlxs_mb_put(hba, mbox);
2714 			}
2715 			if ((mbox = (MAILBOXQ *) emlxs_mem_get(hba,
2716 			    MEM_MBOX | MEM_PRI))) {
2717 				/*
2718 				 * If link not already down then
2719 				 * declare it down now
2720 				 */
2721 				if (emlxs_mb_read_sparam(hba,
2722 				    (MAILBOX *) mbox) == 0) {
2723 					emlxs_mb_put(hba, mbox);
2724 				} else {
2725 					(void) emlxs_mem_put(hba, MEM_MBOX,
2726 					    (uint8_t *)mbox);
2727 				}
2728 			}
2729 			if ((mbox = (MAILBOXQ *) emlxs_mem_get(hba,
2730 			    MEM_MBOX | MEM_PRI))) {
2731 				emlxs_mb_config_link(hba,
2732 				    (MAILBOX *) mbox);
2733 
2734 				emlxs_mb_put(hba, mbox);
2735 			}
2736 			/* Declare the linkup here */
2737 			emlxs_linkup(hba);
2738 		}
2739 		/* If link not already down then declare it down now */
2740 		else if ((la.attType == AT_LINK_DOWN) &&
2741 		    (hba->state > FC_LINK_DOWN)) {
2742 			/* Declare link down here */
2743 			emlxs_linkdown(hba);
2744 		}
2745 		/* Enable Link attention interrupt */
2746 		mutex_enter(&EMLXS_PORT_LOCK);
2747 
2748 		if (!(hba->hc_copy & HC_LAINT_ENA)) {
2749 			/*
2750 			 * hba->hc_copy  = READ_CSR_REG(hba,
2751 			 * FC_HC_REG(hba, hba->csr_addr));
2752 			 */
2753 			hba->hc_copy |= HC_LAINT_ENA;
2754 			WRITE_CSR_REG(hba, FC_HC_REG(hba,
2755 			    hba->csr_addr), hba->hc_copy);
2756 		}
2757 		mutex_exit(&EMLXS_PORT_LOCK);
2758 
2759 		/* Log the link event */
2760 		emlxs_log_link_event(port);
2761 
2762 		break;
2763 
2764 	case MBX_CLEAR_LA:
2765 		/* Enable on Link Attention interrupts */
2766 		mutex_enter(&EMLXS_PORT_LOCK);
2767 
2768 		if (!(hba->hc_copy & HC_LAINT_ENA)) {
2769 			/*
2770 			 * hba->hc_copy  = READ_CSR_REG(hba, FC_HC_REG(hba,
2771 			 * hba->csr_addr));
2772 			 */
2773 			hba->hc_copy |= HC_LAINT_ENA;
2774 			WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr),
2775 			    hba->hc_copy);
2776 		}
2777 		if (hba->state >= FC_LINK_UP) {
2778 			emlxs_ffstate_change_locked(hba, FC_READY);
2779 		}
2780 		mutex_exit(&EMLXS_PORT_LOCK);
2781 
2782 		/* Adapter is now ready for FCP traffic */
2783 		if (hba->state == FC_READY) {
2784 			/* Register vpi's for all ports that have did's */
2785 			for (i = 0; i < MAX_VPORTS; i++) {
2786 				vport = &VPORT(i);
2787 
2788 				if (!(vport->flag & EMLXS_PORT_BOUND) ||
2789 				    !(vport->did)) {
2790 					continue;
2791 				}
2792 				(void) emlxs_mb_reg_vpi(vport);
2793 			}
2794 
2795 			/* Attempt to send any pending IO */
2796 			emlxs_issue_iocb_cmd(hba, &hba->ring[FC_FCP_RING], 0);
2797 		}
2798 		break;
2799 
2800 	default:
2801 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_completion_error_msg,
2802 		    "Unknown mailbox cmd: 0x%x", mb->mbxCommand);
2803 		HBASTATS.MboxInvalid++;
2804 		break;
2805 	}
2806 
2807 	return (0);
2808 
2809 } /* emlxs_mb_handle_cmd() */
2810 
2811 
2812 /* MBX_NOWAIT - returns MBX_BUSY or MBX_SUCCESS or MBX_HARDWARE_ERROR */
2813 /* MBX_WAIT   - returns MBX_TIMEOUT or mailbox_status */
2814 /* MBX_SLEEP  - returns MBX_TIMEOUT or mailbox_status */
2815 /* MBX_POLL   - returns MBX_TIMEOUT or mailbox_status */
2816 
2817 extern uint32_t
2818 emlxs_mb_issue_cmd(emlxs_hba_t *hba, MAILBOX *mb, int32_t flag, uint32_t tmo)
2819 {
2820 	emlxs_port_t *port = &PPORT;
2821 	MAILBOX *mbox;
2822 	MAILBOXQ *mbq;
2823 	volatile uint32_t word0;
2824 	volatile uint32_t ldata;
2825 	uint32_t ha_copy;
2826 	off_t offset;
2827 	MATCHMAP *mbox_bp;
2828 	uint32_t tmo_local;
2829 	MAILBOX *swpmb;
2830 
2831 	mbq = (MAILBOXQ *) mb;
2832 	swpmb = (MAILBOX *) & word0;
2833 
2834 	mb->mbxStatus = MBX_SUCCESS;
2835 
2836 	/* Check for minimum timeouts */
2837 	switch (mb->mbxCommand) {
2838 		/* Mailbox commands that erase/write flash */
2839 	case MBX_DOWN_LOAD:
2840 	case MBX_UPDATE_CFG:
2841 	case MBX_LOAD_AREA:
2842 	case MBX_LOAD_EXP_ROM:
2843 	case MBX_WRITE_NV:
2844 	case MBX_FLASH_WR_ULA:
2845 	case MBX_DEL_LD_ENTRY:
2846 	case MBX_LOAD_SM:
2847 		if (tmo < 300) {
2848 			tmo = 300;
2849 		}
2850 		break;
2851 
2852 	default:
2853 		if (tmo < 30) {
2854 			tmo = 30;
2855 		}
2856 		break;
2857 	}
2858 
2859 	/* Adjust wait flag */
2860 	if (flag != MBX_NOWAIT) {
2861 		/* If interrupt is enabled, use sleep, otherwise poll */
2862 		if (hba->hc_copy & HC_MBINT_ENA) {
2863 			flag = MBX_SLEEP;
2864 		} else {
2865 			flag = MBX_POLL;
2866 		}
2867 	}
2868 	mutex_enter(&EMLXS_PORT_LOCK);
2869 
2870 	/* Check for hardware error */
2871 	if (hba->flag & FC_HARDWARE_ERROR) {
2872 		mb->mbxStatus = (hba->flag & FC_OVERTEMP_EVENT) ?
2873 		    MBX_OVERTEMP_ERROR : MBX_HARDWARE_ERROR;
2874 
2875 		mutex_exit(&EMLXS_PORT_LOCK);
2876 
2877 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
2878 		    "Hardware error reported. %s failed. status=%x mb=%p",
2879 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mb->mbxStatus, mb);
2880 
2881 		return (MBX_HARDWARE_ERROR);
2882 	}
2883 	if (hba->mbox_queue_flag) {
2884 		/* If we are not polling, then queue it for later */
2885 		if (flag == MBX_NOWAIT) {
2886 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
2887 			    "Busy.      %s: mb=%p NoWait.",
2888 			    emlxs_mb_cmd_xlate(mb->mbxCommand), mb);
2889 
2890 			emlxs_mb_put(hba, mbq);
2891 
2892 			HBASTATS.MboxBusy++;
2893 
2894 			mutex_exit(&EMLXS_PORT_LOCK);
2895 
2896 			return (MBX_BUSY);
2897 		}
2898 		tmo_local = tmo * 20;	/* Convert tmo seconds to 50 */
2899 					/*   millisecond tics */
2900 		while (hba->mbox_queue_flag) {
2901 			mutex_exit(&EMLXS_PORT_LOCK);
2902 
2903 			if (tmo_local-- == 0) {
2904 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_event_msg,
2905 				    "Timeout.   %s: mb=%p tmo=%d Waiting.",
2906 				    emlxs_mb_cmd_xlate(mb->mbxCommand), mb,
2907 				    tmo);
2908 
2909 				/* Non-lethalStatus mailbox timeout */
2910 				/* Does not indicate a hardware error */
2911 				mb->mbxStatus = MBX_TIMEOUT;
2912 				return (MBX_TIMEOUT);
2913 			}
2914 			DELAYMS(50);
2915 			mutex_enter(&EMLXS_PORT_LOCK);
2916 		}
2917 	}
2918 	/* Initialize mailbox area */
2919 	emlxs_mb_init(hba, mbq, flag, tmo);
2920 
2921 	switch (flag) {
2922 	case MBX_NOWAIT:
2923 
2924 		if (mb->mbxCommand != MBX_HEARTBEAT) {
2925 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
2926 			    "Sending.   %s: mb=%p NoWait.",
2927 			    emlxs_mb_cmd_xlate(mb->mbxCommand), mb);
2928 		}
2929 		break;
2930 
2931 	case MBX_SLEEP:
2932 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
2933 		    "Sending.   %s: mb=%p Sleep.",
2934 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mb);
2935 
2936 		break;
2937 
2938 	case MBX_POLL:
2939 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
2940 		    "Sending.   %s: mb=%p Polled.",
2941 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mb);
2942 		break;
2943 	}
2944 
2945 	mb->mbxOwner = OWN_CHIP;
2946 
2947 	/* Clear the attention bit */
2948 	WRITE_CSR_REG(hba, FC_HA_REG(hba, hba->csr_addr), HA_MBATT);
2949 
2950 	if (hba->flag & FC_SLIM2_MODE) {
2951 		/* First copy command data */
2952 		mbox = FC_SLIM2_MAILBOX(hba);
2953 		offset = (off_t)((uint64_t)(unsigned long)mbox -
2954 		    (uint64_t)(unsigned long)hba->slim2.virt);
2955 
2956 #ifdef MBOX_EXT_SUPPORT
2957 		if (hba->mbox_ext) {
2958 			uint32_t *mbox_ext = (uint32_t *)((uint8_t *)mbox +
2959 			    MBOX_EXTENSION_OFFSET);
2960 			off_t offset_ext = offset + MBOX_EXTENSION_OFFSET;
2961 
2962 			emlxs_pcimem_bcopy((uint32_t *)hba->mbox_ext, mbox_ext,
2963 			    hba->mbox_ext_size);
2964 			emlxs_mpdata_sync(hba->slim2.dma_handle, offset_ext,
2965 			    hba->mbox_ext_size, DDI_DMA_SYNC_FORDEV);
2966 		}
2967 #endif	/* MBOX_EXT_SUPPORT */
2968 
2969 		emlxs_pcimem_bcopy((uint32_t *)mb, (uint32_t *)mbox,
2970 		    MAILBOX_CMD_BSIZE);
2971 		emlxs_mpdata_sync(hba->slim2.dma_handle, offset,
2972 		    MAILBOX_CMD_BSIZE, DDI_DMA_SYNC_FORDEV);
2973 	}
2974 	/* Check for config port command */
2975 	else if (mb->mbxCommand == MBX_CONFIG_PORT) {
2976 		/* copy command data into host mbox for cmpl */
2977 		mbox = FC_SLIM2_MAILBOX(hba);
2978 		offset = (off_t)((uint64_t)(unsigned long)mbox -
2979 		    (uint64_t)(unsigned long)hba->slim2.virt);
2980 
2981 		emlxs_pcimem_bcopy((uint32_t *)mb, (uint32_t *)mbox,
2982 		    MAILBOX_CMD_BSIZE);
2983 		emlxs_mpdata_sync(hba->slim2.dma_handle, offset,
2984 		    MAILBOX_CMD_BSIZE, DDI_DMA_SYNC_FORDEV);
2985 
2986 		/* First copy command data */
2987 		mbox = FC_SLIM1_MAILBOX(hba);
2988 		WRITE_SLIM_COPY(hba, &mb->un.varWords, &mbox->un.varWords,
2989 		    (MAILBOX_CMD_WSIZE - 1));
2990 
2991 		/* copy over last word, with mbxOwner set */
2992 		ldata = *((volatile uint32_t *) mb);
2993 		WRITE_SLIM_ADDR(hba, ((volatile uint32_t *) mbox), ldata);
2994 
2995 		/* switch over to host mailbox */
2996 		/*
2997 		 * hba->mbox_queueaddr = (uint32_t *)&((SLIM2 *)
2998 		 * hba->slim2.virt)->mbx;
2999 		 */
3000 		hba->flag |= FC_SLIM2_MODE;
3001 	} else {	/* SLIM 1 */
3002 		mbox = FC_SLIM1_MAILBOX(hba);
3003 
3004 #ifdef MBOX_EXT_SUPPORT
3005 		if (hba->mbox_ext) {
3006 			uint32_t *mbox_ext = (uint32_t *)((uint8_t *)mbox +
3007 			    MBOX_EXTENSION_OFFSET);
3008 			WRITE_SLIM_COPY(hba, (uint32_t *)hba->mbox_ext,
3009 			    mbox_ext, (hba->mbox_ext_size / 4));
3010 		}
3011 #endif	/* MBOX_EXT_SUPPORT */
3012 
3013 		/* First copy command data */
3014 		WRITE_SLIM_COPY(hba, &mb->un.varWords, &mbox->un.varWords,
3015 		    (MAILBOX_CMD_WSIZE - 1));
3016 
3017 		/* copy over last word, with mbxOwner set */
3018 		ldata = *((volatile uint32_t *) mb);
3019 		WRITE_SLIM_ADDR(hba, ((volatile uint32_t *) mbox), ldata);
3020 	}
3021 
3022 	/* Interrupt board to do it right away */
3023 	WRITE_CSR_REG(hba, FC_CA_REG(hba, hba->csr_addr), CA_MBATT);
3024 
3025 	mutex_exit(&EMLXS_PORT_LOCK);
3026 
3027 	switch (flag) {
3028 	case MBX_NOWAIT:
3029 		return (MBX_SUCCESS);
3030 
3031 	case MBX_SLEEP:
3032 
3033 		/* Wait for completion */
3034 		/* The driver clock is timing the mailbox. */
3035 		/* emlxs_mb_fini() will be called externally. */
3036 
3037 		mutex_enter(&EMLXS_MBOX_LOCK);
3038 		while (!(mbq->flag & MBQ_COMPLETED)) {
3039 			cv_wait(&EMLXS_MBOX_CV, &EMLXS_MBOX_LOCK);
3040 		}
3041 		mutex_exit(&EMLXS_MBOX_LOCK);
3042 
3043 		if (mb->mbxStatus == MBX_TIMEOUT) {
3044 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_event_msg,
3045 			    "Timeout.   %s: mb=%p tmo=%d. Sleep.",
3046 			    emlxs_mb_cmd_xlate(mb->mbxCommand), mb, tmo);
3047 		} else {
3048 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
3049 			    "Completed. %s: mb=%p status=%x Sleep.",
3050 			    emlxs_mb_cmd_xlate(mb->mbxCommand), mb,
3051 			    mb->mbxStatus);
3052 		}
3053 
3054 		break;
3055 
3056 	case MBX_POLL:
3057 
3058 		tmo_local = tmo * 2000;	/* Convert tmo seconds to 500 usec */
3059 					/*   tics */
3060 
3061 		if (hba->state >= FC_INIT_START) {
3062 			ha_copy = READ_CSR_REG(hba, FC_HA_REG(hba,
3063 			    hba->csr_addr));
3064 
3065 			/* Wait for command to complete */
3066 			while (!(ha_copy & HA_MBATT) &&
3067 			    !(mbq->flag & MBQ_COMPLETED)) {
3068 				if (!hba->timer_id && (tmo_local-- == 0)) {
3069 					/* self time */
3070 					EMLXS_MSGF(EMLXS_CONTEXT,
3071 					    &emlxs_hardware_error_msg,
3072 					    "Mailbox Timeout: %s: mb=%p Polled",
3073 					    emlxs_mb_cmd_xlate(mb->mbxCommand),
3074 					    mb);
3075 
3076 					hba->flag |= FC_MBOX_TIMEOUT;
3077 					emlxs_ffstate_change(hba, FC_ERROR);
3078 					emlxs_mb_fini(hba, NULL, MBX_TIMEOUT);
3079 
3080 					break;
3081 				}
3082 				DELAYUS(500);
3083 				ha_copy = READ_CSR_REG(hba,
3084 				    FC_HA_REG(hba, hba->csr_addr));
3085 			}
3086 
3087 			if (mb->mbxStatus == MBX_TIMEOUT) {
3088 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_event_msg,
3089 				    "Timeout.   %s: mb=%p tmo=%d. Polled.",
3090 				    emlxs_mb_cmd_xlate(mb->mbxCommand), mb,
3091 				    tmo);
3092 
3093 				break;
3094 			}
3095 		}
3096 		/* Get first word of mailbox */
3097 		if (hba->flag & FC_SLIM2_MODE) {
3098 			mbox = FC_SLIM2_MAILBOX(hba);
3099 			offset = (off_t)((uint64_t)(unsigned long)mbox -
3100 			    (uint64_t)(unsigned long)hba->slim2.virt);
3101 
3102 			emlxs_mpdata_sync(hba->slim2.dma_handle, offset,
3103 			    sizeof (uint32_t), DDI_DMA_SYNC_FORKERNEL);
3104 			word0 = *((volatile uint32_t *) mbox);
3105 			word0 = PCIMEM_LONG(word0);
3106 		} else {
3107 			mbox = FC_SLIM1_MAILBOX(hba);
3108 			word0 = READ_SLIM_ADDR(hba,
3109 			    ((volatile uint32_t *) mbox));
3110 		}
3111 
3112 		/* Wait for command to complete */
3113 		while ((swpmb->mbxOwner == OWN_CHIP) &&
3114 		    !(mbq->flag & MBQ_COMPLETED)) {
3115 			if (!hba->timer_id && (tmo_local-- == 0)) {
3116 				/* self time */
3117 				EMLXS_MSGF(EMLXS_CONTEXT,
3118 				    &emlxs_hardware_error_msg,
3119 				    "Mailbox Timeout: %s: mb=%p Polled.",
3120 				    emlxs_mb_cmd_xlate(mb->mbxCommand), mb);
3121 
3122 				hba->flag |= FC_MBOX_TIMEOUT;
3123 				emlxs_ffstate_change(hba, FC_ERROR);
3124 				emlxs_mb_fini(hba, NULL, MBX_TIMEOUT);
3125 
3126 				break;
3127 			}
3128 			DELAYUS(500);
3129 
3130 			/* Get first word of mailbox */
3131 			if (hba->flag & FC_SLIM2_MODE) {
3132 				emlxs_mpdata_sync(hba->slim2.dma_handle, offset,
3133 				    sizeof (uint32_t), DDI_DMA_SYNC_FORKERNEL);
3134 				word0 = *((volatile uint32_t *) mbox);
3135 				word0 = PCIMEM_LONG(word0);
3136 			} else {
3137 				word0 = READ_SLIM_ADDR(hba,
3138 				    ((volatile uint32_t *) mbox));
3139 			}
3140 
3141 		}	/* while */
3142 
3143 		if (mb->mbxStatus == MBX_TIMEOUT) {
3144 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_event_msg,
3145 			    "Timeout.   %s: mb=%p tmo=%d. Polled.",
3146 			    emlxs_mb_cmd_xlate(mb->mbxCommand), mb, tmo);
3147 
3148 			break;
3149 		}
3150 		/* copy results back to user */
3151 		if (hba->flag & FC_SLIM2_MODE) {
3152 			emlxs_mpdata_sync(hba->slim2.dma_handle, offset,
3153 			    MAILBOX_CMD_BSIZE, DDI_DMA_SYNC_FORKERNEL);
3154 			emlxs_pcimem_bcopy((uint32_t *)mbox, (uint32_t *)mb,
3155 			    MAILBOX_CMD_BSIZE);
3156 		} else {
3157 			READ_SLIM_COPY(hba, (uint32_t *)mb, (uint32_t *)mbox,
3158 			    MAILBOX_CMD_WSIZE);
3159 		}
3160 
3161 #ifdef MBOX_EXT_SUPPORT
3162 		if (hba->mbox_ext) {
3163 			uint32_t *mbox_ext = (uint32_t *)((uint8_t *)mbox +
3164 			    MBOX_EXTENSION_OFFSET);
3165 			off_t offset_ext = offset + MBOX_EXTENSION_OFFSET;
3166 
3167 			if (hba->flag & FC_SLIM2_MODE) {
3168 				emlxs_mpdata_sync(hba->slim2.dma_handle,
3169 				    offset_ext, hba->mbox_ext_size,
3170 				    DDI_DMA_SYNC_FORKERNEL);
3171 				emlxs_pcimem_bcopy(mbox_ext,
3172 				    (uint32_t *)hba->mbox_ext,
3173 				    hba->mbox_ext_size);
3174 			} else {
3175 				READ_SLIM_COPY(hba, (uint32_t *)hba->mbox_ext,
3176 				    mbox_ext, (hba->mbox_ext_size / 4));
3177 			}
3178 		}
3179 #endif	/* MBOX_EXT_SUPPORT */
3180 
3181 		/* Sync the memory buffer */
3182 		if (hba->mbox_bp) {
3183 			mbox_bp = (MATCHMAP *) hba->mbox_bp;
3184 			emlxs_mpdata_sync(mbox_bp->dma_handle, 0, mbox_bp->size,
3185 			    DDI_DMA_SYNC_FORKERNEL);
3186 		}
3187 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mbox_detail_msg,
3188 		    "Completed. %s: mb=%p status=%x Polled.",
3189 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mb, mb->mbxStatus);
3190 
3191 		/* Process the result */
3192 		if (!(mbq->flag & MBQ_PASSTHRU)) {
3193 			(void) emlxs_mb_handle_cmd(hba, mb);
3194 		}
3195 		/* Clear the attention bit */
3196 		WRITE_CSR_REG(hba, FC_HA_REG(hba, hba->csr_addr), HA_MBATT);
3197 
3198 		/* Clean up the mailbox area */
3199 		emlxs_mb_fini(hba, NULL, mb->mbxStatus);
3200 
3201 		break;
3202 
3203 	}	/* switch (flag) */
3204 
3205 	return (mb->mbxStatus);
3206 
3207 } /* emlxs_mb_issue_cmd() */
3208 
3209 
3210 
3211 extern char *
3212 emlxs_mb_cmd_xlate(uint8_t cmd)
3213 {
3214 	static char buffer[32];
3215 	uint32_t i;
3216 	uint32_t count;
3217 
3218 	count = sizeof (emlxs_mb_cmd_table) / sizeof (emlxs_table_t);
3219 	for (i = 0; i < count; i++) {
3220 		if (cmd == emlxs_mb_cmd_table[i].code) {
3221 			return (emlxs_mb_cmd_table[i].string);
3222 		}
3223 	}
3224 
3225 	(void) sprintf(buffer, "Cmd=0x%x", cmd);
3226 	return (buffer);
3227 
3228 } /* emlxs_mb_cmd_xlate() */
3229