1*fcf3ce44SJohn Forte /*
2*fcf3ce44SJohn Forte  * CDDL HEADER START
3*fcf3ce44SJohn Forte  *
4*fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5*fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6*fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7*fcf3ce44SJohn Forte  *
8*fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10*fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11*fcf3ce44SJohn Forte  * and limitations under the License.
12*fcf3ce44SJohn Forte  *
13*fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14*fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16*fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17*fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18*fcf3ce44SJohn Forte  *
19*fcf3ce44SJohn Forte  * CDDL HEADER END
20*fcf3ce44SJohn Forte  */
21*fcf3ce44SJohn Forte 
22*fcf3ce44SJohn Forte /*
23*fcf3ce44SJohn Forte  * Copyright 2008 Emulex.  All rights reserved.
24*fcf3ce44SJohn Forte  * Use is subject to License terms.
25*fcf3ce44SJohn Forte  */
26*fcf3ce44SJohn Forte 
27*fcf3ce44SJohn Forte 
28*fcf3ce44SJohn Forte #include "emlxs.h"
29*fcf3ce44SJohn Forte 
30*fcf3ce44SJohn Forte /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
31*fcf3ce44SJohn Forte EMLXS_MSG_DEF(EMLXS_FCP_C);
32*fcf3ce44SJohn Forte 
33*fcf3ce44SJohn Forte #define	EMLXS_GET_VADDR(hba, rp, icmd) emlxs_mem_get_vaddr(hba, rp, \
34*fcf3ce44SJohn Forte 	getPaddr(icmd->un.cont64[i].addrHigh, icmd->un.cont64[i].addrLow));
35*fcf3ce44SJohn Forte 
36*fcf3ce44SJohn Forte static void emlxs_sbp_abort_add(emlxs_port_t *port, emlxs_buf_t *sbp, Q *abort,
37*fcf3ce44SJohn Forte     uint8_t *flag, emlxs_buf_t *fpkt);
38*fcf3ce44SJohn Forte static uint32_t emlxs_iotag_flush(emlxs_hba_t *hba);
39*fcf3ce44SJohn Forte 
40*fcf3ce44SJohn Forte /*
41*fcf3ce44SJohn Forte  * This routine copies data from src then potentially swaps the destination to
42*fcf3ce44SJohn Forte  * big endian. Assumes cnt is a multiple of * sizeof(uint32_t).
43*fcf3ce44SJohn Forte  */
44*fcf3ce44SJohn Forte extern void
45*fcf3ce44SJohn Forte emlxs_pcimem_bcopy(uint32_t *src, uint32_t *dest, uint32_t cnt)
46*fcf3ce44SJohn Forte {
47*fcf3ce44SJohn Forte 	uint32_t ldata;
48*fcf3ce44SJohn Forte 	int32_t i;
49*fcf3ce44SJohn Forte 
50*fcf3ce44SJohn Forte 	for (i = 0; i < (int)cnt; i += sizeof (uint32_t)) {
51*fcf3ce44SJohn Forte 		ldata = *src++;
52*fcf3ce44SJohn Forte 		ldata = PCIMEM_LONG(ldata);
53*fcf3ce44SJohn Forte 		*dest++ = ldata;
54*fcf3ce44SJohn Forte 	}
55*fcf3ce44SJohn Forte } /* emlxs_pcimem_bcopy */
56*fcf3ce44SJohn Forte 
57*fcf3ce44SJohn Forte 
58*fcf3ce44SJohn Forte /*
59*fcf3ce44SJohn Forte  * This routine copies data from src then swaps the destination to big endian.
60*fcf3ce44SJohn Forte  * Assumes cnt is a multiple of sizeof(uint32_t).
61*fcf3ce44SJohn Forte  */
62*fcf3ce44SJohn Forte extern void
63*fcf3ce44SJohn Forte emlxs_swap_bcopy(uint32_t *src, uint32_t *dest, uint32_t cnt)
64*fcf3ce44SJohn Forte {
65*fcf3ce44SJohn Forte 	uint32_t ldata;
66*fcf3ce44SJohn Forte 	int32_t i;
67*fcf3ce44SJohn Forte 
68*fcf3ce44SJohn Forte 	for (i = 0; i < (int)cnt; i += sizeof (uint32_t)) {
69*fcf3ce44SJohn Forte 		ldata = *src++;
70*fcf3ce44SJohn Forte 		ldata = SWAP_DATA32(ldata);
71*fcf3ce44SJohn Forte 		*dest++ = ldata;
72*fcf3ce44SJohn Forte 	}
73*fcf3ce44SJohn Forte } /* End fc_swap_bcopy */
74*fcf3ce44SJohn Forte 
75*fcf3ce44SJohn Forte 
76*fcf3ce44SJohn Forte #define	SCSI3_PERSISTENT_RESERVE_IN	0x5e
77*fcf3ce44SJohn Forte #define	SCSI_INQUIRY	0x12
78*fcf3ce44SJohn Forte #define	SCSI_RX_DIAG    0x1C
79*fcf3ce44SJohn Forte 
80*fcf3ce44SJohn Forte 
81*fcf3ce44SJohn Forte /*
82*fcf3ce44SJohn Forte  *  emlxs_handle_fcp_event
83*fcf3ce44SJohn Forte  *
84*fcf3ce44SJohn Forte  *  Description: Process an FCP Rsp Ring completion
85*fcf3ce44SJohn Forte  *
86*fcf3ce44SJohn Forte  */
87*fcf3ce44SJohn Forte /* ARGSUSED */
88*fcf3ce44SJohn Forte extern void
89*fcf3ce44SJohn Forte emlxs_handle_fcp_event(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq)
90*fcf3ce44SJohn Forte {
91*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
92*fcf3ce44SJohn Forte 	IOCB *cmd;
93*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
94*fcf3ce44SJohn Forte 	fc_packet_t *pkt = NULL;
95*fcf3ce44SJohn Forte 	uint32_t iostat;
96*fcf3ce44SJohn Forte 	uint8_t localstat;
97*fcf3ce44SJohn Forte 	fcp_rsp_t *rsp;
98*fcf3ce44SJohn Forte 	uint32_t rsp_data_resid;
99*fcf3ce44SJohn Forte 	uint32_t check_underrun;
100*fcf3ce44SJohn Forte 	uint8_t asc;
101*fcf3ce44SJohn Forte 	uint8_t ascq;
102*fcf3ce44SJohn Forte 	uint8_t scsi_status;
103*fcf3ce44SJohn Forte 	uint8_t sense;
104*fcf3ce44SJohn Forte 	uint32_t did;
105*fcf3ce44SJohn Forte 	uint32_t fix_it;
106*fcf3ce44SJohn Forte 	uint8_t *scsi_cmd;
107*fcf3ce44SJohn Forte 	uint8_t scsi_opcode;
108*fcf3ce44SJohn Forte 	uint16_t scsi_dl;
109*fcf3ce44SJohn Forte 	uint32_t data_rx;
110*fcf3ce44SJohn Forte 
111*fcf3ce44SJohn Forte 	cmd = &iocbq->iocb;
112*fcf3ce44SJohn Forte 
113*fcf3ce44SJohn Forte 	/* Initialize the status */
114*fcf3ce44SJohn Forte 	iostat = cmd->ulpStatus;
115*fcf3ce44SJohn Forte 	localstat = 0;
116*fcf3ce44SJohn Forte 	scsi_status = 0;
117*fcf3ce44SJohn Forte 	asc = 0;
118*fcf3ce44SJohn Forte 	ascq = 0;
119*fcf3ce44SJohn Forte 	sense = 0;
120*fcf3ce44SJohn Forte 	check_underrun = 0;
121*fcf3ce44SJohn Forte 	fix_it = 0;
122*fcf3ce44SJohn Forte 
123*fcf3ce44SJohn Forte 	HBASTATS.FcpEvent++;
124*fcf3ce44SJohn Forte 
125*fcf3ce44SJohn Forte 	sbp = (emlxs_buf_t *)iocbq->sbp;
126*fcf3ce44SJohn Forte 
127*fcf3ce44SJohn Forte 	if (!sbp) {
128*fcf3ce44SJohn Forte 		/* completion with missing xmit command */
129*fcf3ce44SJohn Forte 		HBASTATS.FcpStray++;
130*fcf3ce44SJohn Forte 
131*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_fcp_completion_msg,
132*fcf3ce44SJohn Forte 		    "cmd=%x iotag=%x",
133*fcf3ce44SJohn Forte 		    cmd->ulpCommand, cmd->ulpIoTag);
134*fcf3ce44SJohn Forte 
135*fcf3ce44SJohn Forte 		return;
136*fcf3ce44SJohn Forte 	}
137*fcf3ce44SJohn Forte 	HBASTATS.FcpCompleted++;
138*fcf3ce44SJohn Forte 
139*fcf3ce44SJohn Forte 	pkt = PRIV2PKT(sbp);
140*fcf3ce44SJohn Forte 
141*fcf3ce44SJohn Forte 	did = SWAP_DATA24_LO(pkt->pkt_cmd_fhdr.d_id);
142*fcf3ce44SJohn Forte 	scsi_cmd = (uint8_t *)pkt->pkt_cmd;
143*fcf3ce44SJohn Forte 	scsi_opcode = scsi_cmd[12];
144*fcf3ce44SJohn Forte 	data_rx = 0;
145*fcf3ce44SJohn Forte 
146*fcf3ce44SJohn Forte 	/* Sync data in data buffer only on FC_PKT_FCP_READ */
147*fcf3ce44SJohn Forte 	if (pkt->pkt_datalen && (pkt->pkt_tran_type == FC_PKT_FCP_READ)) {
148*fcf3ce44SJohn Forte 		emlxs_mpdata_sync(pkt->pkt_data_dma, 0, pkt->pkt_datalen,
149*fcf3ce44SJohn Forte 		    DDI_DMA_SYNC_FORKERNEL);
150*fcf3ce44SJohn Forte 
151*fcf3ce44SJohn Forte #ifdef TEST_SUPPORT
152*fcf3ce44SJohn Forte 		if (hba->underrun_counter && (iostat == IOSTAT_SUCCESS) &&
153*fcf3ce44SJohn Forte 		    (pkt->pkt_datalen >= 512)) {
154*fcf3ce44SJohn Forte 			hba->underrun_counter--;
155*fcf3ce44SJohn Forte 			iostat = IOSTAT_FCP_RSP_ERROR;
156*fcf3ce44SJohn Forte 
157*fcf3ce44SJohn Forte 			/* Report 512 bytes missing by adapter */
158*fcf3ce44SJohn Forte 			cmd->un.fcpi.fcpi_parm = pkt->pkt_datalen - 512;
159*fcf3ce44SJohn Forte 
160*fcf3ce44SJohn Forte 			/* Corrupt 512 bytes of Data buffer */
161*fcf3ce44SJohn Forte 			bzero((uint8_t *)pkt->pkt_data, 512);
162*fcf3ce44SJohn Forte 
163*fcf3ce44SJohn Forte 			/* Set FCP response to STATUS_GOOD */
164*fcf3ce44SJohn Forte 			bzero((uint8_t *)pkt->pkt_resp, pkt->pkt_rsplen);
165*fcf3ce44SJohn Forte 		}
166*fcf3ce44SJohn Forte #endif	/* TEST_SUPPORT */
167*fcf3ce44SJohn Forte 	}
168*fcf3ce44SJohn Forte 	/* Process the pkt */
169*fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
170*fcf3ce44SJohn Forte 
171*fcf3ce44SJohn Forte 	/* Check for immediate return */
172*fcf3ce44SJohn Forte 	if ((iostat == IOSTAT_SUCCESS) &&
173*fcf3ce44SJohn Forte 	    (pkt->pkt_comp) &&
174*fcf3ce44SJohn Forte 	    !(sbp->pkt_flags & (PACKET_RETURNED | PACKET_COMPLETED |
175*fcf3ce44SJohn Forte 	    PACKET_IN_COMPLETION | PACKET_IN_TXQ | PACKET_IN_CHIPQ |
176*fcf3ce44SJohn Forte 	    PACKET_IN_DONEQ | PACKET_IN_TIMEOUT | PACKET_IN_FLUSH |
177*fcf3ce44SJohn Forte 	    PACKET_IN_ABORT | PACKET_POLLED))) {
178*fcf3ce44SJohn Forte 		HBASTATS.FcpGood++;
179*fcf3ce44SJohn Forte 
180*fcf3ce44SJohn Forte 		sbp->pkt_flags |= (PACKET_STATE_VALID | PACKET_IN_COMPLETION |
181*fcf3ce44SJohn Forte 		    PACKET_COMPLETED | PACKET_RETURNED);
182*fcf3ce44SJohn Forte 		mutex_exit(&sbp->mtx);
183*fcf3ce44SJohn Forte 
184*fcf3ce44SJohn Forte #if (EMLXS_MODREVX == EMLXS_MODREV2X)
185*fcf3ce44SJohn Forte 		emlxs_unswap_pkt(sbp);
186*fcf3ce44SJohn Forte #endif	/* EMLXS_MODREV2X */
187*fcf3ce44SJohn Forte 
188*fcf3ce44SJohn Forte 		(*pkt->pkt_comp) (pkt);
189*fcf3ce44SJohn Forte 
190*fcf3ce44SJohn Forte 		return;
191*fcf3ce44SJohn Forte 	}
192*fcf3ce44SJohn Forte 	/*
193*fcf3ce44SJohn Forte 	 * A response is only placed in the resp buffer if
194*fcf3ce44SJohn Forte 	 * IOSTAT_FCP_RSP_ERROR is reported
195*fcf3ce44SJohn Forte 	 */
196*fcf3ce44SJohn Forte 
197*fcf3ce44SJohn Forte 	/* Check if a response buffer was provided */
198*fcf3ce44SJohn Forte 	if ((iostat == IOSTAT_FCP_RSP_ERROR) && pkt->pkt_rsplen) {
199*fcf3ce44SJohn Forte 		emlxs_mpdata_sync(pkt->pkt_resp_dma, 0, pkt->pkt_rsplen,
200*fcf3ce44SJohn Forte 		    DDI_DMA_SYNC_FORKERNEL);
201*fcf3ce44SJohn Forte 
202*fcf3ce44SJohn Forte 		/* Get the response buffer pointer */
203*fcf3ce44SJohn Forte 		rsp = (fcp_rsp_t *)pkt->pkt_resp;
204*fcf3ce44SJohn Forte 
205*fcf3ce44SJohn Forte 		/* Set the valid response flag */
206*fcf3ce44SJohn Forte 		sbp->pkt_flags |= PACKET_FCP_RSP_VALID;
207*fcf3ce44SJohn Forte 
208*fcf3ce44SJohn Forte 		scsi_status = rsp->fcp_u.fcp_status.scsi_status;
209*fcf3ce44SJohn Forte 
210*fcf3ce44SJohn Forte 		/*
211*fcf3ce44SJohn Forte 		 * Convert a task abort to a check condition with no data
212*fcf3ce44SJohn Forte 		 * transferred
213*fcf3ce44SJohn Forte 		 */
214*fcf3ce44SJohn Forte 		/*
215*fcf3ce44SJohn Forte 		 * We saw a data corruption when Solaris received a Task
216*fcf3ce44SJohn Forte 		 * Abort from a tape
217*fcf3ce44SJohn Forte 		 */
218*fcf3ce44SJohn Forte 		if (scsi_status == SCSI_STAT_TASK_ABORT) {
219*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT,
220*fcf3ce44SJohn Forte 			    &emlxs_fcp_completion_error_msg,
221*fcf3ce44SJohn Forte 			    "Task Abort. Fixed. "
222*fcf3ce44SJohn Forte 			    "did=0x%06x sbp=%p cmd=%02x dl=%d",
223*fcf3ce44SJohn Forte 			    did, sbp, scsi_opcode, pkt->pkt_datalen);
224*fcf3ce44SJohn Forte 
225*fcf3ce44SJohn Forte 			rsp->fcp_u.fcp_status.scsi_status =
226*fcf3ce44SJohn Forte 			    SCSI_STAT_CHECK_COND;
227*fcf3ce44SJohn Forte 			rsp->fcp_u.fcp_status.rsp_len_set = 0;
228*fcf3ce44SJohn Forte 			rsp->fcp_u.fcp_status.sense_len_set = 0;
229*fcf3ce44SJohn Forte 			rsp->fcp_u.fcp_status.resid_over = 0;
230*fcf3ce44SJohn Forte 
231*fcf3ce44SJohn Forte 			if (pkt->pkt_datalen) {
232*fcf3ce44SJohn Forte 				rsp->fcp_u.fcp_status.resid_under = 1;
233*fcf3ce44SJohn Forte 				rsp->fcp_resid = SWAP_DATA32(pkt->pkt_datalen);
234*fcf3ce44SJohn Forte 			} else {
235*fcf3ce44SJohn Forte 				rsp->fcp_u.fcp_status.resid_under = 0;
236*fcf3ce44SJohn Forte 				rsp->fcp_resid = 0;
237*fcf3ce44SJohn Forte 			}
238*fcf3ce44SJohn Forte 
239*fcf3ce44SJohn Forte 			scsi_status = SCSI_STAT_CHECK_COND;
240*fcf3ce44SJohn Forte 		}
241*fcf3ce44SJohn Forte 		/*
242*fcf3ce44SJohn Forte 		 * We only need to check underrun if data could have been
243*fcf3ce44SJohn Forte 		 * sent
244*fcf3ce44SJohn Forte 		 */
245*fcf3ce44SJohn Forte 
246*fcf3ce44SJohn Forte 		/* Always check underrun if status is good */
247*fcf3ce44SJohn Forte 		if (scsi_status == SCSI_STAT_GOOD) {
248*fcf3ce44SJohn Forte 			check_underrun = 1;
249*fcf3ce44SJohn Forte 		}
250*fcf3ce44SJohn Forte 		/* Check the sense codes if this is a check condition */
251*fcf3ce44SJohn Forte 		else if (scsi_status == SCSI_STAT_CHECK_COND) {
252*fcf3ce44SJohn Forte 			check_underrun = 1;
253*fcf3ce44SJohn Forte 
254*fcf3ce44SJohn Forte 			/* Check if sense data was provided */
255*fcf3ce44SJohn Forte 			if (SWAP_DATA32(rsp->fcp_sense_len) >= 14) {
256*fcf3ce44SJohn Forte 				sense = *((uint8_t *)rsp + 32 + 2);
257*fcf3ce44SJohn Forte 				asc = *((uint8_t *)rsp + 32 + 12);
258*fcf3ce44SJohn Forte 				ascq = *((uint8_t *)rsp + 32 + 13);
259*fcf3ce44SJohn Forte 			}
260*fcf3ce44SJohn Forte 		}
261*fcf3ce44SJohn Forte 		/* Status is not good and this is not a check condition */
262*fcf3ce44SJohn Forte 		/* No data should have been sent */
263*fcf3ce44SJohn Forte 		else {
264*fcf3ce44SJohn Forte 			check_underrun = 0;
265*fcf3ce44SJohn Forte 		}
266*fcf3ce44SJohn Forte 
267*fcf3ce44SJohn Forte 		/* Get the residual underrun count reported by the SCSI reply */
268*fcf3ce44SJohn Forte 		rsp_data_resid = (pkt->pkt_datalen &&
269*fcf3ce44SJohn Forte 		    rsp->fcp_u.fcp_status.resid_under)
270*fcf3ce44SJohn Forte 		    ? SWAP_DATA32(rsp->fcp_resid) : 0;
271*fcf3ce44SJohn Forte 
272*fcf3ce44SJohn Forte 		/* Set the pkt resp_resid field */
273*fcf3ce44SJohn Forte 		pkt->pkt_resp_resid = 0;
274*fcf3ce44SJohn Forte 
275*fcf3ce44SJohn Forte 		/* Set the pkt data_resid field */
276*fcf3ce44SJohn Forte 		if (pkt->pkt_datalen &&
277*fcf3ce44SJohn Forte 		    (pkt->pkt_tran_type == FC_PKT_FCP_READ)) {
278*fcf3ce44SJohn Forte 			/*
279*fcf3ce44SJohn Forte 			 * Get the residual underrun count reported by our
280*fcf3ce44SJohn Forte 			 * adapter
281*fcf3ce44SJohn Forte 			 */
282*fcf3ce44SJohn Forte 			pkt->pkt_data_resid = cmd->un.fcpi.fcpi_parm;
283*fcf3ce44SJohn Forte 
284*fcf3ce44SJohn Forte 			/* Get the actual amount of data transferred */
285*fcf3ce44SJohn Forte 			data_rx = pkt->pkt_datalen - pkt->pkt_data_resid;
286*fcf3ce44SJohn Forte 
287*fcf3ce44SJohn Forte 			/*
288*fcf3ce44SJohn Forte 			 * If the residual being reported by the adapter is
289*fcf3ce44SJohn Forte 			 * greater than the residual being reported in the
290*fcf3ce44SJohn Forte 			 * reply, then we have a true underrun.
291*fcf3ce44SJohn Forte 			 */
292*fcf3ce44SJohn Forte 			if (check_underrun &&
293*fcf3ce44SJohn Forte 			    (pkt->pkt_data_resid > rsp_data_resid)) {
294*fcf3ce44SJohn Forte 				switch (scsi_opcode) {
295*fcf3ce44SJohn Forte 				case SCSI_INQUIRY:
296*fcf3ce44SJohn Forte 					scsi_dl = scsi_cmd[16];
297*fcf3ce44SJohn Forte 					break;
298*fcf3ce44SJohn Forte 
299*fcf3ce44SJohn Forte 				case SCSI_RX_DIAG:
300*fcf3ce44SJohn Forte 					scsi_dl = (scsi_cmd[15] * 0x100) +
301*fcf3ce44SJohn Forte 					    scsi_cmd[16];
302*fcf3ce44SJohn Forte 					break;
303*fcf3ce44SJohn Forte 
304*fcf3ce44SJohn Forte 				default:
305*fcf3ce44SJohn Forte 					scsi_dl = pkt->pkt_datalen;
306*fcf3ce44SJohn Forte 				}
307*fcf3ce44SJohn Forte 
308*fcf3ce44SJohn Forte #ifdef FCP_UNDERRUN_PATCH1
309*fcf3ce44SJohn Forte 				/*
310*fcf3ce44SJohn Forte 				 * If status is not good and no data was
311*fcf3ce44SJohn Forte 				 * actually transferred, then we must fix the
312*fcf3ce44SJohn Forte 				 * issue
313*fcf3ce44SJohn Forte 				 */
314*fcf3ce44SJohn Forte 				if ((scsi_status != SCSI_STAT_GOOD) &&
315*fcf3ce44SJohn Forte 				    (data_rx == 0)) {
316*fcf3ce44SJohn Forte 					fix_it = 1;
317*fcf3ce44SJohn Forte 
318*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
319*fcf3ce44SJohn Forte 					    &emlxs_fcp_completion_error_msg,
320*fcf3ce44SJohn Forte 					    "Underrun(1). Fixed. did=0x%06x "
321*fcf3ce44SJohn Forte 					    "sbp=%p cmd=%02x dl=%d,%d rx=%d "
322*fcf3ce44SJohn Forte 					    "rsp=%d",
323*fcf3ce44SJohn Forte 					    did, sbp, scsi_opcode,
324*fcf3ce44SJohn Forte 					    pkt->pkt_datalen, scsi_dl,
325*fcf3ce44SJohn Forte 					    (pkt->pkt_datalen -
326*fcf3ce44SJohn Forte 					    cmd->un.fcpi.fcpi_parm),
327*fcf3ce44SJohn Forte 					    rsp_data_resid);
328*fcf3ce44SJohn Forte 
329*fcf3ce44SJohn Forte 				}
330*fcf3ce44SJohn Forte #endif	/* FCP_UNDERRUN_PATCH1 */
331*fcf3ce44SJohn Forte 
332*fcf3ce44SJohn Forte 
333*fcf3ce44SJohn Forte #ifdef FCP_UNDERRUN_PATCH2
334*fcf3ce44SJohn Forte 				if ((scsi_status == SCSI_STAT_GOOD)) {
335*fcf3ce44SJohn Forte 					emlxs_msg_t *msg;
336*fcf3ce44SJohn Forte 
337*fcf3ce44SJohn Forte 					msg = &emlxs_fcp_completion_error_msg;
338*fcf3ce44SJohn Forte 					/*
339*fcf3ce44SJohn Forte 					 * If status is good and this is an
340*fcf3ce44SJohn Forte 					 * inquiry request and the amount of
341*fcf3ce44SJohn Forte 					 * data
342*fcf3ce44SJohn Forte 					 */
343*fcf3ce44SJohn Forte 					/*
344*fcf3ce44SJohn Forte 					 * requested <= data received, then
345*fcf3ce44SJohn Forte 					 * we must fix the issue.
346*fcf3ce44SJohn Forte 					 */
347*fcf3ce44SJohn Forte 
348*fcf3ce44SJohn Forte 					if ((scsi_opcode == SCSI_INQUIRY) &&
349*fcf3ce44SJohn Forte 					    (pkt->pkt_datalen >= data_rx) &&
350*fcf3ce44SJohn Forte 					    (scsi_dl <= data_rx)) {
351*fcf3ce44SJohn Forte 						fix_it = 1;
352*fcf3ce44SJohn Forte 
353*fcf3ce44SJohn Forte 						EMLXS_MSGF(EMLXS_CONTEXT,
354*fcf3ce44SJohn Forte 						    msg,
355*fcf3ce44SJohn Forte 						    "Underrun(2). Fixed. "
356*fcf3ce44SJohn Forte 						    "did=0x%06x sbp=%p "
357*fcf3ce44SJohn Forte 						    "cmd=%02x dl=%d,%d "
358*fcf3ce44SJohn Forte 						    "rx=%d rsp=%d",
359*fcf3ce44SJohn Forte 						    did, sbp, scsi_opcode,
360*fcf3ce44SJohn Forte 						    pkt->pkt_datalen, scsi_dl,
361*fcf3ce44SJohn Forte 						    data_rx, rsp_data_resid);
362*fcf3ce44SJohn Forte 
363*fcf3ce44SJohn Forte 					}
364*fcf3ce44SJohn Forte 					/*
365*fcf3ce44SJohn Forte 					 * If status is good and this is an
366*fcf3ce44SJohn Forte 					 * inquiry request and the amount of
367*fcf3ce44SJohn Forte 					 * data
368*fcf3ce44SJohn Forte 					 */
369*fcf3ce44SJohn Forte 					/*
370*fcf3ce44SJohn Forte 					 * requested >= 128 bytes, but only
371*fcf3ce44SJohn Forte 					 * 128 bytes were received,
372*fcf3ce44SJohn Forte 					 */
373*fcf3ce44SJohn Forte 					/* then we must fix the issue. */
374*fcf3ce44SJohn Forte 					else if ((scsi_opcode == SCSI_INQUIRY)&&
375*fcf3ce44SJohn Forte 					    (pkt->pkt_datalen >= 128) &&
376*fcf3ce44SJohn Forte 					    (scsi_dl >= 128) &&
377*fcf3ce44SJohn Forte 					    (data_rx == 128)) {
378*fcf3ce44SJohn Forte 						fix_it = 1;
379*fcf3ce44SJohn Forte 
380*fcf3ce44SJohn Forte 						EMLXS_MSGF(EMLXS_CONTEXT,
381*fcf3ce44SJohn Forte 						    msg,
382*fcf3ce44SJohn Forte 						    "Underrun(3). Fixed. "
383*fcf3ce44SJohn Forte 						    "did=0x%06x sbp=%p "
384*fcf3ce44SJohn Forte 						    "cmd=%02x dl=%d,%d rx=%d "
385*fcf3ce44SJohn Forte 						    "rsp=%d",
386*fcf3ce44SJohn Forte 						    did, sbp, scsi_opcode,
387*fcf3ce44SJohn Forte 						    pkt->pkt_datalen, scsi_dl,
388*fcf3ce44SJohn Forte 						    data_rx, rsp_data_resid);
389*fcf3ce44SJohn Forte 
390*fcf3ce44SJohn Forte 					}
391*fcf3ce44SJohn Forte 				}
392*fcf3ce44SJohn Forte #endif	/* FCP_UNDERRUN_PATCH2 */
393*fcf3ce44SJohn Forte 
394*fcf3ce44SJohn Forte 				/*
395*fcf3ce44SJohn Forte 				 * Check if SCSI response payload should be
396*fcf3ce44SJohn Forte 				 * fixed or
397*fcf3ce44SJohn Forte 				 */
398*fcf3ce44SJohn Forte 				/* if a DATA_UNDERRUN should be reported */
399*fcf3ce44SJohn Forte 				if (fix_it) {
400*fcf3ce44SJohn Forte 					/*
401*fcf3ce44SJohn Forte 					 * Fix the SCSI response payload
402*fcf3ce44SJohn Forte 					 * itself
403*fcf3ce44SJohn Forte 					 */
404*fcf3ce44SJohn Forte 					rsp->fcp_u.fcp_status.resid_under = 1;
405*fcf3ce44SJohn Forte 					rsp->fcp_resid =
406*fcf3ce44SJohn Forte 					    SWAP_DATA32(pkt->pkt_data_resid);
407*fcf3ce44SJohn Forte 				} else {
408*fcf3ce44SJohn Forte 					/*
409*fcf3ce44SJohn Forte 					 * Change the status from
410*fcf3ce44SJohn Forte 					 * IOSTAT_FCP_RSP_ERROR to
411*fcf3ce44SJohn Forte 					 * IOSTAT_DATA_UNDERRUN
412*fcf3ce44SJohn Forte 					 */
413*fcf3ce44SJohn Forte 					iostat = IOSTAT_DATA_UNDERRUN;
414*fcf3ce44SJohn Forte 					pkt->pkt_data_resid = pkt->pkt_datalen;
415*fcf3ce44SJohn Forte 				}
416*fcf3ce44SJohn Forte 			}
417*fcf3ce44SJohn Forte 			/*
418*fcf3ce44SJohn Forte 			 * If the residual being reported by the adapter is
419*fcf3ce44SJohn Forte 			 * less than the residual being reported in the
420*fcf3ce44SJohn Forte 			 * reply, then we have a true overrun. Since we don't
421*fcf3ce44SJohn Forte 			 * know where the extra data came from or went to
422*fcf3ce44SJohn Forte 			 * then we cannot trust anything we received
423*fcf3ce44SJohn Forte 			 */
424*fcf3ce44SJohn Forte 			else if (rsp_data_resid > pkt->pkt_data_resid) {
425*fcf3ce44SJohn Forte 				/*
426*fcf3ce44SJohn Forte 				 * Change the status from
427*fcf3ce44SJohn Forte 				 * IOSTAT_FCP_RSP_ERROR to
428*fcf3ce44SJohn Forte 				 * IOSTAT_DATA_OVERRUN
429*fcf3ce44SJohn Forte 				 */
430*fcf3ce44SJohn Forte 				iostat = IOSTAT_DATA_OVERRUN;
431*fcf3ce44SJohn Forte 				pkt->pkt_data_resid = pkt->pkt_datalen;
432*fcf3ce44SJohn Forte 			}
433*fcf3ce44SJohn Forte 		} else {	/* pkt->pkt_datalen==0 or FC_PKT_FCP_WRITE */
434*fcf3ce44SJohn Forte 			/* Report whatever the target reported */
435*fcf3ce44SJohn Forte 			pkt->pkt_data_resid = rsp_data_resid;
436*fcf3ce44SJohn Forte 		}
437*fcf3ce44SJohn Forte 	}
438*fcf3ce44SJohn Forte 	/*
439*fcf3ce44SJohn Forte 	 * If pkt is tagged for timeout then set the return codes
440*fcf3ce44SJohn Forte 	 * appropriately
441*fcf3ce44SJohn Forte 	 */
442*fcf3ce44SJohn Forte 	if (sbp->pkt_flags & PACKET_IN_TIMEOUT) {
443*fcf3ce44SJohn Forte 		iostat = IOSTAT_LOCAL_REJECT;
444*fcf3ce44SJohn Forte 		localstat = IOERR_ABORT_TIMEOUT;
445*fcf3ce44SJohn Forte 		goto done;
446*fcf3ce44SJohn Forte 	}
447*fcf3ce44SJohn Forte 	/* If pkt is tagged for abort then set the return codes appropriately */
448*fcf3ce44SJohn Forte 	if (sbp->pkt_flags & (PACKET_IN_FLUSH | PACKET_IN_ABORT)) {
449*fcf3ce44SJohn Forte 		iostat = IOSTAT_LOCAL_REJECT;
450*fcf3ce44SJohn Forte 		localstat = IOERR_ABORT_REQUESTED;
451*fcf3ce44SJohn Forte 		goto done;
452*fcf3ce44SJohn Forte 	}
453*fcf3ce44SJohn Forte 	/* Print completion message */
454*fcf3ce44SJohn Forte 	switch (iostat) {
455*fcf3ce44SJohn Forte 	case IOSTAT_SUCCESS:
456*fcf3ce44SJohn Forte 		/* Build SCSI GOOD status */
457*fcf3ce44SJohn Forte 		if (pkt->pkt_rsplen) {
458*fcf3ce44SJohn Forte 			bzero((uint8_t *)pkt->pkt_resp, pkt->pkt_rsplen);
459*fcf3ce44SJohn Forte 		}
460*fcf3ce44SJohn Forte 		break;
461*fcf3ce44SJohn Forte 
462*fcf3ce44SJohn Forte 	case IOSTAT_FCP_RSP_ERROR:
463*fcf3ce44SJohn Forte 		break;
464*fcf3ce44SJohn Forte 
465*fcf3ce44SJohn Forte 	case IOSTAT_REMOTE_STOP:
466*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
467*fcf3ce44SJohn Forte 		    "Remote Stop. did=0x%06x sbp=%p cmd=%02x",
468*fcf3ce44SJohn Forte 		    did, sbp, scsi_opcode);
469*fcf3ce44SJohn Forte 		break;
470*fcf3ce44SJohn Forte 
471*fcf3ce44SJohn Forte 	case IOSTAT_LOCAL_REJECT:
472*fcf3ce44SJohn Forte 		localstat = cmd->un.grsp.perr.statLocalError;
473*fcf3ce44SJohn Forte 
474*fcf3ce44SJohn Forte 		switch (localstat) {
475*fcf3ce44SJohn Forte 		case IOERR_SEQUENCE_TIMEOUT:
476*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT,
477*fcf3ce44SJohn Forte 			    &emlxs_fcp_completion_error_msg,
478*fcf3ce44SJohn Forte 			    "Local reject. %s did=0x%06x sbp=%p "
479*fcf3ce44SJohn Forte 			    "cmd=%02x tmo=%d ",
480*fcf3ce44SJohn Forte 			    emlxs_error_xlate(localstat), did, sbp,
481*fcf3ce44SJohn Forte 			    scsi_opcode, pkt->pkt_timeout);
482*fcf3ce44SJohn Forte 			break;
483*fcf3ce44SJohn Forte 
484*fcf3ce44SJohn Forte 		default:
485*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT,
486*fcf3ce44SJohn Forte 			    &emlxs_fcp_completion_error_msg,
487*fcf3ce44SJohn Forte 			    "Local reject. %s did=0x%06x sbp=%p cmd=%02x",
488*fcf3ce44SJohn Forte 			    emlxs_error_xlate(localstat), did,
489*fcf3ce44SJohn Forte 			    sbp, scsi_opcode);
490*fcf3ce44SJohn Forte 		}
491*fcf3ce44SJohn Forte 
492*fcf3ce44SJohn Forte 		break;
493*fcf3ce44SJohn Forte 
494*fcf3ce44SJohn Forte 	case IOSTAT_NPORT_RJT:
495*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
496*fcf3ce44SJohn Forte 		    "Nport reject. did=0x%06x sbp=%p cmd=%02x",
497*fcf3ce44SJohn Forte 		    did, sbp, scsi_opcode);
498*fcf3ce44SJohn Forte 		break;
499*fcf3ce44SJohn Forte 
500*fcf3ce44SJohn Forte 	case IOSTAT_FABRIC_RJT:
501*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
502*fcf3ce44SJohn Forte 		    "Fabric reject. did=0x%06x sbp=%p cmd=%02x",
503*fcf3ce44SJohn Forte 		    did, sbp, scsi_opcode);
504*fcf3ce44SJohn Forte 		break;
505*fcf3ce44SJohn Forte 
506*fcf3ce44SJohn Forte 	case IOSTAT_NPORT_BSY:
507*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
508*fcf3ce44SJohn Forte 		    "Nport busy. did=0x%06x sbp=%p cmd=%02x",
509*fcf3ce44SJohn Forte 		    did, sbp, scsi_opcode);
510*fcf3ce44SJohn Forte 		break;
511*fcf3ce44SJohn Forte 
512*fcf3ce44SJohn Forte 	case IOSTAT_FABRIC_BSY:
513*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
514*fcf3ce44SJohn Forte 		    "Fabric busy. did=0x%06x sbp=%p cmd=%02x",
515*fcf3ce44SJohn Forte 		    did, sbp, scsi_opcode);
516*fcf3ce44SJohn Forte 		break;
517*fcf3ce44SJohn Forte 
518*fcf3ce44SJohn Forte 	case IOSTAT_INTERMED_RSP:
519*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
520*fcf3ce44SJohn Forte 		    "Intermediate response. did=0x%06x sbp=%p cmd=%02x",
521*fcf3ce44SJohn Forte 		    did, sbp, scsi_opcode);
522*fcf3ce44SJohn Forte 		break;
523*fcf3ce44SJohn Forte 
524*fcf3ce44SJohn Forte 	case IOSTAT_LS_RJT:
525*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
526*fcf3ce44SJohn Forte 		    "LS Reject. did=0x%06x sbp=%p cmd=%02x",
527*fcf3ce44SJohn Forte 		    did, sbp, scsi_opcode);
528*fcf3ce44SJohn Forte 		break;
529*fcf3ce44SJohn Forte 
530*fcf3ce44SJohn Forte 	case IOSTAT_DATA_UNDERRUN:
531*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
532*fcf3ce44SJohn Forte 		    "Underrun. did=0x%06x sbp=%p cmd=%02x dl=%d,%d rx=%d "
533*fcf3ce44SJohn Forte 		    "rsp=%d (%02x,%02x,%02x,%02x)",
534*fcf3ce44SJohn Forte 		    did, sbp, scsi_opcode, pkt->pkt_datalen, scsi_dl,
535*fcf3ce44SJohn Forte 		    data_rx, rsp_data_resid, scsi_status, sense, asc, ascq);
536*fcf3ce44SJohn Forte 		break;
537*fcf3ce44SJohn Forte 
538*fcf3ce44SJohn Forte 	case IOSTAT_DATA_OVERRUN:
539*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
540*fcf3ce44SJohn Forte 		    "Overrun. did=0x%06x sbp=%p cmd=%02x dl=%d,%d rx=%d "
541*fcf3ce44SJohn Forte 		    "rsp=%d (%02x,%02x,%02x,%02x)",
542*fcf3ce44SJohn Forte 		    did, sbp, scsi_opcode, pkt->pkt_datalen, scsi_dl,
543*fcf3ce44SJohn Forte 		    data_rx, rsp_data_resid, scsi_status, sense, asc, ascq);
544*fcf3ce44SJohn Forte 		break;
545*fcf3ce44SJohn Forte 
546*fcf3ce44SJohn Forte 	default:
547*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
548*fcf3ce44SJohn Forte 		    "Unknown status=%x reason=%x did=0x%06x sbp=%p cmd=%02x",
549*fcf3ce44SJohn Forte 		    iostat, cmd->un.grsp.perr.statLocalError, did,
550*fcf3ce44SJohn Forte 		    sbp, scsi_opcode);
551*fcf3ce44SJohn Forte 		break;
552*fcf3ce44SJohn Forte 	}
553*fcf3ce44SJohn Forte 
554*fcf3ce44SJohn Forte done:
555*fcf3ce44SJohn Forte 
556*fcf3ce44SJohn Forte 	if (iostat == IOSTAT_SUCCESS) {
557*fcf3ce44SJohn Forte 		HBASTATS.FcpGood++;
558*fcf3ce44SJohn Forte 	} else {
559*fcf3ce44SJohn Forte 		HBASTATS.FcpError++;
560*fcf3ce44SJohn Forte 	}
561*fcf3ce44SJohn Forte 
562*fcf3ce44SJohn Forte 	mutex_exit(&sbp->mtx);
563*fcf3ce44SJohn Forte 
564*fcf3ce44SJohn Forte 	emlxs_pkt_complete(sbp, iostat, localstat, 0);
565*fcf3ce44SJohn Forte 
566*fcf3ce44SJohn Forte 	return;
567*fcf3ce44SJohn Forte 
568*fcf3ce44SJohn Forte } /* emlxs_handle_fcp_event() */
569*fcf3ce44SJohn Forte 
570*fcf3ce44SJohn Forte 
571*fcf3ce44SJohn Forte 
572*fcf3ce44SJohn Forte /*
573*fcf3ce44SJohn Forte  *  emlxs_post_buffer
574*fcf3ce44SJohn Forte  *
575*fcf3ce44SJohn Forte  *  This routine will post count buffers to the
576*fcf3ce44SJohn Forte  *  ring with the QUE_RING_BUF_CN command. This
577*fcf3ce44SJohn Forte  *  allows 2 buffers / command to be posted.
578*fcf3ce44SJohn Forte  *  Returns the number of buffers NOT posted.
579*fcf3ce44SJohn Forte  */
580*fcf3ce44SJohn Forte extern int
581*fcf3ce44SJohn Forte emlxs_post_buffer(emlxs_hba_t *hba, RING *rp, int16_t cnt)
582*fcf3ce44SJohn Forte {
583*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
584*fcf3ce44SJohn Forte 	IOCB *icmd;
585*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
586*fcf3ce44SJohn Forte 	MATCHMAP *mp;
587*fcf3ce44SJohn Forte 	uint16_t tag;
588*fcf3ce44SJohn Forte 	uint32_t maxqbuf;
589*fcf3ce44SJohn Forte 	int32_t i;
590*fcf3ce44SJohn Forte 	int32_t j;
591*fcf3ce44SJohn Forte 	uint32_t seg;
592*fcf3ce44SJohn Forte 	uint32_t size;
593*fcf3ce44SJohn Forte 
594*fcf3ce44SJohn Forte 	mp = 0;
595*fcf3ce44SJohn Forte 	maxqbuf = 2;
596*fcf3ce44SJohn Forte 	tag = (uint16_t)cnt;
597*fcf3ce44SJohn Forte 	cnt += rp->fc_missbufcnt;
598*fcf3ce44SJohn Forte 
599*fcf3ce44SJohn Forte 	if (rp->ringno == FC_ELS_RING) {
600*fcf3ce44SJohn Forte 		seg = MEM_BUF;
601*fcf3ce44SJohn Forte 		size = MEM_ELSBUF_SIZE;
602*fcf3ce44SJohn Forte 	} else if (rp->ringno == FC_IP_RING) {
603*fcf3ce44SJohn Forte 		seg = MEM_IPBUF;
604*fcf3ce44SJohn Forte 		size = MEM_IPBUF_SIZE;
605*fcf3ce44SJohn Forte 	} else if (rp->ringno == FC_CT_RING) {
606*fcf3ce44SJohn Forte 		seg = MEM_CTBUF;
607*fcf3ce44SJohn Forte 		size = MEM_CTBUF_SIZE;
608*fcf3ce44SJohn Forte 	}
609*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
610*fcf3ce44SJohn Forte 	else if (rp->ringno == FC_FCT_RING) {
611*fcf3ce44SJohn Forte 		seg = MEM_FCTBUF;
612*fcf3ce44SJohn Forte 		size = MEM_FCTBUF_SIZE;
613*fcf3ce44SJohn Forte 	}
614*fcf3ce44SJohn Forte #endif	/* SFCT_SUPPORT */
615*fcf3ce44SJohn Forte 	else {
616*fcf3ce44SJohn Forte 		return (0);
617*fcf3ce44SJohn Forte 	}
618*fcf3ce44SJohn Forte 
619*fcf3ce44SJohn Forte 	/*
620*fcf3ce44SJohn Forte 	 * While there are buffers to post
621*fcf3ce44SJohn Forte 	 */
622*fcf3ce44SJohn Forte 	while (cnt) {
623*fcf3ce44SJohn Forte 		if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == 0) {
624*fcf3ce44SJohn Forte 			rp->fc_missbufcnt = cnt;
625*fcf3ce44SJohn Forte 			return (cnt);
626*fcf3ce44SJohn Forte 		}
627*fcf3ce44SJohn Forte 		iocbq->ring = (void *)rp;
628*fcf3ce44SJohn Forte 		iocbq->port = (void *)port;
629*fcf3ce44SJohn Forte 		iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
630*fcf3ce44SJohn Forte 
631*fcf3ce44SJohn Forte 		icmd = &iocbq->iocb;
632*fcf3ce44SJohn Forte 
633*fcf3ce44SJohn Forte 		/*
634*fcf3ce44SJohn Forte 		 * Max buffers can be posted per command
635*fcf3ce44SJohn Forte 		 */
636*fcf3ce44SJohn Forte 		for (i = 0; i < maxqbuf; i++) {
637*fcf3ce44SJohn Forte 			if (cnt <= 0)
638*fcf3ce44SJohn Forte 				break;
639*fcf3ce44SJohn Forte 
640*fcf3ce44SJohn Forte 			/* fill in BDEs for command */
641*fcf3ce44SJohn Forte 			if ((mp = (MATCHMAP *)emlxs_mem_get(hba, seg)) == 0) {
642*fcf3ce44SJohn Forte 				uint32_t H;
643*fcf3ce44SJohn Forte 				uint32_t L;
644*fcf3ce44SJohn Forte 
645*fcf3ce44SJohn Forte 				icmd->ulpBdeCount = i;
646*fcf3ce44SJohn Forte 				for (j = 0; j < i; j++) {
647*fcf3ce44SJohn Forte 					H = icmd->un.cont64[j].addrHigh;
648*fcf3ce44SJohn Forte 					L = icmd->un.cont64[j].addrLow;
649*fcf3ce44SJohn Forte 					mp = emlxs_mem_get_vaddr(hba, rp,
650*fcf3ce44SJohn Forte 					    getPaddr(H, L));
651*fcf3ce44SJohn Forte 					if (mp) {
652*fcf3ce44SJohn Forte 						(void) emlxs_mem_put(hba, seg,
653*fcf3ce44SJohn Forte 						    (uint8_t *)mp);
654*fcf3ce44SJohn Forte 					}
655*fcf3ce44SJohn Forte 				}
656*fcf3ce44SJohn Forte 
657*fcf3ce44SJohn Forte 				rp->fc_missbufcnt = cnt + i;
658*fcf3ce44SJohn Forte 
659*fcf3ce44SJohn Forte 				(void) emlxs_mem_put(hba, MEM_IOCB,
660*fcf3ce44SJohn Forte 				    (uint8_t *)iocbq);
661*fcf3ce44SJohn Forte 
662*fcf3ce44SJohn Forte 				return (cnt + i);
663*fcf3ce44SJohn Forte 			}
664*fcf3ce44SJohn Forte 			/*
665*fcf3ce44SJohn Forte 			 * map that page and save the address pair for lookup
666*fcf3ce44SJohn Forte 			 * later
667*fcf3ce44SJohn Forte 			 */
668*fcf3ce44SJohn Forte 			emlxs_mem_map_vaddr(hba, rp, mp,
669*fcf3ce44SJohn Forte 			    (uint32_t *)&icmd->un.cont64[i].addrHigh,
670*fcf3ce44SJohn Forte 			    (uint32_t *)&icmd->un.cont64[i].addrLow);
671*fcf3ce44SJohn Forte 
672*fcf3ce44SJohn Forte 			icmd->un.cont64[i].tus.f.bdeSize = size;
673*fcf3ce44SJohn Forte 			icmd->ulpCommand = CMD_QUE_RING_BUF64_CN;
674*fcf3ce44SJohn Forte 
675*fcf3ce44SJohn Forte /*
676*fcf3ce44SJohn Forte  *			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
677*fcf3ce44SJohn Forte  *			    "UB Post: ring=%d addr=%08x%08x size=%d",
678*fcf3ce44SJohn Forte  *			    rp->ringno, icmd->un.cont64[i].addrHigh,
679*fcf3ce44SJohn Forte  *			    icmd->un.cont64[i].addrLow, size);
680*fcf3ce44SJohn Forte  */
681*fcf3ce44SJohn Forte 
682*fcf3ce44SJohn Forte 			cnt--;
683*fcf3ce44SJohn Forte 		}
684*fcf3ce44SJohn Forte 
685*fcf3ce44SJohn Forte 		icmd->ulpIoTag = tag;
686*fcf3ce44SJohn Forte 		icmd->ulpBdeCount = i;
687*fcf3ce44SJohn Forte 		icmd->ulpLe = 1;
688*fcf3ce44SJohn Forte 		icmd->ulpOwner = OWN_CHIP;
689*fcf3ce44SJohn Forte 		iocbq->bp = (uint8_t *)mp;  /* used for delimiter between */
690*fcf3ce44SJohn Forte 					    /* commands */
691*fcf3ce44SJohn Forte 
692*fcf3ce44SJohn Forte 		emlxs_issue_iocb_cmd(hba, rp, iocbq);
693*fcf3ce44SJohn Forte 	}
694*fcf3ce44SJohn Forte 
695*fcf3ce44SJohn Forte 	rp->fc_missbufcnt = 0;
696*fcf3ce44SJohn Forte 
697*fcf3ce44SJohn Forte 	return (0);
698*fcf3ce44SJohn Forte 
699*fcf3ce44SJohn Forte } /* emlxs_post_buffer() */
700*fcf3ce44SJohn Forte 
701*fcf3ce44SJohn Forte 
702*fcf3ce44SJohn Forte extern int
703*fcf3ce44SJohn Forte emlxs_port_offline(emlxs_port_t *port, uint32_t scope)
704*fcf3ce44SJohn Forte {
705*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
706*fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
707*fcf3ce44SJohn Forte 	NODELIST *nlp;
708*fcf3ce44SJohn Forte 	fc_affected_id_t *aid;
709*fcf3ce44SJohn Forte 	uint32_t mask;
710*fcf3ce44SJohn Forte 	uint32_t aff_d_id;
711*fcf3ce44SJohn Forte 	uint32_t linkdown;
712*fcf3ce44SJohn Forte 	uint32_t vlinkdown;
713*fcf3ce44SJohn Forte 	uint32_t action;
714*fcf3ce44SJohn Forte 	int i;
715*fcf3ce44SJohn Forte 	uint32_t unreg_vpi;
716*fcf3ce44SJohn Forte 	uint32_t update;
717*fcf3ce44SJohn Forte 	uint32_t adisc_support;
718*fcf3ce44SJohn Forte 
719*fcf3ce44SJohn Forte 	/* Target mode only uses this routine for linkdowns */
720*fcf3ce44SJohn Forte 	if (port->tgt_mode && (scope != 0xffffffff) && (scope != 0xfeffffff)) {
721*fcf3ce44SJohn Forte 		return (0);
722*fcf3ce44SJohn Forte 	}
723*fcf3ce44SJohn Forte 	cfg = &CFG;
724*fcf3ce44SJohn Forte 	aid = (fc_affected_id_t *)&scope;
725*fcf3ce44SJohn Forte 	linkdown = 0;
726*fcf3ce44SJohn Forte 	vlinkdown = 0;
727*fcf3ce44SJohn Forte 	unreg_vpi = 0;
728*fcf3ce44SJohn Forte 	update = 0;
729*fcf3ce44SJohn Forte 
730*fcf3ce44SJohn Forte 	if (!(port->flag & EMLXS_PORT_BOUND)) {
731*fcf3ce44SJohn Forte 		return (0);
732*fcf3ce44SJohn Forte 	}
733*fcf3ce44SJohn Forte 	switch (aid->aff_format) {
734*fcf3ce44SJohn Forte 	case 0:	/* Port */
735*fcf3ce44SJohn Forte 		mask = 0x00ffffff;
736*fcf3ce44SJohn Forte 		break;
737*fcf3ce44SJohn Forte 
738*fcf3ce44SJohn Forte 	case 1:	/* Area */
739*fcf3ce44SJohn Forte 		mask = 0x00ffff00;
740*fcf3ce44SJohn Forte 		break;
741*fcf3ce44SJohn Forte 
742*fcf3ce44SJohn Forte 	case 2:	/* Domain */
743*fcf3ce44SJohn Forte 		mask = 0x00ff0000;
744*fcf3ce44SJohn Forte 		break;
745*fcf3ce44SJohn Forte 
746*fcf3ce44SJohn Forte 	case 3:	/* Network */
747*fcf3ce44SJohn Forte 		mask = 0x00000000;
748*fcf3ce44SJohn Forte 		break;
749*fcf3ce44SJohn Forte 
750*fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
751*fcf3ce44SJohn Forte 	case 0xfe:	/* Virtual link down */
752*fcf3ce44SJohn Forte 		mask = 0x00000000;
753*fcf3ce44SJohn Forte 		vlinkdown = 1;
754*fcf3ce44SJohn Forte 		break;
755*fcf3ce44SJohn Forte #endif	/* DHCHAP_SUPPORT */
756*fcf3ce44SJohn Forte 
757*fcf3ce44SJohn Forte 	case 0xff:	/* link is down */
758*fcf3ce44SJohn Forte 		mask = 0x00000000;
759*fcf3ce44SJohn Forte 		linkdown = 1;
760*fcf3ce44SJohn Forte 		break;
761*fcf3ce44SJohn Forte 
762*fcf3ce44SJohn Forte 	}
763*fcf3ce44SJohn Forte 
764*fcf3ce44SJohn Forte 	aff_d_id = aid->aff_d_id & mask;
765*fcf3ce44SJohn Forte 
766*fcf3ce44SJohn Forte 
767*fcf3ce44SJohn Forte 	/* If link is down then this is a hard shutdown and flush */
768*fcf3ce44SJohn Forte 	/*
769*fcf3ce44SJohn Forte 	 * If link not down then this is a soft shutdown and flush (e.g.
770*fcf3ce44SJohn Forte 	 * RSCN)
771*fcf3ce44SJohn Forte 	 */
772*fcf3ce44SJohn Forte 	if (linkdown) {
773*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
774*fcf3ce44SJohn Forte 
775*fcf3ce44SJohn Forte 		port->flag &= EMLXS_PORT_LINKDOWN_MASK;
776*fcf3ce44SJohn Forte 		port->prev_did = port->did;
777*fcf3ce44SJohn Forte 		port->did = 0;
778*fcf3ce44SJohn Forte 
779*fcf3ce44SJohn Forte 		if (port->ulp_statec != FC_STATE_OFFLINE) {
780*fcf3ce44SJohn Forte 			port->ulp_statec = FC_STATE_OFFLINE;
781*fcf3ce44SJohn Forte 			update = 1;
782*fcf3ce44SJohn Forte 		}
783*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
784*fcf3ce44SJohn Forte 
785*fcf3ce44SJohn Forte 		/* Tell ULP about it */
786*fcf3ce44SJohn Forte 		if (update) {
787*fcf3ce44SJohn Forte 			if (port->flag & EMLXS_PORT_BOUND) {
788*fcf3ce44SJohn Forte 				if (port->vpi == 0) {
789*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
790*fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
791*fcf3ce44SJohn Forte 					    NULL);
792*fcf3ce44SJohn Forte 				}
793*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
794*fcf3ce44SJohn Forte 				if (port->tgt_mode) {
795*fcf3ce44SJohn Forte 					emlxs_fct_link_down(port);
796*fcf3ce44SJohn Forte 
797*fcf3ce44SJohn Forte 				} else if (port->ini_mode) {
798*fcf3ce44SJohn Forte 					port->ulp_statec_cb(port->ulp_handle,
799*fcf3ce44SJohn Forte 					    FC_STATE_OFFLINE);
800*fcf3ce44SJohn Forte 				}
801*fcf3ce44SJohn Forte #else
802*fcf3ce44SJohn Forte 				port->ulp_statec_cb(port->ulp_handle,
803*fcf3ce44SJohn Forte 				    FC_STATE_OFFLINE);
804*fcf3ce44SJohn Forte #endif	/* SFCT_SUPPORT */
805*fcf3ce44SJohn Forte 			} else {
806*fcf3ce44SJohn Forte 				if (port->vpi == 0) {
807*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
808*fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
809*fcf3ce44SJohn Forte 					    "*");
810*fcf3ce44SJohn Forte 				}
811*fcf3ce44SJohn Forte 			}
812*fcf3ce44SJohn Forte 
813*fcf3ce44SJohn Forte 
814*fcf3ce44SJohn Forte 		}
815*fcf3ce44SJohn Forte 		unreg_vpi = 1;
816*fcf3ce44SJohn Forte 
817*fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
818*fcf3ce44SJohn Forte 		/* Stop authentication with all nodes */
819*fcf3ce44SJohn Forte 		emlxs_dhc_auth_stop(port, NULL);
820*fcf3ce44SJohn Forte #endif	/* DHCHAP_SUPPORT */
821*fcf3ce44SJohn Forte 
822*fcf3ce44SJohn Forte 		/* Flush the base node */
823*fcf3ce44SJohn Forte 		(void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0);
824*fcf3ce44SJohn Forte 		(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);
825*fcf3ce44SJohn Forte 
826*fcf3ce44SJohn Forte 		/* Flush any pending ub buffers */
827*fcf3ce44SJohn Forte 		emlxs_ub_flush(port);
828*fcf3ce44SJohn Forte 	}
829*fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
830*fcf3ce44SJohn Forte 	/* virtual link down */
831*fcf3ce44SJohn Forte 	else if (vlinkdown) {
832*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
833*fcf3ce44SJohn Forte 
834*fcf3ce44SJohn Forte 		if (port->ulp_statec != FC_STATE_OFFLINE) {
835*fcf3ce44SJohn Forte 			port->ulp_statec = FC_STATE_OFFLINE;
836*fcf3ce44SJohn Forte 			update = 1;
837*fcf3ce44SJohn Forte 		}
838*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
839*fcf3ce44SJohn Forte 
840*fcf3ce44SJohn Forte 		/* Tell ULP about it */
841*fcf3ce44SJohn Forte 		if (update) {
842*fcf3ce44SJohn Forte 			if (port->flag & EMLXS_PORT_BOUND) {
843*fcf3ce44SJohn Forte 				if (port->vpi == 0) {
844*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
845*fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
846*fcf3ce44SJohn Forte 					    "Switch authentication failed.");
847*fcf3ce44SJohn Forte 				}
848*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
849*fcf3ce44SJohn Forte 				if (port->tgt_mode) {
850*fcf3ce44SJohn Forte 					emlxs_fct_link_down(port);
851*fcf3ce44SJohn Forte 				} else if (port->ini_mode) {
852*fcf3ce44SJohn Forte 					port->ulp_statec_cb(port->ulp_handle,
853*fcf3ce44SJohn Forte 					    FC_STATE_OFFLINE);
854*fcf3ce44SJohn Forte 				}
855*fcf3ce44SJohn Forte #else
856*fcf3ce44SJohn Forte 				port->ulp_statec_cb(port->ulp_handle,
857*fcf3ce44SJohn Forte 				    FC_STATE_OFFLINE);
858*fcf3ce44SJohn Forte #endif	/* SFCT_SUPPORT */
859*fcf3ce44SJohn Forte 			} else {
860*fcf3ce44SJohn Forte 				if (port->vpi == 0) {
861*fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
862*fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
863*fcf3ce44SJohn Forte 					    "Switch authentication failed. *");
864*fcf3ce44SJohn Forte 				}
865*fcf3ce44SJohn Forte 			}
866*fcf3ce44SJohn Forte 
867*fcf3ce44SJohn Forte 
868*fcf3ce44SJohn Forte 		}
869*fcf3ce44SJohn Forte 		/* Flush the base node */
870*fcf3ce44SJohn Forte 		(void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0);
871*fcf3ce44SJohn Forte 		(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);
872*fcf3ce44SJohn Forte 	}
873*fcf3ce44SJohn Forte #endif	/* DHCHAP_SUPPORT */
874*fcf3ce44SJohn Forte 
875*fcf3ce44SJohn Forte 	if (port->tgt_mode) {
876*fcf3ce44SJohn Forte 		goto done;
877*fcf3ce44SJohn Forte 	}
878*fcf3ce44SJohn Forte 	/* Set the node tags */
879*fcf3ce44SJohn Forte 	/* We will process all nodes with this tag */
880*fcf3ce44SJohn Forte 	rw_enter(&port->node_rwlock, RW_READER);
881*fcf3ce44SJohn Forte 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
882*fcf3ce44SJohn Forte 		nlp = port->node_table[i];
883*fcf3ce44SJohn Forte 		while (nlp != NULL) {
884*fcf3ce44SJohn Forte 			nlp->nlp_tag = 1;
885*fcf3ce44SJohn Forte 			nlp = nlp->nlp_list_next;
886*fcf3ce44SJohn Forte 		}
887*fcf3ce44SJohn Forte 	}
888*fcf3ce44SJohn Forte 	rw_exit(&port->node_rwlock);
889*fcf3ce44SJohn Forte 
890*fcf3ce44SJohn Forte 	if (hba->flag & FC_ONLINE_MODE) {
891*fcf3ce44SJohn Forte 		adisc_support = cfg[CFG_ADISC_SUPPORT].current;
892*fcf3ce44SJohn Forte 	} else {
893*fcf3ce44SJohn Forte 		adisc_support = 0;
894*fcf3ce44SJohn Forte 	}
895*fcf3ce44SJohn Forte 
896*fcf3ce44SJohn Forte 	/* Check ADISC support level */
897*fcf3ce44SJohn Forte 	switch (adisc_support) {
898*fcf3ce44SJohn Forte 	case 0:	/* No support - Flush all IO to all matching nodes */
899*fcf3ce44SJohn Forte 
900*fcf3ce44SJohn Forte 		for (; ; ) {
901*fcf3ce44SJohn Forte 			/*
902*fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
903*fcf3ce44SJohn Forte 			 * emlxs_mb_unreg_did and the flush routines enter
904*fcf3ce44SJohn Forte 			 * the same locks. Also, when we release the lock the
905*fcf3ce44SJohn Forte 			 * list can change out from under us.
906*fcf3ce44SJohn Forte 			 */
907*fcf3ce44SJohn Forte 
908*fcf3ce44SJohn Forte 			/* Find first node */
909*fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
910*fcf3ce44SJohn Forte 			action = 0;
911*fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
912*fcf3ce44SJohn Forte 				nlp = port->node_table[i];
913*fcf3ce44SJohn Forte 				while (nlp != NULL) {
914*fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
915*fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
916*fcf3ce44SJohn Forte 						continue;
917*fcf3ce44SJohn Forte 					}
918*fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
919*fcf3ce44SJohn Forte 
920*fcf3ce44SJohn Forte 					/*
921*fcf3ce44SJohn Forte 					 * Check for any device that matches
922*fcf3ce44SJohn Forte 					 * our mask
923*fcf3ce44SJohn Forte 					 */
924*fcf3ce44SJohn Forte 					if ((nlp->nlp_DID & mask) == aff_d_id) {
925*fcf3ce44SJohn Forte 						if (linkdown) {
926*fcf3ce44SJohn Forte 							action = 1;
927*fcf3ce44SJohn Forte 							break;
928*fcf3ce44SJohn Forte 						} else {  /* Must be an RCSN */
929*fcf3ce44SJohn Forte 							action = 2;
930*fcf3ce44SJohn Forte 							break;
931*fcf3ce44SJohn Forte 						}
932*fcf3ce44SJohn Forte 					}
933*fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
934*fcf3ce44SJohn Forte 				}
935*fcf3ce44SJohn Forte 
936*fcf3ce44SJohn Forte 				if (action) {
937*fcf3ce44SJohn Forte 					break;
938*fcf3ce44SJohn Forte 				}
939*fcf3ce44SJohn Forte 			}
940*fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
941*fcf3ce44SJohn Forte 
942*fcf3ce44SJohn Forte 
943*fcf3ce44SJohn Forte 			/* Check if nothing was found */
944*fcf3ce44SJohn Forte 			if (action == 0) {
945*fcf3ce44SJohn Forte 				break;
946*fcf3ce44SJohn Forte 			} else if (action == 1) {
947*fcf3ce44SJohn Forte 				(void) emlxs_mb_unreg_did(port, nlp->nlp_DID,
948*fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
949*fcf3ce44SJohn Forte 			} else if (action == 2) {
950*fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
951*fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
952*fcf3ce44SJohn Forte #endif	/* DHCHAP_SUPPORT */
953*fcf3ce44SJohn Forte 
954*fcf3ce44SJohn Forte 				/* Close the node for any further normal IO */
955*fcf3ce44SJohn Forte 				/* A PLOGI with reopen the node */
956*fcf3ce44SJohn Forte 				emlxs_node_close(port, nlp, FC_FCP_RING, 60);
957*fcf3ce44SJohn Forte 				emlxs_node_close(port, nlp, FC_IP_RING, 60);
958*fcf3ce44SJohn Forte 
959*fcf3ce44SJohn Forte 				/* Flush tx queue */
960*fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
961*fcf3ce44SJohn Forte 
962*fcf3ce44SJohn Forte 				/* Flush chip queue */
963*fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
964*fcf3ce44SJohn Forte 			}
965*fcf3ce44SJohn Forte 		}
966*fcf3ce44SJohn Forte 
967*fcf3ce44SJohn Forte 		break;
968*fcf3ce44SJohn Forte 
969*fcf3ce44SJohn Forte 	case 1:	/* Partial support - Flush IO for non-FCP2 matching * nodes */
970*fcf3ce44SJohn Forte 
971*fcf3ce44SJohn Forte 		for (;;) {
972*fcf3ce44SJohn Forte 
973*fcf3ce44SJohn Forte 			/*
974*fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
975*fcf3ce44SJohn Forte 			 * emlxs_mb_unreg_did and the flush routines enter
976*fcf3ce44SJohn Forte 			 * the same locks. Also, when we release the lock the
977*fcf3ce44SJohn Forte 			 * list can change out from under us.
978*fcf3ce44SJohn Forte 			 */
979*fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
980*fcf3ce44SJohn Forte 			action = 0;
981*fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
982*fcf3ce44SJohn Forte 				nlp = port->node_table[i];
983*fcf3ce44SJohn Forte 				while (nlp != NULL) {
984*fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
985*fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
986*fcf3ce44SJohn Forte 						continue;
987*fcf3ce44SJohn Forte 					}
988*fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
989*fcf3ce44SJohn Forte 
990*fcf3ce44SJohn Forte 					/*
991*fcf3ce44SJohn Forte 					 * Check for special FCP2 target
992*fcf3ce44SJohn Forte 					 * device that matches our mask
993*fcf3ce44SJohn Forte 					 */
994*fcf3ce44SJohn Forte 					if ((nlp->nlp_fcp_info &
995*fcf3ce44SJohn Forte 					    NLP_FCP_TGT_DEVICE) &&
996*fcf3ce44SJohn Forte 					    (nlp->nlp_fcp_info &
997*fcf3ce44SJohn Forte 					    NLP_FCP_2_DEVICE) &&
998*fcf3ce44SJohn Forte 					    (nlp->nlp_DID & mask) == aff_d_id) {
999*fcf3ce44SJohn Forte 						action = 3;
1000*fcf3ce44SJohn Forte 						break;
1001*fcf3ce44SJohn Forte 					}
1002*fcf3ce44SJohn Forte 					/*
1003*fcf3ce44SJohn Forte 					 * Check for any other device that
1004*fcf3ce44SJohn Forte 					 * matches our mask
1005*fcf3ce44SJohn Forte 					 */
1006*fcf3ce44SJohn Forte 					else if ((nlp->nlp_DID & mask) ==
1007*fcf3ce44SJohn Forte 					    aff_d_id) {
1008*fcf3ce44SJohn Forte 						if (linkdown) {
1009*fcf3ce44SJohn Forte 							action = 1;
1010*fcf3ce44SJohn Forte 							break;
1011*fcf3ce44SJohn Forte 						} else {   /* Must be an RSCN */
1012*fcf3ce44SJohn Forte 							action = 2;
1013*fcf3ce44SJohn Forte 							break;
1014*fcf3ce44SJohn Forte 						}
1015*fcf3ce44SJohn Forte 					}
1016*fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1017*fcf3ce44SJohn Forte 				}
1018*fcf3ce44SJohn Forte 
1019*fcf3ce44SJohn Forte 				if (action) {
1020*fcf3ce44SJohn Forte 					break;
1021*fcf3ce44SJohn Forte 				}
1022*fcf3ce44SJohn Forte 			}
1023*fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1024*fcf3ce44SJohn Forte 
1025*fcf3ce44SJohn Forte 			/* Check if nothing was found */
1026*fcf3ce44SJohn Forte 			if (action == 0) {
1027*fcf3ce44SJohn Forte 				break;
1028*fcf3ce44SJohn Forte 			} else if (action == 1) {
1029*fcf3ce44SJohn Forte 				(void) emlxs_mb_unreg_did(port, nlp->nlp_DID,
1030*fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1031*fcf3ce44SJohn Forte 			} else if (action == 2) {
1032*fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1033*fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1034*fcf3ce44SJohn Forte #endif	/* DHCHAP_SUPPORT */
1035*fcf3ce44SJohn Forte 
1036*fcf3ce44SJohn Forte 				/* Close the node for any further normal IO */
1037*fcf3ce44SJohn Forte 				/* A PLOGI with reopen the node */
1038*fcf3ce44SJohn Forte 				emlxs_node_close(port, nlp, FC_FCP_RING, 60);
1039*fcf3ce44SJohn Forte 				emlxs_node_close(port, nlp, FC_IP_RING, 60);
1040*fcf3ce44SJohn Forte 
1041*fcf3ce44SJohn Forte 				/* Flush tx queue */
1042*fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1043*fcf3ce44SJohn Forte 
1044*fcf3ce44SJohn Forte 				/* Flush chip queue */
1045*fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1046*fcf3ce44SJohn Forte 			} else if (action == 3) {	/* FCP2 devices */
1047*fcf3ce44SJohn Forte 				unreg_vpi = 0;
1048*fcf3ce44SJohn Forte 
1049*fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1050*fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1051*fcf3ce44SJohn Forte #endif	/* DHCHAP_SUPPORT */
1052*fcf3ce44SJohn Forte 
1053*fcf3ce44SJohn Forte 				/* Close the node for any further normal IO */
1054*fcf3ce44SJohn Forte 				/* An ADISC or a PLOGI with reopen the node */
1055*fcf3ce44SJohn Forte 				emlxs_node_close(port, nlp, FC_FCP_RING,
1056*fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1057*fcf3ce44SJohn Forte 				emlxs_node_close(port, nlp, FC_IP_RING,
1058*fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1059*fcf3ce44SJohn Forte 
1060*fcf3ce44SJohn Forte 				/* Flush tx queues except for FCP ring */
1061*fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
1062*fcf3ce44SJohn Forte 				    &hba->ring[FC_CT_RING], 0, 0);
1063*fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
1064*fcf3ce44SJohn Forte 				    &hba->ring[FC_ELS_RING], 0, 0);
1065*fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
1066*fcf3ce44SJohn Forte 				    &hba->ring[FC_IP_RING], 0, 0);
1067*fcf3ce44SJohn Forte 
1068*fcf3ce44SJohn Forte 				/* Clear IP XRI */
1069*fcf3ce44SJohn Forte 				nlp->nlp_Xri = 0;
1070*fcf3ce44SJohn Forte 
1071*fcf3ce44SJohn Forte 				/* Flush chip queues except for FCP ring */
1072*fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
1073*fcf3ce44SJohn Forte 				    &hba->ring[FC_CT_RING], nlp, 0);
1074*fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
1075*fcf3ce44SJohn Forte 				    &hba->ring[FC_ELS_RING], nlp, 0);
1076*fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
1077*fcf3ce44SJohn Forte 				    &hba->ring[FC_IP_RING], nlp, 0);
1078*fcf3ce44SJohn Forte 			}
1079*fcf3ce44SJohn Forte 		}
1080*fcf3ce44SJohn Forte 		break;
1081*fcf3ce44SJohn Forte 
1082*fcf3ce44SJohn Forte 	case 2:	/* Full support - Hold FCP IO to FCP target matching nodes */
1083*fcf3ce44SJohn Forte 
1084*fcf3ce44SJohn Forte 		if (!linkdown && !vlinkdown) {
1085*fcf3ce44SJohn Forte 			break;
1086*fcf3ce44SJohn Forte 		}
1087*fcf3ce44SJohn Forte 		for (;;) {
1088*fcf3ce44SJohn Forte 			/*
1089*fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
1090*fcf3ce44SJohn Forte 			 * emlxs_mb_unreg_did and the flush routines enter
1091*fcf3ce44SJohn Forte 			 * the same locks. Also, when we release the lock the
1092*fcf3ce44SJohn Forte 			 * list can change out from under us.
1093*fcf3ce44SJohn Forte 			 */
1094*fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1095*fcf3ce44SJohn Forte 			action = 0;
1096*fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1097*fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1098*fcf3ce44SJohn Forte 				while (nlp != NULL) {
1099*fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1100*fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1101*fcf3ce44SJohn Forte 						continue;
1102*fcf3ce44SJohn Forte 					}
1103*fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1104*fcf3ce44SJohn Forte 
1105*fcf3ce44SJohn Forte 					/*
1106*fcf3ce44SJohn Forte 					 * Check for FCP target device that
1107*fcf3ce44SJohn Forte 					 * matches our mask
1108*fcf3ce44SJohn Forte 					 */
1109*fcf3ce44SJohn Forte 					if ((nlp->nlp_fcp_info &
1110*fcf3ce44SJohn Forte 					    NLP_FCP_TGT_DEVICE) &&
1111*fcf3ce44SJohn Forte 					    (nlp->nlp_DID & mask) == aff_d_id) {
1112*fcf3ce44SJohn Forte 						action = 3;
1113*fcf3ce44SJohn Forte 						break;
1114*fcf3ce44SJohn Forte 					}
1115*fcf3ce44SJohn Forte 					/*
1116*fcf3ce44SJohn Forte 					 * Check for any other device that
1117*fcf3ce44SJohn Forte 					 * matches our mask
1118*fcf3ce44SJohn Forte 					 */
1119*fcf3ce44SJohn Forte 					else if ((nlp->nlp_DID & mask) ==
1120*fcf3ce44SJohn Forte 					    aff_d_id) {
1121*fcf3ce44SJohn Forte 						if (linkdown) {
1122*fcf3ce44SJohn Forte 							action = 1;
1123*fcf3ce44SJohn Forte 							break;
1124*fcf3ce44SJohn Forte 						} else { /* Must be an RSCN */
1125*fcf3ce44SJohn Forte 							action = 2;
1126*fcf3ce44SJohn Forte 							break;
1127*fcf3ce44SJohn Forte 						}
1128*fcf3ce44SJohn Forte 					}
1129*fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1130*fcf3ce44SJohn Forte 				}
1131*fcf3ce44SJohn Forte 				if (action) {
1132*fcf3ce44SJohn Forte 					break;
1133*fcf3ce44SJohn Forte 				}
1134*fcf3ce44SJohn Forte 			}
1135*fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1136*fcf3ce44SJohn Forte 
1137*fcf3ce44SJohn Forte 			/* Check if nothing was found */
1138*fcf3ce44SJohn Forte 			if (action == 0) {
1139*fcf3ce44SJohn Forte 				break;
1140*fcf3ce44SJohn Forte 			} else if (action == 1) {
1141*fcf3ce44SJohn Forte 				(void) emlxs_mb_unreg_did(port, nlp->nlp_DID,
1142*fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1143*fcf3ce44SJohn Forte 			} else if (action == 2) {
1144*fcf3ce44SJohn Forte 				/* Close the node for any further normal IO */
1145*fcf3ce44SJohn Forte 				/* A PLOGI with reopen the node */
1146*fcf3ce44SJohn Forte 				emlxs_node_close(port, nlp, FC_FCP_RING, 60);
1147*fcf3ce44SJohn Forte 				emlxs_node_close(port, nlp, FC_IP_RING, 60);
1148*fcf3ce44SJohn Forte 
1149*fcf3ce44SJohn Forte 				/* Flush tx queue */
1150*fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1151*fcf3ce44SJohn Forte 
1152*fcf3ce44SJohn Forte 				/* Flush chip queue */
1153*fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1154*fcf3ce44SJohn Forte 
1155*fcf3ce44SJohn Forte 			} else if (action == 3) {	/* FCP2 devices */
1156*fcf3ce44SJohn Forte 				unreg_vpi = 0;
1157*fcf3ce44SJohn Forte 
1158*fcf3ce44SJohn Forte 				/* Close the node for any further normal IO */
1159*fcf3ce44SJohn Forte 				/* An ADISC or a PLOGI with reopen the node */
1160*fcf3ce44SJohn Forte 				emlxs_node_close(port, nlp, FC_FCP_RING,
1161*fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1162*fcf3ce44SJohn Forte 				emlxs_node_close(port, nlp, FC_IP_RING,
1163*fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1164*fcf3ce44SJohn Forte 
1165*fcf3ce44SJohn Forte 				/* Flush tx queues except for FCP ring */
1166*fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
1167*fcf3ce44SJohn Forte 				    &hba->ring[FC_CT_RING], 0, 0);
1168*fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
1169*fcf3ce44SJohn Forte 				    &hba->ring[FC_ELS_RING], 0, 0);
1170*fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
1171*fcf3ce44SJohn Forte 				    &hba->ring[FC_IP_RING], 0, 0);
1172*fcf3ce44SJohn Forte 
1173*fcf3ce44SJohn Forte 				/* Clear IP XRI */
1174*fcf3ce44SJohn Forte 				nlp->nlp_Xri = 0;
1175*fcf3ce44SJohn Forte 
1176*fcf3ce44SJohn Forte 				/* Flush chip queues except for FCP ring */
1177*fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
1178*fcf3ce44SJohn Forte 				    &hba->ring[FC_CT_RING], nlp, 0);
1179*fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
1180*fcf3ce44SJohn Forte 				    &hba->ring[FC_ELS_RING], nlp, 0);
1181*fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
1182*fcf3ce44SJohn Forte 				    &hba->ring[FC_IP_RING], nlp, 0);
1183*fcf3ce44SJohn Forte 			}
1184*fcf3ce44SJohn Forte 		}
1185*fcf3ce44SJohn Forte 
1186*fcf3ce44SJohn Forte 		break;
1187*fcf3ce44SJohn Forte 
1188*fcf3ce44SJohn Forte 
1189*fcf3ce44SJohn Forte 	}	/* switch() */
1190*fcf3ce44SJohn Forte 
1191*fcf3ce44SJohn Forte done:
1192*fcf3ce44SJohn Forte 
1193*fcf3ce44SJohn Forte 	if (unreg_vpi) {
1194*fcf3ce44SJohn Forte 		(void) emlxs_mb_unreg_vpi(port);
1195*fcf3ce44SJohn Forte 	}
1196*fcf3ce44SJohn Forte 	return (0);
1197*fcf3ce44SJohn Forte 
1198*fcf3ce44SJohn Forte } /* emlxs_port_offline() */
1199*fcf3ce44SJohn Forte 
1200*fcf3ce44SJohn Forte 
1201*fcf3ce44SJohn Forte 
1202*fcf3ce44SJohn Forte extern void
1203*fcf3ce44SJohn Forte emlxs_port_online(emlxs_port_t *vport)
1204*fcf3ce44SJohn Forte {
1205*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = vport->hba;
1206*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1207*fcf3ce44SJohn Forte 	uint32_t state;
1208*fcf3ce44SJohn Forte 	uint32_t update;
1209*fcf3ce44SJohn Forte 	uint32_t npiv_linkup;
1210*fcf3ce44SJohn Forte 	char topology[32];
1211*fcf3ce44SJohn Forte 	char linkspeed[32];
1212*fcf3ce44SJohn Forte 	char mode[32];
1213*fcf3ce44SJohn Forte 
1214*fcf3ce44SJohn Forte 	/*
1215*fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg, "linkup_callback.
1216*fcf3ce44SJohn Forte 	 * vpi=%d fc_flag=%x", vport->vpi, hba->flag);
1217*fcf3ce44SJohn Forte 	 */
1218*fcf3ce44SJohn Forte 
1219*fcf3ce44SJohn Forte 	if ((vport->vpi > 0) &&
1220*fcf3ce44SJohn Forte 	    (!(hba->flag & FC_NPIV_ENABLED) ||
1221*fcf3ce44SJohn Forte 	    !(hba->flag & FC_NPIV_SUPPORTED))) {
1222*fcf3ce44SJohn Forte 		return;
1223*fcf3ce44SJohn Forte 	}
1224*fcf3ce44SJohn Forte 	if (!(vport->flag & EMLXS_PORT_BOUND) ||
1225*fcf3ce44SJohn Forte 	    !(vport->flag & EMLXS_PORT_ENABLE)) {
1226*fcf3ce44SJohn Forte 		return;
1227*fcf3ce44SJohn Forte 	}
1228*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1229*fcf3ce44SJohn Forte 
1230*fcf3ce44SJohn Forte 	/* Check for mode */
1231*fcf3ce44SJohn Forte 	if (port->tgt_mode) {
1232*fcf3ce44SJohn Forte 		(void) strcpy(mode, ", target");
1233*fcf3ce44SJohn Forte 	} else if (port->ini_mode) {
1234*fcf3ce44SJohn Forte 		(void) strcpy(mode, ", initiator");
1235*fcf3ce44SJohn Forte 	} else {
1236*fcf3ce44SJohn Forte 		(void) strcpy(mode, "");
1237*fcf3ce44SJohn Forte 	}
1238*fcf3ce44SJohn Forte 
1239*fcf3ce44SJohn Forte 	/* Check for loop topology */
1240*fcf3ce44SJohn Forte 	if (hba->topology == TOPOLOGY_LOOP) {
1241*fcf3ce44SJohn Forte 		state = FC_STATE_LOOP;
1242*fcf3ce44SJohn Forte 		(void) strcpy(topology, ", loop");
1243*fcf3ce44SJohn Forte 	} else {
1244*fcf3ce44SJohn Forte 		state = FC_STATE_ONLINE;
1245*fcf3ce44SJohn Forte 		(void) strcpy(topology, ", fabric");
1246*fcf3ce44SJohn Forte 	}
1247*fcf3ce44SJohn Forte 
1248*fcf3ce44SJohn Forte 	/* Set the link speed */
1249*fcf3ce44SJohn Forte 	switch (hba->linkspeed) {
1250*fcf3ce44SJohn Forte 	case 0:
1251*fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "Gb");
1252*fcf3ce44SJohn Forte 		state |= FC_STATE_1GBIT_SPEED;
1253*fcf3ce44SJohn Forte 		break;
1254*fcf3ce44SJohn Forte 
1255*fcf3ce44SJohn Forte 	case LA_1GHZ_LINK:
1256*fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "1Gb");
1257*fcf3ce44SJohn Forte 		state |= FC_STATE_1GBIT_SPEED;
1258*fcf3ce44SJohn Forte 		break;
1259*fcf3ce44SJohn Forte 	case LA_2GHZ_LINK:
1260*fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "2Gb");
1261*fcf3ce44SJohn Forte 		state |= FC_STATE_2GBIT_SPEED;
1262*fcf3ce44SJohn Forte 		break;
1263*fcf3ce44SJohn Forte 	case LA_4GHZ_LINK:
1264*fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "4Gb");
1265*fcf3ce44SJohn Forte 		state |= FC_STATE_4GBIT_SPEED;
1266*fcf3ce44SJohn Forte 		break;
1267*fcf3ce44SJohn Forte 	case LA_8GHZ_LINK:
1268*fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "8Gb");
1269*fcf3ce44SJohn Forte 		state |= FC_STATE_8GBIT_SPEED;
1270*fcf3ce44SJohn Forte 		break;
1271*fcf3ce44SJohn Forte 	case LA_10GHZ_LINK:
1272*fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "10Gb");
1273*fcf3ce44SJohn Forte 		state |= FC_STATE_10GBIT_SPEED;
1274*fcf3ce44SJohn Forte 		break;
1275*fcf3ce44SJohn Forte 	default:
1276*fcf3ce44SJohn Forte 		(void) sprintf(linkspeed, "unknown(0x%x)", hba->linkspeed);
1277*fcf3ce44SJohn Forte 		break;
1278*fcf3ce44SJohn Forte 	}
1279*fcf3ce44SJohn Forte 
1280*fcf3ce44SJohn Forte 	npiv_linkup = 0;
1281*fcf3ce44SJohn Forte 	update = 0;
1282*fcf3ce44SJohn Forte 
1283*fcf3ce44SJohn Forte 	if ((hba->state >= FC_LINK_UP) &&
1284*fcf3ce44SJohn Forte 	    !(hba->flag & FC_LOOPBACK_MODE) &&
1285*fcf3ce44SJohn Forte 	    (vport->ulp_statec != state)) {
1286*fcf3ce44SJohn Forte 		update = 1;
1287*fcf3ce44SJohn Forte 		vport->ulp_statec = state;
1288*fcf3ce44SJohn Forte 
1289*fcf3ce44SJohn Forte 		if ((vport->vpi > 0) && !(hba->flag & FC_NPIV_LINKUP)) {
1290*fcf3ce44SJohn Forte 			hba->flag |= FC_NPIV_LINKUP;
1291*fcf3ce44SJohn Forte 			npiv_linkup = 1;
1292*fcf3ce44SJohn Forte 		}
1293*fcf3ce44SJohn Forte 	}
1294*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1295*fcf3ce44SJohn Forte 
1296*fcf3ce44SJohn Forte 	/*
1297*fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg, "linkup_callback:
1298*fcf3ce44SJohn Forte 	 * update=%d vpi=%d flag=%d fc_flag=%x state=%x statec=%x", update,
1299*fcf3ce44SJohn Forte 	 * vport->vpi, npiv_linkup, hba->flag, hba->state,
1300*fcf3ce44SJohn Forte 	 * vport->ulp_statec);
1301*fcf3ce44SJohn Forte 	 */
1302*fcf3ce44SJohn Forte 	if (update) {
1303*fcf3ce44SJohn Forte 		if (vport->flag & EMLXS_PORT_BOUND) {
1304*fcf3ce44SJohn Forte 			if (vport->vpi == 0) {
1305*fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1306*fcf3ce44SJohn Forte 				    "%s%s%s",
1307*fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1308*fcf3ce44SJohn Forte 			} else if (npiv_linkup) {
1309*fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT,
1310*fcf3ce44SJohn Forte 				    &emlxs_npiv_link_up_msg,
1311*fcf3ce44SJohn Forte 				    "%s%s%s",
1312*fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1313*fcf3ce44SJohn Forte 			}
1314*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
1315*fcf3ce44SJohn Forte 			if (vport->tgt_mode) {
1316*fcf3ce44SJohn Forte 				emlxs_fct_link_up(vport);
1317*fcf3ce44SJohn Forte 			} else if (vport->ini_mode) {
1318*fcf3ce44SJohn Forte 				vport->ulp_statec_cb(vport->ulp_handle, state);
1319*fcf3ce44SJohn Forte 			}
1320*fcf3ce44SJohn Forte #else
1321*fcf3ce44SJohn Forte 			vport->ulp_statec_cb(vport->ulp_handle, state);
1322*fcf3ce44SJohn Forte #endif	/* SFCT_SUPPORT */
1323*fcf3ce44SJohn Forte 		} else {
1324*fcf3ce44SJohn Forte 			if (vport->vpi == 0) {
1325*fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1326*fcf3ce44SJohn Forte 				    "%s%s%s *",
1327*fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1328*fcf3ce44SJohn Forte 			} else if (npiv_linkup) {
1329*fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT,
1330*fcf3ce44SJohn Forte 				    &emlxs_npiv_link_up_msg,
1331*fcf3ce44SJohn Forte 				    "%s%s%s *",
1332*fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1333*fcf3ce44SJohn Forte 			}
1334*fcf3ce44SJohn Forte 		}
1335*fcf3ce44SJohn Forte 
1336*fcf3ce44SJohn Forte 		/* Check for waiting threads */
1337*fcf3ce44SJohn Forte 		if (vport->vpi == 0) {
1338*fcf3ce44SJohn Forte 			mutex_enter(&EMLXS_LINKUP_LOCK);
1339*fcf3ce44SJohn Forte 			if (hba->linkup_wait_flag == TRUE) {
1340*fcf3ce44SJohn Forte 				hba->linkup_wait_flag = FALSE;
1341*fcf3ce44SJohn Forte 				cv_broadcast(&EMLXS_LINKUP_CV);
1342*fcf3ce44SJohn Forte 			}
1343*fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_LINKUP_LOCK);
1344*fcf3ce44SJohn Forte 		}
1345*fcf3ce44SJohn Forte 		/* Flush any pending ub buffers */
1346*fcf3ce44SJohn Forte 		emlxs_ub_flush(vport);
1347*fcf3ce44SJohn Forte 	}
1348*fcf3ce44SJohn Forte 	return;
1349*fcf3ce44SJohn Forte 
1350*fcf3ce44SJohn Forte } /* emlxs_port_online() */
1351*fcf3ce44SJohn Forte 
1352*fcf3ce44SJohn Forte 
1353*fcf3ce44SJohn Forte extern void
1354*fcf3ce44SJohn Forte emlxs_linkdown(emlxs_hba_t *hba)
1355*fcf3ce44SJohn Forte {
1356*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1357*fcf3ce44SJohn Forte 	int i;
1358*fcf3ce44SJohn Forte 
1359*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1360*fcf3ce44SJohn Forte 
1361*fcf3ce44SJohn Forte 	HBASTATS.LinkDown++;
1362*fcf3ce44SJohn Forte 	emlxs_ffstate_change_locked(hba, FC_LINK_DOWN);
1363*fcf3ce44SJohn Forte 
1364*fcf3ce44SJohn Forte 	/* Filter hba flags */
1365*fcf3ce44SJohn Forte 	hba->flag &= FC_LINKDOWN_MASK;
1366*fcf3ce44SJohn Forte 	hba->discovery_timer = 0;
1367*fcf3ce44SJohn Forte 	hba->linkup_timer = 0;
1368*fcf3ce44SJohn Forte 
1369*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1370*fcf3ce44SJohn Forte 
1371*fcf3ce44SJohn Forte 	for (i = 0; i < MAX_VPORTS; i++) {
1372*fcf3ce44SJohn Forte 		port = &VPORT(i);
1373*fcf3ce44SJohn Forte 
1374*fcf3ce44SJohn Forte 		if (!(port->flag & EMLXS_PORT_BOUND)) {
1375*fcf3ce44SJohn Forte 			continue;
1376*fcf3ce44SJohn Forte 		}
1377*fcf3ce44SJohn Forte 		(void) emlxs_port_offline(port, 0xffffffff);
1378*fcf3ce44SJohn Forte 
1379*fcf3ce44SJohn Forte 	}
1380*fcf3ce44SJohn Forte 
1381*fcf3ce44SJohn Forte 	return;
1382*fcf3ce44SJohn Forte 
1383*fcf3ce44SJohn Forte } /* emlxs_linkdown() */
1384*fcf3ce44SJohn Forte 
1385*fcf3ce44SJohn Forte 
1386*fcf3ce44SJohn Forte extern void
1387*fcf3ce44SJohn Forte emlxs_linkup(emlxs_hba_t *hba)
1388*fcf3ce44SJohn Forte {
1389*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1390*fcf3ce44SJohn Forte 	emlxs_config_t *cfg = &CFG;
1391*fcf3ce44SJohn Forte 
1392*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1393*fcf3ce44SJohn Forte 
1394*fcf3ce44SJohn Forte 	HBASTATS.LinkUp++;
1395*fcf3ce44SJohn Forte 	emlxs_ffstate_change_locked(hba, FC_LINK_UP);
1396*fcf3ce44SJohn Forte 
1397*fcf3ce44SJohn Forte #ifdef MENLO_TEST
1398*fcf3ce44SJohn Forte 	if ((hba->model_info.device_id == PCI_DEVICE_ID_LP21000_M) &&
1399*fcf3ce44SJohn Forte 	    (cfg[CFG_HORNET_FLOGI].current == 0)) {
1400*fcf3ce44SJohn Forte 		hba->flag |= FC_MENLO_MODE;
1401*fcf3ce44SJohn Forte 	}
1402*fcf3ce44SJohn Forte #endif	/* MENLO_TEST */
1403*fcf3ce44SJohn Forte 
1404*fcf3ce44SJohn Forte #ifdef MENLO_SUPPORT
1405*fcf3ce44SJohn Forte 	if (hba->flag & FC_MENLO_MODE) {
1406*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1407*fcf3ce44SJohn Forte 
1408*fcf3ce44SJohn Forte 		/*
1409*fcf3ce44SJohn Forte 		 * Trigger linkup CV and don't start linkup & discovery
1410*fcf3ce44SJohn Forte 		 * timers
1411*fcf3ce44SJohn Forte 		 */
1412*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_LINKUP_LOCK);
1413*fcf3ce44SJohn Forte 		cv_broadcast(&EMLXS_LINKUP_CV);
1414*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_LINKUP_LOCK);
1415*fcf3ce44SJohn Forte 
1416*fcf3ce44SJohn Forte 		return;
1417*fcf3ce44SJohn Forte 	}
1418*fcf3ce44SJohn Forte #endif	/* MENLO_SUPPORT */
1419*fcf3ce44SJohn Forte 
1420*fcf3ce44SJohn Forte 	/* Set the linkup & discovery timers */
1421*fcf3ce44SJohn Forte 	hba->linkup_timer = hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current;
1422*fcf3ce44SJohn Forte 	hba->discovery_timer = hba->timer_tics +
1423*fcf3ce44SJohn Forte 	    cfg[CFG_LINKUP_TIMEOUT].current + cfg[CFG_DISC_TIMEOUT].current;
1424*fcf3ce44SJohn Forte 
1425*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1426*fcf3ce44SJohn Forte 
1427*fcf3ce44SJohn Forte 	return;
1428*fcf3ce44SJohn Forte 
1429*fcf3ce44SJohn Forte } /* emlxs_linkup() */
1430*fcf3ce44SJohn Forte 
1431*fcf3ce44SJohn Forte 
1432*fcf3ce44SJohn Forte /*
1433*fcf3ce44SJohn Forte  *  emlxs_reset_link
1434*fcf3ce44SJohn Forte  *
1435*fcf3ce44SJohn Forte  *  Description:
1436*fcf3ce44SJohn Forte  *  Called to reset the link with an init_link
1437*fcf3ce44SJohn Forte  *
1438*fcf3ce44SJohn Forte  *    Returns:
1439*fcf3ce44SJohn Forte  *
1440*fcf3ce44SJohn Forte  */
1441*fcf3ce44SJohn Forte extern int
1442*fcf3ce44SJohn Forte emlxs_reset_link(emlxs_hba_t *hba, uint32_t linkup)
1443*fcf3ce44SJohn Forte {
1444*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1445*fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
1446*fcf3ce44SJohn Forte 	MAILBOX *mb;
1447*fcf3ce44SJohn Forte 
1448*fcf3ce44SJohn Forte 	/*
1449*fcf3ce44SJohn Forte 	 * Get a buffer to use for the mailbox command
1450*fcf3ce44SJohn Forte 	 */
1451*fcf3ce44SJohn Forte 	if ((mb = (MAILBOX *)emlxs_mem_get(hba, MEM_MBOX | MEM_PRI)) == NULL) {
1452*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_failed_msg,
1453*fcf3ce44SJohn Forte 		    "Unable to allocate mailbox buffer.");
1454*fcf3ce44SJohn Forte 
1455*fcf3ce44SJohn Forte 		return (1);
1456*fcf3ce44SJohn Forte 	}
1457*fcf3ce44SJohn Forte 	cfg = &CFG;
1458*fcf3ce44SJohn Forte 
1459*fcf3ce44SJohn Forte 	if (linkup) {
1460*fcf3ce44SJohn Forte 		/*
1461*fcf3ce44SJohn Forte 		 * Setup and issue mailbox INITIALIZE LINK command
1462*fcf3ce44SJohn Forte 		 */
1463*fcf3ce44SJohn Forte 
1464*fcf3ce44SJohn Forte 		emlxs_mb_init_link(hba, (MAILBOX *)mb,
1465*fcf3ce44SJohn Forte 		    cfg[CFG_TOPOLOGY].current, cfg[CFG_LINK_SPEED].current);
1466*fcf3ce44SJohn Forte 
1467*fcf3ce44SJohn Forte 		mb->un.varInitLnk.lipsr_AL_PA = 0;
1468*fcf3ce44SJohn Forte 
1469*fcf3ce44SJohn Forte 		/* Clear the loopback mode */
1470*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1471*fcf3ce44SJohn Forte 		hba->flag &= ~FC_LOOPBACK_MODE;
1472*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1473*fcf3ce44SJohn Forte 
1474*fcf3ce44SJohn Forte 		if (emlxs_mb_issue_cmd(hba, (MAILBOX *)mb,
1475*fcf3ce44SJohn Forte 		    MBX_NOWAIT, 0) != MBX_BUSY) {
1476*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
1477*fcf3ce44SJohn Forte 		}
1478*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg, NULL);
1479*fcf3ce44SJohn Forte 
1480*fcf3ce44SJohn Forte 	} else {	/* hold link down */
1481*fcf3ce44SJohn Forte 		emlxs_mb_down_link(hba, (MAILBOX *)mb);
1482*fcf3ce44SJohn Forte 
1483*fcf3ce44SJohn Forte 		if (emlxs_mb_issue_cmd(hba, (MAILBOX *)mb,
1484*fcf3ce44SJohn Forte 		    MBX_NOWAIT, 0) != MBX_BUSY) {
1485*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb);
1486*fcf3ce44SJohn Forte 		}
1487*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg,
1488*fcf3ce44SJohn Forte 		    "Disabling link...");
1489*fcf3ce44SJohn Forte 	}
1490*fcf3ce44SJohn Forte 
1491*fcf3ce44SJohn Forte 	return (0);
1492*fcf3ce44SJohn Forte 
1493*fcf3ce44SJohn Forte } /* emlxs_reset_link() */
1494*fcf3ce44SJohn Forte 
1495*fcf3ce44SJohn Forte 
1496*fcf3ce44SJohn Forte extern int
1497*fcf3ce44SJohn Forte emlxs_online(emlxs_hba_t *hba)
1498*fcf3ce44SJohn Forte {
1499*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1500*fcf3ce44SJohn Forte 	int32_t rval = 0;
1501*fcf3ce44SJohn Forte 	uint32_t i = 0;
1502*fcf3ce44SJohn Forte 
1503*fcf3ce44SJohn Forte 	/* Make sure adapter is offline or exit trying (30 seconds) */
1504*fcf3ce44SJohn Forte 	for (; ; ) {
1505*fcf3ce44SJohn Forte 		/* Check if adapter is already going online */
1506*fcf3ce44SJohn Forte 		if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) {
1507*fcf3ce44SJohn Forte 			return (0);
1508*fcf3ce44SJohn Forte 		}
1509*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1510*fcf3ce44SJohn Forte 
1511*fcf3ce44SJohn Forte 		/* Check again */
1512*fcf3ce44SJohn Forte 		if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) {
1513*fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1514*fcf3ce44SJohn Forte 			return (0);
1515*fcf3ce44SJohn Forte 		}
1516*fcf3ce44SJohn Forte 		/* Check if adapter is offline */
1517*fcf3ce44SJohn Forte 		if (hba->flag & FC_OFFLINE_MODE) {
1518*fcf3ce44SJohn Forte 			/* Mark it going online */
1519*fcf3ce44SJohn Forte 			hba->flag &= ~FC_OFFLINE_MODE;
1520*fcf3ce44SJohn Forte 			hba->flag |= FC_ONLINING_MODE;
1521*fcf3ce44SJohn Forte 
1522*fcf3ce44SJohn Forte 			/* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */
1523*fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1524*fcf3ce44SJohn Forte 			break;
1525*fcf3ce44SJohn Forte 		}
1526*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1527*fcf3ce44SJohn Forte 
1528*fcf3ce44SJohn Forte 		if (i++ > 30) {
1529*fcf3ce44SJohn Forte 			/* Return on timeout */
1530*fcf3ce44SJohn Forte 			return (1);
1531*fcf3ce44SJohn Forte 		}
1532*fcf3ce44SJohn Forte 		DELAYMS(1000);
1533*fcf3ce44SJohn Forte 	}
1534*fcf3ce44SJohn Forte 
1535*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
1536*fcf3ce44SJohn Forte 	    "Going online...");
1537*fcf3ce44SJohn Forte 
1538*fcf3ce44SJohn Forte 	if (hba->bus_type == SBUS_FC) {
1539*fcf3ce44SJohn Forte 		(void) READ_SBUS_CSR_REG(hba, FC_SHS_REG(hba,
1540*fcf3ce44SJohn Forte 		    hba->sbus_csr_addr));
1541*fcf3ce44SJohn Forte 	}
1542*fcf3ce44SJohn Forte 	if (rval = emlxs_ffinit(hba)) {
1543*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg,
1544*fcf3ce44SJohn Forte 		    "status=%x",
1545*fcf3ce44SJohn Forte 		    rval);
1546*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL);
1547*fcf3ce44SJohn Forte 
1548*fcf3ce44SJohn Forte 		/* Set FC_OFFLINE_MODE */
1549*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1550*fcf3ce44SJohn Forte 		emlxs_diag_state = DDI_OFFDI;
1551*fcf3ce44SJohn Forte 		hba->flag |= FC_OFFLINE_MODE;
1552*fcf3ce44SJohn Forte 		hba->flag &= ~FC_ONLINING_MODE;
1553*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1554*fcf3ce44SJohn Forte 
1555*fcf3ce44SJohn Forte 		return (rval);
1556*fcf3ce44SJohn Forte 	}
1557*fcf3ce44SJohn Forte 	/* Start the timer */
1558*fcf3ce44SJohn Forte 	emlxs_timer_start(hba);
1559*fcf3ce44SJohn Forte 
1560*fcf3ce44SJohn Forte 	/* Set FC_ONLINE_MODE */
1561*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1562*fcf3ce44SJohn Forte 	emlxs_diag_state = DDI_ONDI;
1563*fcf3ce44SJohn Forte 	hba->flag |= FC_ONLINE_MODE;
1564*fcf3ce44SJohn Forte 	hba->flag &= ~FC_ONLINING_MODE;
1565*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1566*fcf3ce44SJohn Forte 
1567*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_online_msg, NULL);
1568*fcf3ce44SJohn Forte 
1569*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
1570*fcf3ce44SJohn Forte 	(void) emlxs_fct_port_initialize(port);
1571*fcf3ce44SJohn Forte #endif	/* SFCT_SUPPORT */
1572*fcf3ce44SJohn Forte 
1573*fcf3ce44SJohn Forte 	return (rval);
1574*fcf3ce44SJohn Forte 
1575*fcf3ce44SJohn Forte } /* emlxs_online() */
1576*fcf3ce44SJohn Forte 
1577*fcf3ce44SJohn Forte 
1578*fcf3ce44SJohn Forte extern int
1579*fcf3ce44SJohn Forte emlxs_offline(emlxs_hba_t *hba)
1580*fcf3ce44SJohn Forte {
1581*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1582*fcf3ce44SJohn Forte 	uint32_t i = 0;
1583*fcf3ce44SJohn Forte 	int rval = 1;
1584*fcf3ce44SJohn Forte 
1585*fcf3ce44SJohn Forte 	/* Make sure adapter is online or exit trying (30 seconds) */
1586*fcf3ce44SJohn Forte 	for (; ; ) {
1587*fcf3ce44SJohn Forte 		/* Check if adapter is already going offline */
1588*fcf3ce44SJohn Forte 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1589*fcf3ce44SJohn Forte 			return (0);
1590*fcf3ce44SJohn Forte 		}
1591*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1592*fcf3ce44SJohn Forte 
1593*fcf3ce44SJohn Forte 		/* Check again */
1594*fcf3ce44SJohn Forte 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1595*fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1596*fcf3ce44SJohn Forte 			return (0);
1597*fcf3ce44SJohn Forte 		}
1598*fcf3ce44SJohn Forte 		/* Check if adapter is online */
1599*fcf3ce44SJohn Forte 		if (hba->flag & FC_ONLINE_MODE) {
1600*fcf3ce44SJohn Forte 			/* Mark it going offline */
1601*fcf3ce44SJohn Forte 			hba->flag &= ~FC_ONLINE_MODE;
1602*fcf3ce44SJohn Forte 			hba->flag |= FC_OFFLINING_MODE;
1603*fcf3ce44SJohn Forte 
1604*fcf3ce44SJohn Forte 			/* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */
1605*fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1606*fcf3ce44SJohn Forte 			break;
1607*fcf3ce44SJohn Forte 		}
1608*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1609*fcf3ce44SJohn Forte 
1610*fcf3ce44SJohn Forte 		if (i++ > 30) {
1611*fcf3ce44SJohn Forte 			/* Return on timeout */
1612*fcf3ce44SJohn Forte 			return (1);
1613*fcf3ce44SJohn Forte 		}
1614*fcf3ce44SJohn Forte 		DELAYMS(1000);
1615*fcf3ce44SJohn Forte 	}
1616*fcf3ce44SJohn Forte 
1617*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg, "Going offline...");
1618*fcf3ce44SJohn Forte 
1619*fcf3ce44SJohn Forte 	if (port->ini_mode) {
1620*fcf3ce44SJohn Forte 		/* Flush all IO */
1621*fcf3ce44SJohn Forte 		emlxs_linkdown(hba);
1622*fcf3ce44SJohn Forte 
1623*fcf3ce44SJohn Forte 	}
1624*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
1625*fcf3ce44SJohn Forte 	else {
1626*fcf3ce44SJohn Forte 		(void) emlxs_fct_port_shutdown(port);
1627*fcf3ce44SJohn Forte 	}
1628*fcf3ce44SJohn Forte #endif	/* SFCT_SUPPORT */
1629*fcf3ce44SJohn Forte 
1630*fcf3ce44SJohn Forte 	/* Check if adapter was shutdown */
1631*fcf3ce44SJohn Forte 	if (hba->flag & FC_HARDWARE_ERROR) {
1632*fcf3ce44SJohn Forte 		/* Force mailbox cleanup */
1633*fcf3ce44SJohn Forte 		/* This will wake any sleeping or polling threads */
1634*fcf3ce44SJohn Forte 		emlxs_mb_fini(hba, NULL, MBX_HARDWARE_ERROR);
1635*fcf3ce44SJohn Forte 	}
1636*fcf3ce44SJohn Forte 	/* Pause here for the IO to settle */
1637*fcf3ce44SJohn Forte 	delay(drv_usectohz(1000000));	/* 1 sec */
1638*fcf3ce44SJohn Forte 
1639*fcf3ce44SJohn Forte 	/* Unregister all nodes */
1640*fcf3ce44SJohn Forte 	emlxs_ffcleanup(hba);
1641*fcf3ce44SJohn Forte 
1642*fcf3ce44SJohn Forte 
1643*fcf3ce44SJohn Forte 	if (hba->bus_type == SBUS_FC) {
1644*fcf3ce44SJohn Forte 		WRITE_SBUS_CSR_REG(hba,
1645*fcf3ce44SJohn Forte 		    FC_SHS_REG(hba, hba->sbus_csr_addr), 0x9A);
1646*fcf3ce44SJohn Forte 	}
1647*fcf3ce44SJohn Forte 	/* Stop the timer */
1648*fcf3ce44SJohn Forte 	emlxs_timer_stop(hba);
1649*fcf3ce44SJohn Forte 
1650*fcf3ce44SJohn Forte 	/* For safety flush every iotag list */
1651*fcf3ce44SJohn Forte 	if (emlxs_iotag_flush(hba)) {
1652*fcf3ce44SJohn Forte 		/* Pause here for the IO to flush */
1653*fcf3ce44SJohn Forte 		DELAYMS(1000);
1654*fcf3ce44SJohn Forte 	}
1655*fcf3ce44SJohn Forte 	/* Interlock the adapter to take it down */
1656*fcf3ce44SJohn Forte 	(void) emlxs_interlock(hba);
1657*fcf3ce44SJohn Forte 
1658*fcf3ce44SJohn Forte 	/* Free all the shared memory */
1659*fcf3ce44SJohn Forte 	(void) emlxs_mem_free_buffer(hba);
1660*fcf3ce44SJohn Forte 
1661*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1662*fcf3ce44SJohn Forte 	hba->flag |= FC_OFFLINE_MODE;
1663*fcf3ce44SJohn Forte 	hba->flag &= ~FC_OFFLINING_MODE;
1664*fcf3ce44SJohn Forte 	emlxs_diag_state = DDI_OFFDI;
1665*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1666*fcf3ce44SJohn Forte 
1667*fcf3ce44SJohn Forte 	rval = 0;
1668*fcf3ce44SJohn Forte 
1669*fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL);
1670*fcf3ce44SJohn Forte 
1671*fcf3ce44SJohn Forte done:
1672*fcf3ce44SJohn Forte 
1673*fcf3ce44SJohn Forte 	return (rval);
1674*fcf3ce44SJohn Forte 
1675*fcf3ce44SJohn Forte } /* emlxs_offline() */
1676*fcf3ce44SJohn Forte 
1677*fcf3ce44SJohn Forte 
1678*fcf3ce44SJohn Forte 
1679*fcf3ce44SJohn Forte extern int
1680*fcf3ce44SJohn Forte emlxs_power_down(emlxs_hba_t *hba)
1681*fcf3ce44SJohn Forte {
1682*fcf3ce44SJohn Forte 	int32_t rval = 0;
1683*fcf3ce44SJohn Forte 	uint32_t *ptr;
1684*fcf3ce44SJohn Forte 	uint32_t i;
1685*fcf3ce44SJohn Forte 
1686*fcf3ce44SJohn Forte 	if ((rval = emlxs_offline(hba))) {
1687*fcf3ce44SJohn Forte 		return (rval);
1688*fcf3ce44SJohn Forte 	}
1689*fcf3ce44SJohn Forte 	/* Save pci config space */
1690*fcf3ce44SJohn Forte 	ptr = (uint32_t *)hba->pm_config;
1691*fcf3ce44SJohn Forte 	for (i = 0; i < PCI_CONFIG_SIZE; i += 4, ptr++) {
1692*fcf3ce44SJohn Forte 		*ptr = ddi_get32(hba->pci_acc_handle,
1693*fcf3ce44SJohn Forte 		    (uint32_t *)(hba->pci_addr + i));
1694*fcf3ce44SJohn Forte 	}
1695*fcf3ce44SJohn Forte 
1696*fcf3ce44SJohn Forte 	/* Put chip in D3 state */
1697*fcf3ce44SJohn Forte 	(void) ddi_put8(hba->pci_acc_handle,
1698*fcf3ce44SJohn Forte 	    (uint8_t *)(hba->pci_addr + PCI_PM_CONTROL_REGISTER),
1699*fcf3ce44SJohn Forte 	    (uint8_t)PCI_PM_D3_STATE);
1700*fcf3ce44SJohn Forte 
1701*fcf3ce44SJohn Forte 	return (0);
1702*fcf3ce44SJohn Forte 
1703*fcf3ce44SJohn Forte } /* End emlxs_power_down */
1704*fcf3ce44SJohn Forte 
1705*fcf3ce44SJohn Forte 
1706*fcf3ce44SJohn Forte extern int
1707*fcf3ce44SJohn Forte emlxs_power_up(emlxs_hba_t *hba)
1708*fcf3ce44SJohn Forte {
1709*fcf3ce44SJohn Forte 	int32_t rval = 0;
1710*fcf3ce44SJohn Forte 	uint32_t *ptr;
1711*fcf3ce44SJohn Forte 	uint32_t i;
1712*fcf3ce44SJohn Forte 
1713*fcf3ce44SJohn Forte 
1714*fcf3ce44SJohn Forte 	/* Take chip out of D3 state */
1715*fcf3ce44SJohn Forte 	(void) ddi_put8(hba->pci_acc_handle,
1716*fcf3ce44SJohn Forte 	    (uint8_t *)(hba->pci_addr + PCI_PM_CONTROL_REGISTER),
1717*fcf3ce44SJohn Forte 	    (uint8_t)PCI_PM_D0_STATE);
1718*fcf3ce44SJohn Forte 
1719*fcf3ce44SJohn Forte 	/* Must have at least 10 ms delay here */
1720*fcf3ce44SJohn Forte 	DELAYMS(100);
1721*fcf3ce44SJohn Forte 
1722*fcf3ce44SJohn Forte 	/* Restore pci config space */
1723*fcf3ce44SJohn Forte 	ptr = (uint32_t *)hba->pm_config;
1724*fcf3ce44SJohn Forte 	for (i = 0; i < PCI_CONFIG_SIZE; i += 4, ptr++) {
1725*fcf3ce44SJohn Forte 		(void) ddi_put32(hba->pci_acc_handle,
1726*fcf3ce44SJohn Forte 		    (uint32_t *)(hba->pci_addr + i), *ptr);
1727*fcf3ce44SJohn Forte 	}
1728*fcf3ce44SJohn Forte 
1729*fcf3ce44SJohn Forte 	/* Bring adapter online */
1730*fcf3ce44SJohn Forte 	if ((rval = emlxs_online(hba))) {
1731*fcf3ce44SJohn Forte 		(void) ddi_put8(hba->pci_acc_handle,
1732*fcf3ce44SJohn Forte 		    (uint8_t *)(hba->pci_addr + PCI_PM_CONTROL_REGISTER),
1733*fcf3ce44SJohn Forte 		    (uint8_t)PCI_PM_D3_STATE);
1734*fcf3ce44SJohn Forte 
1735*fcf3ce44SJohn Forte 		return (rval);
1736*fcf3ce44SJohn Forte 	}
1737*fcf3ce44SJohn Forte 	return (rval);
1738*fcf3ce44SJohn Forte 
1739*fcf3ce44SJohn Forte } /* End emlxs_power_up */
1740*fcf3ce44SJohn Forte 
1741*fcf3ce44SJohn Forte 
1742*fcf3ce44SJohn Forte /*
1743*fcf3ce44SJohn Forte  * NAME:     emlxs_ffcleanup
1744*fcf3ce44SJohn Forte  *
1745*fcf3ce44SJohn Forte  * FUNCTION: Cleanup all the Firefly resources used by configuring the adapter
1746*fcf3ce44SJohn Forte  *
1747*fcf3ce44SJohn Forte  * EXECUTION ENVIRONMENT: process only
1748*fcf3ce44SJohn Forte  *
1749*fcf3ce44SJohn Forte  * CALLED FROM: CFG_TERM
1750*fcf3ce44SJohn Forte  *
1751*fcf3ce44SJohn Forte  * INPUT: hba       - pointer to the dev_ctl area.
1752*fcf3ce44SJohn Forte  *
1753*fcf3ce44SJohn Forte  * RETURNS: none
1754*fcf3ce44SJohn Forte  */
1755*fcf3ce44SJohn Forte extern void
1756*fcf3ce44SJohn Forte emlxs_ffcleanup(emlxs_hba_t *hba)
1757*fcf3ce44SJohn Forte {
1758*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1759*fcf3ce44SJohn Forte 	uint32_t j;
1760*fcf3ce44SJohn Forte 
1761*fcf3ce44SJohn Forte 	/* Disable all but the mailbox interrupt */
1762*fcf3ce44SJohn Forte 	hba->hc_copy = HC_MBINT_ENA;
1763*fcf3ce44SJohn Forte 	WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr), hba->hc_copy);
1764*fcf3ce44SJohn Forte 
1765*fcf3ce44SJohn Forte 	/* Make sure all port nodes are destroyed */
1766*fcf3ce44SJohn Forte 	for (j = 0; j < MAX_VPORTS; j++) {
1767*fcf3ce44SJohn Forte 		port = &VPORT(j);
1768*fcf3ce44SJohn Forte 
1769*fcf3ce44SJohn Forte 		if (port->node_count) {
1770*fcf3ce44SJohn Forte 			(void) emlxs_mb_unreg_rpi(port, 0xffff, 0, 0, 0);
1771*fcf3ce44SJohn Forte 		}
1772*fcf3ce44SJohn Forte 	}
1773*fcf3ce44SJohn Forte 
1774*fcf3ce44SJohn Forte 	/* Clear all interrupt enable conditions */
1775*fcf3ce44SJohn Forte 	hba->hc_copy = 0;
1776*fcf3ce44SJohn Forte 	WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr), hba->hc_copy);
1777*fcf3ce44SJohn Forte 
1778*fcf3ce44SJohn Forte 	return;
1779*fcf3ce44SJohn Forte 
1780*fcf3ce44SJohn Forte } /* emlxs_ffcleanup() */
1781*fcf3ce44SJohn Forte 
1782*fcf3ce44SJohn Forte 
1783*fcf3ce44SJohn Forte extern uint16_t
1784*fcf3ce44SJohn Forte emlxs_register_pkt(RING *rp, emlxs_buf_t *sbp)
1785*fcf3ce44SJohn Forte {
1786*fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
1787*fcf3ce44SJohn Forte 	emlxs_port_t *port;
1788*fcf3ce44SJohn Forte 	uint16_t iotag;
1789*fcf3ce44SJohn Forte 	uint32_t i;
1790*fcf3ce44SJohn Forte 
1791*fcf3ce44SJohn Forte 	hba = rp->hba;
1792*fcf3ce44SJohn Forte 
1793*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_FCTAB_LOCK(rp->ringno));
1794*fcf3ce44SJohn Forte 
1795*fcf3ce44SJohn Forte 	if (sbp->iotag != 0) {
1796*fcf3ce44SJohn Forte 		port = &PPORT;
1797*fcf3ce44SJohn Forte 
1798*fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
1799*fcf3ce44SJohn Forte 		    "Pkt already registered! ringo=%d iotag=%d sbp=%p",
1800*fcf3ce44SJohn Forte 		    sbp->ring, sbp->iotag, sbp);
1801*fcf3ce44SJohn Forte 	}
1802*fcf3ce44SJohn Forte 	iotag = 0;
1803*fcf3ce44SJohn Forte 	for (i = 0; i < rp->max_iotag; i++) {
1804*fcf3ce44SJohn Forte 		if (!rp->fc_iotag || rp->fc_iotag >= rp->max_iotag) {
1805*fcf3ce44SJohn Forte 			rp->fc_iotag = 1;
1806*fcf3ce44SJohn Forte 		}
1807*fcf3ce44SJohn Forte 		iotag = rp->fc_iotag++;
1808*fcf3ce44SJohn Forte 
1809*fcf3ce44SJohn Forte 		if (rp->fc_table[iotag] == 0 ||
1810*fcf3ce44SJohn Forte 		    rp->fc_table[iotag] == STALE_PACKET) {
1811*fcf3ce44SJohn Forte 			hba->io_count[rp->ringno]++;
1812*fcf3ce44SJohn Forte 			rp->fc_table[iotag] = sbp;
1813*fcf3ce44SJohn Forte 
1814*fcf3ce44SJohn Forte 			sbp->iotag = iotag;
1815*fcf3ce44SJohn Forte 			sbp->ring = rp;
1816*fcf3ce44SJohn Forte 
1817*fcf3ce44SJohn Forte 			break;
1818*fcf3ce44SJohn Forte 		}
1819*fcf3ce44SJohn Forte 		iotag = 0;
1820*fcf3ce44SJohn Forte 	}
1821*fcf3ce44SJohn Forte 
1822*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_FCTAB_LOCK(rp->ringno));
1823*fcf3ce44SJohn Forte 
1824*fcf3ce44SJohn Forte 	/*
1825*fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
1826*fcf3ce44SJohn Forte 	 * "emlxs_register_pkt: ringo=%d iotag=%d sbp=%p", rp->ringno, iotag,
1827*fcf3ce44SJohn Forte 	 * sbp);
1828*fcf3ce44SJohn Forte 	 */
1829*fcf3ce44SJohn Forte 
1830*fcf3ce44SJohn Forte 	return (iotag);
1831*fcf3ce44SJohn Forte 
1832*fcf3ce44SJohn Forte } /* emlxs_register_pkt() */
1833*fcf3ce44SJohn Forte 
1834*fcf3ce44SJohn Forte 
1835*fcf3ce44SJohn Forte 
1836*fcf3ce44SJohn Forte extern emlxs_buf_t *
1837*fcf3ce44SJohn Forte emlxs_unregister_pkt(RING *rp, uint16_t iotag, uint32_t forced)
1838*fcf3ce44SJohn Forte {
1839*fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
1840*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
1841*fcf3ce44SJohn Forte 	uint32_t ringno;
1842*fcf3ce44SJohn Forte 
1843*fcf3ce44SJohn Forte 	/* Check the iotag range */
1844*fcf3ce44SJohn Forte 	if ((iotag == 0) || (iotag >= rp->max_iotag)) {
1845*fcf3ce44SJohn Forte 		return (NULL);
1846*fcf3ce44SJohn Forte 	}
1847*fcf3ce44SJohn Forte 	sbp = NULL;
1848*fcf3ce44SJohn Forte 	hba = rp->hba;
1849*fcf3ce44SJohn Forte 	ringno = rp->ringno;
1850*fcf3ce44SJohn Forte 
1851*fcf3ce44SJohn Forte 	/* Remove the sbp from the table */
1852*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_FCTAB_LOCK(ringno));
1853*fcf3ce44SJohn Forte 	sbp = rp->fc_table[iotag];
1854*fcf3ce44SJohn Forte 
1855*fcf3ce44SJohn Forte 	if (!sbp || (sbp == STALE_PACKET)) {
1856*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_FCTAB_LOCK(ringno));
1857*fcf3ce44SJohn Forte 		return (sbp);
1858*fcf3ce44SJohn Forte 	}
1859*fcf3ce44SJohn Forte 	rp->fc_table[iotag] = ((forced) ? STALE_PACKET : NULL);
1860*fcf3ce44SJohn Forte 	hba->io_count[ringno]--;
1861*fcf3ce44SJohn Forte 	sbp->iotag = 0;
1862*fcf3ce44SJohn Forte 
1863*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_FCTAB_LOCK(ringno));
1864*fcf3ce44SJohn Forte 
1865*fcf3ce44SJohn Forte 
1866*fcf3ce44SJohn Forte 	/* Clean up the sbp */
1867*fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
1868*fcf3ce44SJohn Forte 
1869*fcf3ce44SJohn Forte 	if (sbp->pkt_flags & PACKET_IN_TXQ) {
1870*fcf3ce44SJohn Forte 		sbp->pkt_flags &= ~PACKET_IN_TXQ;
1871*fcf3ce44SJohn Forte 		hba->ring_tx_count[ringno]--;
1872*fcf3ce44SJohn Forte 	}
1873*fcf3ce44SJohn Forte 	if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
1874*fcf3ce44SJohn Forte 		sbp->pkt_flags &= ~PACKET_IN_CHIPQ;
1875*fcf3ce44SJohn Forte 	}
1876*fcf3ce44SJohn Forte 	if (sbp->bmp) {
1877*fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_BPL, (uint8_t *)sbp->bmp);
1878*fcf3ce44SJohn Forte 		sbp->bmp = 0;
1879*fcf3ce44SJohn Forte 	}
1880*fcf3ce44SJohn Forte 	mutex_exit(&sbp->mtx);
1881*fcf3ce44SJohn Forte 
1882*fcf3ce44SJohn Forte 
1883*fcf3ce44SJohn Forte 	/*
1884*fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
1885*fcf3ce44SJohn Forte 	 * "emlxs_unregister_pkt: ringo=%d iotag=%d sbp=%p", rp->ringno,
1886*fcf3ce44SJohn Forte 	 * iotag, sbp);
1887*fcf3ce44SJohn Forte 	 */
1888*fcf3ce44SJohn Forte 
1889*fcf3ce44SJohn Forte 	return (sbp);
1890*fcf3ce44SJohn Forte 
1891*fcf3ce44SJohn Forte } /* emlxs_unregister_pkt() */
1892*fcf3ce44SJohn Forte 
1893*fcf3ce44SJohn Forte 
1894*fcf3ce44SJohn Forte 
1895*fcf3ce44SJohn Forte /* Flush all IO's to all nodes for a given ring */
1896*fcf3ce44SJohn Forte extern uint32_t
1897*fcf3ce44SJohn Forte emlxs_tx_ring_flush(emlxs_hba_t *hba, RING *rp, emlxs_buf_t *fpkt)
1898*fcf3ce44SJohn Forte {
1899*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1900*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
1901*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
1902*fcf3ce44SJohn Forte 	IOCBQ *next;
1903*fcf3ce44SJohn Forte 	IOCB *iocb;
1904*fcf3ce44SJohn Forte 	uint32_t ringno;
1905*fcf3ce44SJohn Forte 	Q abort;
1906*fcf3ce44SJohn Forte 	NODELIST *ndlp;
1907*fcf3ce44SJohn Forte 	IOCB *icmd;
1908*fcf3ce44SJohn Forte 	MATCHMAP *mp;
1909*fcf3ce44SJohn Forte 	uint32_t i;
1910*fcf3ce44SJohn Forte 
1911*fcf3ce44SJohn Forte 	ringno = rp->ringno;
1912*fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
1913*fcf3ce44SJohn Forte 
1914*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_RINGTX_LOCK);
1915*fcf3ce44SJohn Forte 
1916*fcf3ce44SJohn Forte 	/* While a node needs servicing */
1917*fcf3ce44SJohn Forte 	while (rp->nodeq.q_first) {
1918*fcf3ce44SJohn Forte 		ndlp = (NODELIST *)rp->nodeq.q_first;
1919*fcf3ce44SJohn Forte 
1920*fcf3ce44SJohn Forte 		/* Check if priority queue is not empty */
1921*fcf3ce44SJohn Forte 		if (ndlp->nlp_ptx[ringno].q_first) {
1922*fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
1923*fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
1924*fcf3ce44SJohn Forte 				abort.q_first = ndlp->nlp_ptx[ringno].q_first;
1925*fcf3ce44SJohn Forte 				abort.q_last = ndlp->nlp_ptx[ringno].q_last;
1926*fcf3ce44SJohn Forte 			} else {
1927*fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
1928*fcf3ce44SJohn Forte 				    (IOCBQ *)ndlp->nlp_ptx[ringno].q_first;
1929*fcf3ce44SJohn Forte 			}
1930*fcf3ce44SJohn Forte 
1931*fcf3ce44SJohn Forte 			abort.q_cnt += ndlp->nlp_ptx[ringno].q_cnt;
1932*fcf3ce44SJohn Forte 		}
1933*fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
1934*fcf3ce44SJohn Forte 		if (ndlp->nlp_tx[ringno].q_first) {
1935*fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
1936*fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
1937*fcf3ce44SJohn Forte 				abort.q_first = ndlp->nlp_tx[ringno].q_first;
1938*fcf3ce44SJohn Forte 				abort.q_last = ndlp->nlp_tx[ringno].q_last;
1939*fcf3ce44SJohn Forte 			} else {
1940*fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
1941*fcf3ce44SJohn Forte 				    (IOCBQ *)ndlp->nlp_tx[ringno].q_first;
1942*fcf3ce44SJohn Forte 			}
1943*fcf3ce44SJohn Forte 
1944*fcf3ce44SJohn Forte 			abort.q_cnt += ndlp->nlp_tx[ringno].q_cnt;
1945*fcf3ce44SJohn Forte 
1946*fcf3ce44SJohn Forte 		}
1947*fcf3ce44SJohn Forte 		/* Clear the queue pointers */
1948*fcf3ce44SJohn Forte 		ndlp->nlp_ptx[ringno].q_first = NULL;
1949*fcf3ce44SJohn Forte 		ndlp->nlp_ptx[ringno].q_last = NULL;
1950*fcf3ce44SJohn Forte 		ndlp->nlp_ptx[ringno].q_cnt = 0;
1951*fcf3ce44SJohn Forte 
1952*fcf3ce44SJohn Forte 		ndlp->nlp_tx[ringno].q_first = NULL;
1953*fcf3ce44SJohn Forte 		ndlp->nlp_tx[ringno].q_last = NULL;
1954*fcf3ce44SJohn Forte 		ndlp->nlp_tx[ringno].q_cnt = 0;
1955*fcf3ce44SJohn Forte 
1956*fcf3ce44SJohn Forte 		/* Remove node from service queue */
1957*fcf3ce44SJohn Forte 
1958*fcf3ce44SJohn Forte 		/* If this is the last node on list */
1959*fcf3ce44SJohn Forte 		if (rp->nodeq.q_last == (void *)ndlp) {
1960*fcf3ce44SJohn Forte 			rp->nodeq.q_last = NULL;
1961*fcf3ce44SJohn Forte 			rp->nodeq.q_first = NULL;
1962*fcf3ce44SJohn Forte 			rp->nodeq.q_cnt = 0;
1963*fcf3ce44SJohn Forte 		} else {
1964*fcf3ce44SJohn Forte 			/* Remove node from head */
1965*fcf3ce44SJohn Forte 			rp->nodeq.q_first = ndlp->nlp_next[ringno];
1966*fcf3ce44SJohn Forte 			((NODELIST *)rp->nodeq.q_last)->nlp_next[ringno] =
1967*fcf3ce44SJohn Forte 			    rp->nodeq.q_first;
1968*fcf3ce44SJohn Forte 			rp->nodeq.q_cnt--;
1969*fcf3ce44SJohn Forte 		}
1970*fcf3ce44SJohn Forte 
1971*fcf3ce44SJohn Forte 		/* Clear node */
1972*fcf3ce44SJohn Forte 		ndlp->nlp_next[ringno] = NULL;
1973*fcf3ce44SJohn Forte 	}
1974*fcf3ce44SJohn Forte 
1975*fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
1976*fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
1977*fcf3ce44SJohn Forte 	while (iocbq) {
1978*fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
1979*fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
1980*fcf3ce44SJohn Forte 		sbp = emlxs_unregister_pkt(iocbq->ring, iocb->ulpIoTag, 0);
1981*fcf3ce44SJohn Forte 
1982*fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
1983*fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
1984*fcf3ce44SJohn Forte 
1985*fcf3ce44SJohn Forte 			if (sbp->pkt_flags & PACKET_IN_TXQ) {
1986*fcf3ce44SJohn Forte 				sbp->pkt_flags &= ~PACKET_IN_TXQ;
1987*fcf3ce44SJohn Forte 				hba->ring_tx_count[ringno]--;
1988*fcf3ce44SJohn Forte 			}
1989*fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
1990*fcf3ce44SJohn Forte 
1991*fcf3ce44SJohn Forte 			/*
1992*fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
1993*fcf3ce44SJohn Forte 			 * alone
1994*fcf3ce44SJohn Forte 			 */
1995*fcf3ce44SJohn Forte 			/*
1996*fcf3ce44SJohn Forte 			 * This ensures that this pkt is only accounted for
1997*fcf3ce44SJohn Forte 			 * on one fpkt->flush_count
1998*fcf3ce44SJohn Forte 			 */
1999*fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2000*fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2001*fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2002*fcf3ce44SJohn Forte 				fpkt->flush_count++;
2003*fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2004*fcf3ce44SJohn Forte 			}
2005*fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2006*fcf3ce44SJohn Forte 		}
2007*fcf3ce44SJohn Forte 		iocbq = (IOCBQ *)iocbq->next;
2008*fcf3ce44SJohn Forte 
2009*fcf3ce44SJohn Forte 	}	/* end of while */
2010*fcf3ce44SJohn Forte 
2011*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_RINGTX_LOCK);
2012*fcf3ce44SJohn Forte 
2013*fcf3ce44SJohn Forte 	/* Now abort the iocb's */
2014*fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2015*fcf3ce44SJohn Forte 	while (iocbq) {
2016*fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2017*fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2018*fcf3ce44SJohn Forte 
2019*fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2020*fcf3ce44SJohn Forte 		iocbq->next = NULL;
2021*fcf3ce44SJohn Forte 
2022*fcf3ce44SJohn Forte 		/* Get the pkt */
2023*fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2024*fcf3ce44SJohn Forte 
2025*fcf3ce44SJohn Forte 		if (sbp) {
2026*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2027*fcf3ce44SJohn Forte 			    "tx: sbp=%p node=%p",
2028*fcf3ce44SJohn Forte 			    sbp, sbp->node);
2029*fcf3ce44SJohn Forte 
2030*fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2031*fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2032*fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2033*fcf3ce44SJohn Forte 			} else {
2034*fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2035*fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2036*fcf3ce44SJohn Forte 			}
2037*fcf3ce44SJohn Forte 
2038*fcf3ce44SJohn Forte 		}
2039*fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2040*fcf3ce44SJohn Forte 		else {
2041*fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
2042*fcf3ce44SJohn Forte 			if (icmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
2043*fcf3ce44SJohn Forte 			    icmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
2044*fcf3ce44SJohn Forte 			    icmd->ulpCommand == CMD_QUE_RING_LIST64_CN) {
2045*fcf3ce44SJohn Forte 				if ((hba->flag &
2046*fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2047*fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
2048*fcf3ce44SJohn Forte 					if (icmd->ulpCommand !=
2049*fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2050*fcf3ce44SJohn Forte 						uint8_t *tmp;
2051*fcf3ce44SJohn Forte 
2052*fcf3ce44SJohn Forte 						for (i = 0;
2053*fcf3ce44SJohn Forte 						    i < icmd->ulpBdeCount;
2054*fcf3ce44SJohn Forte 						    i++) {
2055*fcf3ce44SJohn Forte 
2056*fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2057*fcf3ce44SJohn Forte 							    hba, rp, icmd);
2058*fcf3ce44SJohn Forte 
2059*fcf3ce44SJohn Forte 							tmp = (uint8_t *)mp;
2060*fcf3ce44SJohn Forte 							if (mp) {
2061*fcf3ce44SJohn Forte 	(void) emlxs_mem_put(hba, MEM_BUF, tmp);
2062*fcf3ce44SJohn Forte 							}
2063*fcf3ce44SJohn Forte 						}
2064*fcf3ce44SJohn Forte 					}
2065*fcf3ce44SJohn Forte 					(void) emlxs_mem_put(hba, MEM_IOCB,
2066*fcf3ce44SJohn Forte 					    (uint8_t *)iocbq);
2067*fcf3ce44SJohn Forte 				} else {
2068*fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
2069*fcf3ce44SJohn Forte 					emlxs_issue_iocb_cmd(hba, rp, iocbq);
2070*fcf3ce44SJohn Forte 				}
2071*fcf3ce44SJohn Forte 			}
2072*fcf3ce44SJohn Forte 		}
2073*fcf3ce44SJohn Forte 
2074*fcf3ce44SJohn Forte 		iocbq = next;
2075*fcf3ce44SJohn Forte 
2076*fcf3ce44SJohn Forte 	}	/* end of while */
2077*fcf3ce44SJohn Forte 
2078*fcf3ce44SJohn Forte 	return (abort.q_cnt);
2079*fcf3ce44SJohn Forte 
2080*fcf3ce44SJohn Forte } /* emlxs_tx_ring_flush() */
2081*fcf3ce44SJohn Forte 
2082*fcf3ce44SJohn Forte 
2083*fcf3ce44SJohn Forte /* Flush all IO's on all or a given ring for a given node */
2084*fcf3ce44SJohn Forte extern uint32_t
2085*fcf3ce44SJohn Forte emlxs_tx_node_flush(emlxs_port_t *port, NODELIST *ndlp, RING *ring,
2086*fcf3ce44SJohn Forte     uint32_t shutdown, emlxs_buf_t *fpkt)
2087*fcf3ce44SJohn Forte {
2088*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2089*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2090*fcf3ce44SJohn Forte 	uint32_t ringno;
2091*fcf3ce44SJohn Forte 	RING *rp;
2092*fcf3ce44SJohn Forte 	IOCB *icmd;
2093*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2094*fcf3ce44SJohn Forte 	NODELIST *prev;
2095*fcf3ce44SJohn Forte 	IOCBQ *next;
2096*fcf3ce44SJohn Forte 	IOCB *iocb;
2097*fcf3ce44SJohn Forte 	Q abort;
2098*fcf3ce44SJohn Forte 	uint32_t i;
2099*fcf3ce44SJohn Forte 	MATCHMAP *mp;
2100*fcf3ce44SJohn Forte 
2101*fcf3ce44SJohn Forte 
2102*fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
2103*fcf3ce44SJohn Forte 
2104*fcf3ce44SJohn Forte 	/* Flush all I/O's on tx queue to this target */
2105*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_RINGTX_LOCK);
2106*fcf3ce44SJohn Forte 
2107*fcf3ce44SJohn Forte 	if (!ndlp->nlp_base && shutdown) {
2108*fcf3ce44SJohn Forte 		ndlp->nlp_active = 0;
2109*fcf3ce44SJohn Forte 	}
2110*fcf3ce44SJohn Forte 	for (ringno = 0; ringno < hba->ring_count; ringno++) {
2111*fcf3ce44SJohn Forte 		rp = &hba->ring[ringno];
2112*fcf3ce44SJohn Forte 
2113*fcf3ce44SJohn Forte 		if (ring && rp != ring) {
2114*fcf3ce44SJohn Forte 			continue;
2115*fcf3ce44SJohn Forte 		}
2116*fcf3ce44SJohn Forte 		if (!ndlp->nlp_base || shutdown) {
2117*fcf3ce44SJohn Forte 			/* Check if priority queue is not empty */
2118*fcf3ce44SJohn Forte 			if (ndlp->nlp_ptx[ringno].q_first) {
2119*fcf3ce44SJohn Forte 				/* Transfer all iocb's to local queue */
2120*fcf3ce44SJohn Forte 				if (abort.q_first == 0) {
2121*fcf3ce44SJohn Forte 					abort.q_first =
2122*fcf3ce44SJohn Forte 					    ndlp->nlp_ptx[ringno].q_first;
2123*fcf3ce44SJohn Forte 					abort.q_last =
2124*fcf3ce44SJohn Forte 					    ndlp->nlp_ptx[ringno].q_last;
2125*fcf3ce44SJohn Forte 				} else {
2126*fcf3ce44SJohn Forte 					emlxs_queue_t *q;
2127*fcf3ce44SJohn Forte 
2128*fcf3ce44SJohn Forte 					q = &ndlp->nlp_ptx[ringno];
2129*fcf3ce44SJohn Forte 					((IOCBQ *)abort.q_last)->next =
2130*fcf3ce44SJohn Forte 					    (IOCBQ *)q->q_first;
2131*fcf3ce44SJohn Forte 					/*
2132*fcf3ce44SJohn Forte 					 * ((IOCBQ *)abort.q_last)->next =
2133*fcf3ce44SJohn Forte 					 * (IOCBQ *)
2134*fcf3ce44SJohn Forte 					 * ndlp->nlp_ptx[ringno].q_first;
2135*fcf3ce44SJohn Forte 					 */
2136*fcf3ce44SJohn Forte 				}
2137*fcf3ce44SJohn Forte 
2138*fcf3ce44SJohn Forte 				abort.q_cnt += ndlp->nlp_ptx[ringno].q_cnt;
2139*fcf3ce44SJohn Forte 			}
2140*fcf3ce44SJohn Forte 		}
2141*fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
2142*fcf3ce44SJohn Forte 		if (ndlp->nlp_tx[ringno].q_first) {
2143*fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2144*fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
2145*fcf3ce44SJohn Forte 				abort.q_first = ndlp->nlp_tx[ringno].q_first;
2146*fcf3ce44SJohn Forte 				abort.q_last = ndlp->nlp_tx[ringno].q_last;
2147*fcf3ce44SJohn Forte 			} else {
2148*fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
2149*fcf3ce44SJohn Forte 				    (IOCBQ *)ndlp->nlp_tx[ringno].q_first;
2150*fcf3ce44SJohn Forte 			}
2151*fcf3ce44SJohn Forte 
2152*fcf3ce44SJohn Forte 			abort.q_cnt += ndlp->nlp_tx[ringno].q_cnt;
2153*fcf3ce44SJohn Forte 		}
2154*fcf3ce44SJohn Forte 		/* Clear the queue pointers */
2155*fcf3ce44SJohn Forte 		ndlp->nlp_ptx[ringno].q_first = NULL;
2156*fcf3ce44SJohn Forte 		ndlp->nlp_ptx[ringno].q_last = NULL;
2157*fcf3ce44SJohn Forte 		ndlp->nlp_ptx[ringno].q_cnt = 0;
2158*fcf3ce44SJohn Forte 
2159*fcf3ce44SJohn Forte 		ndlp->nlp_tx[ringno].q_first = NULL;
2160*fcf3ce44SJohn Forte 		ndlp->nlp_tx[ringno].q_last = NULL;
2161*fcf3ce44SJohn Forte 		ndlp->nlp_tx[ringno].q_cnt = 0;
2162*fcf3ce44SJohn Forte 
2163*fcf3ce44SJohn Forte 		/* If this node was on the ring queue, remove it */
2164*fcf3ce44SJohn Forte 		if (ndlp->nlp_next[ringno]) {
2165*fcf3ce44SJohn Forte 			/* If this is the only node on list */
2166*fcf3ce44SJohn Forte 			if (rp->nodeq.q_first == (void *)ndlp &&
2167*fcf3ce44SJohn Forte 			    rp->nodeq.q_last == (void *)ndlp) {
2168*fcf3ce44SJohn Forte 				rp->nodeq.q_last = NULL;
2169*fcf3ce44SJohn Forte 				rp->nodeq.q_first = NULL;
2170*fcf3ce44SJohn Forte 				rp->nodeq.q_cnt = 0;
2171*fcf3ce44SJohn Forte 			} else if (rp->nodeq.q_first == (void *)ndlp) {
2172*fcf3ce44SJohn Forte 				NODELIST *nd;
2173*fcf3ce44SJohn Forte 
2174*fcf3ce44SJohn Forte 				rp->nodeq.q_first = ndlp->nlp_next[ringno];
2175*fcf3ce44SJohn Forte 				nd = (NODELIST *)rp->nodeq.q_last;
2176*fcf3ce44SJohn Forte 				nd->nlp_next[ringno] = rp->nodeq.q_first;
2177*fcf3ce44SJohn Forte 				rp->nodeq.q_cnt--;
2178*fcf3ce44SJohn Forte 			} else {	/* This is a little more difficult */
2179*fcf3ce44SJohn Forte 				/*
2180*fcf3ce44SJohn Forte 				 * Find the previous node in the circular
2181*fcf3ce44SJohn Forte 				 * ring queue
2182*fcf3ce44SJohn Forte 				 */
2183*fcf3ce44SJohn Forte 				prev = ndlp;
2184*fcf3ce44SJohn Forte 				while (prev->nlp_next[ringno] != ndlp) {
2185*fcf3ce44SJohn Forte 					prev = prev->nlp_next[ringno];
2186*fcf3ce44SJohn Forte 				}
2187*fcf3ce44SJohn Forte 
2188*fcf3ce44SJohn Forte 				prev->nlp_next[ringno] = ndlp->nlp_next[ringno];
2189*fcf3ce44SJohn Forte 
2190*fcf3ce44SJohn Forte 				if (rp->nodeq.q_last == (void *)ndlp) {
2191*fcf3ce44SJohn Forte 					rp->nodeq.q_last = (void *)prev;
2192*fcf3ce44SJohn Forte 				}
2193*fcf3ce44SJohn Forte 				rp->nodeq.q_cnt--;
2194*fcf3ce44SJohn Forte 
2195*fcf3ce44SJohn Forte 			}
2196*fcf3ce44SJohn Forte 
2197*fcf3ce44SJohn Forte 			/* Clear node */
2198*fcf3ce44SJohn Forte 			ndlp->nlp_next[ringno] = NULL;
2199*fcf3ce44SJohn Forte 		}
2200*fcf3ce44SJohn Forte 	}
2201*fcf3ce44SJohn Forte 
2202*fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2203*fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2204*fcf3ce44SJohn Forte 	while (iocbq) {
2205*fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2206*fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
2207*fcf3ce44SJohn Forte 		sbp = emlxs_unregister_pkt(iocbq->ring, iocb->ulpIoTag, 0);
2208*fcf3ce44SJohn Forte 
2209*fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2210*fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2211*fcf3ce44SJohn Forte 			if (sbp->pkt_flags & PACKET_IN_TXQ) {
2212*fcf3ce44SJohn Forte 				sbp->pkt_flags &= ~PACKET_IN_TXQ;
2213*fcf3ce44SJohn Forte 				hba->ring_tx_count[ring->ringno]--;
2214*fcf3ce44SJohn Forte 			}
2215*fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2216*fcf3ce44SJohn Forte 
2217*fcf3ce44SJohn Forte 			/*
2218*fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2219*fcf3ce44SJohn Forte 			 * alone
2220*fcf3ce44SJohn Forte 			 */
2221*fcf3ce44SJohn Forte 			/*
2222*fcf3ce44SJohn Forte 			 * This ensures that this pkt is only accounted for
2223*fcf3ce44SJohn Forte 			 * on one fpkt->flush_count
2224*fcf3ce44SJohn Forte 			 */
2225*fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2226*fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2227*fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2228*fcf3ce44SJohn Forte 				fpkt->flush_count++;
2229*fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2230*fcf3ce44SJohn Forte 			}
2231*fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2232*fcf3ce44SJohn Forte 		}
2233*fcf3ce44SJohn Forte 		iocbq = (IOCBQ *)iocbq->next;
2234*fcf3ce44SJohn Forte 
2235*fcf3ce44SJohn Forte 	}	/* end of while */
2236*fcf3ce44SJohn Forte 
2237*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_RINGTX_LOCK);
2238*fcf3ce44SJohn Forte 
2239*fcf3ce44SJohn Forte 	/* Now abort the iocb's outside the locks */
2240*fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2241*fcf3ce44SJohn Forte 	while (iocbq) {
2242*fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2243*fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2244*fcf3ce44SJohn Forte 
2245*fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2246*fcf3ce44SJohn Forte 		iocbq->next = NULL;
2247*fcf3ce44SJohn Forte 
2248*fcf3ce44SJohn Forte 		/* Get the pkt */
2249*fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2250*fcf3ce44SJohn Forte 
2251*fcf3ce44SJohn Forte 		if (sbp) {
2252*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2253*fcf3ce44SJohn Forte 			    "tx: sbp=%p node=%p",
2254*fcf3ce44SJohn Forte 			    sbp, sbp->node);
2255*fcf3ce44SJohn Forte 
2256*fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2257*fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2258*fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2259*fcf3ce44SJohn Forte 			} else {
2260*fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2261*fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2262*fcf3ce44SJohn Forte 			}
2263*fcf3ce44SJohn Forte 
2264*fcf3ce44SJohn Forte 		}
2265*fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2266*fcf3ce44SJohn Forte 		else {
2267*fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
2268*fcf3ce44SJohn Forte 			if (icmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
2269*fcf3ce44SJohn Forte 			    icmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
2270*fcf3ce44SJohn Forte 			    icmd->ulpCommand == CMD_QUE_RING_LIST64_CN) {
2271*fcf3ce44SJohn Forte 				if ((hba->flag &
2272*fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2273*fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
2274*fcf3ce44SJohn Forte 					if (icmd->ulpCommand !=
2275*fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2276*fcf3ce44SJohn Forte 						uint8_t *tmp;
2277*fcf3ce44SJohn Forte 
2278*fcf3ce44SJohn Forte 						for (i = 0;
2279*fcf3ce44SJohn Forte 						    i < icmd->ulpBdeCount;
2280*fcf3ce44SJohn Forte 						    i++) {
2281*fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2282*fcf3ce44SJohn Forte 							    hba, rp, icmd);
2283*fcf3ce44SJohn Forte 
2284*fcf3ce44SJohn Forte 							tmp = (uint8_t *)mp;
2285*fcf3ce44SJohn Forte 							if (mp) {
2286*fcf3ce44SJohn Forte 	(void) emlxs_mem_put(hba, MEM_BUF, tmp);
2287*fcf3ce44SJohn Forte 							}
2288*fcf3ce44SJohn Forte 						}
2289*fcf3ce44SJohn Forte 					}
2290*fcf3ce44SJohn Forte 					(void) emlxs_mem_put(hba, MEM_IOCB,
2291*fcf3ce44SJohn Forte 					    (uint8_t *)iocbq);
2292*fcf3ce44SJohn Forte 				} else {
2293*fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
2294*fcf3ce44SJohn Forte 					emlxs_issue_iocb_cmd(hba, rp, iocbq);
2295*fcf3ce44SJohn Forte 				}
2296*fcf3ce44SJohn Forte 			}
2297*fcf3ce44SJohn Forte 		}
2298*fcf3ce44SJohn Forte 
2299*fcf3ce44SJohn Forte 		iocbq = next;
2300*fcf3ce44SJohn Forte 
2301*fcf3ce44SJohn Forte 	}	/* end of while */
2302*fcf3ce44SJohn Forte 
2303*fcf3ce44SJohn Forte 	return (abort.q_cnt);
2304*fcf3ce44SJohn Forte 
2305*fcf3ce44SJohn Forte } /* emlxs_tx_node_flush() */
2306*fcf3ce44SJohn Forte 
2307*fcf3ce44SJohn Forte 
2308*fcf3ce44SJohn Forte /* Check for IO's on all or a given ring for a given node */
2309*fcf3ce44SJohn Forte extern uint32_t
2310*fcf3ce44SJohn Forte emlxs_tx_node_check(emlxs_port_t *port, NODELIST *ndlp, RING *ring)
2311*fcf3ce44SJohn Forte {
2312*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2313*fcf3ce44SJohn Forte 	uint32_t ringno;
2314*fcf3ce44SJohn Forte 	RING *rp;
2315*fcf3ce44SJohn Forte 	uint32_t count;
2316*fcf3ce44SJohn Forte 
2317*fcf3ce44SJohn Forte 	count = 0;
2318*fcf3ce44SJohn Forte 
2319*fcf3ce44SJohn Forte 	/* Flush all I/O's on tx queue to this target */
2320*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_RINGTX_LOCK);
2321*fcf3ce44SJohn Forte 
2322*fcf3ce44SJohn Forte 	for (ringno = 0; ringno < hba->ring_count; ringno++) {
2323*fcf3ce44SJohn Forte 		rp = &hba->ring[ringno];
2324*fcf3ce44SJohn Forte 
2325*fcf3ce44SJohn Forte 		if (ring && rp != ring) {
2326*fcf3ce44SJohn Forte 			continue;
2327*fcf3ce44SJohn Forte 		}
2328*fcf3ce44SJohn Forte 		/* Check if priority queue is not empty */
2329*fcf3ce44SJohn Forte 		if (ndlp->nlp_ptx[ringno].q_first) {
2330*fcf3ce44SJohn Forte 			count += ndlp->nlp_ptx[ringno].q_cnt;
2331*fcf3ce44SJohn Forte 		}
2332*fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
2333*fcf3ce44SJohn Forte 		if (ndlp->nlp_tx[ringno].q_first) {
2334*fcf3ce44SJohn Forte 			count += ndlp->nlp_tx[ringno].q_cnt;
2335*fcf3ce44SJohn Forte 		}
2336*fcf3ce44SJohn Forte 	}
2337*fcf3ce44SJohn Forte 
2338*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_RINGTX_LOCK);
2339*fcf3ce44SJohn Forte 
2340*fcf3ce44SJohn Forte 	return (count);
2341*fcf3ce44SJohn Forte 
2342*fcf3ce44SJohn Forte } /* emlxs_tx_node_check() */
2343*fcf3ce44SJohn Forte 
2344*fcf3ce44SJohn Forte 
2345*fcf3ce44SJohn Forte 
2346*fcf3ce44SJohn Forte /* Flush all IO's on the FCP ring for a given node's lun */
2347*fcf3ce44SJohn Forte extern uint32_t
2348*fcf3ce44SJohn Forte emlxs_tx_lun_flush(emlxs_port_t *port, NODELIST *ndlp,
2349*fcf3ce44SJohn Forte     uint32_t lun, emlxs_buf_t *fpkt)
2350*fcf3ce44SJohn Forte {
2351*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2352*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2353*fcf3ce44SJohn Forte 	uint32_t ringno;
2354*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2355*fcf3ce44SJohn Forte 	IOCBQ *prev;
2356*fcf3ce44SJohn Forte 	IOCBQ *next;
2357*fcf3ce44SJohn Forte 	IOCB *iocb;
2358*fcf3ce44SJohn Forte 	IOCB *icmd;
2359*fcf3ce44SJohn Forte 	Q abort;
2360*fcf3ce44SJohn Forte 	uint32_t i;
2361*fcf3ce44SJohn Forte 	MATCHMAP *mp;
2362*fcf3ce44SJohn Forte 	RING *rp;
2363*fcf3ce44SJohn Forte 
2364*fcf3ce44SJohn Forte 	ringno = FC_FCP_RING;
2365*fcf3ce44SJohn Forte 	rp = &hba->ring[ringno];
2366*fcf3ce44SJohn Forte 
2367*fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
2368*fcf3ce44SJohn Forte 
2369*fcf3ce44SJohn Forte 	/* Flush I/O's on txQ to this target's lun */
2370*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_RINGTX_LOCK);
2371*fcf3ce44SJohn Forte 
2372*fcf3ce44SJohn Forte 	/* Scan the priority queue first */
2373*fcf3ce44SJohn Forte 	prev = NULL;
2374*fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)ndlp->nlp_ptx[ringno].q_first;
2375*fcf3ce44SJohn Forte 
2376*fcf3ce44SJohn Forte 	while (iocbq) {
2377*fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2378*fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
2379*fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2380*fcf3ce44SJohn Forte 
2381*fcf3ce44SJohn Forte 		/* Check if this IO is for our lun */
2382*fcf3ce44SJohn Forte 		if (sbp->lun == lun) {
2383*fcf3ce44SJohn Forte 			/* Remove iocb from the node's tx queue */
2384*fcf3ce44SJohn Forte 			if (next == 0) {
2385*fcf3ce44SJohn Forte 				ndlp->nlp_ptx[ringno].q_last = (uint8_t *)prev;
2386*fcf3ce44SJohn Forte 			}
2387*fcf3ce44SJohn Forte 			if (prev == 0) {
2388*fcf3ce44SJohn Forte 				ndlp->nlp_ptx[ringno].q_first = (uint8_t *)next;
2389*fcf3ce44SJohn Forte 			} else {
2390*fcf3ce44SJohn Forte 				prev->next = next;
2391*fcf3ce44SJohn Forte 			}
2392*fcf3ce44SJohn Forte 
2393*fcf3ce44SJohn Forte 			iocbq->next = NULL;
2394*fcf3ce44SJohn Forte 			ndlp->nlp_ptx[ringno].q_cnt--;
2395*fcf3ce44SJohn Forte 
2396*fcf3ce44SJohn Forte 			/* Add this iocb to our local abort Q */
2397*fcf3ce44SJohn Forte 			/* This way we don't hold the RINGTX lock too long */
2398*fcf3ce44SJohn Forte 			if (abort.q_first) {
2399*fcf3ce44SJohn Forte 				((IOCBQ *) abort.q_last)->next = iocbq;
2400*fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
2401*fcf3ce44SJohn Forte 				abort.q_cnt++;
2402*fcf3ce44SJohn Forte 			} else {
2403*fcf3ce44SJohn Forte 				abort.q_first = (uint8_t *)iocbq;
2404*fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
2405*fcf3ce44SJohn Forte 				abort.q_cnt = 1;
2406*fcf3ce44SJohn Forte 			}
2407*fcf3ce44SJohn Forte 			iocbq->next = NULL;
2408*fcf3ce44SJohn Forte 		} else {
2409*fcf3ce44SJohn Forte 			prev = iocbq;
2410*fcf3ce44SJohn Forte 		}
2411*fcf3ce44SJohn Forte 
2412*fcf3ce44SJohn Forte 		iocbq = next;
2413*fcf3ce44SJohn Forte 
2414*fcf3ce44SJohn Forte 	}	/* while (iocbq) */
2415*fcf3ce44SJohn Forte 
2416*fcf3ce44SJohn Forte 
2417*fcf3ce44SJohn Forte 	/* Scan the regular queue */
2418*fcf3ce44SJohn Forte 	prev = NULL;
2419*fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)ndlp->nlp_tx[ringno].q_first;
2420*fcf3ce44SJohn Forte 
2421*fcf3ce44SJohn Forte 	while (iocbq) {
2422*fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2423*fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
2424*fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2425*fcf3ce44SJohn Forte 
2426*fcf3ce44SJohn Forte 		/* Check if this IO is for our lun */
2427*fcf3ce44SJohn Forte 		if (sbp->lun == lun) {
2428*fcf3ce44SJohn Forte 			/* Remove iocb from the node's tx queue */
2429*fcf3ce44SJohn Forte 			if (next == 0) {
2430*fcf3ce44SJohn Forte 				ndlp->nlp_tx[ringno].q_last = (uint8_t *)prev;
2431*fcf3ce44SJohn Forte 			}
2432*fcf3ce44SJohn Forte 			if (prev == 0) {
2433*fcf3ce44SJohn Forte 				ndlp->nlp_tx[ringno].q_first = (uint8_t *)next;
2434*fcf3ce44SJohn Forte 			} else {
2435*fcf3ce44SJohn Forte 				prev->next = next;
2436*fcf3ce44SJohn Forte 			}
2437*fcf3ce44SJohn Forte 
2438*fcf3ce44SJohn Forte 			iocbq->next = NULL;
2439*fcf3ce44SJohn Forte 			ndlp->nlp_tx[ringno].q_cnt--;
2440*fcf3ce44SJohn Forte 
2441*fcf3ce44SJohn Forte 			/* Add this iocb to our local abort Q */
2442*fcf3ce44SJohn Forte 			/* This way we don't hold the RINGTX lock too long */
2443*fcf3ce44SJohn Forte 			if (abort.q_first) {
2444*fcf3ce44SJohn Forte 				((IOCBQ *) abort.q_last)->next = iocbq;
2445*fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
2446*fcf3ce44SJohn Forte 				abort.q_cnt++;
2447*fcf3ce44SJohn Forte 			} else {
2448*fcf3ce44SJohn Forte 				abort.q_first = (uint8_t *)iocbq;
2449*fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
2450*fcf3ce44SJohn Forte 				abort.q_cnt = 1;
2451*fcf3ce44SJohn Forte 			}
2452*fcf3ce44SJohn Forte 			iocbq->next = NULL;
2453*fcf3ce44SJohn Forte 		} else {
2454*fcf3ce44SJohn Forte 			prev = iocbq;
2455*fcf3ce44SJohn Forte 		}
2456*fcf3ce44SJohn Forte 
2457*fcf3ce44SJohn Forte 		iocbq = next;
2458*fcf3ce44SJohn Forte 
2459*fcf3ce44SJohn Forte 	}	/* while (iocbq) */
2460*fcf3ce44SJohn Forte 
2461*fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2462*fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2463*fcf3ce44SJohn Forte 	while (iocbq) {
2464*fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2465*fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
2466*fcf3ce44SJohn Forte 		sbp = emlxs_unregister_pkt(iocbq->ring, iocb->ulpIoTag, 0);
2467*fcf3ce44SJohn Forte 
2468*fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2469*fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2470*fcf3ce44SJohn Forte 			if (sbp->pkt_flags & PACKET_IN_TXQ) {
2471*fcf3ce44SJohn Forte 				sbp->pkt_flags &= ~PACKET_IN_TXQ;
2472*fcf3ce44SJohn Forte 				hba->ring_tx_count[ringno]--;
2473*fcf3ce44SJohn Forte 			}
2474*fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2475*fcf3ce44SJohn Forte 
2476*fcf3ce44SJohn Forte 			/*
2477*fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2478*fcf3ce44SJohn Forte 			 * alone
2479*fcf3ce44SJohn Forte 			 */
2480*fcf3ce44SJohn Forte 			/*
2481*fcf3ce44SJohn Forte 			 * This ensures that this pkt is only accounted for
2482*fcf3ce44SJohn Forte 			 * on one fpkt->flush_count
2483*fcf3ce44SJohn Forte 			 */
2484*fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2485*fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2486*fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2487*fcf3ce44SJohn Forte 				fpkt->flush_count++;
2488*fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2489*fcf3ce44SJohn Forte 			}
2490*fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2491*fcf3ce44SJohn Forte 		}
2492*fcf3ce44SJohn Forte 		iocbq = (IOCBQ *)iocbq->next;
2493*fcf3ce44SJohn Forte 
2494*fcf3ce44SJohn Forte 	}	/* end of while */
2495*fcf3ce44SJohn Forte 
2496*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_RINGTX_LOCK);
2497*fcf3ce44SJohn Forte 
2498*fcf3ce44SJohn Forte 	/* Now abort the iocb's outside the locks */
2499*fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2500*fcf3ce44SJohn Forte 	while (iocbq) {
2501*fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2502*fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2503*fcf3ce44SJohn Forte 
2504*fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2505*fcf3ce44SJohn Forte 		iocbq->next = NULL;
2506*fcf3ce44SJohn Forte 
2507*fcf3ce44SJohn Forte 		/* Get the pkt */
2508*fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2509*fcf3ce44SJohn Forte 
2510*fcf3ce44SJohn Forte 		if (sbp) {
2511*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2512*fcf3ce44SJohn Forte 			    "tx: sbp=%p node=%p",
2513*fcf3ce44SJohn Forte 			    sbp, sbp->node);
2514*fcf3ce44SJohn Forte 
2515*fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2516*fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2517*fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2518*fcf3ce44SJohn Forte 			} else {
2519*fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2520*fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2521*fcf3ce44SJohn Forte 			}
2522*fcf3ce44SJohn Forte 		}
2523*fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2524*fcf3ce44SJohn Forte 		else {
2525*fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
2526*fcf3ce44SJohn Forte 
2527*fcf3ce44SJohn Forte 			if (icmd->ulpCommand == CMD_QUE_RING_BUF64_CN ||
2528*fcf3ce44SJohn Forte 			    icmd->ulpCommand == CMD_QUE_RING_BUF_CN ||
2529*fcf3ce44SJohn Forte 			    icmd->ulpCommand == CMD_QUE_RING_LIST64_CN) {
2530*fcf3ce44SJohn Forte 				if ((hba->flag &
2531*fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2532*fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
2533*fcf3ce44SJohn Forte 					if (icmd->ulpCommand !=
2534*fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2535*fcf3ce44SJohn Forte 						uint8_t *tmp;
2536*fcf3ce44SJohn Forte 
2537*fcf3ce44SJohn Forte 						for (i = 0;
2538*fcf3ce44SJohn Forte 						    i < icmd->ulpBdeCount;
2539*fcf3ce44SJohn Forte 						    i++) {
2540*fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2541*fcf3ce44SJohn Forte 							    hba, rp, icmd);
2542*fcf3ce44SJohn Forte 
2543*fcf3ce44SJohn Forte 							tmp = (uint8_t *)mp;
2544*fcf3ce44SJohn Forte 							if (mp) {
2545*fcf3ce44SJohn Forte 	(void) emlxs_mem_put(hba, MEM_BUF, tmp);
2546*fcf3ce44SJohn Forte 							}
2547*fcf3ce44SJohn Forte 						}
2548*fcf3ce44SJohn Forte 					}
2549*fcf3ce44SJohn Forte 					(void) emlxs_mem_put(hba, MEM_IOCB,
2550*fcf3ce44SJohn Forte 					    (uint8_t *)iocbq);
2551*fcf3ce44SJohn Forte 				} else {
2552*fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
2553*fcf3ce44SJohn Forte 					emlxs_issue_iocb_cmd(hba, rp, iocbq);
2554*fcf3ce44SJohn Forte 				}
2555*fcf3ce44SJohn Forte 			}
2556*fcf3ce44SJohn Forte 		}
2557*fcf3ce44SJohn Forte 
2558*fcf3ce44SJohn Forte 		iocbq = next;
2559*fcf3ce44SJohn Forte 
2560*fcf3ce44SJohn Forte 	}	/* end of while */
2561*fcf3ce44SJohn Forte 
2562*fcf3ce44SJohn Forte 
2563*fcf3ce44SJohn Forte 	return (abort.q_cnt);
2564*fcf3ce44SJohn Forte 
2565*fcf3ce44SJohn Forte } /* emlxs_tx_lun_flush() */
2566*fcf3ce44SJohn Forte 
2567*fcf3ce44SJohn Forte 
2568*fcf3ce44SJohn Forte extern void
2569*fcf3ce44SJohn Forte emlxs_tx_put(IOCBQ *iocbq, uint32_t lock)
2570*fcf3ce44SJohn Forte {
2571*fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
2572*fcf3ce44SJohn Forte 	emlxs_port_t *port;
2573*fcf3ce44SJohn Forte 	uint32_t ringno;
2574*fcf3ce44SJohn Forte 	NODELIST *nlp;
2575*fcf3ce44SJohn Forte 	RING *rp;
2576*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2577*fcf3ce44SJohn Forte 
2578*fcf3ce44SJohn Forte 	port = (emlxs_port_t *)iocbq->port;
2579*fcf3ce44SJohn Forte 	hba = HBA;
2580*fcf3ce44SJohn Forte 	rp = (RING *)iocbq->ring;
2581*fcf3ce44SJohn Forte 	nlp = (NODELIST *)iocbq->node;
2582*fcf3ce44SJohn Forte 	ringno = rp->ringno;
2583*fcf3ce44SJohn Forte 	sbp = (emlxs_buf_t *)iocbq->sbp;
2584*fcf3ce44SJohn Forte 
2585*fcf3ce44SJohn Forte 	if (nlp == NULL) {
2586*fcf3ce44SJohn Forte 		/* Set node to base node by default */
2587*fcf3ce44SJohn Forte 		nlp = &port->node_base;
2588*fcf3ce44SJohn Forte 
2589*fcf3ce44SJohn Forte 		iocbq->node = (void *)nlp;
2590*fcf3ce44SJohn Forte 
2591*fcf3ce44SJohn Forte 		if (sbp) {
2592*fcf3ce44SJohn Forte 			sbp->node = (void *)nlp;
2593*fcf3ce44SJohn Forte 		}
2594*fcf3ce44SJohn Forte 	}
2595*fcf3ce44SJohn Forte 	if (lock) {
2596*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_RINGTX_LOCK);
2597*fcf3ce44SJohn Forte 	}
2598*fcf3ce44SJohn Forte 	if (!nlp->nlp_active || (sbp && (sbp->pkt_flags & PACKET_IN_ABORT))) {
2599*fcf3ce44SJohn Forte 		if (sbp) {
2600*fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2601*fcf3ce44SJohn Forte 
2602*fcf3ce44SJohn Forte 			if (sbp->pkt_flags & PACKET_IN_TXQ) {
2603*fcf3ce44SJohn Forte 				sbp->pkt_flags &= ~PACKET_IN_TXQ;
2604*fcf3ce44SJohn Forte 				hba->ring_tx_count[ringno]--;
2605*fcf3ce44SJohn Forte 			}
2606*fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2607*fcf3ce44SJohn Forte 
2608*fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2609*fcf3ce44SJohn Forte 
2610*fcf3ce44SJohn Forte 			/* Free the ulpIoTag and the bmp */
2611*fcf3ce44SJohn Forte 			(void) emlxs_unregister_pkt(rp, sbp->iotag, 0);
2612*fcf3ce44SJohn Forte 
2613*fcf3ce44SJohn Forte 			if (lock) {
2614*fcf3ce44SJohn Forte 				mutex_exit(&EMLXS_RINGTX_LOCK);
2615*fcf3ce44SJohn Forte 			}
2616*fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2617*fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2618*fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2619*fcf3ce44SJohn Forte 			} else {
2620*fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2621*fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2622*fcf3ce44SJohn Forte 			}
2623*fcf3ce44SJohn Forte 
2624*fcf3ce44SJohn Forte 			return;
2625*fcf3ce44SJohn Forte 		} else {
2626*fcf3ce44SJohn Forte 			if (lock) {
2627*fcf3ce44SJohn Forte 				mutex_exit(&EMLXS_RINGTX_LOCK);
2628*fcf3ce44SJohn Forte 			}
2629*fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_IOCB, (uint8_t *)iocbq);
2630*fcf3ce44SJohn Forte 		}
2631*fcf3ce44SJohn Forte 
2632*fcf3ce44SJohn Forte 		return;
2633*fcf3ce44SJohn Forte 	}
2634*fcf3ce44SJohn Forte 	if (sbp) {
2635*fcf3ce44SJohn Forte 
2636*fcf3ce44SJohn Forte 		mutex_enter(&sbp->mtx);
2637*fcf3ce44SJohn Forte 
2638*fcf3ce44SJohn Forte 		if (sbp->pkt_flags & (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ |
2639*fcf3ce44SJohn Forte 		    PACKET_IN_TXQ)) {
2640*fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2641*fcf3ce44SJohn Forte 			if (lock) {
2642*fcf3ce44SJohn Forte 				mutex_exit(&EMLXS_RINGTX_LOCK);
2643*fcf3ce44SJohn Forte 			}
2644*fcf3ce44SJohn Forte 			return;
2645*fcf3ce44SJohn Forte 		}
2646*fcf3ce44SJohn Forte 		sbp->pkt_flags |= PACKET_IN_TXQ;
2647*fcf3ce44SJohn Forte 		hba->ring_tx_count[ringno]++;
2648*fcf3ce44SJohn Forte 
2649*fcf3ce44SJohn Forte 		mutex_exit(&sbp->mtx);
2650*fcf3ce44SJohn Forte 	}
2651*fcf3ce44SJohn Forte 	/* Check iocbq priority */
2652*fcf3ce44SJohn Forte 	if (iocbq->flag & IOCB_PRIORITY) {
2653*fcf3ce44SJohn Forte 		/* Add the iocb to the bottom of the node's ptx queue */
2654*fcf3ce44SJohn Forte 		if (nlp->nlp_ptx[ringno].q_first) {
2655*fcf3ce44SJohn Forte 			((IOCBQ *)nlp->nlp_ptx[ringno].q_last)->next = iocbq;
2656*fcf3ce44SJohn Forte 			nlp->nlp_ptx[ringno].q_last = (uint8_t *)iocbq;
2657*fcf3ce44SJohn Forte 			nlp->nlp_ptx[ringno].q_cnt++;
2658*fcf3ce44SJohn Forte 		} else {
2659*fcf3ce44SJohn Forte 			nlp->nlp_ptx[ringno].q_first = (uint8_t *)iocbq;
2660*fcf3ce44SJohn Forte 			nlp->nlp_ptx[ringno].q_last = (uint8_t *)iocbq;
2661*fcf3ce44SJohn Forte 			nlp->nlp_ptx[ringno].q_cnt = 1;
2662*fcf3ce44SJohn Forte 		}
2663*fcf3ce44SJohn Forte 
2664*fcf3ce44SJohn Forte 		iocbq->next = NULL;
2665*fcf3ce44SJohn Forte 	} else {	/* Normal priority */
2666*fcf3ce44SJohn Forte 
2667*fcf3ce44SJohn Forte 		/* Add the iocb to the bottom of the node's tx queue */
2668*fcf3ce44SJohn Forte 		if (nlp->nlp_tx[ringno].q_first) {
2669*fcf3ce44SJohn Forte 			((IOCBQ *)nlp->nlp_tx[ringno].q_last)->next = iocbq;
2670*fcf3ce44SJohn Forte 			nlp->nlp_tx[ringno].q_last = (uint8_t *)iocbq;
2671*fcf3ce44SJohn Forte 			nlp->nlp_tx[ringno].q_cnt++;
2672*fcf3ce44SJohn Forte 		} else {
2673*fcf3ce44SJohn Forte 			nlp->nlp_tx[ringno].q_first = (uint8_t *)iocbq;
2674*fcf3ce44SJohn Forte 			nlp->nlp_tx[ringno].q_last = (uint8_t *)iocbq;
2675*fcf3ce44SJohn Forte 			nlp->nlp_tx[ringno].q_cnt = 1;
2676*fcf3ce44SJohn Forte 		}
2677*fcf3ce44SJohn Forte 
2678*fcf3ce44SJohn Forte 		iocbq->next = NULL;
2679*fcf3ce44SJohn Forte 	}
2680*fcf3ce44SJohn Forte 
2681*fcf3ce44SJohn Forte 
2682*fcf3ce44SJohn Forte 	/*
2683*fcf3ce44SJohn Forte 	 * Check if the node is not already on ring queue and (is not closed
2684*fcf3ce44SJohn Forte 	 * or  is a priority request)
2685*fcf3ce44SJohn Forte 	 */
2686*fcf3ce44SJohn Forte 	if (!nlp->nlp_next[ringno] && (!(nlp->nlp_flag[ringno] & NLP_CLOSED) ||
2687*fcf3ce44SJohn Forte 	    (iocbq->flag & IOCB_PRIORITY))) {
2688*fcf3ce44SJohn Forte 		/* If so, then add it to the ring queue */
2689*fcf3ce44SJohn Forte 		if (rp->nodeq.q_first) {
2690*fcf3ce44SJohn Forte 			((NODELIST *)rp->nodeq.q_last)->nlp_next[ringno] =
2691*fcf3ce44SJohn Forte 			    (uint8_t *)nlp;
2692*fcf3ce44SJohn Forte 			nlp->nlp_next[ringno] = rp->nodeq.q_first;
2693*fcf3ce44SJohn Forte 
2694*fcf3ce44SJohn Forte 			/*
2695*fcf3ce44SJohn Forte 			 * If this is not the base node then add it to the
2696*fcf3ce44SJohn Forte 			 * tail
2697*fcf3ce44SJohn Forte 			 */
2698*fcf3ce44SJohn Forte 			if (!nlp->nlp_base) {
2699*fcf3ce44SJohn Forte 				rp->nodeq.q_last = (uint8_t *)nlp;
2700*fcf3ce44SJohn Forte 			} else {	/* Otherwise, add it to the head */
2701*fcf3ce44SJohn Forte 				/* The command node always gets priority */
2702*fcf3ce44SJohn Forte 				rp->nodeq.q_first = (uint8_t *)nlp;
2703*fcf3ce44SJohn Forte 			}
2704*fcf3ce44SJohn Forte 
2705*fcf3ce44SJohn Forte 			rp->nodeq.q_cnt++;
2706*fcf3ce44SJohn Forte 		} else {
2707*fcf3ce44SJohn Forte 			rp->nodeq.q_first = (uint8_t *)nlp;
2708*fcf3ce44SJohn Forte 			rp->nodeq.q_last = (uint8_t *)nlp;
2709*fcf3ce44SJohn Forte 			nlp->nlp_next[ringno] = nlp;
2710*fcf3ce44SJohn Forte 			rp->nodeq.q_cnt = 1;
2711*fcf3ce44SJohn Forte 		}
2712*fcf3ce44SJohn Forte 	}
2713*fcf3ce44SJohn Forte 	HBASTATS.IocbTxPut[ringno]++;
2714*fcf3ce44SJohn Forte 
2715*fcf3ce44SJohn Forte 	/* Adjust the ring timeout timer */
2716*fcf3ce44SJohn Forte 	rp->timeout = hba->timer_tics + 5;
2717*fcf3ce44SJohn Forte 
2718*fcf3ce44SJohn Forte 	if (lock) {
2719*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_RINGTX_LOCK);
2720*fcf3ce44SJohn Forte 	}
2721*fcf3ce44SJohn Forte 	return;
2722*fcf3ce44SJohn Forte 
2723*fcf3ce44SJohn Forte } /* emlxs_tx_put() */
2724*fcf3ce44SJohn Forte 
2725*fcf3ce44SJohn Forte 
2726*fcf3ce44SJohn Forte extern IOCBQ *
2727*fcf3ce44SJohn Forte emlxs_tx_get(RING *rp, uint32_t lock)
2728*fcf3ce44SJohn Forte {
2729*fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
2730*fcf3ce44SJohn Forte 	uint32_t ringno;
2731*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2732*fcf3ce44SJohn Forte 	NODELIST *nlp;
2733*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2734*fcf3ce44SJohn Forte 
2735*fcf3ce44SJohn Forte 	hba = rp->hba;
2736*fcf3ce44SJohn Forte 	ringno = rp->ringno;
2737*fcf3ce44SJohn Forte 
2738*fcf3ce44SJohn Forte 	if (lock) {
2739*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_RINGTX_LOCK);
2740*fcf3ce44SJohn Forte 	}
2741*fcf3ce44SJohn Forte begin:
2742*fcf3ce44SJohn Forte 
2743*fcf3ce44SJohn Forte 	iocbq = NULL;
2744*fcf3ce44SJohn Forte 
2745*fcf3ce44SJohn Forte 	/* Check if a node needs servicing */
2746*fcf3ce44SJohn Forte 	if (rp->nodeq.q_first) {
2747*fcf3ce44SJohn Forte 		nlp = (NODELIST *)rp->nodeq.q_first;
2748*fcf3ce44SJohn Forte 
2749*fcf3ce44SJohn Forte 		/* Get next iocb from node's priority queue */
2750*fcf3ce44SJohn Forte 
2751*fcf3ce44SJohn Forte 		if (nlp->nlp_ptx[ringno].q_first) {
2752*fcf3ce44SJohn Forte 			iocbq = (IOCBQ *)nlp->nlp_ptx[ringno].q_first;
2753*fcf3ce44SJohn Forte 
2754*fcf3ce44SJohn Forte 			/* Check if this is last entry */
2755*fcf3ce44SJohn Forte 			if (nlp->nlp_ptx[ringno].q_last == (void *)iocbq) {
2756*fcf3ce44SJohn Forte 				nlp->nlp_ptx[ringno].q_first = NULL;
2757*fcf3ce44SJohn Forte 				nlp->nlp_ptx[ringno].q_last = NULL;
2758*fcf3ce44SJohn Forte 				nlp->nlp_ptx[ringno].q_cnt = 0;
2759*fcf3ce44SJohn Forte 			} else {
2760*fcf3ce44SJohn Forte 				/* Remove iocb from head */
2761*fcf3ce44SJohn Forte 				nlp->nlp_ptx[ringno].q_first =
2762*fcf3ce44SJohn Forte 				    (void *)iocbq->next;
2763*fcf3ce44SJohn Forte 				nlp->nlp_ptx[ringno].q_cnt--;
2764*fcf3ce44SJohn Forte 			}
2765*fcf3ce44SJohn Forte 
2766*fcf3ce44SJohn Forte 			iocbq->next = NULL;
2767*fcf3ce44SJohn Forte 		}
2768*fcf3ce44SJohn Forte 		/* Get next iocb from node tx queue if node not closed */
2769*fcf3ce44SJohn Forte 		else if (nlp->nlp_tx[ringno].q_first &&
2770*fcf3ce44SJohn Forte 		    !(nlp->nlp_flag[ringno] & NLP_CLOSED)) {
2771*fcf3ce44SJohn Forte 			iocbq = (IOCBQ *)nlp->nlp_tx[ringno].q_first;
2772*fcf3ce44SJohn Forte 
2773*fcf3ce44SJohn Forte 			/* Check if this is last entry */
2774*fcf3ce44SJohn Forte 			if (nlp->nlp_tx[ringno].q_last == (void *)iocbq) {
2775*fcf3ce44SJohn Forte 				nlp->nlp_tx[ringno].q_first = NULL;
2776*fcf3ce44SJohn Forte 				nlp->nlp_tx[ringno].q_last = NULL;
2777*fcf3ce44SJohn Forte 				nlp->nlp_tx[ringno].q_cnt = 0;
2778*fcf3ce44SJohn Forte 			} else {
2779*fcf3ce44SJohn Forte 				/* Remove iocb from head */
2780*fcf3ce44SJohn Forte 				nlp->nlp_tx[ringno].q_first =
2781*fcf3ce44SJohn Forte 				    (void *)iocbq->next;
2782*fcf3ce44SJohn Forte 				nlp->nlp_tx[ringno].q_cnt--;
2783*fcf3ce44SJohn Forte 			}
2784*fcf3ce44SJohn Forte 
2785*fcf3ce44SJohn Forte 			iocbq->next = NULL;
2786*fcf3ce44SJohn Forte 		}
2787*fcf3ce44SJohn Forte 		/* Now deal with node itself */
2788*fcf3ce44SJohn Forte 
2789*fcf3ce44SJohn Forte 		/* Check if node still needs servicing */
2790*fcf3ce44SJohn Forte 		if ((nlp->nlp_ptx[ringno].q_first) ||
2791*fcf3ce44SJohn Forte 		    (nlp->nlp_tx[ringno].q_first &&
2792*fcf3ce44SJohn Forte 		    !(nlp->nlp_flag[ringno] & NLP_CLOSED))) {
2793*fcf3ce44SJohn Forte 
2794*fcf3ce44SJohn Forte 			/*
2795*fcf3ce44SJohn Forte 			 * If this is the base node, then don't shift the
2796*fcf3ce44SJohn Forte 			 * pointers
2797*fcf3ce44SJohn Forte 			 */
2798*fcf3ce44SJohn Forte 			/* We want to drain the base node before moving on */
2799*fcf3ce44SJohn Forte 			if (!nlp->nlp_base) {
2800*fcf3ce44SJohn Forte 				/*
2801*fcf3ce44SJohn Forte 				 * Just shift ring queue pointers to next
2802*fcf3ce44SJohn Forte 				 * node
2803*fcf3ce44SJohn Forte 				 */
2804*fcf3ce44SJohn Forte 				rp->nodeq.q_last = (void *)nlp;
2805*fcf3ce44SJohn Forte 				rp->nodeq.q_first = nlp->nlp_next[ringno];
2806*fcf3ce44SJohn Forte 			}
2807*fcf3ce44SJohn Forte 		} else {
2808*fcf3ce44SJohn Forte 			/* Remove node from ring queue */
2809*fcf3ce44SJohn Forte 
2810*fcf3ce44SJohn Forte 			/* If this is the last node on list */
2811*fcf3ce44SJohn Forte 			if (rp->nodeq.q_last == (void *)nlp) {
2812*fcf3ce44SJohn Forte 				rp->nodeq.q_last = NULL;
2813*fcf3ce44SJohn Forte 				rp->nodeq.q_first = NULL;
2814*fcf3ce44SJohn Forte 				rp->nodeq.q_cnt = 0;
2815*fcf3ce44SJohn Forte 			} else {
2816*fcf3ce44SJohn Forte 				NODELIST *nd;
2817*fcf3ce44SJohn Forte 
2818*fcf3ce44SJohn Forte 				/* Remove node from head */
2819*fcf3ce44SJohn Forte 				rp->nodeq.q_first = nlp->nlp_next[ringno];
2820*fcf3ce44SJohn Forte 				nd = (NODELIST *)rp->nodeq.q_last;
2821*fcf3ce44SJohn Forte 				nd->nlp_next[ringno] = rp->nodeq.q_first;
2822*fcf3ce44SJohn Forte 				rp->nodeq.q_cnt--;
2823*fcf3ce44SJohn Forte 
2824*fcf3ce44SJohn Forte 			}
2825*fcf3ce44SJohn Forte 
2826*fcf3ce44SJohn Forte 			/* Clear node */
2827*fcf3ce44SJohn Forte 			nlp->nlp_next[ringno] = NULL;
2828*fcf3ce44SJohn Forte 		}
2829*fcf3ce44SJohn Forte 
2830*fcf3ce44SJohn Forte 		/*
2831*fcf3ce44SJohn Forte 		 * If no iocbq was found on this node, then it will have been
2832*fcf3ce44SJohn Forte 		 * removed. So try again.
2833*fcf3ce44SJohn Forte 		 */
2834*fcf3ce44SJohn Forte 		if (!iocbq) {
2835*fcf3ce44SJohn Forte 			goto begin;
2836*fcf3ce44SJohn Forte 		}
2837*fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2838*fcf3ce44SJohn Forte 
2839*fcf3ce44SJohn Forte 		if (sbp) {
2840*fcf3ce44SJohn Forte 			/*
2841*fcf3ce44SJohn Forte 			 * Check flags before we enter mutex in case this has
2842*fcf3ce44SJohn Forte 			 * been flushed and destroyed
2843*fcf3ce44SJohn Forte 			 */
2844*fcf3ce44SJohn Forte 			if ((sbp->pkt_flags &
2845*fcf3ce44SJohn Forte 			    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) ||
2846*fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_IN_TXQ)) {
2847*fcf3ce44SJohn Forte 				goto begin;
2848*fcf3ce44SJohn Forte 			}
2849*fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2850*fcf3ce44SJohn Forte 
2851*fcf3ce44SJohn Forte 			if ((sbp->pkt_flags &
2852*fcf3ce44SJohn Forte 			    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) ||
2853*fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_IN_TXQ)) {
2854*fcf3ce44SJohn Forte 				mutex_exit(&sbp->mtx);
2855*fcf3ce44SJohn Forte 				goto begin;
2856*fcf3ce44SJohn Forte 			}
2857*fcf3ce44SJohn Forte 			sbp->pkt_flags &= ~PACKET_IN_TXQ;
2858*fcf3ce44SJohn Forte 			hba->ring_tx_count[ringno]--;
2859*fcf3ce44SJohn Forte 
2860*fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2861*fcf3ce44SJohn Forte 		}
2862*fcf3ce44SJohn Forte 	}
2863*fcf3ce44SJohn Forte 	if (iocbq) {
2864*fcf3ce44SJohn Forte 		HBASTATS.IocbTxGet[ringno]++;
2865*fcf3ce44SJohn Forte 	}
2866*fcf3ce44SJohn Forte 	/* Adjust the ring timeout timer */
2867*fcf3ce44SJohn Forte 	rp->timeout = (rp->nodeq.q_first) ? (hba->timer_tics + 5) : 0;
2868*fcf3ce44SJohn Forte 
2869*fcf3ce44SJohn Forte 	if (lock) {
2870*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_RINGTX_LOCK);
2871*fcf3ce44SJohn Forte 	}
2872*fcf3ce44SJohn Forte 	return (iocbq);
2873*fcf3ce44SJohn Forte 
2874*fcf3ce44SJohn Forte } /* emlxs_tx_get() */
2875*fcf3ce44SJohn Forte 
2876*fcf3ce44SJohn Forte 
2877*fcf3ce44SJohn Forte 
2878*fcf3ce44SJohn Forte extern uint32_t
2879*fcf3ce44SJohn Forte emlxs_chipq_node_flush(emlxs_port_t *port, RING *ring,
2880*fcf3ce44SJohn Forte     NODELIST *ndlp, emlxs_buf_t *fpkt)
2881*fcf3ce44SJohn Forte {
2882*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2883*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2884*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2885*fcf3ce44SJohn Forte 	IOCBQ *next;
2886*fcf3ce44SJohn Forte 	Q abort;
2887*fcf3ce44SJohn Forte 	RING *rp;
2888*fcf3ce44SJohn Forte 	uint32_t ringno;
2889*fcf3ce44SJohn Forte 	uint8_t flag[MAX_RINGS];
2890*fcf3ce44SJohn Forte 	uint32_t iotag;
2891*fcf3ce44SJohn Forte 
2892*fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
2893*fcf3ce44SJohn Forte 	bzero((void *)flag, sizeof (flag));
2894*fcf3ce44SJohn Forte 
2895*fcf3ce44SJohn Forte 	for (ringno = 0; ringno < hba->ring_count; ringno++) {
2896*fcf3ce44SJohn Forte 		rp = &hba->ring[ringno];
2897*fcf3ce44SJohn Forte 
2898*fcf3ce44SJohn Forte 		if (ring && rp != ring) {
2899*fcf3ce44SJohn Forte 			continue;
2900*fcf3ce44SJohn Forte 		}
2901*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_FCTAB_LOCK(ringno));
2902*fcf3ce44SJohn Forte 
2903*fcf3ce44SJohn Forte 		for (iotag = 1; iotag < rp->max_iotag; iotag++) {
2904*fcf3ce44SJohn Forte 			sbp = rp->fc_table[iotag];
2905*fcf3ce44SJohn Forte 
2906*fcf3ce44SJohn Forte 			if (sbp && (sbp != STALE_PACKET) &&
2907*fcf3ce44SJohn Forte 			    (sbp->pkt_flags & PACKET_IN_CHIPQ) &&
2908*fcf3ce44SJohn Forte 			    (sbp->node == ndlp) &&
2909*fcf3ce44SJohn Forte 			    (sbp->ring == rp) &&
2910*fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
2911*fcf3ce44SJohn Forte 				emlxs_sbp_abort_add(port, sbp, &abort,
2912*fcf3ce44SJohn Forte 				    flag, fpkt);
2913*fcf3ce44SJohn Forte 			}
2914*fcf3ce44SJohn Forte 		}
2915*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_FCTAB_LOCK(ringno));
2916*fcf3ce44SJohn Forte 
2917*fcf3ce44SJohn Forte 	}	/* for */
2918*fcf3ce44SJohn Forte 
2919*fcf3ce44SJohn Forte 	/* Now put the iocb's on the tx queue */
2920*fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2921*fcf3ce44SJohn Forte 	while (iocbq) {
2922*fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2923*fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2924*fcf3ce44SJohn Forte 
2925*fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2926*fcf3ce44SJohn Forte 		iocbq->next = NULL;
2927*fcf3ce44SJohn Forte 
2928*fcf3ce44SJohn Forte 		/* Send this iocbq */
2929*fcf3ce44SJohn Forte 		emlxs_tx_put(iocbq, 1);
2930*fcf3ce44SJohn Forte 
2931*fcf3ce44SJohn Forte 		iocbq = next;
2932*fcf3ce44SJohn Forte 	}
2933*fcf3ce44SJohn Forte 
2934*fcf3ce44SJohn Forte 	/* Now trigger ring service */
2935*fcf3ce44SJohn Forte 	for (ringno = 0; ringno < hba->ring_count; ringno++) {
2936*fcf3ce44SJohn Forte 		if (!flag[ringno]) {
2937*fcf3ce44SJohn Forte 			continue;
2938*fcf3ce44SJohn Forte 		}
2939*fcf3ce44SJohn Forte 		rp = &hba->ring[ringno];
2940*fcf3ce44SJohn Forte 
2941*fcf3ce44SJohn Forte 		emlxs_issue_iocb_cmd(hba, rp, 0);
2942*fcf3ce44SJohn Forte 	}
2943*fcf3ce44SJohn Forte 
2944*fcf3ce44SJohn Forte 	return (abort.q_cnt);
2945*fcf3ce44SJohn Forte 
2946*fcf3ce44SJohn Forte } /* emlxs_chipq_node_flush() */
2947*fcf3ce44SJohn Forte 
2948*fcf3ce44SJohn Forte 
2949*fcf3ce44SJohn Forte /* Flush all IO's left on all iotag lists */
2950*fcf3ce44SJohn Forte static uint32_t
2951*fcf3ce44SJohn Forte emlxs_iotag_flush(emlxs_hba_t *hba)
2952*fcf3ce44SJohn Forte {
2953*fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2954*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2955*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2956*fcf3ce44SJohn Forte 	IOCB *iocb;
2957*fcf3ce44SJohn Forte 	Q abort;
2958*fcf3ce44SJohn Forte 	RING *rp;
2959*fcf3ce44SJohn Forte 	uint32_t ringno;
2960*fcf3ce44SJohn Forte 	uint32_t iotag;
2961*fcf3ce44SJohn Forte 	uint32_t count;
2962*fcf3ce44SJohn Forte 
2963*fcf3ce44SJohn Forte 	count = 0;
2964*fcf3ce44SJohn Forte 	for (ringno = 0; ringno < hba->ring_count; ringno++) {
2965*fcf3ce44SJohn Forte 		rp = &hba->ring[ringno];
2966*fcf3ce44SJohn Forte 
2967*fcf3ce44SJohn Forte 		bzero((void *)&abort, sizeof (Q));
2968*fcf3ce44SJohn Forte 
2969*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_FCTAB_LOCK(ringno));
2970*fcf3ce44SJohn Forte 
2971*fcf3ce44SJohn Forte 		for (iotag = 1; iotag < rp->max_iotag; iotag++) {
2972*fcf3ce44SJohn Forte 			sbp = rp->fc_table[iotag];
2973*fcf3ce44SJohn Forte 
2974*fcf3ce44SJohn Forte 			if (!sbp || (sbp == STALE_PACKET)) {
2975*fcf3ce44SJohn Forte 				continue;
2976*fcf3ce44SJohn Forte 			}
2977*fcf3ce44SJohn Forte 			/* Unregister the packet */
2978*fcf3ce44SJohn Forte 			rp->fc_table[iotag] = STALE_PACKET;
2979*fcf3ce44SJohn Forte 			hba->io_count[ringno]--;
2980*fcf3ce44SJohn Forte 			sbp->iotag = 0;
2981*fcf3ce44SJohn Forte 
2982*fcf3ce44SJohn Forte 			/* Clean up the sbp */
2983*fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2984*fcf3ce44SJohn Forte 
2985*fcf3ce44SJohn Forte 			/* Set IOCB status */
2986*fcf3ce44SJohn Forte 			iocbq = &sbp->iocbq;
2987*fcf3ce44SJohn Forte 			iocb = &iocbq->iocb;
2988*fcf3ce44SJohn Forte 
2989*fcf3ce44SJohn Forte 			iocb->ulpStatus = IOSTAT_LOCAL_REJECT;
2990*fcf3ce44SJohn Forte 			iocb->un.grsp.perr.statLocalError = IOERR_LINK_DOWN;
2991*fcf3ce44SJohn Forte 			iocb->ulpLe = 1;
2992*fcf3ce44SJohn Forte 			iocbq->next = NULL;
2993*fcf3ce44SJohn Forte 
2994*fcf3ce44SJohn Forte 			if (sbp->pkt_flags & PACKET_IN_TXQ) {
2995*fcf3ce44SJohn Forte 				sbp->pkt_flags &= ~PACKET_IN_TXQ;
2996*fcf3ce44SJohn Forte 				hba->ring_tx_count[ringno]--;
2997*fcf3ce44SJohn Forte 			}
2998*fcf3ce44SJohn Forte 			if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
2999*fcf3ce44SJohn Forte 				sbp->pkt_flags &= ~PACKET_IN_CHIPQ;
3000*fcf3ce44SJohn Forte 			}
3001*fcf3ce44SJohn Forte 			if (sbp->bmp) {
3002*fcf3ce44SJohn Forte 				(void) emlxs_mem_put(hba, MEM_BPL,
3003*fcf3ce44SJohn Forte 				    (uint8_t *)sbp->bmp);
3004*fcf3ce44SJohn Forte 				sbp->bmp = 0;
3005*fcf3ce44SJohn Forte 			}
3006*fcf3ce44SJohn Forte 			/* At this point all nodes are assumed destroyed */
3007*fcf3ce44SJohn Forte 			sbp->node = 0;
3008*fcf3ce44SJohn Forte 
3009*fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3010*fcf3ce44SJohn Forte 
3011*fcf3ce44SJohn Forte 			/* Add this iocb to our local abort Q */
3012*fcf3ce44SJohn Forte 			if (abort.q_first) {
3013*fcf3ce44SJohn Forte 				((IOCBQ *) abort.q_last)->next = iocbq;
3014*fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
3015*fcf3ce44SJohn Forte 				abort.q_cnt++;
3016*fcf3ce44SJohn Forte 			} else {
3017*fcf3ce44SJohn Forte 				abort.q_first = (uint8_t *)iocbq;
3018*fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
3019*fcf3ce44SJohn Forte 				abort.q_cnt = 1;
3020*fcf3ce44SJohn Forte 			}
3021*fcf3ce44SJohn Forte 		}
3022*fcf3ce44SJohn Forte 
3023*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_FCTAB_LOCK(ringno));
3024*fcf3ce44SJohn Forte 
3025*fcf3ce44SJohn Forte 		/* Trigger deferred completion */
3026*fcf3ce44SJohn Forte 		if (abort.q_first) {
3027*fcf3ce44SJohn Forte 			mutex_enter(&rp->rsp_lock);
3028*fcf3ce44SJohn Forte 			if (rp->rsp_head == NULL) {
3029*fcf3ce44SJohn Forte 				rp->rsp_head = (IOCBQ *)abort.q_first;
3030*fcf3ce44SJohn Forte 				rp->rsp_tail = (IOCBQ *)abort.q_last;
3031*fcf3ce44SJohn Forte 			} else {
3032*fcf3ce44SJohn Forte 				rp->rsp_tail->next = (IOCBQ *)abort.q_first;
3033*fcf3ce44SJohn Forte 				rp->rsp_tail = (IOCBQ *)abort.q_last;
3034*fcf3ce44SJohn Forte 			}
3035*fcf3ce44SJohn Forte 			mutex_exit(&rp->rsp_lock);
3036*fcf3ce44SJohn Forte 
3037*fcf3ce44SJohn Forte 			emlxs_thread_trigger2(&rp->intr_thread,
3038*fcf3ce44SJohn Forte 			    emlxs_proc_ring, rp);
3039*fcf3ce44SJohn Forte 
3040*fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
3041*fcf3ce44SJohn Forte 			    "Forced iotag completion. ring=%d count=%d",
3042*fcf3ce44SJohn Forte 			    ringno, abort.q_cnt);
3043*fcf3ce44SJohn Forte 
3044*fcf3ce44SJohn Forte 			count += abort.q_cnt;
3045*fcf3ce44SJohn Forte 		}
3046*fcf3ce44SJohn Forte 	}
3047*fcf3ce44SJohn Forte 
3048*fcf3ce44SJohn Forte 	return (count);
3049*fcf3ce44SJohn Forte 
3050*fcf3ce44SJohn Forte } /* emlxs_iotag_flush() */
3051*fcf3ce44SJohn Forte 
3052*fcf3ce44SJohn Forte 
3053*fcf3ce44SJohn Forte 
3054*fcf3ce44SJohn Forte /* Checks for IO's on all or a given ring for a given node */
3055*fcf3ce44SJohn Forte extern uint32_t
3056*fcf3ce44SJohn Forte emlxs_chipq_node_check(emlxs_port_t *port, RING *ring, NODELIST *ndlp)
3057*fcf3ce44SJohn Forte {
3058*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3059*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3060*fcf3ce44SJohn Forte 	RING *rp;
3061*fcf3ce44SJohn Forte 	uint32_t ringno;
3062*fcf3ce44SJohn Forte 	uint32_t count;
3063*fcf3ce44SJohn Forte 	uint32_t iotag;
3064*fcf3ce44SJohn Forte 
3065*fcf3ce44SJohn Forte 	count = 0;
3066*fcf3ce44SJohn Forte 
3067*fcf3ce44SJohn Forte 	for (ringno = 0; ringno < hba->ring_count; ringno++) {
3068*fcf3ce44SJohn Forte 		rp = &hba->ring[ringno];
3069*fcf3ce44SJohn Forte 
3070*fcf3ce44SJohn Forte 		if (ring && rp != ring) {
3071*fcf3ce44SJohn Forte 			continue;
3072*fcf3ce44SJohn Forte 		}
3073*fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_FCTAB_LOCK(ringno));
3074*fcf3ce44SJohn Forte 
3075*fcf3ce44SJohn Forte 		for (iotag = 1; iotag < rp->max_iotag; iotag++) {
3076*fcf3ce44SJohn Forte 			sbp = rp->fc_table[iotag];
3077*fcf3ce44SJohn Forte 
3078*fcf3ce44SJohn Forte 			if (sbp && (sbp != STALE_PACKET) &&
3079*fcf3ce44SJohn Forte 			    (sbp->pkt_flags & PACKET_IN_CHIPQ) &&
3080*fcf3ce44SJohn Forte 			    (sbp->node == ndlp) &&
3081*fcf3ce44SJohn Forte 			    (sbp->ring == rp) &&
3082*fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
3083*fcf3ce44SJohn Forte 				count++;
3084*fcf3ce44SJohn Forte 			}
3085*fcf3ce44SJohn Forte 		}
3086*fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_FCTAB_LOCK(ringno));
3087*fcf3ce44SJohn Forte 
3088*fcf3ce44SJohn Forte 	}	/* for */
3089*fcf3ce44SJohn Forte 
3090*fcf3ce44SJohn Forte 	return (count);
3091*fcf3ce44SJohn Forte 
3092*fcf3ce44SJohn Forte } /* emlxs_chipq_node_check() */
3093*fcf3ce44SJohn Forte 
3094*fcf3ce44SJohn Forte 
3095*fcf3ce44SJohn Forte 
3096*fcf3ce44SJohn Forte /* Flush all IO's for a given node's lun (FC_FCP_RING only) */
3097*fcf3ce44SJohn Forte extern uint32_t
3098*fcf3ce44SJohn Forte emlxs_chipq_lun_flush(emlxs_port_t *port, NODELIST *ndlp,
3099*fcf3ce44SJohn Forte     uint32_t lun, emlxs_buf_t *fpkt)
3100*fcf3ce44SJohn Forte {
3101*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3102*fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3103*fcf3ce44SJohn Forte 	RING *rp;
3104*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3105*fcf3ce44SJohn Forte 	IOCBQ *next;
3106*fcf3ce44SJohn Forte 	Q abort;
3107*fcf3ce44SJohn Forte 	uint32_t iotag;
3108*fcf3ce44SJohn Forte 	uint8_t flag[MAX_RINGS];
3109*fcf3ce44SJohn Forte 
3110*fcf3ce44SJohn Forte 	bzero((void *)flag, sizeof (flag));
3111*fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
3112*fcf3ce44SJohn Forte 	rp = &hba->ring[FC_FCP_RING];
3113*fcf3ce44SJohn Forte 
3114*fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_FCTAB_LOCK(FC_FCP_RING));
3115*fcf3ce44SJohn Forte 	for (iotag = 1; iotag < rp->max_iotag; iotag++) {
3116*fcf3ce44SJohn Forte 		sbp = rp->fc_table[iotag];
3117*fcf3ce44SJohn Forte 
3118*fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET) &&
3119*fcf3ce44SJohn Forte 		    sbp->pkt_flags & PACKET_IN_CHIPQ &&
3120*fcf3ce44SJohn Forte 		    sbp->node == ndlp &&
3121*fcf3ce44SJohn Forte 		    sbp->ring == rp &&
3122*fcf3ce44SJohn Forte 		    sbp->lun == lun &&
3123*fcf3ce44SJohn Forte 		    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
3124*fcf3ce44SJohn Forte 			emlxs_sbp_abort_add(port, sbp, &abort, flag, fpkt);
3125*fcf3ce44SJohn Forte 		}
3126*fcf3ce44SJohn Forte 	}
3127*fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_FCTAB_LOCK(FC_FCP_RING));
3128*fcf3ce44SJohn Forte 
3129*fcf3ce44SJohn Forte 	/* Now put the iocb's on the tx queue */
3130*fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
3131*fcf3ce44SJohn Forte 	while (iocbq) {
3132*fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
3133*fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
3134*fcf3ce44SJohn Forte 
3135*fcf3ce44SJohn Forte 		/* Unlink this iocbq */
3136*fcf3ce44SJohn Forte 		iocbq->next = NULL;
3137*fcf3ce44SJohn Forte 
3138*fcf3ce44SJohn Forte 		/* Send this iocbq */
3139*fcf3ce44SJohn Forte 		emlxs_tx_put(iocbq, 1);
3140*fcf3ce44SJohn Forte 
3141*fcf3ce44SJohn Forte 		iocbq = next;
3142*fcf3ce44SJohn Forte 	}
3143*fcf3ce44SJohn Forte 
3144*fcf3ce44SJohn Forte 	/* Now trigger ring service */
3145*fcf3ce44SJohn Forte 	if (abort.q_cnt) {
3146*fcf3ce44SJohn Forte 		emlxs_issue_iocb_cmd(hba, rp, 0);
3147*fcf3ce44SJohn Forte 	}
3148*fcf3ce44SJohn Forte 	return (abort.q_cnt);
3149*fcf3ce44SJohn Forte 
3150*fcf3ce44SJohn Forte } /* emlxs_chipq_lun_flush() */
3151*fcf3ce44SJohn Forte 
3152*fcf3ce44SJohn Forte 
3153*fcf3ce44SJohn Forte 
3154*fcf3ce44SJohn Forte /*
3155*fcf3ce44SJohn Forte  * Issue an ABORT_XRI_CN iocb command to abort an FCP command already issued.
3156*fcf3ce44SJohn Forte  * This must be called while holding the EMLXS_FCCTAB_LOCK
3157*fcf3ce44SJohn Forte  */
3158*fcf3ce44SJohn Forte extern IOCBQ *
3159*fcf3ce44SJohn Forte emlxs_create_abort_xri_cn(emlxs_port_t *port, NODELIST *ndlp, uint16_t iotag,
3160*fcf3ce44SJohn Forte     RING *rp, uint8_t class, int32_t flag)
3161*fcf3ce44SJohn Forte {
3162*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3163*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3164*fcf3ce44SJohn Forte 	IOCB *iocb;
3165*fcf3ce44SJohn Forte 	uint16_t abort_iotag;
3166*fcf3ce44SJohn Forte 
3167*fcf3ce44SJohn Forte 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
3168*fcf3ce44SJohn Forte 		return (NULL);
3169*fcf3ce44SJohn Forte 	}
3170*fcf3ce44SJohn Forte 	iocbq->ring = (void *)rp;
3171*fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
3172*fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
3173*fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
3174*fcf3ce44SJohn Forte 	iocb = &iocbq->iocb;
3175*fcf3ce44SJohn Forte 
3176*fcf3ce44SJohn Forte 	/*
3177*fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
3178*fcf3ce44SJohn Forte 	 */
3179*fcf3ce44SJohn Forte 	if ((rp->fc_abort_iotag < rp->max_iotag)) {
3180*fcf3ce44SJohn Forte 		rp->fc_abort_iotag = rp->max_iotag;
3181*fcf3ce44SJohn Forte 	}
3182*fcf3ce44SJohn Forte 	abort_iotag = rp->fc_abort_iotag++;
3183*fcf3ce44SJohn Forte 
3184*fcf3ce44SJohn Forte 
3185*fcf3ce44SJohn Forte 	iocb->ulpIoTag = abort_iotag;
3186*fcf3ce44SJohn Forte 	iocb->un.acxri.abortType = flag;
3187*fcf3ce44SJohn Forte 	iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi;
3188*fcf3ce44SJohn Forte 	iocb->un.acxri.abortIoTag = iotag;
3189*fcf3ce44SJohn Forte 	iocb->ulpLe = 1;
3190*fcf3ce44SJohn Forte 	iocb->ulpClass = class;
3191*fcf3ce44SJohn Forte 	iocb->ulpCommand = CMD_ABORT_XRI_CN;
3192*fcf3ce44SJohn Forte 	iocb->ulpOwner = OWN_CHIP;
3193*fcf3ce44SJohn Forte 
3194*fcf3ce44SJohn Forte 	return (iocbq);
3195*fcf3ce44SJohn Forte 
3196*fcf3ce44SJohn Forte } /* emlxs_create_abort_xri_cn() */
3197*fcf3ce44SJohn Forte 
3198*fcf3ce44SJohn Forte 
3199*fcf3ce44SJohn Forte extern IOCBQ *
3200*fcf3ce44SJohn Forte emlxs_create_abort_xri_cx(emlxs_port_t *port, NODELIST *ndlp, uint16_t xid,
3201*fcf3ce44SJohn Forte     RING *rp, uint8_t class, int32_t flag)
3202*fcf3ce44SJohn Forte {
3203*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3204*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3205*fcf3ce44SJohn Forte 	IOCB *iocb;
3206*fcf3ce44SJohn Forte 	uint16_t abort_iotag;
3207*fcf3ce44SJohn Forte 
3208*fcf3ce44SJohn Forte 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
3209*fcf3ce44SJohn Forte 		return (NULL);
3210*fcf3ce44SJohn Forte 	}
3211*fcf3ce44SJohn Forte 	iocbq->ring = (void *)rp;
3212*fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
3213*fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
3214*fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
3215*fcf3ce44SJohn Forte 	iocb = &iocbq->iocb;
3216*fcf3ce44SJohn Forte 
3217*fcf3ce44SJohn Forte 	/*
3218*fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
3219*fcf3ce44SJohn Forte 	 */
3220*fcf3ce44SJohn Forte 	if ((rp->fc_abort_iotag < rp->max_iotag)) {
3221*fcf3ce44SJohn Forte 		rp->fc_abort_iotag = rp->max_iotag;
3222*fcf3ce44SJohn Forte 	}
3223*fcf3ce44SJohn Forte 	abort_iotag = rp->fc_abort_iotag++;
3224*fcf3ce44SJohn Forte 
3225*fcf3ce44SJohn Forte 	iocb->ulpContext = xid;
3226*fcf3ce44SJohn Forte 	iocb->ulpIoTag = abort_iotag;
3227*fcf3ce44SJohn Forte 	iocb->un.acxri.abortType = flag;
3228*fcf3ce44SJohn Forte 	iocb->ulpLe = 1;
3229*fcf3ce44SJohn Forte 	iocb->ulpClass = class;
3230*fcf3ce44SJohn Forte 	iocb->ulpCommand = CMD_ABORT_XRI_CX;
3231*fcf3ce44SJohn Forte 	iocb->ulpOwner = OWN_CHIP;
3232*fcf3ce44SJohn Forte 
3233*fcf3ce44SJohn Forte 	return (iocbq);
3234*fcf3ce44SJohn Forte 
3235*fcf3ce44SJohn Forte } /* emlxs_create_abort_xri_cx() */
3236*fcf3ce44SJohn Forte 
3237*fcf3ce44SJohn Forte 
3238*fcf3ce44SJohn Forte 
3239*fcf3ce44SJohn Forte /* This must be called while holding the EMLXS_FCCTAB_LOCK */
3240*fcf3ce44SJohn Forte extern IOCBQ *
3241*fcf3ce44SJohn Forte emlxs_create_close_xri_cn(emlxs_port_t *port, NODELIST *ndlp,
3242*fcf3ce44SJohn Forte     uint16_t iotag, RING *rp)
3243*fcf3ce44SJohn Forte {
3244*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3245*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3246*fcf3ce44SJohn Forte 	IOCB *iocb;
3247*fcf3ce44SJohn Forte 	uint16_t abort_iotag;
3248*fcf3ce44SJohn Forte 
3249*fcf3ce44SJohn Forte 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
3250*fcf3ce44SJohn Forte 		return (NULL);
3251*fcf3ce44SJohn Forte 	}
3252*fcf3ce44SJohn Forte 	iocbq->ring = (void *)rp;
3253*fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
3254*fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
3255*fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
3256*fcf3ce44SJohn Forte 	iocb = &iocbq->iocb;
3257*fcf3ce44SJohn Forte 
3258*fcf3ce44SJohn Forte 	/*
3259*fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
3260*fcf3ce44SJohn Forte 	 */
3261*fcf3ce44SJohn Forte 	if ((rp->fc_abort_iotag < rp->max_iotag)) {
3262*fcf3ce44SJohn Forte 		rp->fc_abort_iotag = rp->max_iotag;
3263*fcf3ce44SJohn Forte 	}
3264*fcf3ce44SJohn Forte 	abort_iotag = rp->fc_abort_iotag++;
3265*fcf3ce44SJohn Forte 
3266*fcf3ce44SJohn Forte 	iocb->ulpIoTag = abort_iotag;
3267*fcf3ce44SJohn Forte 	iocb->un.acxri.abortType = 0;
3268*fcf3ce44SJohn Forte 	iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi;
3269*fcf3ce44SJohn Forte 	iocb->un.acxri.abortIoTag = iotag;
3270*fcf3ce44SJohn Forte 	iocb->ulpLe = 1;
3271*fcf3ce44SJohn Forte 	iocb->ulpClass = 0;
3272*fcf3ce44SJohn Forte 	iocb->ulpCommand = CMD_CLOSE_XRI_CN;
3273*fcf3ce44SJohn Forte 	iocb->ulpOwner = OWN_CHIP;
3274*fcf3ce44SJohn Forte 
3275*fcf3ce44SJohn Forte 	return (iocbq);
3276*fcf3ce44SJohn Forte 
3277*fcf3ce44SJohn Forte } /* emlxs_create_close_xri_cn() */
3278*fcf3ce44SJohn Forte 
3279*fcf3ce44SJohn Forte 
3280*fcf3ce44SJohn Forte /* This must be called while holding the EMLXS_FCCTAB_LOCK */
3281*fcf3ce44SJohn Forte extern IOCBQ *
3282*fcf3ce44SJohn Forte emlxs_create_close_xri_cx(emlxs_port_t *port, NODELIST *ndlp,
3283*fcf3ce44SJohn Forte     uint16_t xid, RING *rp)
3284*fcf3ce44SJohn Forte {
3285*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3286*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3287*fcf3ce44SJohn Forte 	IOCB *iocb;
3288*fcf3ce44SJohn Forte 	uint16_t abort_iotag;
3289*fcf3ce44SJohn Forte 
3290*fcf3ce44SJohn Forte 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
3291*fcf3ce44SJohn Forte 		return (NULL);
3292*fcf3ce44SJohn Forte 	}
3293*fcf3ce44SJohn Forte 	iocbq->ring = (void *)rp;
3294*fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
3295*fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
3296*fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
3297*fcf3ce44SJohn Forte 	iocb = &iocbq->iocb;
3298*fcf3ce44SJohn Forte 
3299*fcf3ce44SJohn Forte 	/*
3300*fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
3301*fcf3ce44SJohn Forte 	 */
3302*fcf3ce44SJohn Forte 	if ((rp->fc_abort_iotag < rp->max_iotag)) {
3303*fcf3ce44SJohn Forte 		rp->fc_abort_iotag = rp->max_iotag;
3304*fcf3ce44SJohn Forte 	}
3305*fcf3ce44SJohn Forte 	abort_iotag = rp->fc_abort_iotag++;
3306*fcf3ce44SJohn Forte 
3307*fcf3ce44SJohn Forte 	iocb->ulpContext = xid;
3308*fcf3ce44SJohn Forte 	iocb->ulpIoTag = abort_iotag;
3309*fcf3ce44SJohn Forte 	iocb->ulpLe = 1;
3310*fcf3ce44SJohn Forte 	iocb->ulpClass = 0;
3311*fcf3ce44SJohn Forte 	iocb->ulpCommand = CMD_CLOSE_XRI_CX;
3312*fcf3ce44SJohn Forte 	iocb->ulpOwner = OWN_CHIP;
3313*fcf3ce44SJohn Forte 
3314*fcf3ce44SJohn Forte 	return (iocbq);
3315*fcf3ce44SJohn Forte 
3316*fcf3ce44SJohn Forte } /* emlxs_create_close_xri_cx() */
3317*fcf3ce44SJohn Forte 
3318*fcf3ce44SJohn Forte 
3319*fcf3ce44SJohn Forte 
3320*fcf3ce44SJohn Forte /* This must be called while holding the EMLXS_FCCTAB_LOCK */
3321*fcf3ce44SJohn Forte static void
3322*fcf3ce44SJohn Forte emlxs_sbp_abort_add(emlxs_port_t *port, emlxs_buf_t *sbp, Q *abort,
3323*fcf3ce44SJohn Forte     uint8_t *flag, emlxs_buf_t *fpkt)
3324*fcf3ce44SJohn Forte {
3325*fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3326*fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3327*fcf3ce44SJohn Forte 	RING *rp;
3328*fcf3ce44SJohn Forte 	NODELIST *ndlp;
3329*fcf3ce44SJohn Forte 
3330*fcf3ce44SJohn Forte 	rp = (RING *)sbp->ring;
3331*fcf3ce44SJohn Forte 	ndlp = sbp->node;
3332*fcf3ce44SJohn Forte 
3333*fcf3ce44SJohn Forte 	/* Create the close XRI IOCB */
3334*fcf3ce44SJohn Forte 	iocbq = emlxs_create_close_xri_cn(port, ndlp, sbp->iotag, rp);
3335*fcf3ce44SJohn Forte 
3336*fcf3ce44SJohn Forte 	/* Add this iocb to our local abort Q */
3337*fcf3ce44SJohn Forte 	/* This way we don't hold the CHIPQ lock too long */
3338*fcf3ce44SJohn Forte 	if (iocbq) {
3339*fcf3ce44SJohn Forte 		if (abort->q_first) {
3340*fcf3ce44SJohn Forte 			((IOCBQ *) abort->q_last)->next = iocbq;
3341*fcf3ce44SJohn Forte 			abort->q_last = (uint8_t *)iocbq;
3342*fcf3ce44SJohn Forte 			abort->q_cnt++;
3343*fcf3ce44SJohn Forte 		} else {
3344*fcf3ce44SJohn Forte 			abort->q_first = (uint8_t *)iocbq;
3345*fcf3ce44SJohn Forte 			abort->q_last = (uint8_t *)iocbq;
3346*fcf3ce44SJohn Forte 			abort->q_cnt = 1;
3347*fcf3ce44SJohn Forte 		}
3348*fcf3ce44SJohn Forte 		iocbq->next = NULL;
3349*fcf3ce44SJohn Forte 	}
3350*fcf3ce44SJohn Forte 	/* set the flags */
3351*fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
3352*fcf3ce44SJohn Forte 
3353*fcf3ce44SJohn Forte 	sbp->pkt_flags |= (PACKET_IN_FLUSH | PACKET_XRI_CLOSED);
3354*fcf3ce44SJohn Forte 	sbp->ticks = hba->timer_tics + 10;
3355*fcf3ce44SJohn Forte 	sbp->abort_attempts++;
3356*fcf3ce44SJohn Forte 
3357*fcf3ce44SJohn Forte 	flag[rp->ringno] = 1;
3358*fcf3ce44SJohn Forte 
3359*fcf3ce44SJohn Forte 	/* If the fpkt is already set, then we will leave it alone */
3360*fcf3ce44SJohn Forte 	/*
3361*fcf3ce44SJohn Forte 	 * This ensures that this pkt is only accounted for on one
3362*fcf3ce44SJohn Forte 	 * fpkt->flush_count
3363*fcf3ce44SJohn Forte 	 */
3364*fcf3ce44SJohn Forte 	if (!sbp->fpkt && fpkt) {
3365*fcf3ce44SJohn Forte 		mutex_enter(&fpkt->mtx);
3366*fcf3ce44SJohn Forte 		sbp->fpkt = fpkt;
3367*fcf3ce44SJohn Forte 		fpkt->flush_count++;
3368*fcf3ce44SJohn Forte 		mutex_exit(&fpkt->mtx);
3369*fcf3ce44SJohn Forte 	}
3370*fcf3ce44SJohn Forte 	mutex_exit(&sbp->mtx);
3371*fcf3ce44SJohn Forte 
3372*fcf3ce44SJohn Forte 	return;
3373*fcf3ce44SJohn Forte 
3374*fcf3ce44SJohn Forte } /* emlxs_sbp_abort_add() */
3375