1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte 
22fcf3ce44SJohn Forte /*
23*a9800bebSGarrett D'Amore  * Copyright 2011 Emulex.  All rights reserved.
2482527734SSukumar Swaminathan  * Use is subject to license terms.
25fcf3ce44SJohn Forte  */
26fcf3ce44SJohn Forte 
2782527734SSukumar Swaminathan 
28291a2b48SSukumar Swaminathan #include <emlxs.h>
29fcf3ce44SJohn Forte 
30fcf3ce44SJohn Forte /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
31fcf3ce44SJohn Forte EMLXS_MSG_DEF(EMLXS_FCP_C);
32fcf3ce44SJohn Forte 
33fcf3ce44SJohn Forte #define	EMLXS_GET_VADDR(hba, rp, icmd) emlxs_mem_get_vaddr(hba, rp, \
3482527734SSukumar Swaminathan 	PADDR(icmd->un.cont64[i].addrHigh, icmd->un.cont64[i].addrLow));
35fcf3ce44SJohn Forte 
36291a2b48SSukumar Swaminathan static void	emlxs_sbp_abort_add(emlxs_port_t *port, emlxs_buf_t *sbp,
37291a2b48SSukumar Swaminathan     Q *abort, uint8_t *flag, emlxs_buf_t *fpkt);
38fcf3ce44SJohn Forte 
39fcf3ce44SJohn Forte #define	SCSI3_PERSISTENT_RESERVE_IN	0x5e
40291a2b48SSukumar Swaminathan #define	SCSI_INQUIRY			0x12
41291a2b48SSukumar Swaminathan #define	SCSI_RX_DIAG    		0x1C
42fcf3ce44SJohn Forte 
43fcf3ce44SJohn Forte 
44fcf3ce44SJohn Forte /*
45fcf3ce44SJohn Forte  *  emlxs_handle_fcp_event
46fcf3ce44SJohn Forte  *
47fcf3ce44SJohn Forte  *  Description: Process an FCP Rsp Ring completion
48fcf3ce44SJohn Forte  *
49fcf3ce44SJohn Forte  */
50fcf3ce44SJohn Forte /* ARGSUSED */
51fcf3ce44SJohn Forte extern void
5282527734SSukumar Swaminathan emlxs_handle_fcp_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
53fcf3ce44SJohn Forte {
54fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
5582527734SSukumar Swaminathan 	emlxs_config_t	*cfg = &CFG;
56fcf3ce44SJohn Forte 	IOCB *cmd;
57fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
58fcf3ce44SJohn Forte 	fc_packet_t *pkt = NULL;
59291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
60291a2b48SSukumar Swaminathan 	NODELIST *ndlp;
61291a2b48SSukumar Swaminathan #endif
62fcf3ce44SJohn Forte 	uint32_t iostat;
63fcf3ce44SJohn Forte 	uint8_t localstat;
64fcf3ce44SJohn Forte 	fcp_rsp_t *rsp;
65fcf3ce44SJohn Forte 	uint32_t rsp_data_resid;
66fcf3ce44SJohn Forte 	uint32_t check_underrun;
67fcf3ce44SJohn Forte 	uint8_t asc;
68fcf3ce44SJohn Forte 	uint8_t ascq;
69fcf3ce44SJohn Forte 	uint8_t scsi_status;
70fcf3ce44SJohn Forte 	uint8_t sense;
71fcf3ce44SJohn Forte 	uint32_t did;
72fcf3ce44SJohn Forte 	uint32_t fix_it;
73fcf3ce44SJohn Forte 	uint8_t *scsi_cmd;
74fcf3ce44SJohn Forte 	uint8_t scsi_opcode;
75fcf3ce44SJohn Forte 	uint16_t scsi_dl;
76fcf3ce44SJohn Forte 	uint32_t data_rx;
77fcf3ce44SJohn Forte 
78fcf3ce44SJohn Forte 	cmd = &iocbq->iocb;
79fcf3ce44SJohn Forte 
80fcf3ce44SJohn Forte 	/* Initialize the status */
8182527734SSukumar Swaminathan 	iostat = cmd->ULPSTATUS;
82fcf3ce44SJohn Forte 	localstat = 0;
83fcf3ce44SJohn Forte 	scsi_status = 0;
84fcf3ce44SJohn Forte 	asc = 0;
85fcf3ce44SJohn Forte 	ascq = 0;
86fcf3ce44SJohn Forte 	sense = 0;
87fcf3ce44SJohn Forte 	check_underrun = 0;
88fcf3ce44SJohn Forte 	fix_it = 0;
89fcf3ce44SJohn Forte 
90fcf3ce44SJohn Forte 	HBASTATS.FcpEvent++;
91fcf3ce44SJohn Forte 
92fcf3ce44SJohn Forte 	sbp = (emlxs_buf_t *)iocbq->sbp;
93fcf3ce44SJohn Forte 
94fcf3ce44SJohn Forte 	if (!sbp) {
95fcf3ce44SJohn Forte 		/* completion with missing xmit command */
96fcf3ce44SJohn Forte 		HBASTATS.FcpStray++;
97fcf3ce44SJohn Forte 
98fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_fcp_completion_msg,
9982527734SSukumar Swaminathan 		    "cmd=%x iotag=%x", cmd->ULPCOMMAND, cmd->ULPIOTAG);
100fcf3ce44SJohn Forte 
101fcf3ce44SJohn Forte 		return;
102fcf3ce44SJohn Forte 	}
103291a2b48SSukumar Swaminathan 
104fcf3ce44SJohn Forte 	HBASTATS.FcpCompleted++;
105fcf3ce44SJohn Forte 
106291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
107291a2b48SSukumar Swaminathan 	emlxs_update_sd_bucket(sbp);
108291a2b48SSukumar Swaminathan #endif /* SAN_DIAG_SUPPORT */
109291a2b48SSukumar Swaminathan 
110fcf3ce44SJohn Forte 	pkt = PRIV2PKT(sbp);
111fcf3ce44SJohn Forte 
11282527734SSukumar Swaminathan 	did = LE_SWAP24_LO(pkt->pkt_cmd_fhdr.d_id);
113fcf3ce44SJohn Forte 	scsi_cmd = (uint8_t *)pkt->pkt_cmd;
114fcf3ce44SJohn Forte 	scsi_opcode = scsi_cmd[12];
115fcf3ce44SJohn Forte 	data_rx = 0;
116fcf3ce44SJohn Forte 
117fcf3ce44SJohn Forte 	/* Sync data in data buffer only on FC_PKT_FCP_READ */
118fcf3ce44SJohn Forte 	if (pkt->pkt_datalen && (pkt->pkt_tran_type == FC_PKT_FCP_READ)) {
11982527734SSukumar Swaminathan 		EMLXS_MPDATA_SYNC(pkt->pkt_data_dma, 0, pkt->pkt_datalen,
120fcf3ce44SJohn Forte 		    DDI_DMA_SYNC_FORKERNEL);
121fcf3ce44SJohn Forte 
122fcf3ce44SJohn Forte #ifdef TEST_SUPPORT
123fcf3ce44SJohn Forte 		if (hba->underrun_counter && (iostat == IOSTAT_SUCCESS) &&
124fcf3ce44SJohn Forte 		    (pkt->pkt_datalen >= 512)) {
125fcf3ce44SJohn Forte 			hba->underrun_counter--;
126fcf3ce44SJohn Forte 			iostat = IOSTAT_FCP_RSP_ERROR;
127fcf3ce44SJohn Forte 
128fcf3ce44SJohn Forte 			/* Report 512 bytes missing by adapter */
129fcf3ce44SJohn Forte 			cmd->un.fcpi.fcpi_parm = pkt->pkt_datalen - 512;
130fcf3ce44SJohn Forte 
131fcf3ce44SJohn Forte 			/* Corrupt 512 bytes of Data buffer */
132fcf3ce44SJohn Forte 			bzero((uint8_t *)pkt->pkt_data, 512);
133fcf3ce44SJohn Forte 
134fcf3ce44SJohn Forte 			/* Set FCP response to STATUS_GOOD */
135fcf3ce44SJohn Forte 			bzero((uint8_t *)pkt->pkt_resp, pkt->pkt_rsplen);
136fcf3ce44SJohn Forte 		}
137291a2b48SSukumar Swaminathan #endif /* TEST_SUPPORT */
138fcf3ce44SJohn Forte 	}
139291a2b48SSukumar Swaminathan 
140fcf3ce44SJohn Forte 	/* Process the pkt */
141fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
142fcf3ce44SJohn Forte 
143fcf3ce44SJohn Forte 	/* Check for immediate return */
144fcf3ce44SJohn Forte 	if ((iostat == IOSTAT_SUCCESS) &&
145fcf3ce44SJohn Forte 	    (pkt->pkt_comp) &&
146291a2b48SSukumar Swaminathan 	    !(sbp->pkt_flags &
14782527734SSukumar Swaminathan 	    (PACKET_ULP_OWNED | PACKET_COMPLETED |
148fcf3ce44SJohn Forte 	    PACKET_IN_COMPLETION | PACKET_IN_TXQ | PACKET_IN_CHIPQ |
149fcf3ce44SJohn Forte 	    PACKET_IN_DONEQ | PACKET_IN_TIMEOUT | PACKET_IN_FLUSH |
150fcf3ce44SJohn Forte 	    PACKET_IN_ABORT | PACKET_POLLED))) {
151fcf3ce44SJohn Forte 		HBASTATS.FcpGood++;
152fcf3ce44SJohn Forte 
153291a2b48SSukumar Swaminathan 		sbp->pkt_flags |=
154291a2b48SSukumar Swaminathan 		    (PACKET_STATE_VALID | PACKET_IN_COMPLETION |
15582527734SSukumar Swaminathan 		    PACKET_COMPLETED | PACKET_ULP_OWNED);
156fcf3ce44SJohn Forte 		mutex_exit(&sbp->mtx);
157fcf3ce44SJohn Forte 
158fcf3ce44SJohn Forte #if (EMLXS_MODREVX == EMLXS_MODREV2X)
159fcf3ce44SJohn Forte 		emlxs_unswap_pkt(sbp);
160291a2b48SSukumar Swaminathan #endif /* EMLXS_MODREV2X */
161b3660a96SSukumar Swaminathan 
162b3660a96SSukumar Swaminathan #ifdef FMA_SUPPORT
163b3660a96SSukumar Swaminathan 		emlxs_check_dma(hba, sbp);
164b3660a96SSukumar Swaminathan #endif  /* FMA_SUPPORT */
165b3660a96SSukumar Swaminathan 
16682527734SSukumar Swaminathan 		cp->ulpCmplCmd++;
167fcf3ce44SJohn Forte 		(*pkt->pkt_comp) (pkt);
168fcf3ce44SJohn Forte 
169b3660a96SSukumar Swaminathan #ifdef FMA_SUPPORT
170b3660a96SSukumar Swaminathan 		if (hba->flag & FC_DMA_CHECK_ERROR) {
171b3660a96SSukumar Swaminathan 			emlxs_thread_spawn(hba, emlxs_restart_thread,
172b3660a96SSukumar Swaminathan 			    NULL, NULL);
173b3660a96SSukumar Swaminathan 		}
174b3660a96SSukumar Swaminathan #endif  /* FMA_SUPPORT */
175b3660a96SSukumar Swaminathan 
176fcf3ce44SJohn Forte 		return;
177fcf3ce44SJohn Forte 	}
178291a2b48SSukumar Swaminathan 
179fcf3ce44SJohn Forte 	/*
180291a2b48SSukumar Swaminathan 	 * A response is only placed in the resp buffer if IOSTAT_FCP_RSP_ERROR
181291a2b48SSukumar Swaminathan 	 * is reported.
182fcf3ce44SJohn Forte 	 */
183fcf3ce44SJohn Forte 
184fcf3ce44SJohn Forte 	/* Check if a response buffer was provided */
185fcf3ce44SJohn Forte 	if ((iostat == IOSTAT_FCP_RSP_ERROR) && pkt->pkt_rsplen) {
18682527734SSukumar Swaminathan 		EMLXS_MPDATA_SYNC(pkt->pkt_resp_dma, 0, pkt->pkt_rsplen,
187fcf3ce44SJohn Forte 		    DDI_DMA_SYNC_FORKERNEL);
188fcf3ce44SJohn Forte 
189fcf3ce44SJohn Forte 		/* Get the response buffer pointer */
190fcf3ce44SJohn Forte 		rsp = (fcp_rsp_t *)pkt->pkt_resp;
191fcf3ce44SJohn Forte 
192fcf3ce44SJohn Forte 		/* Set the valid response flag */
193fcf3ce44SJohn Forte 		sbp->pkt_flags |= PACKET_FCP_RSP_VALID;
194fcf3ce44SJohn Forte 
195fcf3ce44SJohn Forte 		scsi_status = rsp->fcp_u.fcp_status.scsi_status;
196fcf3ce44SJohn Forte 
197291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
198291a2b48SSukumar Swaminathan 		ndlp = (NODELIST *)iocbq->node;
199291a2b48SSukumar Swaminathan 		if (scsi_status == SCSI_STAT_QUE_FULL) {
200291a2b48SSukumar Swaminathan 			emlxs_log_sd_scsi_event(port, SD_SCSI_SUBCATEGORY_QFULL,
201291a2b48SSukumar Swaminathan 			    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun);
202291a2b48SSukumar Swaminathan 		} else if (scsi_status == SCSI_STAT_BUSY) {
203291a2b48SSukumar Swaminathan 			emlxs_log_sd_scsi_event(port,
204291a2b48SSukumar Swaminathan 			    SD_SCSI_SUBCATEGORY_DEVBSY,
205291a2b48SSukumar Swaminathan 			    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun);
206291a2b48SSukumar Swaminathan 		}
207291a2b48SSukumar Swaminathan #endif
208291a2b48SSukumar Swaminathan 
209fcf3ce44SJohn Forte 		/*
210fcf3ce44SJohn Forte 		 * Convert a task abort to a check condition with no data
211291a2b48SSukumar Swaminathan 		 * transferred. We saw a data corruption when Solaris received
212291a2b48SSukumar Swaminathan 		 * a Task Abort from a tape.
213fcf3ce44SJohn Forte 		 */
214*a9800bebSGarrett D'Amore 
215fcf3ce44SJohn Forte 		if (scsi_status == SCSI_STAT_TASK_ABORT) {
216fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT,
217fcf3ce44SJohn Forte 			    &emlxs_fcp_completion_error_msg,
218291a2b48SSukumar Swaminathan 			    "Task Abort. "
219291a2b48SSukumar Swaminathan 			    "Fixed.did=0x%06x sbp=%p cmd=%02x dl=%d",
220fcf3ce44SJohn Forte 			    did, sbp, scsi_opcode, pkt->pkt_datalen);
221fcf3ce44SJohn Forte 
222fcf3ce44SJohn Forte 			rsp->fcp_u.fcp_status.scsi_status =
223fcf3ce44SJohn Forte 			    SCSI_STAT_CHECK_COND;
224fcf3ce44SJohn Forte 			rsp->fcp_u.fcp_status.rsp_len_set = 0;
225fcf3ce44SJohn Forte 			rsp->fcp_u.fcp_status.sense_len_set = 0;
226fcf3ce44SJohn Forte 			rsp->fcp_u.fcp_status.resid_over = 0;
227fcf3ce44SJohn Forte 
228fcf3ce44SJohn Forte 			if (pkt->pkt_datalen) {
229fcf3ce44SJohn Forte 				rsp->fcp_u.fcp_status.resid_under = 1;
230291a2b48SSukumar Swaminathan 				rsp->fcp_resid =
23182527734SSukumar Swaminathan 				    LE_SWAP32(pkt->pkt_datalen);
232fcf3ce44SJohn Forte 			} else {
233fcf3ce44SJohn Forte 				rsp->fcp_u.fcp_status.resid_under = 0;
234fcf3ce44SJohn Forte 				rsp->fcp_resid = 0;
235fcf3ce44SJohn Forte 			}
236fcf3ce44SJohn Forte 
237fcf3ce44SJohn Forte 			scsi_status = SCSI_STAT_CHECK_COND;
238fcf3ce44SJohn Forte 		}
239291a2b48SSukumar Swaminathan 
240fcf3ce44SJohn Forte 		/*
241291a2b48SSukumar Swaminathan 		 * We only need to check underrun if data could
242291a2b48SSukumar Swaminathan 		 * have been sent
243fcf3ce44SJohn Forte 		 */
244fcf3ce44SJohn Forte 
245fcf3ce44SJohn Forte 		/* Always check underrun if status is good */
246fcf3ce44SJohn Forte 		if (scsi_status == SCSI_STAT_GOOD) {
247fcf3ce44SJohn Forte 			check_underrun = 1;
248fcf3ce44SJohn Forte 		}
249fcf3ce44SJohn Forte 		/* Check the sense codes if this is a check condition */
250fcf3ce44SJohn Forte 		else if (scsi_status == SCSI_STAT_CHECK_COND) {
251fcf3ce44SJohn Forte 			check_underrun = 1;
252fcf3ce44SJohn Forte 
253fcf3ce44SJohn Forte 			/* Check if sense data was provided */
25482527734SSukumar Swaminathan 			if (LE_SWAP32(rsp->fcp_sense_len) >= 14) {
255fcf3ce44SJohn Forte 				sense = *((uint8_t *)rsp + 32 + 2);
256fcf3ce44SJohn Forte 				asc = *((uint8_t *)rsp + 32 + 12);
257fcf3ce44SJohn Forte 				ascq = *((uint8_t *)rsp + 32 + 13);
258fcf3ce44SJohn Forte 			}
259291a2b48SSukumar Swaminathan 
260291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
261291a2b48SSukumar Swaminathan 			emlxs_log_sd_scsi_check_event(port,
262291a2b48SSukumar Swaminathan 			    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun,
263291a2b48SSukumar Swaminathan 			    scsi_opcode, sense, asc, ascq);
264291a2b48SSukumar Swaminathan #endif
265fcf3ce44SJohn Forte 		}
266fcf3ce44SJohn Forte 		/* Status is not good and this is not a check condition */
267fcf3ce44SJohn Forte 		/* No data should have been sent */
268fcf3ce44SJohn Forte 		else {
269fcf3ce44SJohn Forte 			check_underrun = 0;
270fcf3ce44SJohn Forte 		}
271fcf3ce44SJohn Forte 
272fcf3ce44SJohn Forte 		/* Get the residual underrun count reported by the SCSI reply */
273fcf3ce44SJohn Forte 		rsp_data_resid = (pkt->pkt_datalen &&
27482527734SSukumar Swaminathan 		    rsp->fcp_u.fcp_status.resid_under) ? LE_SWAP32(rsp->
275291a2b48SSukumar Swaminathan 		    fcp_resid) : 0;
276fcf3ce44SJohn Forte 
277fcf3ce44SJohn Forte 		/* Set the pkt resp_resid field */
278fcf3ce44SJohn Forte 		pkt->pkt_resp_resid = 0;
279fcf3ce44SJohn Forte 
280fcf3ce44SJohn Forte 		/* Set the pkt data_resid field */
281fcf3ce44SJohn Forte 		if (pkt->pkt_datalen &&
282fcf3ce44SJohn Forte 		    (pkt->pkt_tran_type == FC_PKT_FCP_READ)) {
283fcf3ce44SJohn Forte 			/*
284291a2b48SSukumar Swaminathan 			 * Get the residual underrun count reported by
285291a2b48SSukumar Swaminathan 			 * our adapter
286fcf3ce44SJohn Forte 			 */
287fcf3ce44SJohn Forte 			pkt->pkt_data_resid = cmd->un.fcpi.fcpi_parm;
288fcf3ce44SJohn Forte 
289291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
290291a2b48SSukumar Swaminathan 			if ((rsp_data_resid == 0) && (pkt->pkt_data_resid)) {
291291a2b48SSukumar Swaminathan 				emlxs_log_sd_fc_rdchk_event(port,
292291a2b48SSukumar Swaminathan 				    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun,
293291a2b48SSukumar Swaminathan 				    scsi_opcode, pkt->pkt_data_resid);
294291a2b48SSukumar Swaminathan 			}
295291a2b48SSukumar Swaminathan #endif
296291a2b48SSukumar Swaminathan 
297fcf3ce44SJohn Forte 			/* Get the actual amount of data transferred */
298fcf3ce44SJohn Forte 			data_rx = pkt->pkt_datalen - pkt->pkt_data_resid;
299fcf3ce44SJohn Forte 
300fcf3ce44SJohn Forte 			/*
301fcf3ce44SJohn Forte 			 * If the residual being reported by the adapter is
302fcf3ce44SJohn Forte 			 * greater than the residual being reported in the
303fcf3ce44SJohn Forte 			 * reply, then we have a true underrun.
304fcf3ce44SJohn Forte 			 */
305fcf3ce44SJohn Forte 			if (check_underrun &&
306fcf3ce44SJohn Forte 			    (pkt->pkt_data_resid > rsp_data_resid)) {
307fcf3ce44SJohn Forte 				switch (scsi_opcode) {
308fcf3ce44SJohn Forte 				case SCSI_INQUIRY:
309fcf3ce44SJohn Forte 					scsi_dl = scsi_cmd[16];
310fcf3ce44SJohn Forte 					break;
311fcf3ce44SJohn Forte 
312fcf3ce44SJohn Forte 				case SCSI_RX_DIAG:
313291a2b48SSukumar Swaminathan 					scsi_dl =
314291a2b48SSukumar Swaminathan 					    (scsi_cmd[15] * 0x100) +
315fcf3ce44SJohn Forte 					    scsi_cmd[16];
316fcf3ce44SJohn Forte 					break;
317fcf3ce44SJohn Forte 
318fcf3ce44SJohn Forte 				default:
319fcf3ce44SJohn Forte 					scsi_dl = pkt->pkt_datalen;
320fcf3ce44SJohn Forte 				}
321fcf3ce44SJohn Forte 
322fcf3ce44SJohn Forte #ifdef FCP_UNDERRUN_PATCH1
32382527734SSukumar Swaminathan if (cfg[CFG_ENABLE_PATCH].current & FCP_UNDERRUN_PATCH1) {
324fcf3ce44SJohn Forte 				/*
325fcf3ce44SJohn Forte 				 * If status is not good and no data was
326291a2b48SSukumar Swaminathan 				 * actually transferred, then we must fix
327291a2b48SSukumar Swaminathan 				 * the issue
328fcf3ce44SJohn Forte 				 */
329fcf3ce44SJohn Forte 				if ((scsi_status != SCSI_STAT_GOOD) &&
330fcf3ce44SJohn Forte 				    (data_rx == 0)) {
331fcf3ce44SJohn Forte 					fix_it = 1;
332fcf3ce44SJohn Forte 
333fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
334fcf3ce44SJohn Forte 					    &emlxs_fcp_completion_error_msg,
335291a2b48SSukumar Swaminathan 					    "Underrun(1). Fixed. "
336291a2b48SSukumar Swaminathan 					    "did=0x%06x sbp=%p cmd=%02x "
337291a2b48SSukumar Swaminathan 					    "dl=%d,%d rx=%d rsp=%d",
338fcf3ce44SJohn Forte 					    did, sbp, scsi_opcode,
339fcf3ce44SJohn Forte 					    pkt->pkt_datalen, scsi_dl,
340fcf3ce44SJohn Forte 					    (pkt->pkt_datalen -
341fcf3ce44SJohn Forte 					    cmd->un.fcpi.fcpi_parm),
342fcf3ce44SJohn Forte 					    rsp_data_resid);
343fcf3ce44SJohn Forte 
344fcf3ce44SJohn Forte 				}
34582527734SSukumar Swaminathan }
346291a2b48SSukumar Swaminathan #endif /* FCP_UNDERRUN_PATCH1 */
347fcf3ce44SJohn Forte 
348fcf3ce44SJohn Forte 
349fcf3ce44SJohn Forte #ifdef FCP_UNDERRUN_PATCH2
35082527734SSukumar Swaminathan if (cfg[CFG_ENABLE_PATCH].current & FCP_UNDERRUN_PATCH2) {
351fcf3ce44SJohn Forte 				if ((scsi_status == SCSI_STAT_GOOD)) {
352291a2b48SSukumar Swaminathan 					emlxs_msg_t	*msg;
353fcf3ce44SJohn Forte 
354fcf3ce44SJohn Forte 					msg = &emlxs_fcp_completion_error_msg;
355fcf3ce44SJohn Forte 					/*
356fcf3ce44SJohn Forte 					 * If status is good and this is an
357fcf3ce44SJohn Forte 					 * inquiry request and the amount of
358fcf3ce44SJohn Forte 					 * data
359fcf3ce44SJohn Forte 					 */
360fcf3ce44SJohn Forte 					/*
361291a2b48SSukumar Swaminathan 					 * requested <= data received, then we
362291a2b48SSukumar Swaminathan 					 * must fix the issue.
363fcf3ce44SJohn Forte 					 */
364fcf3ce44SJohn Forte 
365fcf3ce44SJohn Forte 					if ((scsi_opcode == SCSI_INQUIRY) &&
366fcf3ce44SJohn Forte 					    (pkt->pkt_datalen >= data_rx) &&
367fcf3ce44SJohn Forte 					    (scsi_dl <= data_rx)) {
368fcf3ce44SJohn Forte 						fix_it = 1;
369fcf3ce44SJohn Forte 
370291a2b48SSukumar Swaminathan 						EMLXS_MSGF(EMLXS_CONTEXT, msg,
371fcf3ce44SJohn Forte 						    "Underrun(2). Fixed. "
372fcf3ce44SJohn Forte 						    "did=0x%06x sbp=%p "
373fcf3ce44SJohn Forte 						    "cmd=%02x dl=%d,%d "
374fcf3ce44SJohn Forte 						    "rx=%d rsp=%d",
375fcf3ce44SJohn Forte 						    did, sbp, scsi_opcode,
376fcf3ce44SJohn Forte 						    pkt->pkt_datalen, scsi_dl,
377fcf3ce44SJohn Forte 						    data_rx, rsp_data_resid);
378fcf3ce44SJohn Forte 
379fcf3ce44SJohn Forte 					}
380291a2b48SSukumar Swaminathan 
381fcf3ce44SJohn Forte 					/*
382fcf3ce44SJohn Forte 					 * If status is good and this is an
383fcf3ce44SJohn Forte 					 * inquiry request and the amount of
384291a2b48SSukumar Swaminathan 					 * data requested >= 128 bytes, but
385291a2b48SSukumar Swaminathan 					 * only 128 bytes were received,
386291a2b48SSukumar Swaminathan 					 * then we must fix the issue.
387fcf3ce44SJohn Forte 					 */
388291a2b48SSukumar Swaminathan 					else if ((scsi_opcode ==
389291a2b48SSukumar Swaminathan 					    SCSI_INQUIRY) &&
390fcf3ce44SJohn Forte 					    (pkt->pkt_datalen >= 128) &&
391fcf3ce44SJohn Forte 					    (scsi_dl >= 128) &&
392fcf3ce44SJohn Forte 					    (data_rx == 128)) {
393fcf3ce44SJohn Forte 						fix_it = 1;
394fcf3ce44SJohn Forte 
395291a2b48SSukumar Swaminathan 						EMLXS_MSGF(EMLXS_CONTEXT, msg,
396fcf3ce44SJohn Forte 						    "Underrun(3). Fixed. "
397fcf3ce44SJohn Forte 						    "did=0x%06x sbp=%p "
398291a2b48SSukumar Swaminathan 						    "cmd=%02x dl=%d,%d "
399291a2b48SSukumar Swaminathan 						    "rx=%d rsp=%d",
400fcf3ce44SJohn Forte 						    did, sbp, scsi_opcode,
401fcf3ce44SJohn Forte 						    pkt->pkt_datalen, scsi_dl,
402fcf3ce44SJohn Forte 						    data_rx, rsp_data_resid);
403fcf3ce44SJohn Forte 
404fcf3ce44SJohn Forte 					}
405291a2b48SSukumar Swaminathan 
406fcf3ce44SJohn Forte 				}
40782527734SSukumar Swaminathan }
408291a2b48SSukumar Swaminathan #endif /* FCP_UNDERRUN_PATCH2 */
409fcf3ce44SJohn Forte 
410fcf3ce44SJohn Forte 				/*
411fcf3ce44SJohn Forte 				 * Check if SCSI response payload should be
412291a2b48SSukumar Swaminathan 				 * fixed or if a DATA_UNDERRUN should be
413291a2b48SSukumar Swaminathan 				 * reported
414fcf3ce44SJohn Forte 				 */
415fcf3ce44SJohn Forte 				if (fix_it) {
416fcf3ce44SJohn Forte 					/*
417291a2b48SSukumar Swaminathan 					 * Fix the SCSI response payload itself
418fcf3ce44SJohn Forte 					 */
419fcf3ce44SJohn Forte 					rsp->fcp_u.fcp_status.resid_under = 1;
420fcf3ce44SJohn Forte 					rsp->fcp_resid =
42182527734SSukumar Swaminathan 					    LE_SWAP32(pkt->pkt_data_resid);
422fcf3ce44SJohn Forte 				} else {
423fcf3ce44SJohn Forte 					/*
424fcf3ce44SJohn Forte 					 * Change the status from
425fcf3ce44SJohn Forte 					 * IOSTAT_FCP_RSP_ERROR to
426fcf3ce44SJohn Forte 					 * IOSTAT_DATA_UNDERRUN
427fcf3ce44SJohn Forte 					 */
428fcf3ce44SJohn Forte 					iostat = IOSTAT_DATA_UNDERRUN;
429291a2b48SSukumar Swaminathan 					pkt->pkt_data_resid =
430291a2b48SSukumar Swaminathan 					    pkt->pkt_datalen;
431fcf3ce44SJohn Forte 				}
432fcf3ce44SJohn Forte 			}
433291a2b48SSukumar Swaminathan 
434fcf3ce44SJohn Forte 			/*
435fcf3ce44SJohn Forte 			 * If the residual being reported by the adapter is
436291a2b48SSukumar Swaminathan 			 * less than the residual being reported in the reply,
437291a2b48SSukumar Swaminathan 			 * then we have a true overrun. Since we don't know
438291a2b48SSukumar Swaminathan 			 * where the extra data came from or went to then we
439291a2b48SSukumar Swaminathan 			 * cannot trust anything we received
440fcf3ce44SJohn Forte 			 */
441fcf3ce44SJohn Forte 			else if (rsp_data_resid > pkt->pkt_data_resid) {
442fcf3ce44SJohn Forte 				/*
443fcf3ce44SJohn Forte 				 * Change the status from
444fcf3ce44SJohn Forte 				 * IOSTAT_FCP_RSP_ERROR to
445fcf3ce44SJohn Forte 				 * IOSTAT_DATA_OVERRUN
446fcf3ce44SJohn Forte 				 */
447fcf3ce44SJohn Forte 				iostat = IOSTAT_DATA_OVERRUN;
448fcf3ce44SJohn Forte 				pkt->pkt_data_resid = pkt->pkt_datalen;
449fcf3ce44SJohn Forte 			}
450fcf3ce44SJohn Forte 		} else {	/* pkt->pkt_datalen==0 or FC_PKT_FCP_WRITE */
451291a2b48SSukumar Swaminathan 
452fcf3ce44SJohn Forte 			/* Report whatever the target reported */
453fcf3ce44SJohn Forte 			pkt->pkt_data_resid = rsp_data_resid;
454fcf3ce44SJohn Forte 		}
455fcf3ce44SJohn Forte 	}
456291a2b48SSukumar Swaminathan 
457fcf3ce44SJohn Forte 	/* Print completion message */
458fcf3ce44SJohn Forte 	switch (iostat) {
459fcf3ce44SJohn Forte 	case IOSTAT_SUCCESS:
460fcf3ce44SJohn Forte 		/* Build SCSI GOOD status */
461fcf3ce44SJohn Forte 		if (pkt->pkt_rsplen) {
462fcf3ce44SJohn Forte 			bzero((uint8_t *)pkt->pkt_resp, pkt->pkt_rsplen);
463fcf3ce44SJohn Forte 		}
464fcf3ce44SJohn Forte 		break;
465fcf3ce44SJohn Forte 
466fcf3ce44SJohn Forte 	case IOSTAT_FCP_RSP_ERROR:
467fcf3ce44SJohn Forte 		break;
468fcf3ce44SJohn Forte 
469fcf3ce44SJohn Forte 	case IOSTAT_REMOTE_STOP:
470fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
471291a2b48SSukumar Swaminathan 		    "Remote Stop. did=0x%06x sbp=%p cmd=%02x", did, sbp,
472291a2b48SSukumar Swaminathan 		    scsi_opcode);
473fcf3ce44SJohn Forte 		break;
474fcf3ce44SJohn Forte 
475fcf3ce44SJohn Forte 	case IOSTAT_LOCAL_REJECT:
476fcf3ce44SJohn Forte 		localstat = cmd->un.grsp.perr.statLocalError;
477fcf3ce44SJohn Forte 
478fcf3ce44SJohn Forte 		switch (localstat) {
479fcf3ce44SJohn Forte 		case IOERR_SEQUENCE_TIMEOUT:
480fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT,
481fcf3ce44SJohn Forte 			    &emlxs_fcp_completion_error_msg,
482291a2b48SSukumar Swaminathan 			    "Local reject. "
483291a2b48SSukumar Swaminathan 			    "%s did=0x%06x sbp=%p cmd=%02x tmo=%d ",
484fcf3ce44SJohn Forte 			    emlxs_error_xlate(localstat), did, sbp,
485fcf3ce44SJohn Forte 			    scsi_opcode, pkt->pkt_timeout);
486fcf3ce44SJohn Forte 			break;
487fcf3ce44SJohn Forte 
488fcf3ce44SJohn Forte 		default:
489fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT,
490fcf3ce44SJohn Forte 			    &emlxs_fcp_completion_error_msg,
491*a9800bebSGarrett D'Amore 			    "Local reject. %s 0x%06x %p %02x (%x)(%x)",
492291a2b48SSukumar Swaminathan 			    emlxs_error_xlate(localstat), did, sbp,
493*a9800bebSGarrett D'Amore 			    scsi_opcode, (uint16_t)cmd->ULPIOTAG,
494*a9800bebSGarrett D'Amore 			    (uint16_t)cmd->ULPCONTEXT);
495fcf3ce44SJohn Forte 		}
496fcf3ce44SJohn Forte 
497fcf3ce44SJohn Forte 		break;
498fcf3ce44SJohn Forte 
499fcf3ce44SJohn Forte 	case IOSTAT_NPORT_RJT:
500fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
501291a2b48SSukumar Swaminathan 		    "Nport reject. did=0x%06x sbp=%p cmd=%02x", did, sbp,
502291a2b48SSukumar Swaminathan 		    scsi_opcode);
503fcf3ce44SJohn Forte 		break;
504fcf3ce44SJohn Forte 
505fcf3ce44SJohn Forte 	case IOSTAT_FABRIC_RJT:
506fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
507291a2b48SSukumar Swaminathan 		    "Fabric reject. did=0x%06x sbp=%p cmd=%02x", did, sbp,
508291a2b48SSukumar Swaminathan 		    scsi_opcode);
509fcf3ce44SJohn Forte 		break;
510fcf3ce44SJohn Forte 
511fcf3ce44SJohn Forte 	case IOSTAT_NPORT_BSY:
512291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
513291a2b48SSukumar Swaminathan 		ndlp = (NODELIST *)iocbq->node;
514291a2b48SSukumar Swaminathan 		emlxs_log_sd_fc_bsy_event(port, (HBA_WWN *)&ndlp->nlp_portname);
515291a2b48SSukumar Swaminathan #endif
516291a2b48SSukumar Swaminathan 
517fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
518291a2b48SSukumar Swaminathan 		    "Nport busy. did=0x%06x sbp=%p cmd=%02x", did, sbp,
519291a2b48SSukumar Swaminathan 		    scsi_opcode);
520fcf3ce44SJohn Forte 		break;
521fcf3ce44SJohn Forte 
522fcf3ce44SJohn Forte 	case IOSTAT_FABRIC_BSY:
523291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
524291a2b48SSukumar Swaminathan 		ndlp = (NODELIST *)iocbq->node;
525291a2b48SSukumar Swaminathan 		emlxs_log_sd_fc_bsy_event(port, NULL);
526291a2b48SSukumar Swaminathan #endif
527291a2b48SSukumar Swaminathan 
528fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
529291a2b48SSukumar Swaminathan 		    "Fabric busy. did=0x%06x sbp=%p cmd=%02x", did, sbp,
530291a2b48SSukumar Swaminathan 		    scsi_opcode);
531fcf3ce44SJohn Forte 		break;
532fcf3ce44SJohn Forte 
533fcf3ce44SJohn Forte 	case IOSTAT_INTERMED_RSP:
534fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
535291a2b48SSukumar Swaminathan 		    "Intermediate response. did=0x%06x sbp=%p cmd=%02x", did,
536291a2b48SSukumar Swaminathan 		    sbp, scsi_opcode);
537fcf3ce44SJohn Forte 		break;
538fcf3ce44SJohn Forte 
539fcf3ce44SJohn Forte 	case IOSTAT_LS_RJT:
540fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
541291a2b48SSukumar Swaminathan 		    "LS Reject. did=0x%06x sbp=%p cmd=%02x", did, sbp,
542291a2b48SSukumar Swaminathan 		    scsi_opcode);
543fcf3ce44SJohn Forte 		break;
544fcf3ce44SJohn Forte 
545fcf3ce44SJohn Forte 	case IOSTAT_DATA_UNDERRUN:
546fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
547291a2b48SSukumar Swaminathan 		    "Underrun. did=0x%06x sbp=%p cmd=%02x "
548291a2b48SSukumar Swaminathan 		    "dl=%d,%d rx=%d rsp=%d (%02x,%02x,%02x,%02x)",
549291a2b48SSukumar Swaminathan 		    did, sbp, scsi_opcode, pkt->pkt_datalen, scsi_dl, data_rx,
550291a2b48SSukumar Swaminathan 		    rsp_data_resid, scsi_status, sense, asc, ascq);
551fcf3ce44SJohn Forte 		break;
552fcf3ce44SJohn Forte 
553fcf3ce44SJohn Forte 	case IOSTAT_DATA_OVERRUN:
554fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
555291a2b48SSukumar Swaminathan 		    "Overrun. did=0x%06x sbp=%p cmd=%02x "
556291a2b48SSukumar Swaminathan 		    "dl=%d,%d rx=%d rsp=%d (%02x,%02x,%02x,%02x)",
557291a2b48SSukumar Swaminathan 		    did, sbp, scsi_opcode, pkt->pkt_datalen, scsi_dl, data_rx,
558291a2b48SSukumar Swaminathan 		    rsp_data_resid, scsi_status, sense, asc, ascq);
559fcf3ce44SJohn Forte 		break;
560fcf3ce44SJohn Forte 
561fcf3ce44SJohn Forte 	default:
562fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
563fcf3ce44SJohn Forte 		    "Unknown status=%x reason=%x did=0x%06x sbp=%p cmd=%02x",
564291a2b48SSukumar Swaminathan 		    iostat, cmd->un.grsp.perr.statLocalError, did, sbp,
565291a2b48SSukumar Swaminathan 		    scsi_opcode);
566fcf3ce44SJohn Forte 		break;
567fcf3ce44SJohn Forte 	}
568fcf3ce44SJohn Forte 
569fcf3ce44SJohn Forte done:
570fcf3ce44SJohn Forte 
571fcf3ce44SJohn Forte 	if (iostat == IOSTAT_SUCCESS) {
572fcf3ce44SJohn Forte 		HBASTATS.FcpGood++;
573fcf3ce44SJohn Forte 	} else {
574fcf3ce44SJohn Forte 		HBASTATS.FcpError++;
575fcf3ce44SJohn Forte 	}
576fcf3ce44SJohn Forte 
577fcf3ce44SJohn Forte 	mutex_exit(&sbp->mtx);
578fcf3ce44SJohn Forte 
579fcf3ce44SJohn Forte 	emlxs_pkt_complete(sbp, iostat, localstat, 0);
580fcf3ce44SJohn Forte 
581fcf3ce44SJohn Forte 	return;
582fcf3ce44SJohn Forte 
58382527734SSukumar Swaminathan } /* emlxs_handle_fcp_event() */
584fcf3ce44SJohn Forte 
585fcf3ce44SJohn Forte 
586fcf3ce44SJohn Forte 
587fcf3ce44SJohn Forte /*
588fcf3ce44SJohn Forte  *  emlxs_post_buffer
589fcf3ce44SJohn Forte  *
590fcf3ce44SJohn Forte  *  This routine will post count buffers to the
591fcf3ce44SJohn Forte  *  ring with the QUE_RING_BUF_CN command. This
592fcf3ce44SJohn Forte  *  allows 2 buffers / command to be posted.
593fcf3ce44SJohn Forte  *  Returns the number of buffers NOT posted.
594fcf3ce44SJohn Forte  */
59582527734SSukumar Swaminathan /* SLI3 */
596fcf3ce44SJohn Forte extern int
597fcf3ce44SJohn Forte emlxs_post_buffer(emlxs_hba_t *hba, RING *rp, int16_t cnt)
598fcf3ce44SJohn Forte {
599fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
600fcf3ce44SJohn Forte 	IOCB *icmd;
601fcf3ce44SJohn Forte 	IOCBQ *iocbq;
602fcf3ce44SJohn Forte 	MATCHMAP *mp;
603fcf3ce44SJohn Forte 	uint16_t tag;
604fcf3ce44SJohn Forte 	uint32_t maxqbuf;
605fcf3ce44SJohn Forte 	int32_t i;
606fcf3ce44SJohn Forte 	int32_t j;
607fcf3ce44SJohn Forte 	uint32_t seg;
608fcf3ce44SJohn Forte 	uint32_t size;
609fcf3ce44SJohn Forte 
610fcf3ce44SJohn Forte 	mp = 0;
611fcf3ce44SJohn Forte 	maxqbuf = 2;
612fcf3ce44SJohn Forte 	tag = (uint16_t)cnt;
613fcf3ce44SJohn Forte 	cnt += rp->fc_missbufcnt;
614fcf3ce44SJohn Forte 
61582527734SSukumar Swaminathan 	if (rp->ringno == hba->channel_els) {
616fcf3ce44SJohn Forte 		seg = MEM_BUF;
617fcf3ce44SJohn Forte 		size = MEM_ELSBUF_SIZE;
61882527734SSukumar Swaminathan 	} else if (rp->ringno == hba->channel_ip) {
619fcf3ce44SJohn Forte 		seg = MEM_IPBUF;
620fcf3ce44SJohn Forte 		size = MEM_IPBUF_SIZE;
62182527734SSukumar Swaminathan 	} else if (rp->ringno == hba->channel_ct) {
622fcf3ce44SJohn Forte 		seg = MEM_CTBUF;
623fcf3ce44SJohn Forte 		size = MEM_CTBUF_SIZE;
624fcf3ce44SJohn Forte 	}
625fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
62682527734SSukumar Swaminathan 	else if (rp->ringno == hba->CHANNEL_FCT) {
627fcf3ce44SJohn Forte 		seg = MEM_FCTBUF;
628fcf3ce44SJohn Forte 		size = MEM_FCTBUF_SIZE;
629fcf3ce44SJohn Forte 	}
630291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
631fcf3ce44SJohn Forte 	else {
632fcf3ce44SJohn Forte 		return (0);
633fcf3ce44SJohn Forte 	}
634fcf3ce44SJohn Forte 
635fcf3ce44SJohn Forte 	/*
636fcf3ce44SJohn Forte 	 * While there are buffers to post
637fcf3ce44SJohn Forte 	 */
638fcf3ce44SJohn Forte 	while (cnt) {
63982527734SSukumar Swaminathan 		if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB, 0)) == 0) {
640fcf3ce44SJohn Forte 			rp->fc_missbufcnt = cnt;
641fcf3ce44SJohn Forte 			return (cnt);
642fcf3ce44SJohn Forte 		}
643291a2b48SSukumar Swaminathan 
64482527734SSukumar Swaminathan 		iocbq->channel = (void *)&hba->chan[rp->ringno];
645fcf3ce44SJohn Forte 		iocbq->port = (void *)port;
646fcf3ce44SJohn Forte 		iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
647fcf3ce44SJohn Forte 
648fcf3ce44SJohn Forte 		icmd = &iocbq->iocb;
649fcf3ce44SJohn Forte 
650fcf3ce44SJohn Forte 		/*
651fcf3ce44SJohn Forte 		 * Max buffers can be posted per command
652fcf3ce44SJohn Forte 		 */
653fcf3ce44SJohn Forte 		for (i = 0; i < maxqbuf; i++) {
654fcf3ce44SJohn Forte 			if (cnt <= 0)
655fcf3ce44SJohn Forte 				break;
656fcf3ce44SJohn Forte 
657fcf3ce44SJohn Forte 			/* fill in BDEs for command */
65882527734SSukumar Swaminathan 			if ((mp = (MATCHMAP *)emlxs_mem_get(hba, seg, 1))
65982527734SSukumar Swaminathan 			    == 0) {
66082527734SSukumar Swaminathan 				icmd->ULPBDECOUNT = i;
661fcf3ce44SJohn Forte 				for (j = 0; j < i; j++) {
662291a2b48SSukumar Swaminathan 					mp = EMLXS_GET_VADDR(hba, rp, icmd);
663fcf3ce44SJohn Forte 					if (mp) {
664*a9800bebSGarrett D'Amore 						emlxs_mem_put(hba, seg,
665*a9800bebSGarrett D'Amore 						    (void *)mp);
666fcf3ce44SJohn Forte 					}
667fcf3ce44SJohn Forte 				}
668fcf3ce44SJohn Forte 
669fcf3ce44SJohn Forte 				rp->fc_missbufcnt = cnt + i;
670fcf3ce44SJohn Forte 
671*a9800bebSGarrett D'Amore 				emlxs_mem_put(hba, MEM_IOCB, (void *)iocbq);
672fcf3ce44SJohn Forte 
673fcf3ce44SJohn Forte 				return (cnt + i);
674fcf3ce44SJohn Forte 			}
675291a2b48SSukumar Swaminathan 
676fcf3ce44SJohn Forte 			/*
677fcf3ce44SJohn Forte 			 * map that page and save the address pair for lookup
678fcf3ce44SJohn Forte 			 * later
679fcf3ce44SJohn Forte 			 */
680291a2b48SSukumar Swaminathan 			emlxs_mem_map_vaddr(hba,
681291a2b48SSukumar Swaminathan 			    rp,
682291a2b48SSukumar Swaminathan 			    mp,
683fcf3ce44SJohn Forte 			    (uint32_t *)&icmd->un.cont64[i].addrHigh,
684fcf3ce44SJohn Forte 			    (uint32_t *)&icmd->un.cont64[i].addrLow);
685fcf3ce44SJohn Forte 
686fcf3ce44SJohn Forte 			icmd->un.cont64[i].tus.f.bdeSize = size;
68782527734SSukumar Swaminathan 			icmd->ULPCOMMAND = CMD_QUE_RING_BUF64_CN;
688fcf3ce44SJohn Forte 
689291a2b48SSukumar Swaminathan 			/*
690291a2b48SSukumar Swaminathan 			 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
691291a2b48SSukumar Swaminathan 			 *    "UB Post: ring=%d addr=%08x%08x size=%d",
692291a2b48SSukumar Swaminathan 			 *    rp->ringno, icmd->un.cont64[i].addrHigh,
693291a2b48SSukumar Swaminathan 			 *    icmd->un.cont64[i].addrLow, size);
694291a2b48SSukumar Swaminathan 			 */
695fcf3ce44SJohn Forte 
696fcf3ce44SJohn Forte 			cnt--;
697fcf3ce44SJohn Forte 		}
698fcf3ce44SJohn Forte 
69982527734SSukumar Swaminathan 		icmd->ULPIOTAG = tag;
70082527734SSukumar Swaminathan 		icmd->ULPBDECOUNT = i;
70182527734SSukumar Swaminathan 		icmd->ULPLE = 1;
70282527734SSukumar Swaminathan 		icmd->ULPOWNER = OWN_CHIP;
703291a2b48SSukumar Swaminathan 		/* used for delimiter between commands */
704*a9800bebSGarrett D'Amore 		iocbq->bp = (void *)mp;
705fcf3ce44SJohn Forte 
70682527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[rp->ringno], iocbq);
707fcf3ce44SJohn Forte 	}
708fcf3ce44SJohn Forte 
709fcf3ce44SJohn Forte 	rp->fc_missbufcnt = 0;
710fcf3ce44SJohn Forte 
711fcf3ce44SJohn Forte 	return (0);
712fcf3ce44SJohn Forte 
71382527734SSukumar Swaminathan } /* emlxs_post_buffer() */
714fcf3ce44SJohn Forte 
715fcf3ce44SJohn Forte 
716fcf3ce44SJohn Forte extern int
717fcf3ce44SJohn Forte emlxs_port_offline(emlxs_port_t *port, uint32_t scope)
718fcf3ce44SJohn Forte {
719fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
720fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
721fcf3ce44SJohn Forte 	NODELIST *nlp;
722fcf3ce44SJohn Forte 	fc_affected_id_t *aid;
723fcf3ce44SJohn Forte 	uint32_t mask;
724fcf3ce44SJohn Forte 	uint32_t aff_d_id;
725fcf3ce44SJohn Forte 	uint32_t linkdown;
726fcf3ce44SJohn Forte 	uint32_t vlinkdown;
727fcf3ce44SJohn Forte 	uint32_t action;
728fcf3ce44SJohn Forte 	int i;
729fcf3ce44SJohn Forte 	uint32_t unreg_vpi;
730fcf3ce44SJohn Forte 	uint32_t update;
731fcf3ce44SJohn Forte 	uint32_t adisc_support;
732*a9800bebSGarrett D'Amore 	uint32_t clear_all;
7333be114edSSukumar Swaminathan 	uint8_t format;
734fcf3ce44SJohn Forte 
735fcf3ce44SJohn Forte 	/* Target mode only uses this routine for linkdowns */
736fcf3ce44SJohn Forte 	if (port->tgt_mode && (scope != 0xffffffff) && (scope != 0xfeffffff)) {
737fcf3ce44SJohn Forte 		return (0);
738fcf3ce44SJohn Forte 	}
739291a2b48SSukumar Swaminathan 
740fcf3ce44SJohn Forte 	cfg = &CFG;
741fcf3ce44SJohn Forte 	aid = (fc_affected_id_t *)&scope;
742fcf3ce44SJohn Forte 	linkdown = 0;
743fcf3ce44SJohn Forte 	vlinkdown = 0;
744fcf3ce44SJohn Forte 	unreg_vpi = 0;
745fcf3ce44SJohn Forte 	update = 0;
746*a9800bebSGarrett D'Amore 	clear_all = 0;
747fcf3ce44SJohn Forte 
748fcf3ce44SJohn Forte 	if (!(port->flag & EMLXS_PORT_BOUND)) {
749fcf3ce44SJohn Forte 		return (0);
750fcf3ce44SJohn Forte 	}
751291a2b48SSukumar Swaminathan 
7523be114edSSukumar Swaminathan 	format = aid->aff_format;
7533be114edSSukumar Swaminathan 
7543be114edSSukumar Swaminathan 	switch (format) {
755fcf3ce44SJohn Forte 	case 0:	/* Port */
756fcf3ce44SJohn Forte 		mask = 0x00ffffff;
757fcf3ce44SJohn Forte 		break;
758fcf3ce44SJohn Forte 
759fcf3ce44SJohn Forte 	case 1:	/* Area */
760fcf3ce44SJohn Forte 		mask = 0x00ffff00;
761fcf3ce44SJohn Forte 		break;
762fcf3ce44SJohn Forte 
763fcf3ce44SJohn Forte 	case 2:	/* Domain */
764fcf3ce44SJohn Forte 		mask = 0x00ff0000;
765fcf3ce44SJohn Forte 		break;
766fcf3ce44SJohn Forte 
767fcf3ce44SJohn Forte 	case 3:	/* Network */
768fcf3ce44SJohn Forte 		mask = 0x00000000;
769fcf3ce44SJohn Forte 		break;
770fcf3ce44SJohn Forte 
771*a9800bebSGarrett D'Amore 	case 0xfd:	/* New fabric */
772*a9800bebSGarrett D'Amore 		mask = 0x00000000;
773*a9800bebSGarrett D'Amore 		linkdown = 1;
774*a9800bebSGarrett D'Amore 		clear_all = 1;
775*a9800bebSGarrett D'Amore 		break;
776*a9800bebSGarrett D'Amore 
777fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
778fcf3ce44SJohn Forte 	case 0xfe:	/* Virtual link down */
779fcf3ce44SJohn Forte 		mask = 0x00000000;
780fcf3ce44SJohn Forte 		vlinkdown = 1;
781fcf3ce44SJohn Forte 		break;
782291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
783fcf3ce44SJohn Forte 
784fcf3ce44SJohn Forte 	case 0xff:	/* link is down */
785fcf3ce44SJohn Forte 		mask = 0x00000000;
786fcf3ce44SJohn Forte 		linkdown = 1;
787fcf3ce44SJohn Forte 		break;
788fcf3ce44SJohn Forte 
789fcf3ce44SJohn Forte 	}
790fcf3ce44SJohn Forte 
791fcf3ce44SJohn Forte 	aff_d_id = aid->aff_d_id & mask;
792fcf3ce44SJohn Forte 
793fcf3ce44SJohn Forte 
794fcf3ce44SJohn Forte 	/*
795291a2b48SSukumar Swaminathan 	 * If link is down then this is a hard shutdown and flush
796291a2b48SSukumar Swaminathan 	 * If link not down then this is a soft shutdown and flush
797291a2b48SSukumar Swaminathan 	 * (e.g. RSCN)
798fcf3ce44SJohn Forte 	 */
799fcf3ce44SJohn Forte 	if (linkdown) {
800fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
801fcf3ce44SJohn Forte 
802fcf3ce44SJohn Forte 		port->flag &= EMLXS_PORT_LINKDOWN_MASK;
803fcf3ce44SJohn Forte 
804fcf3ce44SJohn Forte 		if (port->ulp_statec != FC_STATE_OFFLINE) {
805fcf3ce44SJohn Forte 			port->ulp_statec = FC_STATE_OFFLINE;
806*a9800bebSGarrett D'Amore 			port->prev_did = port->did;
807*a9800bebSGarrett D'Amore 			bcopy(&port->fabric_sparam, &port->prev_fabric_sparam,
808*a9800bebSGarrett D'Amore 			    sizeof (SERV_PARM));
809*a9800bebSGarrett D'Amore 			port->did = 0;
810fcf3ce44SJohn Forte 			update = 1;
811fcf3ce44SJohn Forte 		}
812291a2b48SSukumar Swaminathan 
813fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
814fcf3ce44SJohn Forte 
815fcf3ce44SJohn Forte 		/* Tell ULP about it */
816fcf3ce44SJohn Forte 		if (update) {
817fcf3ce44SJohn Forte 			if (port->flag & EMLXS_PORT_BOUND) {
818fcf3ce44SJohn Forte 				if (port->vpi == 0) {
819fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
820291a2b48SSukumar Swaminathan 					    &emlxs_link_down_msg, NULL);
821fcf3ce44SJohn Forte 				}
822291a2b48SSukumar Swaminathan 
8233be114edSSukumar Swaminathan 				if (port->ini_mode) {
8243be114edSSukumar Swaminathan 					port->ulp_statec_cb(port->ulp_handle,
8253be114edSSukumar Swaminathan 					    FC_STATE_OFFLINE);
8263be114edSSukumar Swaminathan 				}
827291a2b48SSukumar Swaminathan #ifdef SFCT_SUPPORT
8283be114edSSukumar Swaminathan 				else if (port->tgt_mode) {
829fcf3ce44SJohn Forte 					emlxs_fct_link_down(port);
8303be114edSSukumar Swaminathan 				}
831291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
832fcf3ce44SJohn Forte 
833fcf3ce44SJohn Forte 			} else {
834fcf3ce44SJohn Forte 				if (port->vpi == 0) {
835fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
836291a2b48SSukumar Swaminathan 					    &emlxs_link_down_msg, "*");
837fcf3ce44SJohn Forte 				}
838fcf3ce44SJohn Forte 			}
839fcf3ce44SJohn Forte 
840fcf3ce44SJohn Forte 
841fcf3ce44SJohn Forte 		}
842291a2b48SSukumar Swaminathan 
843fcf3ce44SJohn Forte 		unreg_vpi = 1;
844fcf3ce44SJohn Forte 
845fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
846fcf3ce44SJohn Forte 		/* Stop authentication with all nodes */
847fcf3ce44SJohn Forte 		emlxs_dhc_auth_stop(port, NULL);
848291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
849fcf3ce44SJohn Forte 
850fcf3ce44SJohn Forte 		/* Flush the base node */
851fcf3ce44SJohn Forte 		(void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0);
852fcf3ce44SJohn Forte 		(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);
853fcf3ce44SJohn Forte 
854fcf3ce44SJohn Forte 		/* Flush any pending ub buffers */
855fcf3ce44SJohn Forte 		emlxs_ub_flush(port);
856fcf3ce44SJohn Forte 	}
857fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
858fcf3ce44SJohn Forte 	/* virtual link down */
859fcf3ce44SJohn Forte 	else if (vlinkdown) {
860fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
861fcf3ce44SJohn Forte 
862fcf3ce44SJohn Forte 		if (port->ulp_statec != FC_STATE_OFFLINE) {
863fcf3ce44SJohn Forte 			port->ulp_statec = FC_STATE_OFFLINE;
864fcf3ce44SJohn Forte 			update = 1;
865fcf3ce44SJohn Forte 		}
866291a2b48SSukumar Swaminathan 
867fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
868fcf3ce44SJohn Forte 
869fcf3ce44SJohn Forte 		/* Tell ULP about it */
870fcf3ce44SJohn Forte 		if (update) {
871fcf3ce44SJohn Forte 			if (port->flag & EMLXS_PORT_BOUND) {
872fcf3ce44SJohn Forte 				if (port->vpi == 0) {
873fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
874fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
875fcf3ce44SJohn Forte 					    "Switch authentication failed.");
876fcf3ce44SJohn Forte 				}
877291a2b48SSukumar Swaminathan 
878fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
879fcf3ce44SJohn Forte 				if (port->tgt_mode) {
880fcf3ce44SJohn Forte 					emlxs_fct_link_down(port);
881291a2b48SSukumar Swaminathan 
882fcf3ce44SJohn Forte 				} else if (port->ini_mode) {
883fcf3ce44SJohn Forte 					port->ulp_statec_cb(port->ulp_handle,
884fcf3ce44SJohn Forte 					    FC_STATE_OFFLINE);
885fcf3ce44SJohn Forte 				}
886fcf3ce44SJohn Forte #else
887fcf3ce44SJohn Forte 				port->ulp_statec_cb(port->ulp_handle,
888fcf3ce44SJohn Forte 				    FC_STATE_OFFLINE);
889fcf3ce44SJohn Forte #endif	/* SFCT_SUPPORT */
890fcf3ce44SJohn Forte 			} else {
891fcf3ce44SJohn Forte 				if (port->vpi == 0) {
892fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
893fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
894fcf3ce44SJohn Forte 					    "Switch authentication failed. *");
895fcf3ce44SJohn Forte 				}
896fcf3ce44SJohn Forte 			}
897fcf3ce44SJohn Forte 
898fcf3ce44SJohn Forte 
899fcf3ce44SJohn Forte 		}
900291a2b48SSukumar Swaminathan 
901fcf3ce44SJohn Forte 		/* Flush the base node */
902fcf3ce44SJohn Forte 		(void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0);
903fcf3ce44SJohn Forte 		(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);
904fcf3ce44SJohn Forte 	}
905291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
906fcf3ce44SJohn Forte 
907fcf3ce44SJohn Forte 	if (port->tgt_mode) {
908fcf3ce44SJohn Forte 		goto done;
909fcf3ce44SJohn Forte 	}
910291a2b48SSukumar Swaminathan 
911fcf3ce44SJohn Forte 	/* Set the node tags */
912fcf3ce44SJohn Forte 	/* We will process all nodes with this tag */
913fcf3ce44SJohn Forte 	rw_enter(&port->node_rwlock, RW_READER);
914fcf3ce44SJohn Forte 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
915fcf3ce44SJohn Forte 		nlp = port->node_table[i];
916fcf3ce44SJohn Forte 		while (nlp != NULL) {
917fcf3ce44SJohn Forte 			nlp->nlp_tag = 1;
918fcf3ce44SJohn Forte 			nlp = nlp->nlp_list_next;
919fcf3ce44SJohn Forte 		}
920fcf3ce44SJohn Forte 	}
921fcf3ce44SJohn Forte 	rw_exit(&port->node_rwlock);
922fcf3ce44SJohn Forte 
923*a9800bebSGarrett D'Amore 	if (!clear_all && (hba->flag & FC_ONLINE_MODE)) {
924fcf3ce44SJohn Forte 		adisc_support = cfg[CFG_ADISC_SUPPORT].current;
925fcf3ce44SJohn Forte 	} else {
926fcf3ce44SJohn Forte 		adisc_support = 0;
927fcf3ce44SJohn Forte 	}
928fcf3ce44SJohn Forte 
929fcf3ce44SJohn Forte 	/* Check ADISC support level */
930fcf3ce44SJohn Forte 	switch (adisc_support) {
931fcf3ce44SJohn Forte 	case 0:	/* No support - Flush all IO to all matching nodes */
932fcf3ce44SJohn Forte 
933291a2b48SSukumar Swaminathan 		for (;;) {
934fcf3ce44SJohn Forte 			/*
935fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
936*a9800bebSGarrett D'Amore 			 * emlxs_mb_unreg_node and the flush routines enter the
937291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
938291a2b48SSukumar Swaminathan 			 * can change out from under us.
939fcf3ce44SJohn Forte 			 */
940fcf3ce44SJohn Forte 
941fcf3ce44SJohn Forte 			/* Find first node */
942fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
943fcf3ce44SJohn Forte 			action = 0;
944fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
945fcf3ce44SJohn Forte 				nlp = port->node_table[i];
946fcf3ce44SJohn Forte 				while (nlp != NULL) {
947fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
948fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
949fcf3ce44SJohn Forte 						continue;
950fcf3ce44SJohn Forte 					}
951fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
952fcf3ce44SJohn Forte 
953fcf3ce44SJohn Forte 					/*
954fcf3ce44SJohn Forte 					 * Check for any device that matches
955fcf3ce44SJohn Forte 					 * our mask
956fcf3ce44SJohn Forte 					 */
957fcf3ce44SJohn Forte 					if ((nlp->nlp_DID & mask) == aff_d_id) {
958fcf3ce44SJohn Forte 						if (linkdown) {
959fcf3ce44SJohn Forte 							action = 1;
960fcf3ce44SJohn Forte 							break;
961291a2b48SSukumar Swaminathan 						} else { /* Must be an RCSN */
962291a2b48SSukumar Swaminathan 
963fcf3ce44SJohn Forte 							action = 2;
964fcf3ce44SJohn Forte 							break;
965fcf3ce44SJohn Forte 						}
966fcf3ce44SJohn Forte 					}
967fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
968fcf3ce44SJohn Forte 				}
969fcf3ce44SJohn Forte 
970fcf3ce44SJohn Forte 				if (action) {
971fcf3ce44SJohn Forte 					break;
972fcf3ce44SJohn Forte 				}
973fcf3ce44SJohn Forte 			}
974fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
975fcf3ce44SJohn Forte 
976fcf3ce44SJohn Forte 
977fcf3ce44SJohn Forte 			/* Check if nothing was found */
978fcf3ce44SJohn Forte 			if (action == 0) {
979fcf3ce44SJohn Forte 				break;
980fcf3ce44SJohn Forte 			} else if (action == 1) {
981*a9800bebSGarrett D'Amore 				(void) emlxs_mb_unreg_node(port, nlp,
982fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
983fcf3ce44SJohn Forte 			} else if (action == 2) {
984fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
985fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
986291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
987fcf3ce44SJohn Forte 
988291a2b48SSukumar Swaminathan 				/*
989291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
990291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
991291a2b48SSukumar Swaminathan 				 */
99282527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
99382527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
99482527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
99582527734SSukumar Swaminathan 				    hba->channel_ip, 60);
996fcf3ce44SJohn Forte 
997fcf3ce44SJohn Forte 				/* Flush tx queue */
998fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
999fcf3ce44SJohn Forte 
1000fcf3ce44SJohn Forte 				/* Flush chip queue */
1001fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1002fcf3ce44SJohn Forte 			}
1003291a2b48SSukumar Swaminathan 
1004fcf3ce44SJohn Forte 		}
1005fcf3ce44SJohn Forte 
1006fcf3ce44SJohn Forte 		break;
1007fcf3ce44SJohn Forte 
1008291a2b48SSukumar Swaminathan 	case 1:	/* Partial support - Flush IO for non-FCP2 matching nodes */
1009fcf3ce44SJohn Forte 
1010fcf3ce44SJohn Forte 		for (;;) {
1011fcf3ce44SJohn Forte 
1012fcf3ce44SJohn Forte 			/*
1013fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
1014*a9800bebSGarrett D'Amore 			 * emlxs_mb_unreg_node and the flush routines enter the
1015291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
1016291a2b48SSukumar Swaminathan 			 * can change out from under us.
1017fcf3ce44SJohn Forte 			 */
1018fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1019fcf3ce44SJohn Forte 			action = 0;
1020fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1021fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1022fcf3ce44SJohn Forte 				while (nlp != NULL) {
1023fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1024fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1025fcf3ce44SJohn Forte 						continue;
1026fcf3ce44SJohn Forte 					}
1027fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1028fcf3ce44SJohn Forte 
1029fcf3ce44SJohn Forte 					/*
1030291a2b48SSukumar Swaminathan 					 * Check for special FCP2 target device
1031291a2b48SSukumar Swaminathan 					 * that matches our mask
1032fcf3ce44SJohn Forte 					 */
1033fcf3ce44SJohn Forte 					if ((nlp->nlp_fcp_info &
1034fcf3ce44SJohn Forte 					    NLP_FCP_TGT_DEVICE) &&
1035291a2b48SSukumar Swaminathan 					    (nlp-> nlp_fcp_info &
1036fcf3ce44SJohn Forte 					    NLP_FCP_2_DEVICE) &&
1037291a2b48SSukumar Swaminathan 					    (nlp->nlp_DID & mask) ==
1038291a2b48SSukumar Swaminathan 					    aff_d_id) {
1039fcf3ce44SJohn Forte 						action = 3;
1040fcf3ce44SJohn Forte 						break;
1041fcf3ce44SJohn Forte 					}
1042291a2b48SSukumar Swaminathan 
1043fcf3ce44SJohn Forte 					/*
1044fcf3ce44SJohn Forte 					 * Check for any other device that
1045fcf3ce44SJohn Forte 					 * matches our mask
1046fcf3ce44SJohn Forte 					 */
1047fcf3ce44SJohn Forte 					else if ((nlp->nlp_DID & mask) ==
1048fcf3ce44SJohn Forte 					    aff_d_id) {
1049fcf3ce44SJohn Forte 						if (linkdown) {
1050fcf3ce44SJohn Forte 							action = 1;
1051fcf3ce44SJohn Forte 							break;
1052291a2b48SSukumar Swaminathan 						} else { /* Must be an RSCN */
1053291a2b48SSukumar Swaminathan 
1054fcf3ce44SJohn Forte 							action = 2;
1055fcf3ce44SJohn Forte 							break;
1056fcf3ce44SJohn Forte 						}
1057fcf3ce44SJohn Forte 					}
1058291a2b48SSukumar Swaminathan 
1059fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1060fcf3ce44SJohn Forte 				}
1061fcf3ce44SJohn Forte 
1062fcf3ce44SJohn Forte 				if (action) {
1063fcf3ce44SJohn Forte 					break;
1064fcf3ce44SJohn Forte 				}
1065fcf3ce44SJohn Forte 			}
1066fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1067fcf3ce44SJohn Forte 
1068fcf3ce44SJohn Forte 			/* Check if nothing was found */
1069fcf3ce44SJohn Forte 			if (action == 0) {
1070fcf3ce44SJohn Forte 				break;
1071fcf3ce44SJohn Forte 			} else if (action == 1) {
1072*a9800bebSGarrett D'Amore 				(void) emlxs_mb_unreg_node(port, nlp,
1073fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1074fcf3ce44SJohn Forte 			} else if (action == 2) {
1075fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1076fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1077291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1078fcf3ce44SJohn Forte 
1079291a2b48SSukumar Swaminathan 				/*
1080291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1081291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
1082291a2b48SSukumar Swaminathan 				 */
108382527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
108482527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
108582527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
108682527734SSukumar Swaminathan 				    hba->channel_ip, 60);
1087fcf3ce44SJohn Forte 
1088fcf3ce44SJohn Forte 				/* Flush tx queue */
1089fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1090fcf3ce44SJohn Forte 
1091fcf3ce44SJohn Forte 				/* Flush chip queue */
1092fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1093291a2b48SSukumar Swaminathan 
1094fcf3ce44SJohn Forte 			} else if (action == 3) {	/* FCP2 devices */
1095fcf3ce44SJohn Forte 				unreg_vpi = 0;
1096fcf3ce44SJohn Forte 
1097*a9800bebSGarrett D'Amore 				if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1098*a9800bebSGarrett D'Amore 					(void) emlxs_rpi_pause_notify(port,
1099*a9800bebSGarrett D'Amore 					    nlp->rpip);
1100*a9800bebSGarrett D'Amore 				}
1101*a9800bebSGarrett D'Amore 
1102fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1103fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1104291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1105fcf3ce44SJohn Forte 
1106291a2b48SSukumar Swaminathan 				/*
1107291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1108291a2b48SSukumar Swaminathan 				 * An ADISC or a PLOGI with reopen the node
1109291a2b48SSukumar Swaminathan 				 */
111082527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
111182527734SSukumar Swaminathan 				    hba->channel_fcp, -1);
111282527734SSukumar Swaminathan 				emlxs_node_close(port, nlp, hba->channel_ip,
1113fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1114fcf3ce44SJohn Forte 
1115fcf3ce44SJohn Forte 				/* Flush tx queues except for FCP ring */
1116fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
111782527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], 0, 0);
1118fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
111982527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], 0, 0);
1120fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
112182527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], 0, 0);
1122fcf3ce44SJohn Forte 
1123fcf3ce44SJohn Forte 				/* Flush chip queues except for FCP ring */
1124fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
112582527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], nlp, 0);
1126fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
112782527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], nlp, 0);
1128fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
112982527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], nlp, 0);
1130fcf3ce44SJohn Forte 			}
1131fcf3ce44SJohn Forte 		}
1132fcf3ce44SJohn Forte 		break;
1133fcf3ce44SJohn Forte 
1134fcf3ce44SJohn Forte 	case 2:	/* Full support - Hold FCP IO to FCP target matching nodes */
1135fcf3ce44SJohn Forte 
1136fcf3ce44SJohn Forte 		if (!linkdown && !vlinkdown) {
1137fcf3ce44SJohn Forte 			break;
1138fcf3ce44SJohn Forte 		}
1139291a2b48SSukumar Swaminathan 
1140fcf3ce44SJohn Forte 		for (;;) {
1141fcf3ce44SJohn Forte 			/*
1142fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
1143*a9800bebSGarrett D'Amore 			 * emlxs_mb_unreg_node and the flush routines enter the
1144291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
1145291a2b48SSukumar Swaminathan 			 * can change out from under us.
1146fcf3ce44SJohn Forte 			 */
1147fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1148fcf3ce44SJohn Forte 			action = 0;
1149fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1150fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1151fcf3ce44SJohn Forte 				while (nlp != NULL) {
1152fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1153fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1154fcf3ce44SJohn Forte 						continue;
1155fcf3ce44SJohn Forte 					}
1156fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1157fcf3ce44SJohn Forte 
1158fcf3ce44SJohn Forte 					/*
1159fcf3ce44SJohn Forte 					 * Check for FCP target device that
1160fcf3ce44SJohn Forte 					 * matches our mask
1161fcf3ce44SJohn Forte 					 */
1162291a2b48SSukumar Swaminathan 					if ((nlp-> nlp_fcp_info &
1163fcf3ce44SJohn Forte 					    NLP_FCP_TGT_DEVICE) &&
1164291a2b48SSukumar Swaminathan 					    (nlp->nlp_DID & mask) ==
1165291a2b48SSukumar Swaminathan 					    aff_d_id) {
1166fcf3ce44SJohn Forte 						action = 3;
1167fcf3ce44SJohn Forte 						break;
1168fcf3ce44SJohn Forte 					}
1169291a2b48SSukumar Swaminathan 
1170fcf3ce44SJohn Forte 					/*
1171fcf3ce44SJohn Forte 					 * Check for any other device that
1172fcf3ce44SJohn Forte 					 * matches our mask
1173fcf3ce44SJohn Forte 					 */
1174fcf3ce44SJohn Forte 					else if ((nlp->nlp_DID & mask) ==
1175fcf3ce44SJohn Forte 					    aff_d_id) {
1176fcf3ce44SJohn Forte 						if (linkdown) {
1177fcf3ce44SJohn Forte 							action = 1;
1178fcf3ce44SJohn Forte 							break;
1179fcf3ce44SJohn Forte 						} else { /* Must be an RSCN */
1180291a2b48SSukumar Swaminathan 
1181fcf3ce44SJohn Forte 							action = 2;
1182fcf3ce44SJohn Forte 							break;
1183fcf3ce44SJohn Forte 						}
1184fcf3ce44SJohn Forte 					}
1185291a2b48SSukumar Swaminathan 
1186fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1187fcf3ce44SJohn Forte 				}
1188fcf3ce44SJohn Forte 				if (action) {
1189fcf3ce44SJohn Forte 					break;
1190fcf3ce44SJohn Forte 				}
1191fcf3ce44SJohn Forte 			}
1192fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1193fcf3ce44SJohn Forte 
1194fcf3ce44SJohn Forte 			/* Check if nothing was found */
1195fcf3ce44SJohn Forte 			if (action == 0) {
1196fcf3ce44SJohn Forte 				break;
1197fcf3ce44SJohn Forte 			} else if (action == 1) {
1198*a9800bebSGarrett D'Amore 				(void) emlxs_mb_unreg_node(port, nlp,
1199fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1200fcf3ce44SJohn Forte 			} else if (action == 2) {
1201291a2b48SSukumar Swaminathan 				/*
1202291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1203291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
1204291a2b48SSukumar Swaminathan 				 */
120582527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
120682527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
120782527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
120882527734SSukumar Swaminathan 				    hba->channel_ip, 60);
1209fcf3ce44SJohn Forte 
1210fcf3ce44SJohn Forte 				/* Flush tx queue */
1211fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1212fcf3ce44SJohn Forte 
1213fcf3ce44SJohn Forte 				/* Flush chip queue */
1214fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1215fcf3ce44SJohn Forte 
1216fcf3ce44SJohn Forte 			} else if (action == 3) {	/* FCP2 devices */
1217fcf3ce44SJohn Forte 				unreg_vpi = 0;
1218fcf3ce44SJohn Forte 
1219*a9800bebSGarrett D'Amore 				if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1220*a9800bebSGarrett D'Amore 					(void) emlxs_rpi_pause_notify(port,
1221*a9800bebSGarrett D'Amore 					    nlp->rpip);
1222*a9800bebSGarrett D'Amore 				}
1223*a9800bebSGarrett D'Amore 
1224291a2b48SSukumar Swaminathan 				/*
1225291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1226291a2b48SSukumar Swaminathan 				 * An ADISC or a PLOGI with reopen the node
1227291a2b48SSukumar Swaminathan 				 */
122882527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
122982527734SSukumar Swaminathan 				    hba->channel_fcp, -1);
123082527734SSukumar Swaminathan 				emlxs_node_close(port, nlp, hba->channel_ip,
1231fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1232fcf3ce44SJohn Forte 
1233fcf3ce44SJohn Forte 				/* Flush tx queues except for FCP ring */
1234fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
123582527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], 0, 0);
1236fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
123782527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], 0, 0);
1238fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
123982527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], 0, 0);
1240fcf3ce44SJohn Forte 
1241fcf3ce44SJohn Forte 				/* Flush chip queues except for FCP ring */
1242fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
124382527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], nlp, 0);
1244fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
124582527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], nlp, 0);
1246fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
124782527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], nlp, 0);
1248fcf3ce44SJohn Forte 			}
1249fcf3ce44SJohn Forte 		}
1250fcf3ce44SJohn Forte 
1251fcf3ce44SJohn Forte 		break;
1252fcf3ce44SJohn Forte 
1253fcf3ce44SJohn Forte 	}	/* switch() */
1254fcf3ce44SJohn Forte 
1255fcf3ce44SJohn Forte done:
1256fcf3ce44SJohn Forte 
1257*a9800bebSGarrett D'Amore 	if (unreg_vpi) {
1258*a9800bebSGarrett D'Amore 		(void) emlxs_mb_unreg_vpi(port);
1259fcf3ce44SJohn Forte 	}
1260fcf3ce44SJohn Forte 
1261291a2b48SSukumar Swaminathan 	return (0);
1262fcf3ce44SJohn Forte 
126382527734SSukumar Swaminathan } /* emlxs_port_offline() */
1264fcf3ce44SJohn Forte 
1265fcf3ce44SJohn Forte 
1266fcf3ce44SJohn Forte extern void
1267fcf3ce44SJohn Forte emlxs_port_online(emlxs_port_t *vport)
1268fcf3ce44SJohn Forte {
1269fcf3ce44SJohn Forte 	emlxs_hba_t *hba = vport->hba;
1270fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1271fcf3ce44SJohn Forte 	uint32_t state;
1272fcf3ce44SJohn Forte 	uint32_t update;
1273fcf3ce44SJohn Forte 	uint32_t npiv_linkup;
1274fcf3ce44SJohn Forte 	char topology[32];
1275fcf3ce44SJohn Forte 	char linkspeed[32];
1276fcf3ce44SJohn Forte 	char mode[32];
1277fcf3ce44SJohn Forte 
1278fcf3ce44SJohn Forte 	/*
1279291a2b48SSukumar Swaminathan 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1280291a2b48SSukumar Swaminathan 	 *    "linkup_callback. vpi=%d fc_flag=%x", vport->vpi, hba->flag);
1281fcf3ce44SJohn Forte 	 */
1282fcf3ce44SJohn Forte 
1283fcf3ce44SJohn Forte 	if ((vport->vpi > 0) &&
1284fcf3ce44SJohn Forte 	    (!(hba->flag & FC_NPIV_ENABLED) ||
1285fcf3ce44SJohn Forte 	    !(hba->flag & FC_NPIV_SUPPORTED))) {
1286fcf3ce44SJohn Forte 		return;
1287fcf3ce44SJohn Forte 	}
1288291a2b48SSukumar Swaminathan 
1289fcf3ce44SJohn Forte 	if (!(vport->flag & EMLXS_PORT_BOUND) ||
1290fcf3ce44SJohn Forte 	    !(vport->flag & EMLXS_PORT_ENABLE)) {
1291fcf3ce44SJohn Forte 		return;
1292fcf3ce44SJohn Forte 	}
1293291a2b48SSukumar Swaminathan 
1294fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1295fcf3ce44SJohn Forte 
1296fcf3ce44SJohn Forte 	/* Check for mode */
1297fcf3ce44SJohn Forte 	if (port->tgt_mode) {
1298fcf3ce44SJohn Forte 		(void) strcpy(mode, ", target");
1299fcf3ce44SJohn Forte 	} else if (port->ini_mode) {
1300fcf3ce44SJohn Forte 		(void) strcpy(mode, ", initiator");
1301fcf3ce44SJohn Forte 	} else {
1302fcf3ce44SJohn Forte 		(void) strcpy(mode, "");
1303fcf3ce44SJohn Forte 	}
1304fcf3ce44SJohn Forte 
1305fcf3ce44SJohn Forte 	/* Check for loop topology */
1306fcf3ce44SJohn Forte 	if (hba->topology == TOPOLOGY_LOOP) {
1307fcf3ce44SJohn Forte 		state = FC_STATE_LOOP;
1308fcf3ce44SJohn Forte 		(void) strcpy(topology, ", loop");
1309fcf3ce44SJohn Forte 	} else {
1310fcf3ce44SJohn Forte 		state = FC_STATE_ONLINE;
1311fcf3ce44SJohn Forte 		(void) strcpy(topology, ", fabric");
1312fcf3ce44SJohn Forte 	}
1313fcf3ce44SJohn Forte 
1314fcf3ce44SJohn Forte 	/* Set the link speed */
1315fcf3ce44SJohn Forte 	switch (hba->linkspeed) {
1316fcf3ce44SJohn Forte 	case 0:
1317fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "Gb");
1318fcf3ce44SJohn Forte 		state |= FC_STATE_1GBIT_SPEED;
1319fcf3ce44SJohn Forte 		break;
1320fcf3ce44SJohn Forte 
1321fcf3ce44SJohn Forte 	case LA_1GHZ_LINK:
1322fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "1Gb");
1323fcf3ce44SJohn Forte 		state |= FC_STATE_1GBIT_SPEED;
1324fcf3ce44SJohn Forte 		break;
1325fcf3ce44SJohn Forte 	case LA_2GHZ_LINK:
1326fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "2Gb");
1327fcf3ce44SJohn Forte 		state |= FC_STATE_2GBIT_SPEED;
1328fcf3ce44SJohn Forte 		break;
1329fcf3ce44SJohn Forte 	case LA_4GHZ_LINK:
1330fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "4Gb");
1331fcf3ce44SJohn Forte 		state |= FC_STATE_4GBIT_SPEED;
1332fcf3ce44SJohn Forte 		break;
1333fcf3ce44SJohn Forte 	case LA_8GHZ_LINK:
1334fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "8Gb");
1335fcf3ce44SJohn Forte 		state |= FC_STATE_8GBIT_SPEED;
1336fcf3ce44SJohn Forte 		break;
1337fcf3ce44SJohn Forte 	case LA_10GHZ_LINK:
1338fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "10Gb");
1339fcf3ce44SJohn Forte 		state |= FC_STATE_10GBIT_SPEED;
1340fcf3ce44SJohn Forte 		break;
1341fcf3ce44SJohn Forte 	default:
1342fcf3ce44SJohn Forte 		(void) sprintf(linkspeed, "unknown(0x%x)", hba->linkspeed);
1343fcf3ce44SJohn Forte 		break;
1344fcf3ce44SJohn Forte 	}
1345fcf3ce44SJohn Forte 
1346fcf3ce44SJohn Forte 	npiv_linkup = 0;
1347fcf3ce44SJohn Forte 	update = 0;
1348fcf3ce44SJohn Forte 
1349fcf3ce44SJohn Forte 	if ((hba->state >= FC_LINK_UP) &&
1350291a2b48SSukumar Swaminathan 	    !(hba->flag & FC_LOOPBACK_MODE) && (vport->ulp_statec != state)) {
1351fcf3ce44SJohn Forte 		update = 1;
1352fcf3ce44SJohn Forte 		vport->ulp_statec = state;
1353fcf3ce44SJohn Forte 
1354fcf3ce44SJohn Forte 		if ((vport->vpi > 0) && !(hba->flag & FC_NPIV_LINKUP)) {
1355fcf3ce44SJohn Forte 			hba->flag |= FC_NPIV_LINKUP;
1356fcf3ce44SJohn Forte 			npiv_linkup = 1;
1357fcf3ce44SJohn Forte 		}
1358fcf3ce44SJohn Forte 	}
1359291a2b48SSukumar Swaminathan 
1360fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1361fcf3ce44SJohn Forte 
136282527734SSukumar Swaminathan 
1363fcf3ce44SJohn Forte 	/*
1364291a2b48SSukumar Swaminathan 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
136582527734SSukumar Swaminathan 	 *    "linkup_callback: update=%d vpi=%d flag=%d fc_flag=%x state=%x"
136682527734SSukumar Swaminathan 	 *    "statec=%x", update, vport->vpi, npiv_linkup, hba->flag,
1367291a2b48SSukumar Swaminathan 	 *    hba->state, vport->ulp_statec);
1368fcf3ce44SJohn Forte 	 */
136982527734SSukumar Swaminathan 
1370fcf3ce44SJohn Forte 	if (update) {
1371fcf3ce44SJohn Forte 		if (vport->flag & EMLXS_PORT_BOUND) {
1372fcf3ce44SJohn Forte 			if (vport->vpi == 0) {
1373fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1374291a2b48SSukumar Swaminathan 				    "%s%s%s", linkspeed, topology, mode);
13756a573d82SSukumar Swaminathan 
1376fcf3ce44SJohn Forte 			} else if (npiv_linkup) {
1377fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT,
1378291a2b48SSukumar Swaminathan 				    &emlxs_npiv_link_up_msg, "%s%s%s",
1379fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1380fcf3ce44SJohn Forte 			}
1381291a2b48SSukumar Swaminathan 
13823be114edSSukumar Swaminathan 			if (vport->ini_mode) {
1383291a2b48SSukumar Swaminathan 				vport->ulp_statec_cb(vport->ulp_handle,
1384291a2b48SSukumar Swaminathan 				    state);
1385fcf3ce44SJohn Forte 			}
13863be114edSSukumar Swaminathan #ifdef SFCT_SUPPORT
13873be114edSSukumar Swaminathan 			else if (vport->tgt_mode) {
13883be114edSSukumar Swaminathan 				emlxs_fct_link_up(vport);
13893be114edSSukumar Swaminathan 			}
13903be114edSSukumar Swaminathan #endif /* SFCT_SUPPORT */
1391fcf3ce44SJohn Forte 		} else {
1392fcf3ce44SJohn Forte 			if (vport->vpi == 0) {
1393fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1394291a2b48SSukumar Swaminathan 				    "%s%s%s *", linkspeed, topology, mode);
13956a573d82SSukumar Swaminathan 
1396fcf3ce44SJohn Forte 			} else if (npiv_linkup) {
1397fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT,
1398291a2b48SSukumar Swaminathan 				    &emlxs_npiv_link_up_msg, "%s%s%s *",
1399fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1400fcf3ce44SJohn Forte 			}
1401fcf3ce44SJohn Forte 		}
1402fcf3ce44SJohn Forte 
1403fcf3ce44SJohn Forte 		/* Check for waiting threads */
1404fcf3ce44SJohn Forte 		if (vport->vpi == 0) {
1405fcf3ce44SJohn Forte 			mutex_enter(&EMLXS_LINKUP_LOCK);
1406fcf3ce44SJohn Forte 			if (hba->linkup_wait_flag == TRUE) {
1407fcf3ce44SJohn Forte 				hba->linkup_wait_flag = FALSE;
1408fcf3ce44SJohn Forte 				cv_broadcast(&EMLXS_LINKUP_CV);
1409fcf3ce44SJohn Forte 			}
1410fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_LINKUP_LOCK);
1411fcf3ce44SJohn Forte 		}
1412291a2b48SSukumar Swaminathan 
1413fcf3ce44SJohn Forte 		/* Flush any pending ub buffers */
1414fcf3ce44SJohn Forte 		emlxs_ub_flush(vport);
1415fcf3ce44SJohn Forte 	}
1416291a2b48SSukumar Swaminathan 
1417fcf3ce44SJohn Forte 	return;
1418fcf3ce44SJohn Forte 
141982527734SSukumar Swaminathan } /* emlxs_port_online() */
1420fcf3ce44SJohn Forte 
1421fcf3ce44SJohn Forte 
1422*a9800bebSGarrett D'Amore /* SLI3 */
1423fcf3ce44SJohn Forte extern void
1424fcf3ce44SJohn Forte emlxs_linkdown(emlxs_hba_t *hba)
1425fcf3ce44SJohn Forte {
1426fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1427fcf3ce44SJohn Forte 	int i;
1428*a9800bebSGarrett D'Amore 	uint32_t scope;
1429fcf3ce44SJohn Forte 
1430fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1431fcf3ce44SJohn Forte 
143282527734SSukumar Swaminathan 	if (hba->state > FC_LINK_DOWN) {
143382527734SSukumar Swaminathan 		HBASTATS.LinkDown++;
143482527734SSukumar Swaminathan 		EMLXS_STATE_CHANGE_LOCKED(hba, FC_LINK_DOWN);
143582527734SSukumar Swaminathan 	}
1436fcf3ce44SJohn Forte 
1437*a9800bebSGarrett D'Amore 	/* Set scope */
1438*a9800bebSGarrett D'Amore 	scope = (hba->flag & FC_NEW_FABRIC)? 0xFDFFFFFF:0xFFFFFFFF;
1439*a9800bebSGarrett D'Amore 
1440fcf3ce44SJohn Forte 	/* Filter hba flags */
1441fcf3ce44SJohn Forte 	hba->flag &= FC_LINKDOWN_MASK;
1442fcf3ce44SJohn Forte 	hba->discovery_timer = 0;
1443fcf3ce44SJohn Forte 	hba->linkup_timer = 0;
1444fcf3ce44SJohn Forte 
1445fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1446fcf3ce44SJohn Forte 
1447fcf3ce44SJohn Forte 	for (i = 0; i < MAX_VPORTS; i++) {
1448fcf3ce44SJohn Forte 		port = &VPORT(i);
1449fcf3ce44SJohn Forte 
1450fcf3ce44SJohn Forte 		if (!(port->flag & EMLXS_PORT_BOUND)) {
1451fcf3ce44SJohn Forte 			continue;
1452fcf3ce44SJohn Forte 		}
1453291a2b48SSukumar Swaminathan 
1454*a9800bebSGarrett D'Amore 		(void) emlxs_port_offline(port, scope);
1455fcf3ce44SJohn Forte 
1456fcf3ce44SJohn Forte 	}
1457fcf3ce44SJohn Forte 
1458*a9800bebSGarrett D'Amore 	emlxs_log_link_event(port);
1459*a9800bebSGarrett D'Amore 
1460fcf3ce44SJohn Forte 	return;
1461fcf3ce44SJohn Forte 
146282527734SSukumar Swaminathan } /* emlxs_linkdown() */
1463fcf3ce44SJohn Forte 
1464fcf3ce44SJohn Forte 
1465*a9800bebSGarrett D'Amore /* SLI3 */
1466fcf3ce44SJohn Forte extern void
1467fcf3ce44SJohn Forte emlxs_linkup(emlxs_hba_t *hba)
1468fcf3ce44SJohn Forte {
1469fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1470fcf3ce44SJohn Forte 	emlxs_config_t *cfg = &CFG;
1471fcf3ce44SJohn Forte 
1472fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1473fcf3ce44SJohn Forte 
1474fcf3ce44SJohn Forte 	HBASTATS.LinkUp++;
147582527734SSukumar Swaminathan 	EMLXS_STATE_CHANGE_LOCKED(hba, FC_LINK_UP);
1476fcf3ce44SJohn Forte 
1477fcf3ce44SJohn Forte #ifdef MENLO_SUPPORT
1478fcf3ce44SJohn Forte 	if (hba->flag & FC_MENLO_MODE) {
1479fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1480fcf3ce44SJohn Forte 
1481fcf3ce44SJohn Forte 		/*
1482fcf3ce44SJohn Forte 		 * Trigger linkup CV and don't start linkup & discovery
1483fcf3ce44SJohn Forte 		 * timers
1484fcf3ce44SJohn Forte 		 */
1485fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_LINKUP_LOCK);
1486fcf3ce44SJohn Forte 		cv_broadcast(&EMLXS_LINKUP_CV);
1487fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_LINKUP_LOCK);
1488fcf3ce44SJohn Forte 
1489*a9800bebSGarrett D'Amore 		emlxs_log_link_event(port);
1490*a9800bebSGarrett D'Amore 
1491fcf3ce44SJohn Forte 		return;
1492fcf3ce44SJohn Forte 	}
1493291a2b48SSukumar Swaminathan #endif /* MENLO_SUPPORT */
1494fcf3ce44SJohn Forte 
1495fcf3ce44SJohn Forte 	/* Set the linkup & discovery timers */
1496fcf3ce44SJohn Forte 	hba->linkup_timer = hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current;
1497291a2b48SSukumar Swaminathan 	hba->discovery_timer =
1498291a2b48SSukumar Swaminathan 	    hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current +
1499291a2b48SSukumar Swaminathan 	    cfg[CFG_DISC_TIMEOUT].current;
1500fcf3ce44SJohn Forte 
1501fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1502fcf3ce44SJohn Forte 
1503*a9800bebSGarrett D'Amore 	emlxs_log_link_event(port);
1504*a9800bebSGarrett D'Amore 
1505fcf3ce44SJohn Forte 	return;
1506fcf3ce44SJohn Forte 
150782527734SSukumar Swaminathan } /* emlxs_linkup() */
1508fcf3ce44SJohn Forte 
1509fcf3ce44SJohn Forte 
1510fcf3ce44SJohn Forte /*
1511fcf3ce44SJohn Forte  *  emlxs_reset_link
1512fcf3ce44SJohn Forte  *
1513fcf3ce44SJohn Forte  *  Description:
1514fcf3ce44SJohn Forte  *  Called to reset the link with an init_link
1515fcf3ce44SJohn Forte  *
1516fcf3ce44SJohn Forte  *    Returns:
1517fcf3ce44SJohn Forte  *
1518fcf3ce44SJohn Forte  */
1519fcf3ce44SJohn Forte extern int
152082527734SSukumar Swaminathan emlxs_reset_link(emlxs_hba_t *hba, uint32_t linkup, uint32_t wait)
1521fcf3ce44SJohn Forte {
1522fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1523fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
152482527734SSukumar Swaminathan 	MAILBOXQ *mbq = NULL;
152582527734SSukumar Swaminathan 	MAILBOX *mb = NULL;
152682527734SSukumar Swaminathan 	int rval = 0;
152782527734SSukumar Swaminathan 	int rc;
1528fcf3ce44SJohn Forte 
1529fcf3ce44SJohn Forte 	/*
1530fcf3ce44SJohn Forte 	 * Get a buffer to use for the mailbox command
1531fcf3ce44SJohn Forte 	 */
153282527734SSukumar Swaminathan 	if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))
153382527734SSukumar Swaminathan 	    == NULL) {
1534fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_failed_msg,
1535fcf3ce44SJohn Forte 		    "Unable to allocate mailbox buffer.");
153682527734SSukumar Swaminathan 		rval = 1;
153782527734SSukumar Swaminathan 		goto reset_link_fail;
153882527734SSukumar Swaminathan 	}
1539fcf3ce44SJohn Forte 
1540*a9800bebSGarrett D'Amore 	if (linkup) {
1541*a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg,
1542*a9800bebSGarrett D'Amore 		    "Resetting link...");
1543*a9800bebSGarrett D'Amore 	} else {
1544*a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg,
1545*a9800bebSGarrett D'Amore 		    "Disabling link...");
1546*a9800bebSGarrett D'Amore 	}
1547*a9800bebSGarrett D'Amore 
154882527734SSukumar Swaminathan 	mb = (MAILBOX *)mbq;
154982527734SSukumar Swaminathan 
155082527734SSukumar Swaminathan 	/* Bring link down first */
155182527734SSukumar Swaminathan 	emlxs_mb_down_link(hba, mbq);
155282527734SSukumar Swaminathan 
155382527734SSukumar Swaminathan #define	MBXERR_LINK_DOWN	0x33
155482527734SSukumar Swaminathan 
155582527734SSukumar Swaminathan 	if (wait) {
155682527734SSukumar Swaminathan 		wait = MBX_WAIT;
155782527734SSukumar Swaminathan 	} else {
155882527734SSukumar Swaminathan 		wait = MBX_NOWAIT;
155982527734SSukumar Swaminathan 	}
156082527734SSukumar Swaminathan 	rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, wait, 0);
156182527734SSukumar Swaminathan 	if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS) &&
156282527734SSukumar Swaminathan 	    (rc != MBXERR_LINK_DOWN)) {
156382527734SSukumar Swaminathan 		rval = 1;
156482527734SSukumar Swaminathan 		goto reset_link_fail;
1565fcf3ce44SJohn Forte 	}
1566291a2b48SSukumar Swaminathan 
1567fcf3ce44SJohn Forte 	if (linkup) {
1568fcf3ce44SJohn Forte 		/*
1569fcf3ce44SJohn Forte 		 * Setup and issue mailbox INITIALIZE LINK command
1570fcf3ce44SJohn Forte 		 */
1571fcf3ce44SJohn Forte 
157282527734SSukumar Swaminathan 		if (wait == MBX_NOWAIT) {
157382527734SSukumar Swaminathan 			if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))
157482527734SSukumar Swaminathan 			    == NULL) {
157582527734SSukumar Swaminathan 				EMLXS_MSGF(EMLXS_CONTEXT,
157682527734SSukumar Swaminathan 				    &emlxs_link_reset_failed_msg,
157782527734SSukumar Swaminathan 				    "Unable to allocate mailbox buffer.");
157882527734SSukumar Swaminathan 				rval = 1;
157982527734SSukumar Swaminathan 				goto reset_link_fail;
158082527734SSukumar Swaminathan 			}
158182527734SSukumar Swaminathan 			mb = (MAILBOX *)mbq;
158282527734SSukumar Swaminathan 		} else {
158382527734SSukumar Swaminathan 			/* Reuse mbq from previous mbox */
158482527734SSukumar Swaminathan 			mb = (MAILBOX *)mbq;
158582527734SSukumar Swaminathan 		}
158682527734SSukumar Swaminathan 		cfg = &CFG;
158782527734SSukumar Swaminathan 
158882527734SSukumar Swaminathan 		emlxs_mb_init_link(hba, mbq,
1589fcf3ce44SJohn Forte 		    cfg[CFG_TOPOLOGY].current, cfg[CFG_LINK_SPEED].current);
1590fcf3ce44SJohn Forte 
1591fcf3ce44SJohn Forte 		mb->un.varInitLnk.lipsr_AL_PA = 0;
1592fcf3ce44SJohn Forte 
1593fcf3ce44SJohn Forte 		/* Clear the loopback mode */
1594fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1595fcf3ce44SJohn Forte 		hba->flag &= ~FC_LOOPBACK_MODE;
1596291a2b48SSukumar Swaminathan 		hba->loopback_tics = 0;
1597fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1598fcf3ce44SJohn Forte 
159982527734SSukumar Swaminathan 		rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, wait, 0);
160082527734SSukumar Swaminathan 		if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
160182527734SSukumar Swaminathan 			rval = 1;
160282527734SSukumar Swaminathan 			goto reset_link_fail;
1603fcf3ce44SJohn Forte 		}
1604291a2b48SSukumar Swaminathan 
1605fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg, NULL);
160682527734SSukumar Swaminathan 	}
1607fcf3ce44SJohn Forte 
160882527734SSukumar Swaminathan reset_link_fail:
1609291a2b48SSukumar Swaminathan 
161082527734SSukumar Swaminathan 	if ((wait == MBX_WAIT) && mbq) {
1611*a9800bebSGarrett D'Amore 		emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
1612fcf3ce44SJohn Forte 	}
1613fcf3ce44SJohn Forte 
161482527734SSukumar Swaminathan 	return (rval);
161582527734SSukumar Swaminathan } /* emlxs_reset_link() */
1616fcf3ce44SJohn Forte 
1617fcf3ce44SJohn Forte 
1618fcf3ce44SJohn Forte extern int
1619fcf3ce44SJohn Forte emlxs_online(emlxs_hba_t *hba)
1620fcf3ce44SJohn Forte {
1621fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1622fcf3ce44SJohn Forte 	int32_t rval = 0;
1623fcf3ce44SJohn Forte 	uint32_t i = 0;
1624fcf3ce44SJohn Forte 
1625fcf3ce44SJohn Forte 	/* Make sure adapter is offline or exit trying (30 seconds) */
1626291a2b48SSukumar Swaminathan 	while (i++ < 30) {
1627fcf3ce44SJohn Forte 		/* Check if adapter is already going online */
1628fcf3ce44SJohn Forte 		if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) {
1629fcf3ce44SJohn Forte 			return (0);
1630fcf3ce44SJohn Forte 		}
1631291a2b48SSukumar Swaminathan 
1632fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1633fcf3ce44SJohn Forte 
1634fcf3ce44SJohn Forte 		/* Check again */
1635fcf3ce44SJohn Forte 		if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) {
1636fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1637fcf3ce44SJohn Forte 			return (0);
1638fcf3ce44SJohn Forte 		}
1639291a2b48SSukumar Swaminathan 
1640fcf3ce44SJohn Forte 		/* Check if adapter is offline */
1641fcf3ce44SJohn Forte 		if (hba->flag & FC_OFFLINE_MODE) {
1642fcf3ce44SJohn Forte 			/* Mark it going online */
1643fcf3ce44SJohn Forte 			hba->flag &= ~FC_OFFLINE_MODE;
1644fcf3ce44SJohn Forte 			hba->flag |= FC_ONLINING_MODE;
1645fcf3ce44SJohn Forte 
1646fcf3ce44SJohn Forte 			/* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */
1647fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1648fcf3ce44SJohn Forte 			break;
1649fcf3ce44SJohn Forte 		}
1650291a2b48SSukumar Swaminathan 
1651fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1652fcf3ce44SJohn Forte 
1653fcf3ce44SJohn Forte 		DELAYMS(1000);
1654fcf3ce44SJohn Forte 	}
1655fcf3ce44SJohn Forte 
1656fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
1657fcf3ce44SJohn Forte 	    "Going online...");
1658fcf3ce44SJohn Forte 
165982527734SSukumar Swaminathan 	if (rval = EMLXS_SLI_ONLINE(hba)) {
1660291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg, "status=%x",
1661fcf3ce44SJohn Forte 		    rval);
1662fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL);
1663fcf3ce44SJohn Forte 
1664fcf3ce44SJohn Forte 		/* Set FC_OFFLINE_MODE */
1665fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1666fcf3ce44SJohn Forte 		emlxs_diag_state = DDI_OFFDI;
1667fcf3ce44SJohn Forte 		hba->flag |= FC_OFFLINE_MODE;
1668fcf3ce44SJohn Forte 		hba->flag &= ~FC_ONLINING_MODE;
1669fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1670fcf3ce44SJohn Forte 
1671fcf3ce44SJohn Forte 		return (rval);
1672fcf3ce44SJohn Forte 	}
1673291a2b48SSukumar Swaminathan 
1674fcf3ce44SJohn Forte 	/* Start the timer */
1675fcf3ce44SJohn Forte 	emlxs_timer_start(hba);
1676fcf3ce44SJohn Forte 
1677fcf3ce44SJohn Forte 	/* Set FC_ONLINE_MODE */
1678fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1679fcf3ce44SJohn Forte 	emlxs_diag_state = DDI_ONDI;
1680fcf3ce44SJohn Forte 	hba->flag |= FC_ONLINE_MODE;
1681fcf3ce44SJohn Forte 	hba->flag &= ~FC_ONLINING_MODE;
1682fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1683fcf3ce44SJohn Forte 
1684fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_online_msg, NULL);
1685fcf3ce44SJohn Forte 
1686fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
1687fcf3ce44SJohn Forte 	(void) emlxs_fct_port_initialize(port);
1688291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
1689fcf3ce44SJohn Forte 
1690fcf3ce44SJohn Forte 	return (rval);
1691fcf3ce44SJohn Forte 
169282527734SSukumar Swaminathan } /* emlxs_online() */
1693fcf3ce44SJohn Forte 
1694fcf3ce44SJohn Forte 
1695fcf3ce44SJohn Forte extern int
1696fcf3ce44SJohn Forte emlxs_offline(emlxs_hba_t *hba)
1697fcf3ce44SJohn Forte {
1698fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1699fcf3ce44SJohn Forte 	uint32_t i = 0;
1700fcf3ce44SJohn Forte 	int rval = 1;
1701fcf3ce44SJohn Forte 
1702fcf3ce44SJohn Forte 	/* Make sure adapter is online or exit trying (30 seconds) */
1703291a2b48SSukumar Swaminathan 	while (i++ < 30) {
1704fcf3ce44SJohn Forte 		/* Check if adapter is already going offline */
1705fcf3ce44SJohn Forte 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1706fcf3ce44SJohn Forte 			return (0);
1707fcf3ce44SJohn Forte 		}
1708291a2b48SSukumar Swaminathan 
1709fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1710fcf3ce44SJohn Forte 
1711fcf3ce44SJohn Forte 		/* Check again */
1712fcf3ce44SJohn Forte 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1713fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1714fcf3ce44SJohn Forte 			return (0);
1715fcf3ce44SJohn Forte 		}
1716291a2b48SSukumar Swaminathan 
1717fcf3ce44SJohn Forte 		/* Check if adapter is online */
1718fcf3ce44SJohn Forte 		if (hba->flag & FC_ONLINE_MODE) {
1719fcf3ce44SJohn Forte 			/* Mark it going offline */
1720fcf3ce44SJohn Forte 			hba->flag &= ~FC_ONLINE_MODE;
1721fcf3ce44SJohn Forte 			hba->flag |= FC_OFFLINING_MODE;
1722fcf3ce44SJohn Forte 
1723fcf3ce44SJohn Forte 			/* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */
1724fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1725fcf3ce44SJohn Forte 			break;
1726fcf3ce44SJohn Forte 		}
1727291a2b48SSukumar Swaminathan 
1728fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1729fcf3ce44SJohn Forte 
1730fcf3ce44SJohn Forte 		DELAYMS(1000);
1731fcf3ce44SJohn Forte 	}
1732fcf3ce44SJohn Forte 
1733291a2b48SSukumar Swaminathan 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
1734291a2b48SSukumar Swaminathan 	    "Going offline...");
1735fcf3ce44SJohn Forte 
1736fcf3ce44SJohn Forte 	if (port->ini_mode) {
1737*a9800bebSGarrett D'Amore 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1738*a9800bebSGarrett D'Amore 			(void) emlxs_fcf_shutdown_notify(port, 1);
1739*a9800bebSGarrett D'Amore 		} else {
1740*a9800bebSGarrett D'Amore 			emlxs_linkdown(hba);
1741*a9800bebSGarrett D'Amore 		}
1742fcf3ce44SJohn Forte 	}
1743fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
1744fcf3ce44SJohn Forte 	else {
1745fcf3ce44SJohn Forte 		(void) emlxs_fct_port_shutdown(port);
1746fcf3ce44SJohn Forte 	}
1747291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
1748fcf3ce44SJohn Forte 
1749fcf3ce44SJohn Forte 	/* Check if adapter was shutdown */
1750fcf3ce44SJohn Forte 	if (hba->flag & FC_HARDWARE_ERROR) {
1751291a2b48SSukumar Swaminathan 		/*
1752291a2b48SSukumar Swaminathan 		 * Force mailbox cleanup
1753291a2b48SSukumar Swaminathan 		 * This will wake any sleeping or polling threads
1754291a2b48SSukumar Swaminathan 		 */
1755fcf3ce44SJohn Forte 		emlxs_mb_fini(hba, NULL, MBX_HARDWARE_ERROR);
1756fcf3ce44SJohn Forte 	}
1757291a2b48SSukumar Swaminathan 
1758fcf3ce44SJohn Forte 	/* Pause here for the IO to settle */
1759fcf3ce44SJohn Forte 	delay(drv_usectohz(1000000));	/* 1 sec */
1760fcf3ce44SJohn Forte 
1761fcf3ce44SJohn Forte 	/* Unregister all nodes */
1762fcf3ce44SJohn Forte 	emlxs_ffcleanup(hba);
1763fcf3ce44SJohn Forte 
1764fcf3ce44SJohn Forte 	if (hba->bus_type == SBUS_FC) {
176582527734SSukumar Swaminathan 		WRITE_SBUS_CSR_REG(hba, FC_SHS_REG(hba), 0x9A);
17664baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
176782527734SSukumar Swaminathan 		/* Access handle validation */
176882527734SSukumar Swaminathan 		EMLXS_CHK_ACC_HANDLE(hba, hba->sli.sli3.sbus_csr_handle);
17694baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
1770fcf3ce44SJohn Forte 	}
1771291a2b48SSukumar Swaminathan 
1772fcf3ce44SJohn Forte 	/* Stop the timer */
1773fcf3ce44SJohn Forte 	emlxs_timer_stop(hba);
1774fcf3ce44SJohn Forte 
1775fcf3ce44SJohn Forte 	/* For safety flush every iotag list */
1776fcf3ce44SJohn Forte 	if (emlxs_iotag_flush(hba)) {
1777fcf3ce44SJohn Forte 		/* Pause here for the IO to flush */
1778728bdc9bSSukumar Swaminathan 		delay(drv_usectohz(1000));
1779728bdc9bSSukumar Swaminathan 	}
1780728bdc9bSSukumar Swaminathan 
1781728bdc9bSSukumar Swaminathan 	/* Wait for poll command request to settle */
1782728bdc9bSSukumar Swaminathan 	while (hba->io_poll_count > 0) {
1783728bdc9bSSukumar Swaminathan 		delay(drv_usectohz(2000000));   /* 2 sec */
1784fcf3ce44SJohn Forte 	}
1785728bdc9bSSukumar Swaminathan 
178682527734SSukumar Swaminathan 	/* Shutdown the adapter interface */
178782527734SSukumar Swaminathan 	EMLXS_SLI_OFFLINE(hba);
1788fcf3ce44SJohn Forte 
1789fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1790fcf3ce44SJohn Forte 	hba->flag |= FC_OFFLINE_MODE;
1791fcf3ce44SJohn Forte 	hba->flag &= ~FC_OFFLINING_MODE;
1792fcf3ce44SJohn Forte 	emlxs_diag_state = DDI_OFFDI;
1793fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1794fcf3ce44SJohn Forte 
1795fcf3ce44SJohn Forte 	rval = 0;
1796fcf3ce44SJohn Forte 
1797fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL);
1798fcf3ce44SJohn Forte 
1799fcf3ce44SJohn Forte done:
1800fcf3ce44SJohn Forte 
1801fcf3ce44SJohn Forte 	return (rval);
1802fcf3ce44SJohn Forte 
180382527734SSukumar Swaminathan } /* emlxs_offline() */
1804fcf3ce44SJohn Forte 
1805fcf3ce44SJohn Forte 
1806fcf3ce44SJohn Forte 
1807fcf3ce44SJohn Forte extern int
1808fcf3ce44SJohn Forte emlxs_power_down(emlxs_hba_t *hba)
1809fcf3ce44SJohn Forte {
18104baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
18114baa2c25SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
18124baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
1813fcf3ce44SJohn Forte 	int32_t rval = 0;
1814fcf3ce44SJohn Forte 
1815fcf3ce44SJohn Forte 	if ((rval = emlxs_offline(hba))) {
1816fcf3ce44SJohn Forte 		return (rval);
1817fcf3ce44SJohn Forte 	}
181882527734SSukumar Swaminathan 	EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
1819291a2b48SSukumar Swaminathan 
1820fcf3ce44SJohn Forte 
18214baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
18224baa2c25SSukumar Swaminathan 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
18234baa2c25SSukumar Swaminathan 	    != DDI_FM_OK) {
18244baa2c25SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT,
18254baa2c25SSukumar Swaminathan 		    &emlxs_invalid_access_handle_msg, NULL);
18264baa2c25SSukumar Swaminathan 		return (1);
18274baa2c25SSukumar Swaminathan 	}
18284baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
18294baa2c25SSukumar Swaminathan 
1830fcf3ce44SJohn Forte 	return (0);
1831fcf3ce44SJohn Forte 
183282527734SSukumar Swaminathan } /* End emlxs_power_down */
1833fcf3ce44SJohn Forte 
1834fcf3ce44SJohn Forte 
1835fcf3ce44SJohn Forte extern int
1836fcf3ce44SJohn Forte emlxs_power_up(emlxs_hba_t *hba)
1837fcf3ce44SJohn Forte {
18384baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
18394baa2c25SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
18404baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
1841fcf3ce44SJohn Forte 	int32_t rval = 0;
1842fcf3ce44SJohn Forte 
1843fcf3ce44SJohn Forte 
18444baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
18454baa2c25SSukumar Swaminathan 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
18464baa2c25SSukumar Swaminathan 	    != DDI_FM_OK) {
18474baa2c25SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT,
18484baa2c25SSukumar Swaminathan 		    &emlxs_invalid_access_handle_msg, NULL);
18494baa2c25SSukumar Swaminathan 		return (1);
18504baa2c25SSukumar Swaminathan 	}
18514baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
18524baa2c25SSukumar Swaminathan 
1853fcf3ce44SJohn Forte 	/* Bring adapter online */
1854fcf3ce44SJohn Forte 	if ((rval = emlxs_online(hba))) {
1855*a9800bebSGarrett D'Amore 		if (hba->pci_cap_offset[PCI_CAP_ID_PM]) {
1856*a9800bebSGarrett D'Amore 			/* Put chip in D3 state */
1857*a9800bebSGarrett D'Amore 			(void) ddi_put8(hba->pci_acc_handle,
1858*a9800bebSGarrett D'Amore 			    (uint8_t *)(hba->pci_addr +
1859*a9800bebSGarrett D'Amore 			    hba->pci_cap_offset[PCI_CAP_ID_PM] +
1860*a9800bebSGarrett D'Amore 			    PCI_PMCSR),
1861*a9800bebSGarrett D'Amore 			    (uint8_t)PCI_PMCSR_D3HOT);
1862*a9800bebSGarrett D'Amore 		}
1863fcf3ce44SJohn Forte 		return (rval);
1864fcf3ce44SJohn Forte 	}
1865291a2b48SSukumar Swaminathan 
1866fcf3ce44SJohn Forte 	return (rval);
1867fcf3ce44SJohn Forte 
186882527734SSukumar Swaminathan } /* End emlxs_power_up */
1869fcf3ce44SJohn Forte 
1870fcf3ce44SJohn Forte 
1871fcf3ce44SJohn Forte /*
1872291a2b48SSukumar Swaminathan  *
1873fcf3ce44SJohn Forte  * NAME:     emlxs_ffcleanup
1874fcf3ce44SJohn Forte  *
1875fcf3ce44SJohn Forte  * FUNCTION: Cleanup all the Firefly resources used by configuring the adapter
1876fcf3ce44SJohn Forte  *
1877fcf3ce44SJohn Forte  * EXECUTION ENVIRONMENT: process only
1878fcf3ce44SJohn Forte  *
1879fcf3ce44SJohn Forte  * CALLED FROM: CFG_TERM
1880fcf3ce44SJohn Forte  *
1881fcf3ce44SJohn Forte  * INPUT: hba       - pointer to the dev_ctl area.
1882fcf3ce44SJohn Forte  *
1883fcf3ce44SJohn Forte  * RETURNS: none
1884fcf3ce44SJohn Forte  */
1885fcf3ce44SJohn Forte extern void
1886fcf3ce44SJohn Forte emlxs_ffcleanup(emlxs_hba_t *hba)
1887fcf3ce44SJohn Forte {
1888fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1889291a2b48SSukumar Swaminathan 	uint32_t i;
1890fcf3ce44SJohn Forte 
1891fcf3ce44SJohn Forte 	/* Disable all but the mailbox interrupt */
189282527734SSukumar Swaminathan 	EMLXS_SLI_DISABLE_INTR(hba, HC_MBINT_ENA);
1893fcf3ce44SJohn Forte 
1894fcf3ce44SJohn Forte 	/* Make sure all port nodes are destroyed */
1895291a2b48SSukumar Swaminathan 	for (i = 0; i < MAX_VPORTS; i++) {
1896291a2b48SSukumar Swaminathan 		port = &VPORT(i);
1897fcf3ce44SJohn Forte 
1898fcf3ce44SJohn Forte 		if (port->node_count) {
1899*a9800bebSGarrett D'Amore 			(void) emlxs_mb_unreg_node(port, 0, 0, 0, 0);
1900fcf3ce44SJohn Forte 		}
1901fcf3ce44SJohn Forte 	}
1902fcf3ce44SJohn Forte 
1903fcf3ce44SJohn Forte 	/* Clear all interrupt enable conditions */
190482527734SSukumar Swaminathan 	EMLXS_SLI_DISABLE_INTR(hba, 0);
1905fcf3ce44SJohn Forte 
1906fcf3ce44SJohn Forte 	return;
1907fcf3ce44SJohn Forte 
190882527734SSukumar Swaminathan } /* emlxs_ffcleanup() */
1909fcf3ce44SJohn Forte 
1910fcf3ce44SJohn Forte 
1911fcf3ce44SJohn Forte extern uint16_t
191282527734SSukumar Swaminathan emlxs_register_pkt(CHANNEL *cp, emlxs_buf_t *sbp)
1913fcf3ce44SJohn Forte {
1914fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
1915fcf3ce44SJohn Forte 	emlxs_port_t *port;
1916fcf3ce44SJohn Forte 	uint16_t iotag;
1917fcf3ce44SJohn Forte 	uint32_t i;
1918fcf3ce44SJohn Forte 
191982527734SSukumar Swaminathan 	hba = cp->hba;
1920fcf3ce44SJohn Forte 
192182527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
1922fcf3ce44SJohn Forte 
1923fcf3ce44SJohn Forte 	if (sbp->iotag != 0) {
1924fcf3ce44SJohn Forte 		port = &PPORT;
1925fcf3ce44SJohn Forte 
1926fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
192782527734SSukumar Swaminathan 		    "Pkt already registered! channel=%d iotag=%d sbp=%p",
192882527734SSukumar Swaminathan 		    sbp->channel, sbp->iotag, sbp);
1929fcf3ce44SJohn Forte 	}
1930291a2b48SSukumar Swaminathan 
1931fcf3ce44SJohn Forte 	iotag = 0;
193282527734SSukumar Swaminathan 	for (i = 0; i < hba->max_iotag; i++) {
193382527734SSukumar Swaminathan 		if (!hba->fc_iotag || hba->fc_iotag >= hba->max_iotag) {
193482527734SSukumar Swaminathan 			hba->fc_iotag = 1;
1935fcf3ce44SJohn Forte 		}
193682527734SSukumar Swaminathan 		iotag = hba->fc_iotag++;
1937fcf3ce44SJohn Forte 
193882527734SSukumar Swaminathan 		if (hba->fc_table[iotag] == 0 ||
193982527734SSukumar Swaminathan 		    hba->fc_table[iotag] == STALE_PACKET) {
194082527734SSukumar Swaminathan 			hba->io_count++;
194182527734SSukumar Swaminathan 			hba->fc_table[iotag] = sbp;
1942fcf3ce44SJohn Forte 
1943fcf3ce44SJohn Forte 			sbp->iotag = iotag;
194482527734SSukumar Swaminathan 			sbp->channel = cp;
1945fcf3ce44SJohn Forte 
1946fcf3ce44SJohn Forte 			break;
1947fcf3ce44SJohn Forte 		}
1948fcf3ce44SJohn Forte 		iotag = 0;
1949fcf3ce44SJohn Forte 	}
1950fcf3ce44SJohn Forte 
195182527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
1952fcf3ce44SJohn Forte 
1953fcf3ce44SJohn Forte 	/*
1954fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
195582527734SSukumar Swaminathan 	 *    "emlxs_register_pkt: channel=%d iotag=%d sbp=%p",
195682527734SSukumar Swaminathan 	 *    cp->channelno, iotag, sbp);
1957fcf3ce44SJohn Forte 	 */
1958fcf3ce44SJohn Forte 
1959fcf3ce44SJohn Forte 	return (iotag);
1960fcf3ce44SJohn Forte 
196182527734SSukumar Swaminathan } /* emlxs_register_pkt() */
1962fcf3ce44SJohn Forte 
1963fcf3ce44SJohn Forte 
1964fcf3ce44SJohn Forte 
1965fcf3ce44SJohn Forte extern emlxs_buf_t *
196682527734SSukumar Swaminathan emlxs_unregister_pkt(CHANNEL *cp, uint16_t iotag, uint32_t forced)
1967fcf3ce44SJohn Forte {
1968fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
1969fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
197082527734SSukumar Swaminathan 
197182527734SSukumar Swaminathan 	sbp = NULL;
197282527734SSukumar Swaminathan 	hba = cp->hba;
1973fcf3ce44SJohn Forte 
1974fcf3ce44SJohn Forte 	/* Check the iotag range */
197582527734SSukumar Swaminathan 	if ((iotag == 0) || (iotag >= hba->max_iotag)) {
1976fcf3ce44SJohn Forte 		return (NULL);
1977fcf3ce44SJohn Forte 	}
1978291a2b48SSukumar Swaminathan 
1979fcf3ce44SJohn Forte 	/* Remove the sbp from the table */
198082527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
198182527734SSukumar Swaminathan 	sbp = hba->fc_table[iotag];
1982fcf3ce44SJohn Forte 
1983fcf3ce44SJohn Forte 	if (!sbp || (sbp == STALE_PACKET)) {
198482527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
1985fcf3ce44SJohn Forte 		return (sbp);
1986fcf3ce44SJohn Forte 	}
1987291a2b48SSukumar Swaminathan 
198882527734SSukumar Swaminathan 	hba->fc_table[iotag] = ((forced) ? STALE_PACKET : NULL);
198982527734SSukumar Swaminathan 	hba->io_count--;
1990fcf3ce44SJohn Forte 	sbp->iotag = 0;
1991fcf3ce44SJohn Forte 
199282527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
1993fcf3ce44SJohn Forte 
1994fcf3ce44SJohn Forte 
1995fcf3ce44SJohn Forte 	/* Clean up the sbp */
1996fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
1997fcf3ce44SJohn Forte 
1998fcf3ce44SJohn Forte 	if (sbp->pkt_flags & PACKET_IN_TXQ) {
1999fcf3ce44SJohn Forte 		sbp->pkt_flags &= ~PACKET_IN_TXQ;
200082527734SSukumar Swaminathan 		hba->channel_tx_count--;
2001fcf3ce44SJohn Forte 	}
2002291a2b48SSukumar Swaminathan 
2003fcf3ce44SJohn Forte 	if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
2004fcf3ce44SJohn Forte 		sbp->pkt_flags &= ~PACKET_IN_CHIPQ;
2005fcf3ce44SJohn Forte 	}
2006291a2b48SSukumar Swaminathan 
2007fcf3ce44SJohn Forte 	if (sbp->bmp) {
2008*a9800bebSGarrett D'Amore 		emlxs_mem_put(hba, MEM_BPL, (void *)sbp->bmp);
2009fcf3ce44SJohn Forte 		sbp->bmp = 0;
2010fcf3ce44SJohn Forte 	}
2011fcf3ce44SJohn Forte 
2012291a2b48SSukumar Swaminathan 	mutex_exit(&sbp->mtx);
2013fcf3ce44SJohn Forte 
2014fcf3ce44SJohn Forte 	return (sbp);
2015fcf3ce44SJohn Forte 
201682527734SSukumar Swaminathan } /* emlxs_unregister_pkt() */
2017fcf3ce44SJohn Forte 
2018fcf3ce44SJohn Forte 
2019fcf3ce44SJohn Forte 
202082527734SSukumar Swaminathan /* Flush all IO's to all nodes for a given IO Channel */
2021fcf3ce44SJohn Forte extern uint32_t
202282527734SSukumar Swaminathan emlxs_tx_channel_flush(emlxs_hba_t *hba, CHANNEL *cp, emlxs_buf_t *fpkt)
2023fcf3ce44SJohn Forte {
2024fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2025fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2026fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2027fcf3ce44SJohn Forte 	IOCBQ *next;
2028fcf3ce44SJohn Forte 	IOCB *iocb;
202982527734SSukumar Swaminathan 	uint32_t channelno;
2030fcf3ce44SJohn Forte 	Q abort;
2031fcf3ce44SJohn Forte 	NODELIST *ndlp;
2032fcf3ce44SJohn Forte 	IOCB *icmd;
2033fcf3ce44SJohn Forte 	MATCHMAP *mp;
2034fcf3ce44SJohn Forte 	uint32_t i;
203582527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2036fcf3ce44SJohn Forte 
203782527734SSukumar Swaminathan 	channelno = cp->channelno;
2038fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
203982527734SSukumar Swaminathan 	bzero((void *)flag, MAX_CHANNEL * sizeof (uint8_t));
2040fcf3ce44SJohn Forte 
204182527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2042fcf3ce44SJohn Forte 
2043fcf3ce44SJohn Forte 	/* While a node needs servicing */
204482527734SSukumar Swaminathan 	while (cp->nodeq.q_first) {
204582527734SSukumar Swaminathan 		ndlp = (NODELIST *) cp->nodeq.q_first;
2046fcf3ce44SJohn Forte 
2047fcf3ce44SJohn Forte 		/* Check if priority queue is not empty */
204882527734SSukumar Swaminathan 		if (ndlp->nlp_ptx[channelno].q_first) {
2049fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2050fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
205182527734SSukumar Swaminathan 				abort.q_first =
205282527734SSukumar Swaminathan 				    ndlp->nlp_ptx[channelno].q_first;
2053fcf3ce44SJohn Forte 			} else {
2054fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
205582527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_ptx[channelno].q_first;
2056fcf3ce44SJohn Forte 			}
205782527734SSukumar Swaminathan 			flag[channelno] = 1;
2058fcf3ce44SJohn Forte 
205982527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_ptx[channelno].q_last;
206082527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_ptx[channelno].q_cnt;
2061fcf3ce44SJohn Forte 		}
2062291a2b48SSukumar Swaminathan 
2063fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
206482527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
2065fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2066fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
206782527734SSukumar Swaminathan 				abort.q_first = ndlp->nlp_tx[channelno].q_first;
2068fcf3ce44SJohn Forte 			} else {
2069fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
207082527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2071fcf3ce44SJohn Forte 			}
2072fcf3ce44SJohn Forte 
207382527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_tx[channelno].q_last;
207482527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_tx[channelno].q_cnt;
2075fcf3ce44SJohn Forte 		}
2076291a2b48SSukumar Swaminathan 
2077fcf3ce44SJohn Forte 		/* Clear the queue pointers */
207882527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_first = NULL;
207982527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_last = NULL;
208082527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_cnt = 0;
2081fcf3ce44SJohn Forte 
208282527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_first = NULL;
208382527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_last = NULL;
208482527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_cnt = 0;
2085fcf3ce44SJohn Forte 
2086fcf3ce44SJohn Forte 		/* Remove node from service queue */
2087fcf3ce44SJohn Forte 
2088fcf3ce44SJohn Forte 		/* If this is the last node on list */
208982527734SSukumar Swaminathan 		if (cp->nodeq.q_last == (void *)ndlp) {
209082527734SSukumar Swaminathan 			cp->nodeq.q_last = NULL;
209182527734SSukumar Swaminathan 			cp->nodeq.q_first = NULL;
209282527734SSukumar Swaminathan 			cp->nodeq.q_cnt = 0;
2093fcf3ce44SJohn Forte 		} else {
2094fcf3ce44SJohn Forte 			/* Remove node from head */
209582527734SSukumar Swaminathan 			cp->nodeq.q_first = ndlp->nlp_next[channelno];
209682527734SSukumar Swaminathan 			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
209782527734SSukumar Swaminathan 			    cp->nodeq.q_first;
209882527734SSukumar Swaminathan 			cp->nodeq.q_cnt--;
2099fcf3ce44SJohn Forte 		}
2100fcf3ce44SJohn Forte 
2101fcf3ce44SJohn Forte 		/* Clear node */
210282527734SSukumar Swaminathan 		ndlp->nlp_next[channelno] = NULL;
2103fcf3ce44SJohn Forte 	}
2104fcf3ce44SJohn Forte 
2105fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2106291a2b48SSukumar Swaminathan 	iocbq = (IOCBQ *) abort.q_first;
2107fcf3ce44SJohn Forte 	while (iocbq) {
2108fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2109fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
211082527734SSukumar Swaminathan 
211182527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
211282527734SSukumar Swaminathan 			sbp = iocbq->sbp;
211382527734SSukumar Swaminathan 			if (sbp) {
2114*a9800bebSGarrett D'Amore 				emlxs_sli4_free_xri(hba, sbp, sbp->xrip, 1);
211582527734SSukumar Swaminathan 			}
211682527734SSukumar Swaminathan 		} else {
211782527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
211882527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
211982527734SSukumar Swaminathan 		}
2120fcf3ce44SJohn Forte 
2121fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2122fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2123fcf3ce44SJohn Forte 
2124fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2125fcf3ce44SJohn Forte 			/*
2126fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2127291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2128291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2129fcf3ce44SJohn Forte 			 */
2130fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2131fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2132fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2133fcf3ce44SJohn Forte 				fpkt->flush_count++;
2134fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2135fcf3ce44SJohn Forte 			}
2136291a2b48SSukumar Swaminathan 
2137fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2138fcf3ce44SJohn Forte 		}
2139291a2b48SSukumar Swaminathan 
2140fcf3ce44SJohn Forte 		iocbq = (IOCBQ *)iocbq->next;
2141fcf3ce44SJohn Forte 	}	/* end of while */
2142fcf3ce44SJohn Forte 
214382527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2144fcf3ce44SJohn Forte 
2145fcf3ce44SJohn Forte 	/* Now abort the iocb's */
2146fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2147fcf3ce44SJohn Forte 	while (iocbq) {
2148fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2149fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2150fcf3ce44SJohn Forte 
2151fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2152fcf3ce44SJohn Forte 		iocbq->next = NULL;
2153fcf3ce44SJohn Forte 
2154fcf3ce44SJohn Forte 		/* Get the pkt */
2155fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2156fcf3ce44SJohn Forte 
2157fcf3ce44SJohn Forte 		if (sbp) {
2158fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2159291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2160fcf3ce44SJohn Forte 
2161fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2162fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2163fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2164fcf3ce44SJohn Forte 			} else {
2165fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2166fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2167fcf3ce44SJohn Forte 			}
2168fcf3ce44SJohn Forte 
2169fcf3ce44SJohn Forte 		}
2170fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2171fcf3ce44SJohn Forte 		else {
2172fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
217382527734SSukumar Swaminathan 
217482527734SSukumar Swaminathan 			/* SLI3 */
217582527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
217682527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
217782527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2178fcf3ce44SJohn Forte 				if ((hba->flag &
2179fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2180fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
218182527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2182fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2183*a9800bebSGarrett D'Amore 						void	*tmp;
218482527734SSukumar Swaminathan 						RING *rp;
2185fcf3ce44SJohn Forte 
218682527734SSukumar Swaminathan 						rp = &hba->sli.sli3.
218782527734SSukumar Swaminathan 						    ring[channelno];
2188fcf3ce44SJohn Forte 						for (i = 0;
218982527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2190fcf3ce44SJohn Forte 						    i++) {
2191fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2192fcf3ce44SJohn Forte 							    hba, rp, icmd);
2193fcf3ce44SJohn Forte 
2194*a9800bebSGarrett D'Amore 							tmp = (void *)mp;
2195fcf3ce44SJohn Forte 							if (mp) {
2196*a9800bebSGarrett D'Amore 							emlxs_mem_put(
2197291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2198fcf3ce44SJohn Forte 							}
2199fcf3ce44SJohn Forte 						}
2200fcf3ce44SJohn Forte 					}
2201291a2b48SSukumar Swaminathan 
2202*a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
2203*a9800bebSGarrett D'Amore 					    (void *)iocbq);
2204fcf3ce44SJohn Forte 				} else {
2205fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
220682527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp,
2207291a2b48SSukumar Swaminathan 					    iocbq);
2208fcf3ce44SJohn Forte 				}
220982527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
221082527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
221182527734SSukumar Swaminathan 
221282527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
2213fcf3ce44SJohn Forte 			}
2214fcf3ce44SJohn Forte 		}
2215fcf3ce44SJohn Forte 
2216fcf3ce44SJohn Forte 		iocbq = next;
2217fcf3ce44SJohn Forte 
2218fcf3ce44SJohn Forte 	}	/* end of while */
2219fcf3ce44SJohn Forte 
222082527734SSukumar Swaminathan 	/* Now trigger channel service */
222182527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
222282527734SSukumar Swaminathan 		if (!flag[channelno]) {
222382527734SSukumar Swaminathan 			continue;
222482527734SSukumar Swaminathan 		}
222582527734SSukumar Swaminathan 
222682527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
222782527734SSukumar Swaminathan 	}
222882527734SSukumar Swaminathan 
2229fcf3ce44SJohn Forte 	return (abort.q_cnt);
2230fcf3ce44SJohn Forte 
223182527734SSukumar Swaminathan } /* emlxs_tx_channel_flush() */
2232fcf3ce44SJohn Forte 
2233fcf3ce44SJohn Forte 
2234fcf3ce44SJohn Forte /* Flush all IO's on all or a given ring for a given node */
2235fcf3ce44SJohn Forte extern uint32_t
223682527734SSukumar Swaminathan emlxs_tx_node_flush(emlxs_port_t *port, NODELIST *ndlp, CHANNEL *chan,
2237fcf3ce44SJohn Forte     uint32_t shutdown, emlxs_buf_t *fpkt)
2238fcf3ce44SJohn Forte {
2239fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2240fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
224182527734SSukumar Swaminathan 	uint32_t channelno;
224282527734SSukumar Swaminathan 	CHANNEL *cp;
2243fcf3ce44SJohn Forte 	IOCB *icmd;
2244fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2245fcf3ce44SJohn Forte 	NODELIST *prev;
2246fcf3ce44SJohn Forte 	IOCBQ *next;
2247fcf3ce44SJohn Forte 	IOCB *iocb;
2248fcf3ce44SJohn Forte 	Q abort;
2249fcf3ce44SJohn Forte 	uint32_t i;
2250fcf3ce44SJohn Forte 	MATCHMAP *mp;
225182527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2252fcf3ce44SJohn Forte 
2253fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
2254fcf3ce44SJohn Forte 
2255fcf3ce44SJohn Forte 	/* Flush all I/O's on tx queue to this target */
225682527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2257fcf3ce44SJohn Forte 
2258fcf3ce44SJohn Forte 	if (!ndlp->nlp_base && shutdown) {
2259fcf3ce44SJohn Forte 		ndlp->nlp_active = 0;
2260fcf3ce44SJohn Forte 	}
2261291a2b48SSukumar Swaminathan 
226282527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
226382527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
2264fcf3ce44SJohn Forte 
226582527734SSukumar Swaminathan 		if (chan && cp != chan) {
2266fcf3ce44SJohn Forte 			continue;
2267fcf3ce44SJohn Forte 		}
2268291a2b48SSukumar Swaminathan 
2269fcf3ce44SJohn Forte 		if (!ndlp->nlp_base || shutdown) {
2270fcf3ce44SJohn Forte 			/* Check if priority queue is not empty */
227182527734SSukumar Swaminathan 			if (ndlp->nlp_ptx[channelno].q_first) {
2272fcf3ce44SJohn Forte 				/* Transfer all iocb's to local queue */
2273fcf3ce44SJohn Forte 				if (abort.q_first == 0) {
2274fcf3ce44SJohn Forte 					abort.q_first =
227582527734SSukumar Swaminathan 					    ndlp->nlp_ptx[channelno].q_first;
2276fcf3ce44SJohn Forte 				} else {
227782527734SSukumar Swaminathan 					((IOCBQ *)(abort.q_last))->next =
227882527734SSukumar Swaminathan 					    (IOCBQ *)ndlp->nlp_ptx[channelno].
2279291a2b48SSukumar Swaminathan 					    q_first;
2280fcf3ce44SJohn Forte 				}
2281fcf3ce44SJohn Forte 
228282527734SSukumar Swaminathan 				flag[channelno] = 1;
228382527734SSukumar Swaminathan 
228482527734SSukumar Swaminathan 				abort.q_last = ndlp->nlp_ptx[channelno].q_last;
228582527734SSukumar Swaminathan 				abort.q_cnt += ndlp->nlp_ptx[channelno].q_cnt;
2286fcf3ce44SJohn Forte 			}
2287fcf3ce44SJohn Forte 		}
2288291a2b48SSukumar Swaminathan 
2289fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
229082527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
229182527734SSukumar Swaminathan 
2292fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2293fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
229482527734SSukumar Swaminathan 				abort.q_first = ndlp->nlp_tx[channelno].q_first;
2295fcf3ce44SJohn Forte 			} else {
2296fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
229782527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2298fcf3ce44SJohn Forte 			}
2299fcf3ce44SJohn Forte 
230082527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_tx[channelno].q_last;
230182527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_tx[channelno].q_cnt;
2302fcf3ce44SJohn Forte 		}
2303291a2b48SSukumar Swaminathan 
2304fcf3ce44SJohn Forte 		/* Clear the queue pointers */
230582527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_first = NULL;
230682527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_last = NULL;
230782527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_cnt = 0;
2308fcf3ce44SJohn Forte 
230982527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_first = NULL;
231082527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_last = NULL;
231182527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_cnt = 0;
2312fcf3ce44SJohn Forte 
231382527734SSukumar Swaminathan 		/* If this node was on the channel queue, remove it */
231482527734SSukumar Swaminathan 		if (ndlp->nlp_next[channelno]) {
2315fcf3ce44SJohn Forte 			/* If this is the only node on list */
231682527734SSukumar Swaminathan 			if (cp->nodeq.q_first == (void *)ndlp &&
231782527734SSukumar Swaminathan 			    cp->nodeq.q_last == (void *)ndlp) {
231882527734SSukumar Swaminathan 				cp->nodeq.q_last = NULL;
231982527734SSukumar Swaminathan 				cp->nodeq.q_first = NULL;
232082527734SSukumar Swaminathan 				cp->nodeq.q_cnt = 0;
232182527734SSukumar Swaminathan 			} else if (cp->nodeq.q_first == (void *)ndlp) {
232282527734SSukumar Swaminathan 				cp->nodeq.q_first = ndlp->nlp_next[channelno];
232382527734SSukumar Swaminathan 				((NODELIST *) cp->nodeq.q_last)->
232482527734SSukumar Swaminathan 				    nlp_next[channelno] = cp->nodeq.q_first;
232582527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
2326291a2b48SSukumar Swaminathan 			} else {
2327fcf3ce44SJohn Forte 				/*
2328291a2b48SSukumar Swaminathan 				 * This is a little more difficult find the
232982527734SSukumar Swaminathan 				 * previous node in the circular channel queue
2330fcf3ce44SJohn Forte 				 */
2331fcf3ce44SJohn Forte 				prev = ndlp;
233282527734SSukumar Swaminathan 				while (prev->nlp_next[channelno] != ndlp) {
233382527734SSukumar Swaminathan 					prev = prev->nlp_next[channelno];
2334fcf3ce44SJohn Forte 				}
2335fcf3ce44SJohn Forte 
233682527734SSukumar Swaminathan 				prev->nlp_next[channelno] =
233782527734SSukumar Swaminathan 				    ndlp->nlp_next[channelno];
2338fcf3ce44SJohn Forte 
233982527734SSukumar Swaminathan 				if (cp->nodeq.q_last == (void *)ndlp) {
234082527734SSukumar Swaminathan 					cp->nodeq.q_last = (void *)prev;
2341fcf3ce44SJohn Forte 				}
234282527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
2343fcf3ce44SJohn Forte 
2344fcf3ce44SJohn Forte 			}
2345fcf3ce44SJohn Forte 
2346fcf3ce44SJohn Forte 			/* Clear node */
234782527734SSukumar Swaminathan 			ndlp->nlp_next[channelno] = NULL;
2348fcf3ce44SJohn Forte 		}
2349291a2b48SSukumar Swaminathan 
2350fcf3ce44SJohn Forte 	}
2351fcf3ce44SJohn Forte 
2352fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2353291a2b48SSukumar Swaminathan 	iocbq = (IOCBQ *) abort.q_first;
2354fcf3ce44SJohn Forte 	while (iocbq) {
2355fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2356fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
235782527734SSukumar Swaminathan 
235882527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
235982527734SSukumar Swaminathan 			sbp = iocbq->sbp;
236082527734SSukumar Swaminathan 			if (sbp) {
2361*a9800bebSGarrett D'Amore 				emlxs_sli4_free_xri(hba, sbp, sbp->xrip, 1);
236282527734SSukumar Swaminathan 			}
236382527734SSukumar Swaminathan 		} else {
236482527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
236582527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
236682527734SSukumar Swaminathan 		}
2367fcf3ce44SJohn Forte 
2368fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2369fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2370fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2371fcf3ce44SJohn Forte 			/*
2372fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2373291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2374291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2375fcf3ce44SJohn Forte 			 */
2376fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2377fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2378fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2379fcf3ce44SJohn Forte 				fpkt->flush_count++;
2380fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2381fcf3ce44SJohn Forte 			}
2382291a2b48SSukumar Swaminathan 
2383fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2384fcf3ce44SJohn Forte 		}
2385291a2b48SSukumar Swaminathan 
2386291a2b48SSukumar Swaminathan 		iocbq = (IOCBQ *) iocbq->next;
2387fcf3ce44SJohn Forte 
2388fcf3ce44SJohn Forte 	}	/* end of while */
2389fcf3ce44SJohn Forte 
239082527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2391fcf3ce44SJohn Forte 
2392fcf3ce44SJohn Forte 	/* Now abort the iocb's outside the locks */
2393fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2394fcf3ce44SJohn Forte 	while (iocbq) {
2395fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2396fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2397fcf3ce44SJohn Forte 
2398fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2399fcf3ce44SJohn Forte 		iocbq->next = NULL;
2400fcf3ce44SJohn Forte 
2401fcf3ce44SJohn Forte 		/* Get the pkt */
2402fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2403fcf3ce44SJohn Forte 
2404fcf3ce44SJohn Forte 		if (sbp) {
2405fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2406291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2407fcf3ce44SJohn Forte 
2408fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2409fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2410fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2411fcf3ce44SJohn Forte 			} else {
2412fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2413fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2414fcf3ce44SJohn Forte 			}
2415fcf3ce44SJohn Forte 
2416fcf3ce44SJohn Forte 		}
2417fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2418fcf3ce44SJohn Forte 		else {
241982527734SSukumar Swaminathan 			/* CMD_CLOSE_XRI_CN should also free the memory */
2420fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
242182527734SSukumar Swaminathan 
242282527734SSukumar Swaminathan 			/* SLI3 */
242382527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
242482527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
242582527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2426fcf3ce44SJohn Forte 				if ((hba->flag &
2427fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2428fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
242982527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2430fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2431*a9800bebSGarrett D'Amore 						void	*tmp;
243282527734SSukumar Swaminathan 						RING *rp;
243382527734SSukumar Swaminathan 						int ch;
2434fcf3ce44SJohn Forte 
243582527734SSukumar Swaminathan 						ch = ((CHANNEL *)
243682527734SSukumar Swaminathan 						    iocbq->channel)->channelno;
243782527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
2438fcf3ce44SJohn Forte 						for (i = 0;
243982527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2440fcf3ce44SJohn Forte 						    i++) {
2441fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2442fcf3ce44SJohn Forte 							    hba, rp, icmd);
2443fcf3ce44SJohn Forte 
2444*a9800bebSGarrett D'Amore 							tmp = (void *)mp;
2445fcf3ce44SJohn Forte 							if (mp) {
2446*a9800bebSGarrett D'Amore 							emlxs_mem_put(
2447291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2448fcf3ce44SJohn Forte 							}
2449fcf3ce44SJohn Forte 						}
2450fcf3ce44SJohn Forte 					}
2451291a2b48SSukumar Swaminathan 
2452*a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
2453*a9800bebSGarrett D'Amore 					    (void *)iocbq);
2454fcf3ce44SJohn Forte 				} else {
2455fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
245682527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
245782527734SSukumar Swaminathan 					    (CHANNEL *)iocbq->channel, iocbq);
2458fcf3ce44SJohn Forte 				}
245982527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
246082527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
246182527734SSukumar Swaminathan 				/*
246282527734SSukumar Swaminathan 				 * Resend the abort iocbq if any
246382527734SSukumar Swaminathan 				 */
246482527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
2465fcf3ce44SJohn Forte 			}
2466fcf3ce44SJohn Forte 		}
2467fcf3ce44SJohn Forte 
2468fcf3ce44SJohn Forte 		iocbq = next;
2469fcf3ce44SJohn Forte 
2470fcf3ce44SJohn Forte 	}	/* end of while */
2471fcf3ce44SJohn Forte 
247282527734SSukumar Swaminathan 	/* Now trigger channel service */
247382527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
247482527734SSukumar Swaminathan 		if (!flag[channelno]) {
247582527734SSukumar Swaminathan 			continue;
247682527734SSukumar Swaminathan 		}
247782527734SSukumar Swaminathan 
247882527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
247982527734SSukumar Swaminathan 	}
248082527734SSukumar Swaminathan 
2481fcf3ce44SJohn Forte 	return (abort.q_cnt);
2482fcf3ce44SJohn Forte 
248382527734SSukumar Swaminathan } /* emlxs_tx_node_flush() */
2484fcf3ce44SJohn Forte 
2485fcf3ce44SJohn Forte 
2486fcf3ce44SJohn Forte /* Check for IO's on all or a given ring for a given node */
2487fcf3ce44SJohn Forte extern uint32_t
248882527734SSukumar Swaminathan emlxs_tx_node_check(emlxs_port_t *port, NODELIST *ndlp, CHANNEL *chan)
2489fcf3ce44SJohn Forte {
2490fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
249182527734SSukumar Swaminathan 	uint32_t channelno;
249282527734SSukumar Swaminathan 	CHANNEL *cp;
2493fcf3ce44SJohn Forte 	uint32_t count;
2494fcf3ce44SJohn Forte 
2495fcf3ce44SJohn Forte 	count = 0;
2496fcf3ce44SJohn Forte 
2497fcf3ce44SJohn Forte 	/* Flush all I/O's on tx queue to this target */
249882527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2499fcf3ce44SJohn Forte 
250082527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
250182527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
2502fcf3ce44SJohn Forte 
250382527734SSukumar Swaminathan 		if (chan && cp != chan) {
2504fcf3ce44SJohn Forte 			continue;
2505fcf3ce44SJohn Forte 		}
2506291a2b48SSukumar Swaminathan 
2507fcf3ce44SJohn Forte 		/* Check if priority queue is not empty */
250882527734SSukumar Swaminathan 		if (ndlp->nlp_ptx[channelno].q_first) {
250982527734SSukumar Swaminathan 			count += ndlp->nlp_ptx[channelno].q_cnt;
2510fcf3ce44SJohn Forte 		}
2511291a2b48SSukumar Swaminathan 
2512fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
251382527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
251482527734SSukumar Swaminathan 			count += ndlp->nlp_tx[channelno].q_cnt;
2515fcf3ce44SJohn Forte 		}
2516291a2b48SSukumar Swaminathan 
2517fcf3ce44SJohn Forte 	}
2518fcf3ce44SJohn Forte 
251982527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2520fcf3ce44SJohn Forte 
2521fcf3ce44SJohn Forte 	return (count);
2522fcf3ce44SJohn Forte 
252382527734SSukumar Swaminathan } /* emlxs_tx_node_check() */
2524fcf3ce44SJohn Forte 
2525fcf3ce44SJohn Forte 
2526fcf3ce44SJohn Forte 
252782527734SSukumar Swaminathan /* Flush all IO's on the any ring for a given node's lun */
2528fcf3ce44SJohn Forte extern uint32_t
2529291a2b48SSukumar Swaminathan emlxs_tx_lun_flush(emlxs_port_t *port, NODELIST *ndlp, uint32_t lun,
2530291a2b48SSukumar Swaminathan     emlxs_buf_t *fpkt)
2531fcf3ce44SJohn Forte {
2532fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2533fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
253482527734SSukumar Swaminathan 	uint32_t channelno;
2535fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2536fcf3ce44SJohn Forte 	IOCBQ *prev;
2537fcf3ce44SJohn Forte 	IOCBQ *next;
2538fcf3ce44SJohn Forte 	IOCB *iocb;
2539fcf3ce44SJohn Forte 	IOCB *icmd;
2540fcf3ce44SJohn Forte 	Q abort;
2541fcf3ce44SJohn Forte 	uint32_t i;
2542fcf3ce44SJohn Forte 	MATCHMAP *mp;
254382527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2544fcf3ce44SJohn Forte 
2545*a9800bebSGarrett D'Amore 	if (lun == EMLXS_LUN_NONE) {
2546*a9800bebSGarrett D'Amore 		return (0);
2547*a9800bebSGarrett D'Amore 	}
2548*a9800bebSGarrett D'Amore 
2549fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
2550fcf3ce44SJohn Forte 
2551fcf3ce44SJohn Forte 	/* Flush I/O's on txQ to this target's lun */
255282527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2553fcf3ce44SJohn Forte 
255482527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
2555291a2b48SSukumar Swaminathan 
255682527734SSukumar Swaminathan 		/* Scan the priority queue first */
255782527734SSukumar Swaminathan 		prev = NULL;
255882527734SSukumar Swaminathan 		iocbq = (IOCBQ *) ndlp->nlp_ptx[channelno].q_first;
2559fcf3ce44SJohn Forte 
256082527734SSukumar Swaminathan 		while (iocbq) {
256182527734SSukumar Swaminathan 			next = (IOCBQ *)iocbq->next;
256282527734SSukumar Swaminathan 			iocb = &iocbq->iocb;
256382527734SSukumar Swaminathan 			sbp = (emlxs_buf_t *)iocbq->sbp;
256482527734SSukumar Swaminathan 
256582527734SSukumar Swaminathan 			/* Check if this IO is for our lun */
256682527734SSukumar Swaminathan 			if (sbp && (sbp->lun == lun)) {
256782527734SSukumar Swaminathan 				/* Remove iocb from the node's ptx queue */
256882527734SSukumar Swaminathan 				if (next == 0) {
256982527734SSukumar Swaminathan 					ndlp->nlp_ptx[channelno].q_last =
257082527734SSukumar Swaminathan 					    (uint8_t *)prev;
257182527734SSukumar Swaminathan 				}
257282527734SSukumar Swaminathan 
257382527734SSukumar Swaminathan 				if (prev == 0) {
257482527734SSukumar Swaminathan 					ndlp->nlp_ptx[channelno].q_first =
257582527734SSukumar Swaminathan 					    (uint8_t *)next;
257682527734SSukumar Swaminathan 				} else {
257782527734SSukumar Swaminathan 					prev->next = next;
257882527734SSukumar Swaminathan 				}
257982527734SSukumar Swaminathan 
258082527734SSukumar Swaminathan 				iocbq->next = NULL;
258182527734SSukumar Swaminathan 				ndlp->nlp_ptx[channelno].q_cnt--;
258282527734SSukumar Swaminathan 
258382527734SSukumar Swaminathan 				/*
258482527734SSukumar Swaminathan 				 * Add this iocb to our local abort Q
258582527734SSukumar Swaminathan 				 */
258682527734SSukumar Swaminathan 				if (abort.q_first) {
258782527734SSukumar Swaminathan 					((IOCBQ *)abort.q_last)->next = iocbq;
258882527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
258982527734SSukumar Swaminathan 					abort.q_cnt++;
259082527734SSukumar Swaminathan 				} else {
259182527734SSukumar Swaminathan 					abort.q_first = (uint8_t *)iocbq;
259282527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
259382527734SSukumar Swaminathan 					abort.q_cnt = 1;
259482527734SSukumar Swaminathan 				}
259582527734SSukumar Swaminathan 				iocbq->next = NULL;
259682527734SSukumar Swaminathan 				flag[channelno] = 1;
2597fcf3ce44SJohn Forte 
2598fcf3ce44SJohn Forte 			} else {
259982527734SSukumar Swaminathan 				prev = iocbq;
2600fcf3ce44SJohn Forte 			}
2601fcf3ce44SJohn Forte 
260282527734SSukumar Swaminathan 			iocbq = next;
2603fcf3ce44SJohn Forte 
260482527734SSukumar Swaminathan 		}	/* while (iocbq) */
2605fcf3ce44SJohn Forte 
2606fcf3ce44SJohn Forte 
260782527734SSukumar Swaminathan 		/* Scan the regular queue */
260882527734SSukumar Swaminathan 		prev = NULL;
260982527734SSukumar Swaminathan 		iocbq = (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2610fcf3ce44SJohn Forte 
261182527734SSukumar Swaminathan 		while (iocbq) {
261282527734SSukumar Swaminathan 			next = (IOCBQ *)iocbq->next;
261382527734SSukumar Swaminathan 			iocb = &iocbq->iocb;
261482527734SSukumar Swaminathan 			sbp = (emlxs_buf_t *)iocbq->sbp;
261582527734SSukumar Swaminathan 
261682527734SSukumar Swaminathan 			/* Check if this IO is for our lun */
261782527734SSukumar Swaminathan 			if (sbp && (sbp->lun == lun)) {
261882527734SSukumar Swaminathan 				/* Remove iocb from the node's tx queue */
261982527734SSukumar Swaminathan 				if (next == 0) {
262082527734SSukumar Swaminathan 					ndlp->nlp_tx[channelno].q_last =
262182527734SSukumar Swaminathan 					    (uint8_t *)prev;
262282527734SSukumar Swaminathan 				}
2623291a2b48SSukumar Swaminathan 
262482527734SSukumar Swaminathan 				if (prev == 0) {
262582527734SSukumar Swaminathan 					ndlp->nlp_tx[channelno].q_first =
262682527734SSukumar Swaminathan 					    (uint8_t *)next;
262782527734SSukumar Swaminathan 				} else {
262882527734SSukumar Swaminathan 					prev->next = next;
262982527734SSukumar Swaminathan 				}
2630fcf3ce44SJohn Forte 
263182527734SSukumar Swaminathan 				iocbq->next = NULL;
263282527734SSukumar Swaminathan 				ndlp->nlp_tx[channelno].q_cnt--;
2633fcf3ce44SJohn Forte 
263482527734SSukumar Swaminathan 				/*
263582527734SSukumar Swaminathan 				 * Add this iocb to our local abort Q
263682527734SSukumar Swaminathan 				 */
263782527734SSukumar Swaminathan 				if (abort.q_first) {
263882527734SSukumar Swaminathan 					((IOCBQ *) abort.q_last)->next = iocbq;
263982527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
264082527734SSukumar Swaminathan 					abort.q_cnt++;
264182527734SSukumar Swaminathan 				} else {
264282527734SSukumar Swaminathan 					abort.q_first = (uint8_t *)iocbq;
264382527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
264482527734SSukumar Swaminathan 					abort.q_cnt = 1;
264582527734SSukumar Swaminathan 				}
264682527734SSukumar Swaminathan 				iocbq->next = NULL;
2647fcf3ce44SJohn Forte 			} else {
264882527734SSukumar Swaminathan 				prev = iocbq;
2649fcf3ce44SJohn Forte 			}
2650fcf3ce44SJohn Forte 
265182527734SSukumar Swaminathan 			iocbq = next;
2652fcf3ce44SJohn Forte 
265382527734SSukumar Swaminathan 		}	/* while (iocbq) */
265482527734SSukumar Swaminathan 	}	/* for loop */
2655fcf3ce44SJohn Forte 
2656fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2657fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2658fcf3ce44SJohn Forte 	while (iocbq) {
2659fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2660fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
266182527734SSukumar Swaminathan 
266282527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
266382527734SSukumar Swaminathan 			sbp = iocbq->sbp;
266482527734SSukumar Swaminathan 			if (sbp) {
2665*a9800bebSGarrett D'Amore 				emlxs_sli4_free_xri(hba, sbp, sbp->xrip, 1);
266682527734SSukumar Swaminathan 			}
266782527734SSukumar Swaminathan 		} else {
266882527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
266982527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
267082527734SSukumar Swaminathan 		}
2671fcf3ce44SJohn Forte 
2672fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2673fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2674fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2675fcf3ce44SJohn Forte 			/*
2676fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2677291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2678291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2679fcf3ce44SJohn Forte 			 */
2680fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2681fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2682fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2683fcf3ce44SJohn Forte 				fpkt->flush_count++;
2684fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2685fcf3ce44SJohn Forte 			}
2686291a2b48SSukumar Swaminathan 
2687fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2688fcf3ce44SJohn Forte 		}
2689291a2b48SSukumar Swaminathan 
2690291a2b48SSukumar Swaminathan 		iocbq = (IOCBQ *) iocbq->next;
2691fcf3ce44SJohn Forte 
2692fcf3ce44SJohn Forte 	}	/* end of while */
2693fcf3ce44SJohn Forte 
269482527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2695fcf3ce44SJohn Forte 
2696fcf3ce44SJohn Forte 	/* Now abort the iocb's outside the locks */
2697fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2698fcf3ce44SJohn Forte 	while (iocbq) {
2699fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2700fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2701fcf3ce44SJohn Forte 
2702fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2703fcf3ce44SJohn Forte 		iocbq->next = NULL;
2704fcf3ce44SJohn Forte 
2705fcf3ce44SJohn Forte 		/* Get the pkt */
2706fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2707fcf3ce44SJohn Forte 
2708fcf3ce44SJohn Forte 		if (sbp) {
2709fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2710291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2711fcf3ce44SJohn Forte 
2712fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2713fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2714fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2715fcf3ce44SJohn Forte 			} else {
2716fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2717fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2718fcf3ce44SJohn Forte 			}
2719fcf3ce44SJohn Forte 		}
2720291a2b48SSukumar Swaminathan 
2721fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2722fcf3ce44SJohn Forte 		else {
272382527734SSukumar Swaminathan 			/* Should never happen! */
2724fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
2725fcf3ce44SJohn Forte 
272682527734SSukumar Swaminathan 			/* SLI3 */
272782527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
272882527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
272982527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2730fcf3ce44SJohn Forte 				if ((hba->flag &
2731fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2732fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
273382527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2734fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2735*a9800bebSGarrett D'Amore 						void	*tmp;
273682527734SSukumar Swaminathan 						RING *rp;
273782527734SSukumar Swaminathan 						int ch;
2738fcf3ce44SJohn Forte 
273982527734SSukumar Swaminathan 						ch = ((CHANNEL *)
274082527734SSukumar Swaminathan 						    iocbq->channel)->channelno;
274182527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
2742fcf3ce44SJohn Forte 						for (i = 0;
274382527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2744fcf3ce44SJohn Forte 						    i++) {
2745fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2746fcf3ce44SJohn Forte 							    hba, rp, icmd);
2747fcf3ce44SJohn Forte 
2748*a9800bebSGarrett D'Amore 							tmp = (void *)mp;
2749fcf3ce44SJohn Forte 							if (mp) {
2750*a9800bebSGarrett D'Amore 							emlxs_mem_put(
2751291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2752fcf3ce44SJohn Forte 							}
2753fcf3ce44SJohn Forte 						}
2754fcf3ce44SJohn Forte 					}
2755291a2b48SSukumar Swaminathan 
2756*a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
2757*a9800bebSGarrett D'Amore 					    (void *)iocbq);
2758fcf3ce44SJohn Forte 				} else {
2759fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
276082527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
276182527734SSukumar Swaminathan 					    (CHANNEL *)iocbq->channel, iocbq);
2762fcf3ce44SJohn Forte 				}
276382527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
276482527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
276582527734SSukumar Swaminathan 				/*
276682527734SSukumar Swaminathan 				 * Resend the abort iocbq if any
276782527734SSukumar Swaminathan 				 */
276882527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
2769fcf3ce44SJohn Forte 			}
2770fcf3ce44SJohn Forte 		}
2771fcf3ce44SJohn Forte 
2772fcf3ce44SJohn Forte 		iocbq = next;
2773fcf3ce44SJohn Forte 
2774fcf3ce44SJohn Forte 	}	/* end of while */
2775fcf3ce44SJohn Forte 
277682527734SSukumar Swaminathan 	/* Now trigger channel service */
277782527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
277882527734SSukumar Swaminathan 		if (!flag[channelno]) {
277982527734SSukumar Swaminathan 			continue;
278082527734SSukumar Swaminathan 		}
278182527734SSukumar Swaminathan 
278282527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
278382527734SSukumar Swaminathan 	}
2784fcf3ce44SJohn Forte 
2785fcf3ce44SJohn Forte 	return (abort.q_cnt);
2786fcf3ce44SJohn Forte 
278782527734SSukumar Swaminathan } /* emlxs_tx_lun_flush() */
2788fcf3ce44SJohn Forte 
2789fcf3ce44SJohn Forte 
2790fcf3ce44SJohn Forte extern void
2791fcf3ce44SJohn Forte emlxs_tx_put(IOCBQ *iocbq, uint32_t lock)
2792fcf3ce44SJohn Forte {
2793fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
2794fcf3ce44SJohn Forte 	emlxs_port_t *port;
279582527734SSukumar Swaminathan 	uint32_t channelno;
2796fcf3ce44SJohn Forte 	NODELIST *nlp;
279782527734SSukumar Swaminathan 	CHANNEL *cp;
2798fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2799fcf3ce44SJohn Forte 
2800fcf3ce44SJohn Forte 	port = (emlxs_port_t *)iocbq->port;
2801fcf3ce44SJohn Forte 	hba = HBA;
280282527734SSukumar Swaminathan 	cp = (CHANNEL *)iocbq->channel;
2803fcf3ce44SJohn Forte 	nlp = (NODELIST *)iocbq->node;
280482527734SSukumar Swaminathan 	channelno = cp->channelno;
2805fcf3ce44SJohn Forte 	sbp = (emlxs_buf_t *)iocbq->sbp;
2806fcf3ce44SJohn Forte 
280782527734SSukumar Swaminathan 	/* under what cases, nlp is NULL */
2808fcf3ce44SJohn Forte 	if (nlp == NULL) {
2809fcf3ce44SJohn Forte 		/* Set node to base node by default */
2810fcf3ce44SJohn Forte 		nlp = &port->node_base;
2811fcf3ce44SJohn Forte 
2812fcf3ce44SJohn Forte 		iocbq->node = (void *)nlp;
2813fcf3ce44SJohn Forte 
2814fcf3ce44SJohn Forte 		if (sbp) {
2815fcf3ce44SJohn Forte 			sbp->node = (void *)nlp;
2816fcf3ce44SJohn Forte 		}
2817fcf3ce44SJohn Forte 	}
2818291a2b48SSukumar Swaminathan 
2819fcf3ce44SJohn Forte 	if (lock) {
282082527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2821fcf3ce44SJohn Forte 	}
2822291a2b48SSukumar Swaminathan 
2823fcf3ce44SJohn Forte 	if (!nlp->nlp_active || (sbp && (sbp->pkt_flags & PACKET_IN_ABORT))) {
2824fcf3ce44SJohn Forte 		if (sbp) {
2825fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2826fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2827fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2828fcf3ce44SJohn Forte 
282982527734SSukumar Swaminathan 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2830*a9800bebSGarrett D'Amore 				emlxs_sli4_free_xri(hba, sbp, sbp->xrip, 1);
283182527734SSukumar Swaminathan 			} else {
283282527734SSukumar Swaminathan 				(void) emlxs_unregister_pkt(cp, sbp->iotag, 0);
283382527734SSukumar Swaminathan 			}
2834fcf3ce44SJohn Forte 
2835fcf3ce44SJohn Forte 			if (lock) {
283682527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2837fcf3ce44SJohn Forte 			}
2838291a2b48SSukumar Swaminathan 
2839fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2840fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2841fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2842fcf3ce44SJohn Forte 			} else {
2843fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2844fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2845fcf3ce44SJohn Forte 			}
2846fcf3ce44SJohn Forte 			return;
2847fcf3ce44SJohn Forte 		} else {
2848fcf3ce44SJohn Forte 			if (lock) {
284982527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2850fcf3ce44SJohn Forte 			}
2851291a2b48SSukumar Swaminathan 
2852*a9800bebSGarrett D'Amore 			emlxs_mem_put(hba, MEM_IOCB, (void *)iocbq);
2853fcf3ce44SJohn Forte 		}
2854fcf3ce44SJohn Forte 
2855fcf3ce44SJohn Forte 		return;
2856fcf3ce44SJohn Forte 	}
2857291a2b48SSukumar Swaminathan 
2858fcf3ce44SJohn Forte 	if (sbp) {
2859fcf3ce44SJohn Forte 
2860fcf3ce44SJohn Forte 		mutex_enter(&sbp->mtx);
2861fcf3ce44SJohn Forte 
2862291a2b48SSukumar Swaminathan 		if (sbp->pkt_flags &
2863291a2b48SSukumar Swaminathan 		    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ | PACKET_IN_TXQ)) {
2864fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2865fcf3ce44SJohn Forte 			if (lock) {
286682527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2867fcf3ce44SJohn Forte 			}
2868fcf3ce44SJohn Forte 			return;
2869fcf3ce44SJohn Forte 		}
2870291a2b48SSukumar Swaminathan 
2871fcf3ce44SJohn Forte 		sbp->pkt_flags |= PACKET_IN_TXQ;
287282527734SSukumar Swaminathan 		hba->channel_tx_count++;
2873fcf3ce44SJohn Forte 
2874fcf3ce44SJohn Forte 		mutex_exit(&sbp->mtx);
2875fcf3ce44SJohn Forte 	}
2876291a2b48SSukumar Swaminathan 
2877291a2b48SSukumar Swaminathan 
2878fcf3ce44SJohn Forte 	/* Check iocbq priority */
287982527734SSukumar Swaminathan 	/* Some IOCB has the high priority like reset/close xri etc */
2880fcf3ce44SJohn Forte 	if (iocbq->flag & IOCB_PRIORITY) {
2881fcf3ce44SJohn Forte 		/* Add the iocb to the bottom of the node's ptx queue */
288282527734SSukumar Swaminathan 		if (nlp->nlp_ptx[channelno].q_first) {
288382527734SSukumar Swaminathan 			((IOCBQ *)nlp->nlp_ptx[channelno].q_last)->next = iocbq;
288482527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_last = (uint8_t *)iocbq;
288582527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_cnt++;
2886fcf3ce44SJohn Forte 		} else {
288782527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_first = (uint8_t *)iocbq;
288882527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_last = (uint8_t *)iocbq;
288982527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_cnt = 1;
2890fcf3ce44SJohn Forte 		}
2891fcf3ce44SJohn Forte 
2892fcf3ce44SJohn Forte 		iocbq->next = NULL;
2893fcf3ce44SJohn Forte 	} else {	/* Normal priority */
2894fcf3ce44SJohn Forte 
2895291a2b48SSukumar Swaminathan 
2896fcf3ce44SJohn Forte 		/* Add the iocb to the bottom of the node's tx queue */
289782527734SSukumar Swaminathan 		if (nlp->nlp_tx[channelno].q_first) {
289882527734SSukumar Swaminathan 			((IOCBQ *)nlp->nlp_tx[channelno].q_last)->next = iocbq;
289982527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_last = (uint8_t *)iocbq;
290082527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_cnt++;
2901fcf3ce44SJohn Forte 		} else {
290282527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_first = (uint8_t *)iocbq;
290382527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_last = (uint8_t *)iocbq;
290482527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_cnt = 1;
2905fcf3ce44SJohn Forte 		}
2906fcf3ce44SJohn Forte 
2907fcf3ce44SJohn Forte 		iocbq->next = NULL;
2908fcf3ce44SJohn Forte 	}
2909fcf3ce44SJohn Forte 
2910fcf3ce44SJohn Forte 
2911fcf3ce44SJohn Forte 	/*
291282527734SSukumar Swaminathan 	 * Check if the node is not already on channel queue and
2913291a2b48SSukumar Swaminathan 	 * (is not closed or  is a priority request)
2914fcf3ce44SJohn Forte 	 */
291582527734SSukumar Swaminathan 	if (!nlp->nlp_next[channelno] &&
291682527734SSukumar Swaminathan 	    (!(nlp->nlp_flag[channelno] & NLP_CLOSED) ||
2917fcf3ce44SJohn Forte 	    (iocbq->flag & IOCB_PRIORITY))) {
291882527734SSukumar Swaminathan 		/* If so, then add it to the channel queue */
291982527734SSukumar Swaminathan 		if (cp->nodeq.q_first) {
292082527734SSukumar Swaminathan 			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
2921fcf3ce44SJohn Forte 			    (uint8_t *)nlp;
292282527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = cp->nodeq.q_first;
2923fcf3ce44SJohn Forte 
2924fcf3ce44SJohn Forte 			/*
2925291a2b48SSukumar Swaminathan 			 * If this is not the base node then add it
2926291a2b48SSukumar Swaminathan 			 * to the tail
2927fcf3ce44SJohn Forte 			 */
2928fcf3ce44SJohn Forte 			if (!nlp->nlp_base) {
292982527734SSukumar Swaminathan 				cp->nodeq.q_last = (uint8_t *)nlp;
2930fcf3ce44SJohn Forte 			} else {	/* Otherwise, add it to the head */
2931291a2b48SSukumar Swaminathan 
2932fcf3ce44SJohn Forte 				/* The command node always gets priority */
293382527734SSukumar Swaminathan 				cp->nodeq.q_first = (uint8_t *)nlp;
2934fcf3ce44SJohn Forte 			}
2935fcf3ce44SJohn Forte 
293682527734SSukumar Swaminathan 			cp->nodeq.q_cnt++;
2937fcf3ce44SJohn Forte 		} else {
293882527734SSukumar Swaminathan 			cp->nodeq.q_first = (uint8_t *)nlp;
293982527734SSukumar Swaminathan 			cp->nodeq.q_last = (uint8_t *)nlp;
294082527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = nlp;
294182527734SSukumar Swaminathan 			cp->nodeq.q_cnt = 1;
2942fcf3ce44SJohn Forte 		}
2943fcf3ce44SJohn Forte 	}
2944291a2b48SSukumar Swaminathan 
294582527734SSukumar Swaminathan 	HBASTATS.IocbTxPut[channelno]++;
2946fcf3ce44SJohn Forte 
294782527734SSukumar Swaminathan 	/* Adjust the channel timeout timer */
294882527734SSukumar Swaminathan 	cp->timeout = hba->timer_tics + 5;
2949fcf3ce44SJohn Forte 
2950fcf3ce44SJohn Forte 	if (lock) {
295182527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2952fcf3ce44SJohn Forte 	}
2953291a2b48SSukumar Swaminathan 
2954fcf3ce44SJohn Forte 	return;
2955fcf3ce44SJohn Forte 
295682527734SSukumar Swaminathan } /* emlxs_tx_put() */
2957fcf3ce44SJohn Forte 
2958fcf3ce44SJohn Forte 
2959fcf3ce44SJohn Forte extern IOCBQ *
296082527734SSukumar Swaminathan emlxs_tx_get(CHANNEL *cp, uint32_t lock)
2961fcf3ce44SJohn Forte {
2962fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
296382527734SSukumar Swaminathan 	uint32_t channelno;
2964fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2965fcf3ce44SJohn Forte 	NODELIST *nlp;
2966fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2967fcf3ce44SJohn Forte 
296882527734SSukumar Swaminathan 	hba = cp->hba;
296982527734SSukumar Swaminathan 	channelno = cp->channelno;
2970fcf3ce44SJohn Forte 
2971fcf3ce44SJohn Forte 	if (lock) {
297282527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2973fcf3ce44SJohn Forte 	}
2974291a2b48SSukumar Swaminathan 
2975fcf3ce44SJohn Forte begin:
2976fcf3ce44SJohn Forte 
2977fcf3ce44SJohn Forte 	iocbq = NULL;
2978fcf3ce44SJohn Forte 
2979fcf3ce44SJohn Forte 	/* Check if a node needs servicing */
298082527734SSukumar Swaminathan 	if (cp->nodeq.q_first) {
298182527734SSukumar Swaminathan 		nlp = (NODELIST *)cp->nodeq.q_first;
2982fcf3ce44SJohn Forte 
2983fcf3ce44SJohn Forte 		/* Get next iocb from node's priority queue */
2984fcf3ce44SJohn Forte 
298582527734SSukumar Swaminathan 		if (nlp->nlp_ptx[channelno].q_first) {
298682527734SSukumar Swaminathan 			iocbq = (IOCBQ *)nlp->nlp_ptx[channelno].q_first;
2987fcf3ce44SJohn Forte 
2988fcf3ce44SJohn Forte 			/* Check if this is last entry */
298982527734SSukumar Swaminathan 			if (nlp->nlp_ptx[channelno].q_last == (void *)iocbq) {
299082527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_first = NULL;
299182527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_last = NULL;
299282527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_cnt = 0;
2993fcf3ce44SJohn Forte 			} else {
2994fcf3ce44SJohn Forte 				/* Remove iocb from head */
299582527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_first =
2996fcf3ce44SJohn Forte 				    (void *)iocbq->next;
299782527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_cnt--;
2998fcf3ce44SJohn Forte 			}
2999fcf3ce44SJohn Forte 
3000fcf3ce44SJohn Forte 			iocbq->next = NULL;
3001fcf3ce44SJohn Forte 		}
3002291a2b48SSukumar Swaminathan 
3003fcf3ce44SJohn Forte 		/* Get next iocb from node tx queue if node not closed */
300482527734SSukumar Swaminathan 		else if (nlp->nlp_tx[channelno].q_first &&
300582527734SSukumar Swaminathan 		    !(nlp->nlp_flag[channelno] & NLP_CLOSED)) {
300682527734SSukumar Swaminathan 			iocbq = (IOCBQ *)nlp->nlp_tx[channelno].q_first;
3007fcf3ce44SJohn Forte 
3008fcf3ce44SJohn Forte 			/* Check if this is last entry */
300982527734SSukumar Swaminathan 			if (nlp->nlp_tx[channelno].q_last == (void *)iocbq) {
301082527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_first = NULL;
301182527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_last = NULL;
301282527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_cnt = 0;
3013fcf3ce44SJohn Forte 			} else {
3014fcf3ce44SJohn Forte 				/* Remove iocb from head */
301582527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_first =
3016fcf3ce44SJohn Forte 				    (void *)iocbq->next;
301782527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_cnt--;
3018fcf3ce44SJohn Forte 			}
3019fcf3ce44SJohn Forte 
3020fcf3ce44SJohn Forte 			iocbq->next = NULL;
3021fcf3ce44SJohn Forte 		}
3022291a2b48SSukumar Swaminathan 
3023fcf3ce44SJohn Forte 		/* Now deal with node itself */
3024fcf3ce44SJohn Forte 
3025fcf3ce44SJohn Forte 		/* Check if node still needs servicing */
302682527734SSukumar Swaminathan 		if ((nlp->nlp_ptx[channelno].q_first) ||
302782527734SSukumar Swaminathan 		    (nlp->nlp_tx[channelno].q_first &&
302882527734SSukumar Swaminathan 		    !(nlp->nlp_flag[channelno] & NLP_CLOSED))) {
3029fcf3ce44SJohn Forte 
3030fcf3ce44SJohn Forte 			/*
3031fcf3ce44SJohn Forte 			 * If this is the base node, then don't shift the
3032291a2b48SSukumar Swaminathan 			 * pointers. We want to drain the base node before
3033291a2b48SSukumar Swaminathan 			 * moving on
3034fcf3ce44SJohn Forte 			 */
3035fcf3ce44SJohn Forte 			if (!nlp->nlp_base) {
3036fcf3ce44SJohn Forte 				/*
303782527734SSukumar Swaminathan 				 * Just shift channel queue pointers to next
3038fcf3ce44SJohn Forte 				 * node
3039fcf3ce44SJohn Forte 				 */
304082527734SSukumar Swaminathan 				cp->nodeq.q_last = (void *)nlp;
304182527734SSukumar Swaminathan 				cp->nodeq.q_first = nlp->nlp_next[channelno];
3042fcf3ce44SJohn Forte 			}
3043fcf3ce44SJohn Forte 		} else {
304482527734SSukumar Swaminathan 			/* Remove node from channel queue */
3045fcf3ce44SJohn Forte 
3046fcf3ce44SJohn Forte 			/* If this is the last node on list */
304782527734SSukumar Swaminathan 			if (cp->nodeq.q_last == (void *)nlp) {
304882527734SSukumar Swaminathan 				cp->nodeq.q_last = NULL;
304982527734SSukumar Swaminathan 				cp->nodeq.q_first = NULL;
305082527734SSukumar Swaminathan 				cp->nodeq.q_cnt = 0;
3051fcf3ce44SJohn Forte 			} else {
3052fcf3ce44SJohn Forte 				/* Remove node from head */
305382527734SSukumar Swaminathan 				cp->nodeq.q_first = nlp->nlp_next[channelno];
305482527734SSukumar Swaminathan 				((NODELIST *)cp->nodeq.q_last)->
305582527734SSukumar Swaminathan 				    nlp_next[channelno] = cp->nodeq.q_first;
305682527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
3057fcf3ce44SJohn Forte 
3058fcf3ce44SJohn Forte 			}
3059fcf3ce44SJohn Forte 
3060fcf3ce44SJohn Forte 			/* Clear node */
306182527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = NULL;
3062fcf3ce44SJohn Forte 		}
3063fcf3ce44SJohn Forte 
3064fcf3ce44SJohn Forte 		/*
3065291a2b48SSukumar Swaminathan 		 * If no iocbq was found on this node, then it will have
3066291a2b48SSukumar Swaminathan 		 * been removed. So try again.
3067fcf3ce44SJohn Forte 		 */
3068fcf3ce44SJohn Forte 		if (!iocbq) {
3069fcf3ce44SJohn Forte 			goto begin;
3070fcf3ce44SJohn Forte 		}
3071291a2b48SSukumar Swaminathan 
3072fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
3073fcf3ce44SJohn Forte 
3074fcf3ce44SJohn Forte 		if (sbp) {
3075fcf3ce44SJohn Forte 			/*
3076291a2b48SSukumar Swaminathan 			 * Check flags before we enter mutex in case this
3077291a2b48SSukumar Swaminathan 			 * has been flushed and destroyed
3078fcf3ce44SJohn Forte 			 */
3079fcf3ce44SJohn Forte 			if ((sbp->pkt_flags &
3080fcf3ce44SJohn Forte 			    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) ||
3081fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_IN_TXQ)) {
3082fcf3ce44SJohn Forte 				goto begin;
3083fcf3ce44SJohn Forte 			}
3084291a2b48SSukumar Swaminathan 
3085fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
3086fcf3ce44SJohn Forte 
3087fcf3ce44SJohn Forte 			if ((sbp->pkt_flags &
3088fcf3ce44SJohn Forte 			    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) ||
3089fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_IN_TXQ)) {
3090fcf3ce44SJohn Forte 				mutex_exit(&sbp->mtx);
3091fcf3ce44SJohn Forte 				goto begin;
3092fcf3ce44SJohn Forte 			}
3093291a2b48SSukumar Swaminathan 
3094fcf3ce44SJohn Forte 			sbp->pkt_flags &= ~PACKET_IN_TXQ;
309582527734SSukumar Swaminathan 			hba->channel_tx_count--;
3096fcf3ce44SJohn Forte 
3097fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3098fcf3ce44SJohn Forte 		}
3099fcf3ce44SJohn Forte 	}
3100291a2b48SSukumar Swaminathan 
3101fcf3ce44SJohn Forte 	if (iocbq) {
310282527734SSukumar Swaminathan 		HBASTATS.IocbTxGet[channelno]++;
3103fcf3ce44SJohn Forte 	}
3104291a2b48SSukumar Swaminathan 
3105fcf3ce44SJohn Forte 	/* Adjust the ring timeout timer */
310682527734SSukumar Swaminathan 	cp->timeout = (cp->nodeq.q_first) ? (hba->timer_tics + 5) : 0;
3107fcf3ce44SJohn Forte 
3108fcf3ce44SJohn Forte 	if (lock) {
310982527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3110fcf3ce44SJohn Forte 	}
3111291a2b48SSukumar Swaminathan 
3112fcf3ce44SJohn Forte 	return (iocbq);
3113fcf3ce44SJohn Forte 
311482527734SSukumar Swaminathan } /* emlxs_tx_get() */
311582527734SSukumar Swaminathan 
3116fcf3ce44SJohn Forte 
311782527734SSukumar Swaminathan /*
311882527734SSukumar Swaminathan  * Remove all cmd from from_rp's txq to to_rp's txq for ndlp.
311982527734SSukumar Swaminathan  * The old IoTag has to be released, the new one has to be
312082527734SSukumar Swaminathan  * allocated.  Others no change
312182527734SSukumar Swaminathan  * TX_CHANNEL lock is held
312282527734SSukumar Swaminathan  */
312382527734SSukumar Swaminathan extern void
312482527734SSukumar Swaminathan emlxs_tx_move(NODELIST *ndlp, CHANNEL *from_chan, CHANNEL *to_chan,
312582527734SSukumar Swaminathan     uint32_t cmd, emlxs_buf_t *fpkt, uint32_t lock)
312682527734SSukumar Swaminathan {
312782527734SSukumar Swaminathan 	emlxs_hba_t *hba;
312882527734SSukumar Swaminathan 	emlxs_port_t *port;
312982527734SSukumar Swaminathan 	uint32_t fchanno, tchanno, i;
313082527734SSukumar Swaminathan 
313182527734SSukumar Swaminathan 	IOCBQ *iocbq;
313282527734SSukumar Swaminathan 	IOCBQ *prev;
313382527734SSukumar Swaminathan 	IOCBQ *next;
313482527734SSukumar Swaminathan 	IOCB *iocb, *icmd;
313582527734SSukumar Swaminathan 	Q tbm;		/* To Be Moved Q */
313682527734SSukumar Swaminathan 	MATCHMAP *mp;
313782527734SSukumar Swaminathan 
313882527734SSukumar Swaminathan 	NODELIST *nlp = ndlp;
313982527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
314082527734SSukumar Swaminathan 
314182527734SSukumar Swaminathan 	NODELIST *n_prev = NULL;
314282527734SSukumar Swaminathan 	NODELIST *n_next = NULL;
314382527734SSukumar Swaminathan 	uint16_t count = 0;
314482527734SSukumar Swaminathan 
314582527734SSukumar Swaminathan 	hba = from_chan->hba;
314682527734SSukumar Swaminathan 	port = &PPORT;
314782527734SSukumar Swaminathan 	cmd = cmd; /* To pass lint */
314882527734SSukumar Swaminathan 
314982527734SSukumar Swaminathan 	fchanno = from_chan->channelno;
315082527734SSukumar Swaminathan 	tchanno = to_chan->channelno;
315182527734SSukumar Swaminathan 
315282527734SSukumar Swaminathan 	if (lock) {
315382527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
315482527734SSukumar Swaminathan 	}
315582527734SSukumar Swaminathan 
315682527734SSukumar Swaminathan 	bzero((void *)&tbm, sizeof (Q));
315782527734SSukumar Swaminathan 
315882527734SSukumar Swaminathan 	/* Scan the ndlp's fchanno txq to get the iocb of fcp cmd */
315982527734SSukumar Swaminathan 	prev = NULL;
316082527734SSukumar Swaminathan 	iocbq = (IOCBQ *)nlp->nlp_tx[fchanno].q_first;
316182527734SSukumar Swaminathan 
316282527734SSukumar Swaminathan 	while (iocbq) {
316382527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
316482527734SSukumar Swaminathan 		/* Check if this iocb is fcp cmd */
316582527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
316682527734SSukumar Swaminathan 
316782527734SSukumar Swaminathan 		switch (iocb->ULPCOMMAND) {
316882527734SSukumar Swaminathan 		/* FCP commands */
316982527734SSukumar Swaminathan 		case CMD_FCP_ICMND_CR:
317082527734SSukumar Swaminathan 		case CMD_FCP_ICMND_CX:
317182527734SSukumar Swaminathan 		case CMD_FCP_IREAD_CR:
317282527734SSukumar Swaminathan 		case CMD_FCP_IREAD_CX:
317382527734SSukumar Swaminathan 		case CMD_FCP_IWRITE_CR:
317482527734SSukumar Swaminathan 		case CMD_FCP_IWRITE_CX:
317582527734SSukumar Swaminathan 		case CMD_FCP_ICMND64_CR:
317682527734SSukumar Swaminathan 		case CMD_FCP_ICMND64_CX:
317782527734SSukumar Swaminathan 		case CMD_FCP_IREAD64_CR:
317882527734SSukumar Swaminathan 		case CMD_FCP_IREAD64_CX:
317982527734SSukumar Swaminathan 		case CMD_FCP_IWRITE64_CR:
318082527734SSukumar Swaminathan 		case CMD_FCP_IWRITE64_CX:
318182527734SSukumar Swaminathan 			/* We found a fcp cmd */
318282527734SSukumar Swaminathan 			break;
318382527734SSukumar Swaminathan 		default:
318482527734SSukumar Swaminathan 			/* this is not fcp cmd continue */
318582527734SSukumar Swaminathan 			prev = iocbq;
318682527734SSukumar Swaminathan 			iocbq = next;
318782527734SSukumar Swaminathan 			continue;
318882527734SSukumar Swaminathan 		}
318982527734SSukumar Swaminathan 
319082527734SSukumar Swaminathan 		/* found a fcp cmd iocb in fchanno txq, now deque it */
319182527734SSukumar Swaminathan 		if (next == NULL) {
319282527734SSukumar Swaminathan 			/* This is the last iocbq */
319382527734SSukumar Swaminathan 			nlp->nlp_tx[fchanno].q_last =
319482527734SSukumar Swaminathan 			    (uint8_t *)prev;
319582527734SSukumar Swaminathan 		}
319682527734SSukumar Swaminathan 
319782527734SSukumar Swaminathan 		if (prev == NULL) {
319882527734SSukumar Swaminathan 			/* This is the first one then remove it from head */
319982527734SSukumar Swaminathan 			nlp->nlp_tx[fchanno].q_first =
320082527734SSukumar Swaminathan 			    (uint8_t *)next;
320182527734SSukumar Swaminathan 		} else {
320282527734SSukumar Swaminathan 			prev->next = next;
320382527734SSukumar Swaminathan 		}
320482527734SSukumar Swaminathan 
320582527734SSukumar Swaminathan 		iocbq->next = NULL;
320682527734SSukumar Swaminathan 		nlp->nlp_tx[fchanno].q_cnt--;
320782527734SSukumar Swaminathan 
320882527734SSukumar Swaminathan 		/* Add this iocb to our local toberemovedq */
320982527734SSukumar Swaminathan 		/* This way we donot hold the TX_CHANNEL lock too long */
321082527734SSukumar Swaminathan 
321182527734SSukumar Swaminathan 		if (tbm.q_first) {
321282527734SSukumar Swaminathan 			((IOCBQ *)tbm.q_last)->next = iocbq;
321382527734SSukumar Swaminathan 			tbm.q_last = (uint8_t *)iocbq;
321482527734SSukumar Swaminathan 			tbm.q_cnt++;
321582527734SSukumar Swaminathan 		} else {
321682527734SSukumar Swaminathan 			tbm.q_first = (uint8_t *)iocbq;
321782527734SSukumar Swaminathan 			tbm.q_last = (uint8_t *)iocbq;
321882527734SSukumar Swaminathan 			tbm.q_cnt = 1;
321982527734SSukumar Swaminathan 		}
322082527734SSukumar Swaminathan 
322182527734SSukumar Swaminathan 		iocbq = next;
322282527734SSukumar Swaminathan 
322382527734SSukumar Swaminathan 	}	/* While (iocbq) */
322482527734SSukumar Swaminathan 
322582527734SSukumar Swaminathan 	if ((tchanno == hba->channel_fcp) && (tbm.q_cnt != 0)) {
322682527734SSukumar Swaminathan 
322782527734SSukumar Swaminathan 		/* from_chan->nodeq.q_first must be non NULL */
322882527734SSukumar Swaminathan 		if (from_chan->nodeq.q_first) {
322982527734SSukumar Swaminathan 
323082527734SSukumar Swaminathan 			/* nodeq is not empty, now deal with the node itself */
323182527734SSukumar Swaminathan 			if ((nlp->nlp_tx[fchanno].q_first)) {
323282527734SSukumar Swaminathan 
323382527734SSukumar Swaminathan 				if (!nlp->nlp_base) {
323482527734SSukumar Swaminathan 					from_chan->nodeq.q_last =
323582527734SSukumar Swaminathan 					    (void *)nlp;
323682527734SSukumar Swaminathan 					from_chan->nodeq.q_first =
323782527734SSukumar Swaminathan 					    nlp->nlp_next[fchanno];
323882527734SSukumar Swaminathan 				}
323982527734SSukumar Swaminathan 
324082527734SSukumar Swaminathan 			} else {
324182527734SSukumar Swaminathan 				n_prev = (NODELIST *)from_chan->nodeq.q_first;
324282527734SSukumar Swaminathan 				count = from_chan->nodeq.q_cnt;
324382527734SSukumar Swaminathan 
324482527734SSukumar Swaminathan 				if (n_prev == nlp) {
324582527734SSukumar Swaminathan 
324682527734SSukumar Swaminathan 					/* If this is the only node on list */
324782527734SSukumar Swaminathan 					if (from_chan->nodeq.q_last ==
324882527734SSukumar Swaminathan 					    (void *)nlp) {
324982527734SSukumar Swaminathan 						from_chan->nodeq.q_last =
325082527734SSukumar Swaminathan 						    NULL;
325182527734SSukumar Swaminathan 						from_chan->nodeq.q_first =
325282527734SSukumar Swaminathan 						    NULL;
325382527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt = 0;
325482527734SSukumar Swaminathan 					} else {
325582527734SSukumar Swaminathan 						from_chan->nodeq.q_first =
325682527734SSukumar Swaminathan 						    nlp->nlp_next[fchanno];
325782527734SSukumar Swaminathan 						((NODELIST *)from_chan->
325882527734SSukumar Swaminathan 						    nodeq.q_last)->
325982527734SSukumar Swaminathan 						    nlp_next[fchanno] =
326082527734SSukumar Swaminathan 						    from_chan->nodeq.q_first;
326182527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt--;
326282527734SSukumar Swaminathan 					}
326382527734SSukumar Swaminathan 					/* Clear node */
326482527734SSukumar Swaminathan 					nlp->nlp_next[fchanno] = NULL;
326582527734SSukumar Swaminathan 				} else {
326682527734SSukumar Swaminathan 					count--;
326782527734SSukumar Swaminathan 					do {
326882527734SSukumar Swaminathan 						n_next =
326982527734SSukumar Swaminathan 						    n_prev->nlp_next[fchanno];
327082527734SSukumar Swaminathan 						if (n_next == nlp) {
327182527734SSukumar Swaminathan 							break;
327282527734SSukumar Swaminathan 						}
327382527734SSukumar Swaminathan 						n_prev = n_next;
327482527734SSukumar Swaminathan 					} while (count--);
327582527734SSukumar Swaminathan 
327682527734SSukumar Swaminathan 					if (count != 0) {
327782527734SSukumar Swaminathan 
327882527734SSukumar Swaminathan 						if (n_next ==
327982527734SSukumar Swaminathan 						    (NODELIST *)from_chan->
328082527734SSukumar Swaminathan 						    nodeq.q_last) {
328182527734SSukumar Swaminathan 							n_prev->
328282527734SSukumar Swaminathan 							    nlp_next[fchanno]
328382527734SSukumar Swaminathan 							    =
328482527734SSukumar Swaminathan 							    ((NODELIST *)
328582527734SSukumar Swaminathan 							    from_chan->
328682527734SSukumar Swaminathan 							    nodeq.q_last)->
328782527734SSukumar Swaminathan 							    nlp_next
328882527734SSukumar Swaminathan 							    [fchanno];
328982527734SSukumar Swaminathan 							from_chan->nodeq.q_last
329082527734SSukumar Swaminathan 							    = (uint8_t *)n_prev;
329182527734SSukumar Swaminathan 						} else {
329282527734SSukumar Swaminathan 
329382527734SSukumar Swaminathan 							n_prev->
329482527734SSukumar Swaminathan 							    nlp_next[fchanno]
329582527734SSukumar Swaminathan 							    =
329682527734SSukumar Swaminathan 							    n_next-> nlp_next
329782527734SSukumar Swaminathan 							    [fchanno];
329882527734SSukumar Swaminathan 						}
329982527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt--;
330082527734SSukumar Swaminathan 						/* Clear node */
330182527734SSukumar Swaminathan 						nlp->nlp_next[fchanno] =
330282527734SSukumar Swaminathan 						    NULL;
330382527734SSukumar Swaminathan 					}
330482527734SSukumar Swaminathan 				}
330582527734SSukumar Swaminathan 			}
330682527734SSukumar Swaminathan 		}
330782527734SSukumar Swaminathan 	}
330882527734SSukumar Swaminathan 
330982527734SSukumar Swaminathan 	/* Now cleanup the iocb's */
331082527734SSukumar Swaminathan 	prev = NULL;
331182527734SSukumar Swaminathan 	iocbq = (IOCBQ *)tbm.q_first;
331282527734SSukumar Swaminathan 
331382527734SSukumar Swaminathan 	while (iocbq) {
331482527734SSukumar Swaminathan 
331582527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
331682527734SSukumar Swaminathan 
331782527734SSukumar Swaminathan 		/* Free the IoTag and the bmp */
331882527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
331982527734SSukumar Swaminathan 
332082527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
332182527734SSukumar Swaminathan 			sbp = iocbq->sbp;
332282527734SSukumar Swaminathan 			if (sbp) {
3323*a9800bebSGarrett D'Amore 				emlxs_sli4_free_xri(hba, sbp, sbp->xrip, 1);
332482527734SSukumar Swaminathan 			}
332582527734SSukumar Swaminathan 		} else {
332682527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
332782527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
332882527734SSukumar Swaminathan 		}
332982527734SSukumar Swaminathan 
333082527734SSukumar Swaminathan 		if (sbp && (sbp != STALE_PACKET)) {
333182527734SSukumar Swaminathan 			mutex_enter(&sbp->mtx);
333282527734SSukumar Swaminathan 			sbp->pkt_flags |= PACKET_IN_FLUSH;
333382527734SSukumar Swaminathan 
333482527734SSukumar Swaminathan 			/*
333582527734SSukumar Swaminathan 			 * If the fpkt is already set, then we will leave it
333682527734SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
333782527734SSukumar Swaminathan 			 * for on one fpkt->flush_count
333882527734SSukumar Swaminathan 			 */
333982527734SSukumar Swaminathan 			if (!sbp->fpkt && fpkt) {
334082527734SSukumar Swaminathan 				mutex_enter(&fpkt->mtx);
334182527734SSukumar Swaminathan 				sbp->fpkt = fpkt;
334282527734SSukumar Swaminathan 				fpkt->flush_count++;
334382527734SSukumar Swaminathan 				mutex_exit(&fpkt->mtx);
334482527734SSukumar Swaminathan 			}
334582527734SSukumar Swaminathan 			mutex_exit(&sbp->mtx);
334682527734SSukumar Swaminathan 		}
334782527734SSukumar Swaminathan 		iocbq = next;
334882527734SSukumar Swaminathan 
334982527734SSukumar Swaminathan 	}	/* end of while */
335082527734SSukumar Swaminathan 
335182527734SSukumar Swaminathan 	iocbq = (IOCBQ *)tbm.q_first;
335282527734SSukumar Swaminathan 	while (iocbq) {
335382527734SSukumar Swaminathan 		/* Save the next iocbq for now */
335482527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
335582527734SSukumar Swaminathan 
335682527734SSukumar Swaminathan 		/* Unlink this iocbq */
335782527734SSukumar Swaminathan 		iocbq->next = NULL;
335882527734SSukumar Swaminathan 
335982527734SSukumar Swaminathan 		/* Get the pkt */
336082527734SSukumar Swaminathan 		sbp = (emlxs_buf_t *)iocbq->sbp;
336182527734SSukumar Swaminathan 
336282527734SSukumar Swaminathan 		if (sbp) {
336382527734SSukumar Swaminathan 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
336482527734SSukumar Swaminathan 			"tx: sbp=%p node=%p", sbp, sbp->node);
336582527734SSukumar Swaminathan 
336682527734SSukumar Swaminathan 			if (hba->state >= FC_LINK_UP) {
336782527734SSukumar Swaminathan 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
336882527734SSukumar Swaminathan 				    IOERR_ABORT_REQUESTED, 1);
336982527734SSukumar Swaminathan 			} else {
337082527734SSukumar Swaminathan 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
337182527734SSukumar Swaminathan 				    IOERR_LINK_DOWN, 1);
337282527734SSukumar Swaminathan 			}
337382527734SSukumar Swaminathan 
337482527734SSukumar Swaminathan 		}
337582527734SSukumar Swaminathan 		/* Free the iocb and its associated buffers */
337682527734SSukumar Swaminathan 		else {
337782527734SSukumar Swaminathan 			icmd = &iocbq->iocb;
337882527734SSukumar Swaminathan 
337982527734SSukumar Swaminathan 			/* SLI3 */
338082527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
338182527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
338282527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
338382527734SSukumar Swaminathan 				if ((hba->flag &
338482527734SSukumar Swaminathan 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
338582527734SSukumar Swaminathan 					/* HBA is detaching or offlining */
338682527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
338782527734SSukumar Swaminathan 					    CMD_QUE_RING_LIST64_CN) {
3388*a9800bebSGarrett D'Amore 						void *tmp;
338982527734SSukumar Swaminathan 						RING *rp;
339082527734SSukumar Swaminathan 						int ch;
339182527734SSukumar Swaminathan 
339282527734SSukumar Swaminathan 						ch = from_chan->channelno;
339382527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
339482527734SSukumar Swaminathan 
339582527734SSukumar Swaminathan 						for (i = 0;
339682527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
339782527734SSukumar Swaminathan 						    i++) {
339882527734SSukumar Swaminathan 							mp = EMLXS_GET_VADDR(
339982527734SSukumar Swaminathan 							    hba, rp, icmd);
340082527734SSukumar Swaminathan 
3401*a9800bebSGarrett D'Amore 							tmp = (void *)mp;
340282527734SSukumar Swaminathan 							if (mp) {
3403*a9800bebSGarrett D'Amore 							emlxs_mem_put(
340482527734SSukumar Swaminathan 							    hba,
340582527734SSukumar Swaminathan 							    MEM_BUF,
340682527734SSukumar Swaminathan 							    tmp);
340782527734SSukumar Swaminathan 							}
340882527734SSukumar Swaminathan 						}
340982527734SSukumar Swaminathan 
341082527734SSukumar Swaminathan 					}
341182527734SSukumar Swaminathan 
3412*a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
3413*a9800bebSGarrett D'Amore 					    (void *)iocbq);
341482527734SSukumar Swaminathan 				} else {
341582527734SSukumar Swaminathan 					/* repost the unsolicited buffer */
341682527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
341782527734SSukumar Swaminathan 					    from_chan, iocbq);
341882527734SSukumar Swaminathan 				}
341982527734SSukumar Swaminathan 			}
342082527734SSukumar Swaminathan 		}
342182527734SSukumar Swaminathan 
342282527734SSukumar Swaminathan 		iocbq = next;
342382527734SSukumar Swaminathan 
342482527734SSukumar Swaminathan 	}	/* end of while */
342582527734SSukumar Swaminathan 
342682527734SSukumar Swaminathan 	/* Now flush the chipq if any */
342782527734SSukumar Swaminathan 	if (!(nlp->nlp_flag[fchanno] & NLP_CLOSED)) {
342882527734SSukumar Swaminathan 
342982527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
343082527734SSukumar Swaminathan 
343182527734SSukumar Swaminathan 		(void) emlxs_chipq_node_flush(port, from_chan, nlp, 0);
343282527734SSukumar Swaminathan 
343382527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
343482527734SSukumar Swaminathan 	}
343582527734SSukumar Swaminathan 
343682527734SSukumar Swaminathan 	if (lock) {
343782527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
343882527734SSukumar Swaminathan 	}
343982527734SSukumar Swaminathan 
344082527734SSukumar Swaminathan 	return;
344182527734SSukumar Swaminathan 
344282527734SSukumar Swaminathan } /* emlxs_tx_move */
3443fcf3ce44SJohn Forte 
3444fcf3ce44SJohn Forte 
3445fcf3ce44SJohn Forte extern uint32_t
344682527734SSukumar Swaminathan emlxs_chipq_node_flush(emlxs_port_t *port, CHANNEL *chan, NODELIST *ndlp,
3447291a2b48SSukumar Swaminathan     emlxs_buf_t *fpkt)
3448fcf3ce44SJohn Forte {
3449fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3450fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3451fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3452fcf3ce44SJohn Forte 	IOCBQ *next;
3453fcf3ce44SJohn Forte 	Q abort;
345482527734SSukumar Swaminathan 	CHANNEL *cp;
345582527734SSukumar Swaminathan 	uint32_t channelno;
345682527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
3457fcf3ce44SJohn Forte 	uint32_t iotag;
3458fcf3ce44SJohn Forte 
3459fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
3460fcf3ce44SJohn Forte 	bzero((void *)flag, sizeof (flag));
3461fcf3ce44SJohn Forte 
346282527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
346382527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3464fcf3ce44SJohn Forte 
346582527734SSukumar Swaminathan 		if (chan && cp != chan) {
3466fcf3ce44SJohn Forte 			continue;
3467fcf3ce44SJohn Forte 		}
3468291a2b48SSukumar Swaminathan 
346982527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3470fcf3ce44SJohn Forte 
347182527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
347282527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3473fcf3ce44SJohn Forte 
3474fcf3ce44SJohn Forte 			if (sbp && (sbp != STALE_PACKET) &&
3475fcf3ce44SJohn Forte 			    (sbp->pkt_flags & PACKET_IN_CHIPQ) &&
3476fcf3ce44SJohn Forte 			    (sbp->node == ndlp) &&
347782527734SSukumar Swaminathan 			    (sbp->channel == cp) &&
3478fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
3479291a2b48SSukumar Swaminathan 				emlxs_sbp_abort_add(port, sbp, &abort, flag,
3480291a2b48SSukumar Swaminathan 				    fpkt);
3481fcf3ce44SJohn Forte 			}
3482291a2b48SSukumar Swaminathan 
3483fcf3ce44SJohn Forte 		}
348482527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3485fcf3ce44SJohn Forte 
3486fcf3ce44SJohn Forte 	}	/* for */
3487fcf3ce44SJohn Forte 
3488fcf3ce44SJohn Forte 	/* Now put the iocb's on the tx queue */
3489fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
3490fcf3ce44SJohn Forte 	while (iocbq) {
3491fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
3492fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
3493fcf3ce44SJohn Forte 
3494fcf3ce44SJohn Forte 		/* Unlink this iocbq */
3495fcf3ce44SJohn Forte 		iocbq->next = NULL;
3496fcf3ce44SJohn Forte 
3497fcf3ce44SJohn Forte 		/* Send this iocbq */
3498fcf3ce44SJohn Forte 		emlxs_tx_put(iocbq, 1);
3499fcf3ce44SJohn Forte 
3500fcf3ce44SJohn Forte 		iocbq = next;
3501fcf3ce44SJohn Forte 	}
3502fcf3ce44SJohn Forte 
350382527734SSukumar Swaminathan 	/* Now trigger channel service */
350482527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
350582527734SSukumar Swaminathan 		if (!flag[channelno]) {
3506fcf3ce44SJohn Forte 			continue;
3507fcf3ce44SJohn Forte 		}
3508291a2b48SSukumar Swaminathan 
350982527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
3510fcf3ce44SJohn Forte 	}
3511fcf3ce44SJohn Forte 
3512fcf3ce44SJohn Forte 	return (abort.q_cnt);
3513fcf3ce44SJohn Forte 
351482527734SSukumar Swaminathan } /* emlxs_chipq_node_flush() */
3515fcf3ce44SJohn Forte 
3516fcf3ce44SJohn Forte 
3517fcf3ce44SJohn Forte /* Flush all IO's left on all iotag lists */
351882527734SSukumar Swaminathan extern uint32_t
3519fcf3ce44SJohn Forte emlxs_iotag_flush(emlxs_hba_t *hba)
3520fcf3ce44SJohn Forte {
3521fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
3522fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3523fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3524fcf3ce44SJohn Forte 	IOCB *iocb;
3525fcf3ce44SJohn Forte 	Q abort;
352682527734SSukumar Swaminathan 	CHANNEL *cp;
352782527734SSukumar Swaminathan 	uint32_t channelno;
3528fcf3ce44SJohn Forte 	uint32_t iotag;
3529fcf3ce44SJohn Forte 	uint32_t count;
3530fcf3ce44SJohn Forte 
3531fcf3ce44SJohn Forte 	count = 0;
353282527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
353382527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3534fcf3ce44SJohn Forte 
3535fcf3ce44SJohn Forte 		bzero((void *)&abort, sizeof (Q));
3536fcf3ce44SJohn Forte 
353782527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3538fcf3ce44SJohn Forte 
353982527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
354082527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3541fcf3ce44SJohn Forte 
354282527734SSukumar Swaminathan 			/* Check if the slot is empty */
3543fcf3ce44SJohn Forte 			if (!sbp || (sbp == STALE_PACKET)) {
3544fcf3ce44SJohn Forte 				continue;
3545fcf3ce44SJohn Forte 			}
3546291a2b48SSukumar Swaminathan 
354782527734SSukumar Swaminathan 			/* We are building an abort list per channel */
354882527734SSukumar Swaminathan 			if (sbp->channel != cp) {
354982527734SSukumar Swaminathan 				continue;
355082527734SSukumar Swaminathan 			}
3551fcf3ce44SJohn Forte 
3552*a9800bebSGarrett D'Amore 			hba->fc_table[iotag] = STALE_PACKET;
3553*a9800bebSGarrett D'Amore 			hba->io_count--;
3554*a9800bebSGarrett D'Amore 
3555*a9800bebSGarrett D'Amore 			/* Check if IO is valid */
3556*a9800bebSGarrett D'Amore 			if (!(sbp->pkt_flags & PACKET_VALID) ||
3557*a9800bebSGarrett D'Amore 			    (sbp->pkt_flags & (PACKET_ULP_OWNED|
3558*a9800bebSGarrett D'Amore 			    PACKET_COMPLETED|PACKET_IN_COMPLETION))) {
3559*a9800bebSGarrett D'Amore 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
3560*a9800bebSGarrett D'Amore 				    "iotag_flush: Invalid IO found. iotag=%x",
3561*a9800bebSGarrett D'Amore 				    iotag);
3562*a9800bebSGarrett D'Amore 
3563*a9800bebSGarrett D'Amore 				continue;
3564*a9800bebSGarrett D'Amore 			}
3565*a9800bebSGarrett D'Amore 
3566*a9800bebSGarrett D'Amore 			sbp->iotag = 0;
3567*a9800bebSGarrett D'Amore 
3568fcf3ce44SJohn Forte 			/* Set IOCB status */
3569fcf3ce44SJohn Forte 			iocbq = &sbp->iocbq;
3570fcf3ce44SJohn Forte 			iocb = &iocbq->iocb;
3571fcf3ce44SJohn Forte 
357282527734SSukumar Swaminathan 			iocb->ULPSTATUS = IOSTAT_LOCAL_REJECT;
3573fcf3ce44SJohn Forte 			iocb->un.grsp.perr.statLocalError = IOERR_LINK_DOWN;
357482527734SSukumar Swaminathan 			iocb->ULPLE = 1;
3575fcf3ce44SJohn Forte 			iocbq->next = NULL;
3576fcf3ce44SJohn Forte 
357782527734SSukumar Swaminathan 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3578*a9800bebSGarrett D'Amore 				if (sbp->xrip) {
3579*a9800bebSGarrett D'Amore 					EMLXS_MSGF(EMLXS_CONTEXT,
3580*a9800bebSGarrett D'Amore 					    &emlxs_sli_debug_msg,
3581*a9800bebSGarrett D'Amore 					    "iotag_flush: iotag=%x sbp=%p "
3582*a9800bebSGarrett D'Amore 					    "xrip=%p state=%x flag=%x",
3583*a9800bebSGarrett D'Amore 					    iotag, sbp, sbp->xrip,
3584*a9800bebSGarrett D'Amore 					    sbp->xrip->state, sbp->xrip->flag);
3585*a9800bebSGarrett D'Amore 				} else {
3586*a9800bebSGarrett D'Amore 					EMLXS_MSGF(EMLXS_CONTEXT,
3587*a9800bebSGarrett D'Amore 					    &emlxs_sli_debug_msg,
3588*a9800bebSGarrett D'Amore 					    "iotag_flush: iotag=%x sbp=%p "
3589*a9800bebSGarrett D'Amore 					    "xrip=NULL",
3590*a9800bebSGarrett D'Amore 					    iotag, sbp);
3591*a9800bebSGarrett D'Amore 				}
3592291a2b48SSukumar Swaminathan 
3593*a9800bebSGarrett D'Amore 				emlxs_sli4_free_xri(hba, sbp, sbp->xrip, 0);
3594*a9800bebSGarrett D'Amore 			} else {
359582527734SSukumar Swaminathan 				/* Clean up the sbp */
359682527734SSukumar Swaminathan 				mutex_enter(&sbp->mtx);
359782527734SSukumar Swaminathan 
359882527734SSukumar Swaminathan 				if (sbp->pkt_flags & PACKET_IN_TXQ) {
359982527734SSukumar Swaminathan 					sbp->pkt_flags &= ~PACKET_IN_TXQ;
360082527734SSukumar Swaminathan 					hba->channel_tx_count --;
360182527734SSukumar Swaminathan 				}
360282527734SSukumar Swaminathan 
360382527734SSukumar Swaminathan 				if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
360482527734SSukumar Swaminathan 					sbp->pkt_flags &= ~PACKET_IN_CHIPQ;
360582527734SSukumar Swaminathan 				}
3606291a2b48SSukumar Swaminathan 
360782527734SSukumar Swaminathan 				if (sbp->bmp) {
3608*a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_BPL,
3609*a9800bebSGarrett D'Amore 					    (void *)sbp->bmp);
361082527734SSukumar Swaminathan 					sbp->bmp = 0;
361182527734SSukumar Swaminathan 				}
361282527734SSukumar Swaminathan 
361382527734SSukumar Swaminathan 				mutex_exit(&sbp->mtx);
3614fcf3ce44SJohn Forte 			}
3615291a2b48SSukumar Swaminathan 
3616fcf3ce44SJohn Forte 			/* At this point all nodes are assumed destroyed */
361782527734SSukumar Swaminathan 			mutex_enter(&sbp->mtx);
3618fcf3ce44SJohn Forte 			sbp->node = 0;
3619fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3620fcf3ce44SJohn Forte 
3621fcf3ce44SJohn Forte 			/* Add this iocb to our local abort Q */
3622fcf3ce44SJohn Forte 			if (abort.q_first) {
3623291a2b48SSukumar Swaminathan 				((IOCBQ *)abort.q_last)->next = iocbq;
3624fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
3625fcf3ce44SJohn Forte 				abort.q_cnt++;
3626fcf3ce44SJohn Forte 			} else {
3627fcf3ce44SJohn Forte 				abort.q_first = (uint8_t *)iocbq;
3628fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
3629fcf3ce44SJohn Forte 				abort.q_cnt = 1;
3630fcf3ce44SJohn Forte 			}
3631fcf3ce44SJohn Forte 		}
3632fcf3ce44SJohn Forte 
363382527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3634fcf3ce44SJohn Forte 
3635fcf3ce44SJohn Forte 		/* Trigger deferred completion */
3636fcf3ce44SJohn Forte 		if (abort.q_first) {
363782527734SSukumar Swaminathan 			mutex_enter(&cp->rsp_lock);
363882527734SSukumar Swaminathan 			if (cp->rsp_head == NULL) {
363982527734SSukumar Swaminathan 				cp->rsp_head = (IOCBQ *)abort.q_first;
364082527734SSukumar Swaminathan 				cp->rsp_tail = (IOCBQ *)abort.q_last;
3641fcf3ce44SJohn Forte 			} else {
364282527734SSukumar Swaminathan 				cp->rsp_tail->next = (IOCBQ *)abort.q_first;
364382527734SSukumar Swaminathan 				cp->rsp_tail = (IOCBQ *)abort.q_last;
3644fcf3ce44SJohn Forte 			}
364582527734SSukumar Swaminathan 			mutex_exit(&cp->rsp_lock);
3646fcf3ce44SJohn Forte 
364782527734SSukumar Swaminathan 			emlxs_thread_trigger2(&cp->intr_thread,
364882527734SSukumar Swaminathan 			    emlxs_proc_channel, cp);
3649fcf3ce44SJohn Forte 
3650*a9800bebSGarrett D'Amore 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
3651*a9800bebSGarrett D'Amore 			    "iotag_flush: channel=%d count=%d",
365282527734SSukumar Swaminathan 			    channelno, abort.q_cnt);
3653fcf3ce44SJohn Forte 
3654fcf3ce44SJohn Forte 			count += abort.q_cnt;
3655fcf3ce44SJohn Forte 		}
3656fcf3ce44SJohn Forte 	}
3657fcf3ce44SJohn Forte 
3658fcf3ce44SJohn Forte 	return (count);
3659fcf3ce44SJohn Forte 
366082527734SSukumar Swaminathan } /* emlxs_iotag_flush() */
3661fcf3ce44SJohn Forte 
3662fcf3ce44SJohn Forte 
3663fcf3ce44SJohn Forte 
366482527734SSukumar Swaminathan /* Checks for IO's on all or a given channel for a given node */
3665fcf3ce44SJohn Forte extern uint32_t
366682527734SSukumar Swaminathan emlxs_chipq_node_check(emlxs_port_t *port, CHANNEL *chan, NODELIST *ndlp)
3667fcf3ce44SJohn Forte {
3668fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3669fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
367082527734SSukumar Swaminathan 	CHANNEL *cp;
367182527734SSukumar Swaminathan 	uint32_t channelno;
3672fcf3ce44SJohn Forte 	uint32_t count;
3673fcf3ce44SJohn Forte 	uint32_t iotag;
3674fcf3ce44SJohn Forte 
3675fcf3ce44SJohn Forte 	count = 0;
3676fcf3ce44SJohn Forte 
367782527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
367882527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3679fcf3ce44SJohn Forte 
368082527734SSukumar Swaminathan 		if (chan && cp != chan) {
3681fcf3ce44SJohn Forte 			continue;
3682fcf3ce44SJohn Forte 		}
3683291a2b48SSukumar Swaminathan 
368482527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3685fcf3ce44SJohn Forte 
368682527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
368782527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3688fcf3ce44SJohn Forte 
3689fcf3ce44SJohn Forte 			if (sbp && (sbp != STALE_PACKET) &&
3690fcf3ce44SJohn Forte 			    (sbp->pkt_flags & PACKET_IN_CHIPQ) &&
3691fcf3ce44SJohn Forte 			    (sbp->node == ndlp) &&
369282527734SSukumar Swaminathan 			    (sbp->channel == cp) &&
3693fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
3694fcf3ce44SJohn Forte 				count++;
3695fcf3ce44SJohn Forte 			}
3696291a2b48SSukumar Swaminathan 
3697fcf3ce44SJohn Forte 		}
369882527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3699fcf3ce44SJohn Forte 
3700fcf3ce44SJohn Forte 	}	/* for */
3701fcf3ce44SJohn Forte 
3702fcf3ce44SJohn Forte 	return (count);
3703fcf3ce44SJohn Forte 
370482527734SSukumar Swaminathan } /* emlxs_chipq_node_check() */
3705fcf3ce44SJohn Forte 
3706fcf3ce44SJohn Forte 
3707fcf3ce44SJohn Forte 
370882527734SSukumar Swaminathan /* Flush all IO's for a given node's lun (on any channel) */
3709fcf3ce44SJohn Forte extern uint32_t
371082527734SSukumar Swaminathan emlxs_chipq_lun_flush(emlxs_port_t *port, NODELIST *ndlp,
371182527734SSukumar Swaminathan     uint32_t lun, emlxs_buf_t *fpkt)
3712fcf3ce44SJohn Forte {
3713fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3714fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3715fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3716fcf3ce44SJohn Forte 	IOCBQ *next;
3717fcf3ce44SJohn Forte 	Q abort;
3718fcf3ce44SJohn Forte 	uint32_t iotag;
371982527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
372082527734SSukumar Swaminathan 	uint32_t channelno;
3721fcf3ce44SJohn Forte 
3722*a9800bebSGarrett D'Amore 	if (lun == EMLXS_LUN_NONE) {
3723*a9800bebSGarrett D'Amore 		return (0);
3724*a9800bebSGarrett D'Amore 	}
3725*a9800bebSGarrett D'Amore 
3726fcf3ce44SJohn Forte 	bzero((void *)flag, sizeof (flag));
3727fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
3728fcf3ce44SJohn Forte 
372982527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
373082527734SSukumar Swaminathan 	for (iotag = 1; iotag < hba->max_iotag; iotag++) {
373182527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
3732fcf3ce44SJohn Forte 
3733fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET) &&
3734fcf3ce44SJohn Forte 		    sbp->pkt_flags & PACKET_IN_CHIPQ &&
3735fcf3ce44SJohn Forte 		    sbp->node == ndlp &&
3736fcf3ce44SJohn Forte 		    sbp->lun == lun &&
3737fcf3ce44SJohn Forte 		    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
373882527734SSukumar Swaminathan 			emlxs_sbp_abort_add(port, sbp,
373982527734SSukumar Swaminathan 			    &abort, flag, fpkt);
3740fcf3ce44SJohn Forte 		}
3741fcf3ce44SJohn Forte 	}
374282527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
3743fcf3ce44SJohn Forte 
3744fcf3ce44SJohn Forte 	/* Now put the iocb's on the tx queue */
3745fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
3746fcf3ce44SJohn Forte 	while (iocbq) {
3747fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
3748fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
3749fcf3ce44SJohn Forte 
3750fcf3ce44SJohn Forte 		/* Unlink this iocbq */
3751fcf3ce44SJohn Forte 		iocbq->next = NULL;
3752fcf3ce44SJohn Forte 
3753fcf3ce44SJohn Forte 		/* Send this iocbq */
3754fcf3ce44SJohn Forte 		emlxs_tx_put(iocbq, 1);
3755fcf3ce44SJohn Forte 
3756fcf3ce44SJohn Forte 		iocbq = next;
3757fcf3ce44SJohn Forte 	}
3758fcf3ce44SJohn Forte 
375982527734SSukumar Swaminathan 	/* Now trigger channel service */
376082527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
376182527734SSukumar Swaminathan 		if (!flag[channelno]) {
376282527734SSukumar Swaminathan 			continue;
376382527734SSukumar Swaminathan 		}
376482527734SSukumar Swaminathan 
376582527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
3766fcf3ce44SJohn Forte 	}
3767291a2b48SSukumar Swaminathan 
3768fcf3ce44SJohn Forte 	return (abort.q_cnt);
3769fcf3ce44SJohn Forte 
377082527734SSukumar Swaminathan } /* emlxs_chipq_lun_flush() */
3771fcf3ce44SJohn Forte 
3772fcf3ce44SJohn Forte 
3773fcf3ce44SJohn Forte 
3774fcf3ce44SJohn Forte /*
3775fcf3ce44SJohn Forte  * Issue an ABORT_XRI_CN iocb command to abort an FCP command already issued.
3776fe199829SSukumar Swaminathan  * This must be called while holding the EMLXS_FCTAB_LOCK
3777fcf3ce44SJohn Forte  */
3778fcf3ce44SJohn Forte extern IOCBQ *
3779291a2b48SSukumar Swaminathan emlxs_create_abort_xri_cn(emlxs_port_t *port, NODELIST *ndlp,
378082527734SSukumar Swaminathan     uint16_t iotag, CHANNEL *cp, uint8_t class, int32_t flag)
3781fcf3ce44SJohn Forte {
3782fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3783fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3784fcf3ce44SJohn Forte 	IOCB *iocb;
378582527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
378682527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
3787fcf3ce44SJohn Forte 	uint16_t abort_iotag;
3788fcf3ce44SJohn Forte 
378982527734SSukumar Swaminathan 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB, 0)) == NULL) {
3790fcf3ce44SJohn Forte 		return (NULL);
3791fcf3ce44SJohn Forte 	}
3792291a2b48SSukumar Swaminathan 
379382527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
3794fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
3795fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
3796fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
3797fcf3ce44SJohn Forte 
3798fcf3ce44SJohn Forte 	/*
3799fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
3800fcf3ce44SJohn Forte 	 */
380182527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
380282527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
3803fcf3ce44SJohn Forte 	}
380482527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
3805291a2b48SSukumar Swaminathan 
3806fcf3ce44SJohn Forte 
380782527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
380882527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
380982527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
3810fcf3ce44SJohn Forte 
381182527734SSukumar Swaminathan 		/* Try to issue abort by XRI if possible */
3812*a9800bebSGarrett D'Amore 		if (sbp == NULL || sbp == STALE_PACKET || sbp->xrip == NULL) {
381382527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_REQ_TAG;
381482527734SSukumar Swaminathan 			wqe->AbortTag = iotag;
381582527734SSukumar Swaminathan 		} else {
381682527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_XRI_TAG;
3817*a9800bebSGarrett D'Amore 			wqe->AbortTag = sbp->xrip->XRI;
381882527734SSukumar Swaminathan 		}
381982527734SSukumar Swaminathan 		wqe->un.Abort.IA = 0;
382082527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
382182527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
382282527734SSukumar Swaminathan 		wqe->Class = CLASS3;
382382527734SSukumar Swaminathan 		wqe->CQId = 0x3ff;
382482527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
382582527734SSukumar Swaminathan 	} else {
382682527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
382782527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
382882527734SSukumar Swaminathan 		iocb->un.acxri.abortType = flag;
382982527734SSukumar Swaminathan 		iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi;
383082527734SSukumar Swaminathan 		iocb->un.acxri.abortIoTag = iotag;
383182527734SSukumar Swaminathan 		iocb->ULPLE = 1;
383282527734SSukumar Swaminathan 		iocb->ULPCLASS = class;
383382527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_ABORT_XRI_CN;
383482527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
383582527734SSukumar Swaminathan 	}
3836fcf3ce44SJohn Forte 
3837fcf3ce44SJohn Forte 	return (iocbq);
3838fcf3ce44SJohn Forte 
383982527734SSukumar Swaminathan } /* emlxs_create_abort_xri_cn() */
3840fcf3ce44SJohn Forte 
3841fcf3ce44SJohn Forte 
3842fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
3843fcf3ce44SJohn Forte extern IOCBQ *
3844fcf3ce44SJohn Forte emlxs_create_abort_xri_cx(emlxs_port_t *port, NODELIST *ndlp, uint16_t xid,
384582527734SSukumar Swaminathan     CHANNEL *cp, uint8_t class, int32_t flag)
3846fcf3ce44SJohn Forte {
3847fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3848fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3849fcf3ce44SJohn Forte 	IOCB *iocb;
385082527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
3851fcf3ce44SJohn Forte 	uint16_t abort_iotag;
3852fcf3ce44SJohn Forte 
385382527734SSukumar Swaminathan 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB, 0)) == NULL) {
3854fcf3ce44SJohn Forte 		return (NULL);
3855fcf3ce44SJohn Forte 	}
3856291a2b48SSukumar Swaminathan 
385782527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
3858fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
3859fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
3860fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
3861fcf3ce44SJohn Forte 
3862fcf3ce44SJohn Forte 	/*
3863fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
3864fcf3ce44SJohn Forte 	 */
386582527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
386682527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
386782527734SSukumar Swaminathan 	}
386882527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
386982527734SSukumar Swaminathan 
387082527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
387182527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
387282527734SSukumar Swaminathan 		wqe->un.Abort.Criteria = ABORT_XRI_TAG;
387382527734SSukumar Swaminathan 		wqe->un.Abort.IA = 0;
387482527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
387582527734SSukumar Swaminathan 		wqe->AbortTag = xid;
387682527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
387782527734SSukumar Swaminathan 		wqe->Class = CLASS3;
387882527734SSukumar Swaminathan 		wqe->CQId = 0x3ff;
387982527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
388082527734SSukumar Swaminathan 	} else {
388182527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
388282527734SSukumar Swaminathan 		iocb->ULPCONTEXT = xid;
388382527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
388482527734SSukumar Swaminathan 		iocb->un.acxri.abortType = flag;
388582527734SSukumar Swaminathan 		iocb->ULPLE = 1;
388682527734SSukumar Swaminathan 		iocb->ULPCLASS = class;
388782527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_ABORT_XRI_CX;
388882527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
3889fcf3ce44SJohn Forte 	}
3890291a2b48SSukumar Swaminathan 
3891fcf3ce44SJohn Forte 	return (iocbq);
3892fcf3ce44SJohn Forte 
389382527734SSukumar Swaminathan } /* emlxs_create_abort_xri_cx() */
3894fcf3ce44SJohn Forte 
3895fcf3ce44SJohn Forte 
3896fcf3ce44SJohn Forte 
3897fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
3898fcf3ce44SJohn Forte extern IOCBQ *
3899fcf3ce44SJohn Forte emlxs_create_close_xri_cn(emlxs_port_t *port, NODELIST *ndlp,
390082527734SSukumar Swaminathan     uint16_t iotag, CHANNEL *cp)
3901fcf3ce44SJohn Forte {
3902fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3903fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3904fcf3ce44SJohn Forte 	IOCB *iocb;
390582527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
390682527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
3907fcf3ce44SJohn Forte 	uint16_t abort_iotag;
3908fcf3ce44SJohn Forte 
390982527734SSukumar Swaminathan 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB, 0)) == NULL) {
3910fcf3ce44SJohn Forte 		return (NULL);
3911fcf3ce44SJohn Forte 	}
3912291a2b48SSukumar Swaminathan 
391382527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
3914fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
3915fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
3916fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
3917fcf3ce44SJohn Forte 
3918fcf3ce44SJohn Forte 	/*
3919fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
3920fcf3ce44SJohn Forte 	 */
392182527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
392282527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
3923fcf3ce44SJohn Forte 	}
392482527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
3925291a2b48SSukumar Swaminathan 
392682527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
392782527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
392882527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
3929fcf3ce44SJohn Forte 
393082527734SSukumar Swaminathan 		/* Try to issue close by XRI if possible */
3931*a9800bebSGarrett D'Amore 		if (sbp == NULL || sbp == STALE_PACKET || sbp->xrip == NULL) {
393282527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_REQ_TAG;
393382527734SSukumar Swaminathan 			wqe->AbortTag = iotag;
393482527734SSukumar Swaminathan 		} else {
393582527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_XRI_TAG;
3936*a9800bebSGarrett D'Amore 			wqe->AbortTag = sbp->xrip->XRI;
393782527734SSukumar Swaminathan 		}
393882527734SSukumar Swaminathan 		wqe->un.Abort.IA = 1;
393982527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
394082527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
394182527734SSukumar Swaminathan 		wqe->Class = CLASS3;
394282527734SSukumar Swaminathan 		wqe->CQId = 0x3ff;
394382527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
394482527734SSukumar Swaminathan 	} else {
394582527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
394682527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
394782527734SSukumar Swaminathan 		iocb->un.acxri.abortType = 0;
394882527734SSukumar Swaminathan 		iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi;
394982527734SSukumar Swaminathan 		iocb->un.acxri.abortIoTag = iotag;
395082527734SSukumar Swaminathan 		iocb->ULPLE = 1;
395182527734SSukumar Swaminathan 		iocb->ULPCLASS = 0;
395282527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_CLOSE_XRI_CN;
395382527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
395482527734SSukumar Swaminathan 	}
3955fcf3ce44SJohn Forte 
3956fcf3ce44SJohn Forte 	return (iocbq);
3957fcf3ce44SJohn Forte 
395882527734SSukumar Swaminathan } /* emlxs_create_close_xri_cn() */
3959fcf3ce44SJohn Forte 
3960fcf3ce44SJohn Forte 
3961fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
3962fcf3ce44SJohn Forte extern IOCBQ *
3963291a2b48SSukumar Swaminathan emlxs_create_close_xri_cx(emlxs_port_t *port, NODELIST *ndlp, uint16_t xid,
396482527734SSukumar Swaminathan     CHANNEL *cp)
3965fcf3ce44SJohn Forte {
3966fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3967fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3968fcf3ce44SJohn Forte 	IOCB *iocb;
396982527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
3970fcf3ce44SJohn Forte 	uint16_t abort_iotag;
3971fcf3ce44SJohn Forte 
397282527734SSukumar Swaminathan 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB, 0)) == NULL) {
3973fcf3ce44SJohn Forte 		return (NULL);
3974fcf3ce44SJohn Forte 	}
3975291a2b48SSukumar Swaminathan 
397682527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
3977fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
3978fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
3979fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
3980fcf3ce44SJohn Forte 
3981fcf3ce44SJohn Forte 	/*
3982fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
3983fcf3ce44SJohn Forte 	 */
398482527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
398582527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
398682527734SSukumar Swaminathan 	}
398782527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
398882527734SSukumar Swaminathan 
398982527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
399082527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
399182527734SSukumar Swaminathan 		wqe->un.Abort.Criteria = ABORT_XRI_TAG;
399282527734SSukumar Swaminathan 		wqe->un.Abort.IA = 1;
399382527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
399482527734SSukumar Swaminathan 		wqe->AbortTag = xid;
399582527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
399682527734SSukumar Swaminathan 		wqe->Class = CLASS3;
399782527734SSukumar Swaminathan 		wqe->CQId = 0x3ff;
399882527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
399982527734SSukumar Swaminathan 	} else {
400082527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
400182527734SSukumar Swaminathan 		iocb->ULPCONTEXT = xid;
400282527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
400382527734SSukumar Swaminathan 		iocb->ULPLE = 1;
400482527734SSukumar Swaminathan 		iocb->ULPCLASS = 0;
400582527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_CLOSE_XRI_CX;
400682527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
4007fcf3ce44SJohn Forte 	}
4008291a2b48SSukumar Swaminathan 
4009fcf3ce44SJohn Forte 	return (iocbq);
4010fcf3ce44SJohn Forte 
401182527734SSukumar Swaminathan } /* emlxs_create_close_xri_cx() */
4012fcf3ce44SJohn Forte 
4013fcf3ce44SJohn Forte 
4014fe199829SSukumar Swaminathan #ifdef SFCT_SUPPORT
4015fe199829SSukumar Swaminathan void
4016fe199829SSukumar Swaminathan emlxs_abort_fct_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4017fe199829SSukumar Swaminathan {
4018fe199829SSukumar Swaminathan 	CHANNEL *cp;
4019fe199829SSukumar Swaminathan 	IOCBQ *iocbq;
4020fe199829SSukumar Swaminathan 	IOCB *iocb;
4021fe199829SSukumar Swaminathan 
4022fe199829SSukumar Swaminathan 	if (rxid == 0 || rxid == 0xFFFF) {
4023fe199829SSukumar Swaminathan 		return;
4024fe199829SSukumar Swaminathan 	}
4025fe199829SSukumar Swaminathan 
4026fe199829SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4027fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4028fe199829SSukumar Swaminathan 		    "Aborting FCT exchange: xid=%x", rxid);
4029fe199829SSukumar Swaminathan 
4030*a9800bebSGarrett D'Amore 		if (emlxs_sli4_unreserve_xri(hba, rxid, 1) == 0) {
4031fe199829SSukumar Swaminathan 			/* We have no way to abort unsolicited exchanges */
4032fe199829SSukumar Swaminathan 			/* that we have not responded to at this time */
4033fe199829SSukumar Swaminathan 			/* So we will return for now */
4034fe199829SSukumar Swaminathan 			return;
4035fe199829SSukumar Swaminathan 		}
4036fe199829SSukumar Swaminathan 	}
4037fe199829SSukumar Swaminathan 
4038fe199829SSukumar Swaminathan 	cp = &hba->chan[hba->channel_fcp];
4039fe199829SSukumar Swaminathan 
4040fe199829SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
4041fe199829SSukumar Swaminathan 
4042fe199829SSukumar Swaminathan 	/* Create the abort IOCB */
4043fe199829SSukumar Swaminathan 	if (hba->state >= FC_LINK_UP) {
4044fe199829SSukumar Swaminathan 		iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4045fe199829SSukumar Swaminathan 		    CLASS3, ABORT_TYPE_ABTS);
4046fe199829SSukumar Swaminathan 	} else {
4047fe199829SSukumar Swaminathan 		iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4048fe199829SSukumar Swaminathan 	}
4049fe199829SSukumar Swaminathan 
4050fe199829SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
4051fe199829SSukumar Swaminathan 
4052fe199829SSukumar Swaminathan 	if (iocbq) {
4053fe199829SSukumar Swaminathan 		iocb = &iocbq->iocb;
4054fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4055fe199829SSukumar Swaminathan 		    "Aborting FCT exchange: xid=%x iotag=%x", rxid,
4056fe199829SSukumar Swaminathan 		    iocb->ULPIOTAG);
4057fe199829SSukumar Swaminathan 
4058fe199829SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4059fe199829SSukumar Swaminathan 	}
4060fe199829SSukumar Swaminathan 
4061fe199829SSukumar Swaminathan } /* emlxs_abort_fct_exchange() */
4062fe199829SSukumar Swaminathan #endif /* SFCT_SUPPORT */
4063fe199829SSukumar Swaminathan 
4064fe199829SSukumar Swaminathan 
4065*a9800bebSGarrett D'Amore void
4066*a9800bebSGarrett D'Amore emlxs_close_els_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4067*a9800bebSGarrett D'Amore {
4068*a9800bebSGarrett D'Amore 	CHANNEL *cp;
4069*a9800bebSGarrett D'Amore 	IOCBQ *iocbq;
4070*a9800bebSGarrett D'Amore 	IOCB *iocb;
4071*a9800bebSGarrett D'Amore 
4072*a9800bebSGarrett D'Amore 	if (rxid == 0 || rxid == 0xFFFF) {
4073*a9800bebSGarrett D'Amore 		return;
4074*a9800bebSGarrett D'Amore 	}
4075*a9800bebSGarrett D'Amore 
4076*a9800bebSGarrett D'Amore 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4077*a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4078*a9800bebSGarrett D'Amore 		    "Closing ELS exchange: xid=%x", rxid);
4079*a9800bebSGarrett D'Amore 
4080*a9800bebSGarrett D'Amore 		if (emlxs_sli4_unreserve_xri(hba, rxid, 1) == 0) {
4081*a9800bebSGarrett D'Amore 			return;
4082*a9800bebSGarrett D'Amore 		}
4083*a9800bebSGarrett D'Amore 	}
4084*a9800bebSGarrett D'Amore 
4085*a9800bebSGarrett D'Amore 	cp = &hba->chan[hba->channel_els];
4086*a9800bebSGarrett D'Amore 
4087*a9800bebSGarrett D'Amore 	mutex_enter(&EMLXS_FCTAB_LOCK);
4088*a9800bebSGarrett D'Amore 
4089*a9800bebSGarrett D'Amore 	/* Create the abort IOCB */
4090*a9800bebSGarrett D'Amore 	iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4091*a9800bebSGarrett D'Amore 
4092*a9800bebSGarrett D'Amore 	mutex_exit(&EMLXS_FCTAB_LOCK);
4093*a9800bebSGarrett D'Amore 
4094*a9800bebSGarrett D'Amore 	if (iocbq) {
4095*a9800bebSGarrett D'Amore 		iocb = &iocbq->iocb;
4096*a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4097*a9800bebSGarrett D'Amore 		    "Closing ELS exchange: xid=%x iotag=%x", rxid,
4098*a9800bebSGarrett D'Amore 		    iocb->ULPIOTAG);
4099*a9800bebSGarrett D'Amore 
4100*a9800bebSGarrett D'Amore 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4101*a9800bebSGarrett D'Amore 	}
4102*a9800bebSGarrett D'Amore 
4103*a9800bebSGarrett D'Amore } /* emlxs_close_els_exchange() */
4104*a9800bebSGarrett D'Amore 
4105*a9800bebSGarrett D'Amore 
4106fe199829SSukumar Swaminathan void
4107fe199829SSukumar Swaminathan emlxs_abort_els_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4108fe199829SSukumar Swaminathan {
4109fe199829SSukumar Swaminathan 	CHANNEL *cp;
4110fe199829SSukumar Swaminathan 	IOCBQ *iocbq;
4111fe199829SSukumar Swaminathan 	IOCB *iocb;
4112fe199829SSukumar Swaminathan 
4113fe199829SSukumar Swaminathan 	if (rxid == 0 || rxid == 0xFFFF) {
4114fe199829SSukumar Swaminathan 		return;
4115fe199829SSukumar Swaminathan 	}
4116fe199829SSukumar Swaminathan 
4117fe199829SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4118fe199829SSukumar Swaminathan 
4119fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4120fe199829SSukumar Swaminathan 		    "Aborting ELS exchange: xid=%x", rxid);
4121fe199829SSukumar Swaminathan 
4122*a9800bebSGarrett D'Amore 		if (emlxs_sli4_unreserve_xri(hba, rxid, 1) == 0) {
4123fe199829SSukumar Swaminathan 			/* We have no way to abort unsolicited exchanges */
4124fe199829SSukumar Swaminathan 			/* that we have not responded to at this time */
4125fe199829SSukumar Swaminathan 			/* So we will return for now */
4126fe199829SSukumar Swaminathan 			return;
4127fe199829SSukumar Swaminathan 		}
4128fe199829SSukumar Swaminathan 	}
4129fe199829SSukumar Swaminathan 
4130fe199829SSukumar Swaminathan 	cp = &hba->chan[hba->channel_els];
4131fe199829SSukumar Swaminathan 
4132fe199829SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
4133fe199829SSukumar Swaminathan 
4134fe199829SSukumar Swaminathan 	/* Create the abort IOCB */
4135fe199829SSukumar Swaminathan 	if (hba->state >= FC_LINK_UP) {
4136fe199829SSukumar Swaminathan 		iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4137fe199829SSukumar Swaminathan 		    CLASS3, ABORT_TYPE_ABTS);
4138fe199829SSukumar Swaminathan 	} else {
4139fe199829SSukumar Swaminathan 		iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4140fe199829SSukumar Swaminathan 	}
4141fe199829SSukumar Swaminathan 
4142fe199829SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
4143fe199829SSukumar Swaminathan 
4144fe199829SSukumar Swaminathan 	if (iocbq) {
4145fe199829SSukumar Swaminathan 		iocb = &iocbq->iocb;
4146fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4147fe199829SSukumar Swaminathan 		    "Aborting ELS exchange: xid=%x iotag=%x", rxid,
4148fe199829SSukumar Swaminathan 		    iocb->ULPIOTAG);
4149fe199829SSukumar Swaminathan 
4150fe199829SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4151fe199829SSukumar Swaminathan 	}
4152fe199829SSukumar Swaminathan 
4153fe199829SSukumar Swaminathan } /* emlxs_abort_els_exchange() */
4154fe199829SSukumar Swaminathan 
4155fe199829SSukumar Swaminathan 
4156728bdc9bSSukumar Swaminathan void
4157bb63f56eSSukumar Swaminathan emlxs_abort_ct_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4158728bdc9bSSukumar Swaminathan {
415982527734SSukumar Swaminathan 	CHANNEL *cp;
4160728bdc9bSSukumar Swaminathan 	IOCBQ *iocbq;
4161fe199829SSukumar Swaminathan 	IOCB *iocb;
4162728bdc9bSSukumar Swaminathan 
4163fe199829SSukumar Swaminathan 	if (rxid == 0 || rxid == 0xFFFF) {
4164fe199829SSukumar Swaminathan 		return;
4165fe199829SSukumar Swaminathan 	}
416682527734SSukumar Swaminathan 
416782527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4168fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ct_msg,
4169fe199829SSukumar Swaminathan 		    "Aborting CT exchange: xid=%x", rxid);
4170fe199829SSukumar Swaminathan 
4171*a9800bebSGarrett D'Amore 		if (emlxs_sli4_unreserve_xri(hba, rxid, 1) == 0) {
417282527734SSukumar Swaminathan 			/* We have no way to abort unsolicited exchanges */
417382527734SSukumar Swaminathan 			/* that we have not responded to at this time */
417482527734SSukumar Swaminathan 			/* So we will return for now */
417582527734SSukumar Swaminathan 			return;
417682527734SSukumar Swaminathan 		}
417782527734SSukumar Swaminathan 	}
417882527734SSukumar Swaminathan 
417982527734SSukumar Swaminathan 	cp = &hba->chan[hba->channel_ct];
4180728bdc9bSSukumar Swaminathan 
4181fe199829SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
4182fe199829SSukumar Swaminathan 
4183728bdc9bSSukumar Swaminathan 	/* Create the abort IOCB */
4184728bdc9bSSukumar Swaminathan 	if (hba->state >= FC_LINK_UP) {
4185fe199829SSukumar Swaminathan 		iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4186fe199829SSukumar Swaminathan 		    CLASS3, ABORT_TYPE_ABTS);
4187291a2b48SSukumar Swaminathan 	} else {
418882527734SSukumar Swaminathan 		iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4189728bdc9bSSukumar Swaminathan 	}
419082527734SSukumar Swaminathan 
4191fe199829SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
4192fe199829SSukumar Swaminathan 
4193bb63f56eSSukumar Swaminathan 	if (iocbq) {
4194fe199829SSukumar Swaminathan 		iocb = &iocbq->iocb;
4195fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4196fe199829SSukumar Swaminathan 		    "Aborting CT exchange: xid=%x iotag=%x", rxid,
4197fe199829SSukumar Swaminathan 		    iocb->ULPIOTAG);
4198fe199829SSukumar Swaminathan 
419982527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4200bb63f56eSSukumar Swaminathan 	}
420182527734SSukumar Swaminathan 
420282527734SSukumar Swaminathan } /* emlxs_abort_ct_exchange() */
4203728bdc9bSSukumar Swaminathan 
4204fcf3ce44SJohn Forte 
4205fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4206fcf3ce44SJohn Forte static void
4207fcf3ce44SJohn Forte emlxs_sbp_abort_add(emlxs_port_t *port, emlxs_buf_t *sbp, Q *abort,
4208fcf3ce44SJohn Forte     uint8_t *flag, emlxs_buf_t *fpkt)
4209fcf3ce44SJohn Forte {
4210fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4211fcf3ce44SJohn Forte 	IOCBQ *iocbq;
421282527734SSukumar Swaminathan 	CHANNEL *cp;
4213fcf3ce44SJohn Forte 	NODELIST *ndlp;
4214fcf3ce44SJohn Forte 
421582527734SSukumar Swaminathan 	cp = (CHANNEL *)sbp->channel;
4216fcf3ce44SJohn Forte 	ndlp = sbp->node;
4217fcf3ce44SJohn Forte 
4218fcf3ce44SJohn Forte 	/* Create the close XRI IOCB */
4219*a9800bebSGarrett D'Amore 	if (hba->state >= FC_LINK_UP) {
4220*a9800bebSGarrett D'Amore 		iocbq = emlxs_create_abort_xri_cn(port, ndlp, sbp->iotag, cp,
4221*a9800bebSGarrett D'Amore 		    CLASS3, ABORT_TYPE_ABTS);
4222*a9800bebSGarrett D'Amore 	} else {
4223*a9800bebSGarrett D'Amore 		iocbq = emlxs_create_close_xri_cn(port, ndlp, sbp->iotag, cp);
4224*a9800bebSGarrett D'Amore 	}
4225291a2b48SSukumar Swaminathan 	/*
4226291a2b48SSukumar Swaminathan 	 * Add this iocb to our local abort Q
4227291a2b48SSukumar Swaminathan 	 * This way we don't hold the CHIPQ lock too long
4228291a2b48SSukumar Swaminathan 	 */
4229fcf3ce44SJohn Forte 	if (iocbq) {
4230fcf3ce44SJohn Forte 		if (abort->q_first) {
4231291a2b48SSukumar Swaminathan 			((IOCBQ *)abort->q_last)->next = iocbq;
4232fcf3ce44SJohn Forte 			abort->q_last = (uint8_t *)iocbq;
4233fcf3ce44SJohn Forte 			abort->q_cnt++;
4234fcf3ce44SJohn Forte 		} else {
4235fcf3ce44SJohn Forte 			abort->q_first = (uint8_t *)iocbq;
4236fcf3ce44SJohn Forte 			abort->q_last = (uint8_t *)iocbq;
4237fcf3ce44SJohn Forte 			abort->q_cnt = 1;
4238fcf3ce44SJohn Forte 		}
4239fcf3ce44SJohn Forte 		iocbq->next = NULL;
4240fcf3ce44SJohn Forte 	}
4241291a2b48SSukumar Swaminathan 
4242fcf3ce44SJohn Forte 	/* set the flags */
4243fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
4244fcf3ce44SJohn Forte 
4245fcf3ce44SJohn Forte 	sbp->pkt_flags |= (PACKET_IN_FLUSH | PACKET_XRI_CLOSED);
424682527734SSukumar Swaminathan 
4247fcf3ce44SJohn Forte 	sbp->ticks = hba->timer_tics + 10;
4248fcf3ce44SJohn Forte 	sbp->abort_attempts++;
4249fcf3ce44SJohn Forte 
425082527734SSukumar Swaminathan 	flag[cp->channelno] = 1;
4251fcf3ce44SJohn Forte 
4252fcf3ce44SJohn Forte 	/*
4253291a2b48SSukumar Swaminathan 	 * If the fpkt is already set, then we will leave it alone
4254fcf3ce44SJohn Forte 	 * This ensures that this pkt is only accounted for on one
4255fcf3ce44SJohn Forte 	 * fpkt->flush_count
4256fcf3ce44SJohn Forte 	 */
4257fcf3ce44SJohn Forte 	if (!sbp->fpkt && fpkt) {
4258fcf3ce44SJohn Forte 		mutex_enter(&fpkt->mtx);
4259fcf3ce44SJohn Forte 		sbp->fpkt = fpkt;
4260fcf3ce44SJohn Forte 		fpkt->flush_count++;
4261fcf3ce44SJohn Forte 		mutex_exit(&fpkt->mtx);
4262fcf3ce44SJohn Forte 	}
4263291a2b48SSukumar Swaminathan 
4264fcf3ce44SJohn Forte 	mutex_exit(&sbp->mtx);
4265fcf3ce44SJohn Forte 
4266fcf3ce44SJohn Forte 	return;
4267fcf3ce44SJohn Forte 
426882527734SSukumar Swaminathan }	/* emlxs_sbp_abort_add() */
4269