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 /*
23291a2b48SSukumar Swaminathan  * Copyright 2009 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 */
161*b3660a96SSukumar Swaminathan 
162*b3660a96SSukumar Swaminathan #ifdef FMA_SUPPORT
163*b3660a96SSukumar Swaminathan 		emlxs_check_dma(hba, sbp);
164*b3660a96SSukumar Swaminathan #endif  /* FMA_SUPPORT */
165*b3660a96SSukumar Swaminathan 
16682527734SSukumar Swaminathan 		cp->ulpCmplCmd++;
167fcf3ce44SJohn Forte 		(*pkt->pkt_comp) (pkt);
168fcf3ce44SJohn Forte 
169*b3660a96SSukumar Swaminathan #ifdef FMA_SUPPORT
170*b3660a96SSukumar Swaminathan 		if (hba->flag & FC_DMA_CHECK_ERROR) {
171*b3660a96SSukumar Swaminathan 			emlxs_thread_spawn(hba, emlxs_restart_thread,
172*b3660a96SSukumar Swaminathan 			    NULL, NULL);
173*b3660a96SSukumar Swaminathan 		}
174*b3660a96SSukumar Swaminathan #endif  /* FMA_SUPPORT */
175*b3660a96SSukumar 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 		 */
214fcf3ce44SJohn Forte 		if (scsi_status == SCSI_STAT_TASK_ABORT) {
215fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT,
216fcf3ce44SJohn Forte 			    &emlxs_fcp_completion_error_msg,
217291a2b48SSukumar Swaminathan 			    "Task Abort. "
218291a2b48SSukumar Swaminathan 			    "Fixed.did=0x%06x sbp=%p cmd=%02x dl=%d",
219fcf3ce44SJohn Forte 			    did, sbp, scsi_opcode, pkt->pkt_datalen);
220fcf3ce44SJohn Forte 
221fcf3ce44SJohn Forte 			rsp->fcp_u.fcp_status.scsi_status =
222fcf3ce44SJohn Forte 			    SCSI_STAT_CHECK_COND;
223fcf3ce44SJohn Forte 			rsp->fcp_u.fcp_status.rsp_len_set = 0;
224fcf3ce44SJohn Forte 			rsp->fcp_u.fcp_status.sense_len_set = 0;
225fcf3ce44SJohn Forte 			rsp->fcp_u.fcp_status.resid_over = 0;
226fcf3ce44SJohn Forte 
227fcf3ce44SJohn Forte 			if (pkt->pkt_datalen) {
228fcf3ce44SJohn Forte 				rsp->fcp_u.fcp_status.resid_under = 1;
229291a2b48SSukumar Swaminathan 				rsp->fcp_resid =
23082527734SSukumar Swaminathan 				    LE_SWAP32(pkt->pkt_datalen);
231fcf3ce44SJohn Forte 			} else {
232fcf3ce44SJohn Forte 				rsp->fcp_u.fcp_status.resid_under = 0;
233fcf3ce44SJohn Forte 				rsp->fcp_resid = 0;
234fcf3ce44SJohn Forte 			}
235fcf3ce44SJohn Forte 
236fcf3ce44SJohn Forte 			scsi_status = SCSI_STAT_CHECK_COND;
237fcf3ce44SJohn Forte 		}
238291a2b48SSukumar Swaminathan 
239fcf3ce44SJohn Forte 		/*
240291a2b48SSukumar Swaminathan 		 * We only need to check underrun if data could
241291a2b48SSukumar Swaminathan 		 * have been sent
242fcf3ce44SJohn Forte 		 */
243fcf3ce44SJohn Forte 
244fcf3ce44SJohn Forte 		/* Always check underrun if status is good */
245fcf3ce44SJohn Forte 		if (scsi_status == SCSI_STAT_GOOD) {
246fcf3ce44SJohn Forte 			check_underrun = 1;
247fcf3ce44SJohn Forte 		}
248fcf3ce44SJohn Forte 		/* Check the sense codes if this is a check condition */
249fcf3ce44SJohn Forte 		else if (scsi_status == SCSI_STAT_CHECK_COND) {
250fcf3ce44SJohn Forte 			check_underrun = 1;
251fcf3ce44SJohn Forte 
252fcf3ce44SJohn Forte 			/* Check if sense data was provided */
25382527734SSukumar Swaminathan 			if (LE_SWAP32(rsp->fcp_sense_len) >= 14) {
254fcf3ce44SJohn Forte 				sense = *((uint8_t *)rsp + 32 + 2);
255fcf3ce44SJohn Forte 				asc = *((uint8_t *)rsp + 32 + 12);
256fcf3ce44SJohn Forte 				ascq = *((uint8_t *)rsp + 32 + 13);
257fcf3ce44SJohn Forte 			}
258291a2b48SSukumar Swaminathan 
259291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
260291a2b48SSukumar Swaminathan 			emlxs_log_sd_scsi_check_event(port,
261291a2b48SSukumar Swaminathan 			    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun,
262291a2b48SSukumar Swaminathan 			    scsi_opcode, sense, asc, ascq);
263291a2b48SSukumar Swaminathan #endif
264fcf3ce44SJohn Forte 		}
265fcf3ce44SJohn Forte 		/* Status is not good and this is not a check condition */
266fcf3ce44SJohn Forte 		/* No data should have been sent */
267fcf3ce44SJohn Forte 		else {
268fcf3ce44SJohn Forte 			check_underrun = 0;
269fcf3ce44SJohn Forte 		}
270fcf3ce44SJohn Forte 
271fcf3ce44SJohn Forte 		/* Get the residual underrun count reported by the SCSI reply */
272fcf3ce44SJohn Forte 		rsp_data_resid = (pkt->pkt_datalen &&
27382527734SSukumar Swaminathan 		    rsp->fcp_u.fcp_status.resid_under) ? LE_SWAP32(rsp->
274291a2b48SSukumar Swaminathan 		    fcp_resid) : 0;
275fcf3ce44SJohn Forte 
276fcf3ce44SJohn Forte 		/* Set the pkt resp_resid field */
277fcf3ce44SJohn Forte 		pkt->pkt_resp_resid = 0;
278fcf3ce44SJohn Forte 
279fcf3ce44SJohn Forte 		/* Set the pkt data_resid field */
280fcf3ce44SJohn Forte 		if (pkt->pkt_datalen &&
281fcf3ce44SJohn Forte 		    (pkt->pkt_tran_type == FC_PKT_FCP_READ)) {
282fcf3ce44SJohn Forte 			/*
283291a2b48SSukumar Swaminathan 			 * Get the residual underrun count reported by
284291a2b48SSukumar Swaminathan 			 * our adapter
285fcf3ce44SJohn Forte 			 */
286fcf3ce44SJohn Forte 			pkt->pkt_data_resid = cmd->un.fcpi.fcpi_parm;
287fcf3ce44SJohn Forte 
288291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
289291a2b48SSukumar Swaminathan 			if ((rsp_data_resid == 0) && (pkt->pkt_data_resid)) {
290291a2b48SSukumar Swaminathan 				emlxs_log_sd_fc_rdchk_event(port,
291291a2b48SSukumar Swaminathan 				    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun,
292291a2b48SSukumar Swaminathan 				    scsi_opcode, pkt->pkt_data_resid);
293291a2b48SSukumar Swaminathan 			}
294291a2b48SSukumar Swaminathan #endif
295291a2b48SSukumar Swaminathan 
296fcf3ce44SJohn Forte 			/* Get the actual amount of data transferred */
297fcf3ce44SJohn Forte 			data_rx = pkt->pkt_datalen - pkt->pkt_data_resid;
298fcf3ce44SJohn Forte 
299fcf3ce44SJohn Forte 			/*
300fcf3ce44SJohn Forte 			 * If the residual being reported by the adapter is
301fcf3ce44SJohn Forte 			 * greater than the residual being reported in the
302fcf3ce44SJohn Forte 			 * reply, then we have a true underrun.
303fcf3ce44SJohn Forte 			 */
304fcf3ce44SJohn Forte 			if (check_underrun &&
305fcf3ce44SJohn Forte 			    (pkt->pkt_data_resid > rsp_data_resid)) {
306fcf3ce44SJohn Forte 				switch (scsi_opcode) {
307fcf3ce44SJohn Forte 				case SCSI_INQUIRY:
308fcf3ce44SJohn Forte 					scsi_dl = scsi_cmd[16];
309fcf3ce44SJohn Forte 					break;
310fcf3ce44SJohn Forte 
311fcf3ce44SJohn Forte 				case SCSI_RX_DIAG:
312291a2b48SSukumar Swaminathan 					scsi_dl =
313291a2b48SSukumar Swaminathan 					    (scsi_cmd[15] * 0x100) +
314fcf3ce44SJohn Forte 					    scsi_cmd[16];
315fcf3ce44SJohn Forte 					break;
316fcf3ce44SJohn Forte 
317fcf3ce44SJohn Forte 				default:
318fcf3ce44SJohn Forte 					scsi_dl = pkt->pkt_datalen;
319fcf3ce44SJohn Forte 				}
320fcf3ce44SJohn Forte 
321fcf3ce44SJohn Forte #ifdef FCP_UNDERRUN_PATCH1
32282527734SSukumar Swaminathan if (cfg[CFG_ENABLE_PATCH].current & FCP_UNDERRUN_PATCH1) {
323fcf3ce44SJohn Forte 				/*
324fcf3ce44SJohn Forte 				 * If status is not good and no data was
325291a2b48SSukumar Swaminathan 				 * actually transferred, then we must fix
326291a2b48SSukumar Swaminathan 				 * the issue
327fcf3ce44SJohn Forte 				 */
328fcf3ce44SJohn Forte 				if ((scsi_status != SCSI_STAT_GOOD) &&
329fcf3ce44SJohn Forte 				    (data_rx == 0)) {
330fcf3ce44SJohn Forte 					fix_it = 1;
331fcf3ce44SJohn Forte 
332fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
333fcf3ce44SJohn Forte 					    &emlxs_fcp_completion_error_msg,
334291a2b48SSukumar Swaminathan 					    "Underrun(1). Fixed. "
335291a2b48SSukumar Swaminathan 					    "did=0x%06x sbp=%p cmd=%02x "
336291a2b48SSukumar Swaminathan 					    "dl=%d,%d rx=%d rsp=%d",
337fcf3ce44SJohn Forte 					    did, sbp, scsi_opcode,
338fcf3ce44SJohn Forte 					    pkt->pkt_datalen, scsi_dl,
339fcf3ce44SJohn Forte 					    (pkt->pkt_datalen -
340fcf3ce44SJohn Forte 					    cmd->un.fcpi.fcpi_parm),
341fcf3ce44SJohn Forte 					    rsp_data_resid);
342fcf3ce44SJohn Forte 
343fcf3ce44SJohn Forte 				}
34482527734SSukumar Swaminathan }
345291a2b48SSukumar Swaminathan #endif /* FCP_UNDERRUN_PATCH1 */
346fcf3ce44SJohn Forte 
347fcf3ce44SJohn Forte 
348fcf3ce44SJohn Forte #ifdef FCP_UNDERRUN_PATCH2
34982527734SSukumar Swaminathan if (cfg[CFG_ENABLE_PATCH].current & FCP_UNDERRUN_PATCH2) {
350fcf3ce44SJohn Forte 				if ((scsi_status == SCSI_STAT_GOOD)) {
351291a2b48SSukumar Swaminathan 					emlxs_msg_t	*msg;
352fcf3ce44SJohn Forte 
353fcf3ce44SJohn Forte 					msg = &emlxs_fcp_completion_error_msg;
354fcf3ce44SJohn Forte 					/*
355fcf3ce44SJohn Forte 					 * If status is good and this is an
356fcf3ce44SJohn Forte 					 * inquiry request and the amount of
357fcf3ce44SJohn Forte 					 * data
358fcf3ce44SJohn Forte 					 */
359fcf3ce44SJohn Forte 					/*
360291a2b48SSukumar Swaminathan 					 * requested <= data received, then we
361291a2b48SSukumar Swaminathan 					 * must fix the issue.
362fcf3ce44SJohn Forte 					 */
363fcf3ce44SJohn Forte 
364fcf3ce44SJohn Forte 					if ((scsi_opcode == SCSI_INQUIRY) &&
365fcf3ce44SJohn Forte 					    (pkt->pkt_datalen >= data_rx) &&
366fcf3ce44SJohn Forte 					    (scsi_dl <= data_rx)) {
367fcf3ce44SJohn Forte 						fix_it = 1;
368fcf3ce44SJohn Forte 
369291a2b48SSukumar Swaminathan 						EMLXS_MSGF(EMLXS_CONTEXT, msg,
370fcf3ce44SJohn Forte 						    "Underrun(2). Fixed. "
371fcf3ce44SJohn Forte 						    "did=0x%06x sbp=%p "
372fcf3ce44SJohn Forte 						    "cmd=%02x dl=%d,%d "
373fcf3ce44SJohn Forte 						    "rx=%d rsp=%d",
374fcf3ce44SJohn Forte 						    did, sbp, scsi_opcode,
375fcf3ce44SJohn Forte 						    pkt->pkt_datalen, scsi_dl,
376fcf3ce44SJohn Forte 						    data_rx, rsp_data_resid);
377fcf3ce44SJohn Forte 
378fcf3ce44SJohn Forte 					}
379291a2b48SSukumar Swaminathan 
380fcf3ce44SJohn Forte 					/*
381fcf3ce44SJohn Forte 					 * If status is good and this is an
382fcf3ce44SJohn Forte 					 * inquiry request and the amount of
383291a2b48SSukumar Swaminathan 					 * data requested >= 128 bytes, but
384291a2b48SSukumar Swaminathan 					 * only 128 bytes were received,
385291a2b48SSukumar Swaminathan 					 * then we must fix the issue.
386fcf3ce44SJohn Forte 					 */
387291a2b48SSukumar Swaminathan 					else if ((scsi_opcode ==
388291a2b48SSukumar Swaminathan 					    SCSI_INQUIRY) &&
389fcf3ce44SJohn Forte 					    (pkt->pkt_datalen >= 128) &&
390fcf3ce44SJohn Forte 					    (scsi_dl >= 128) &&
391fcf3ce44SJohn Forte 					    (data_rx == 128)) {
392fcf3ce44SJohn Forte 						fix_it = 1;
393fcf3ce44SJohn Forte 
394291a2b48SSukumar Swaminathan 						EMLXS_MSGF(EMLXS_CONTEXT, msg,
395fcf3ce44SJohn Forte 						    "Underrun(3). Fixed. "
396fcf3ce44SJohn Forte 						    "did=0x%06x sbp=%p "
397291a2b48SSukumar Swaminathan 						    "cmd=%02x dl=%d,%d "
398291a2b48SSukumar Swaminathan 						    "rx=%d rsp=%d",
399fcf3ce44SJohn Forte 						    did, sbp, scsi_opcode,
400fcf3ce44SJohn Forte 						    pkt->pkt_datalen, scsi_dl,
401fcf3ce44SJohn Forte 						    data_rx, rsp_data_resid);
402fcf3ce44SJohn Forte 
403fcf3ce44SJohn Forte 					}
404291a2b48SSukumar Swaminathan 
405fcf3ce44SJohn Forte 				}
40682527734SSukumar Swaminathan }
407291a2b48SSukumar Swaminathan #endif /* FCP_UNDERRUN_PATCH2 */
408fcf3ce44SJohn Forte 
409fcf3ce44SJohn Forte 				/*
410fcf3ce44SJohn Forte 				 * Check if SCSI response payload should be
411291a2b48SSukumar Swaminathan 				 * fixed or if a DATA_UNDERRUN should be
412291a2b48SSukumar Swaminathan 				 * reported
413fcf3ce44SJohn Forte 				 */
414fcf3ce44SJohn Forte 				if (fix_it) {
415fcf3ce44SJohn Forte 					/*
416291a2b48SSukumar Swaminathan 					 * Fix the SCSI response payload itself
417fcf3ce44SJohn Forte 					 */
418fcf3ce44SJohn Forte 					rsp->fcp_u.fcp_status.resid_under = 1;
419fcf3ce44SJohn Forte 					rsp->fcp_resid =
42082527734SSukumar Swaminathan 					    LE_SWAP32(pkt->pkt_data_resid);
421fcf3ce44SJohn Forte 				} else {
422fcf3ce44SJohn Forte 					/*
423fcf3ce44SJohn Forte 					 * Change the status from
424fcf3ce44SJohn Forte 					 * IOSTAT_FCP_RSP_ERROR to
425fcf3ce44SJohn Forte 					 * IOSTAT_DATA_UNDERRUN
426fcf3ce44SJohn Forte 					 */
427fcf3ce44SJohn Forte 					iostat = IOSTAT_DATA_UNDERRUN;
428291a2b48SSukumar Swaminathan 					pkt->pkt_data_resid =
429291a2b48SSukumar Swaminathan 					    pkt->pkt_datalen;
430fcf3ce44SJohn Forte 				}
431fcf3ce44SJohn Forte 			}
432291a2b48SSukumar Swaminathan 
433fcf3ce44SJohn Forte 			/*
434fcf3ce44SJohn Forte 			 * If the residual being reported by the adapter is
435291a2b48SSukumar Swaminathan 			 * less than the residual being reported in the reply,
436291a2b48SSukumar Swaminathan 			 * then we have a true overrun. Since we don't know
437291a2b48SSukumar Swaminathan 			 * where the extra data came from or went to then we
438291a2b48SSukumar Swaminathan 			 * cannot trust anything we received
439fcf3ce44SJohn Forte 			 */
440fcf3ce44SJohn Forte 			else if (rsp_data_resid > pkt->pkt_data_resid) {
441fcf3ce44SJohn Forte 				/*
442fcf3ce44SJohn Forte 				 * Change the status from
443fcf3ce44SJohn Forte 				 * IOSTAT_FCP_RSP_ERROR to
444fcf3ce44SJohn Forte 				 * IOSTAT_DATA_OVERRUN
445fcf3ce44SJohn Forte 				 */
446fcf3ce44SJohn Forte 				iostat = IOSTAT_DATA_OVERRUN;
447fcf3ce44SJohn Forte 				pkt->pkt_data_resid = pkt->pkt_datalen;
448fcf3ce44SJohn Forte 			}
449fcf3ce44SJohn Forte 		} else {	/* pkt->pkt_datalen==0 or FC_PKT_FCP_WRITE */
450291a2b48SSukumar Swaminathan 
451fcf3ce44SJohn Forte 			/* Report whatever the target reported */
452fcf3ce44SJohn Forte 			pkt->pkt_data_resid = rsp_data_resid;
453fcf3ce44SJohn Forte 		}
454fcf3ce44SJohn Forte 	}
455291a2b48SSukumar Swaminathan 
456fcf3ce44SJohn Forte 	/* Print completion message */
457fcf3ce44SJohn Forte 	switch (iostat) {
458fcf3ce44SJohn Forte 	case IOSTAT_SUCCESS:
459fcf3ce44SJohn Forte 		/* Build SCSI GOOD status */
460fcf3ce44SJohn Forte 		if (pkt->pkt_rsplen) {
461fcf3ce44SJohn Forte 			bzero((uint8_t *)pkt->pkt_resp, pkt->pkt_rsplen);
462fcf3ce44SJohn Forte 		}
463fcf3ce44SJohn Forte 		break;
464fcf3ce44SJohn Forte 
465fcf3ce44SJohn Forte 	case IOSTAT_FCP_RSP_ERROR:
466fcf3ce44SJohn Forte 		break;
467fcf3ce44SJohn Forte 
468fcf3ce44SJohn Forte 	case IOSTAT_REMOTE_STOP:
469fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
470291a2b48SSukumar Swaminathan 		    "Remote Stop. did=0x%06x sbp=%p cmd=%02x", did, sbp,
471291a2b48SSukumar Swaminathan 		    scsi_opcode);
472fcf3ce44SJohn Forte 		break;
473fcf3ce44SJohn Forte 
474fcf3ce44SJohn Forte 	case IOSTAT_LOCAL_REJECT:
475fcf3ce44SJohn Forte 		localstat = cmd->un.grsp.perr.statLocalError;
476fcf3ce44SJohn Forte 
477fcf3ce44SJohn Forte 		switch (localstat) {
478fcf3ce44SJohn Forte 		case IOERR_SEQUENCE_TIMEOUT:
479fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT,
480fcf3ce44SJohn Forte 			    &emlxs_fcp_completion_error_msg,
481291a2b48SSukumar Swaminathan 			    "Local reject. "
482291a2b48SSukumar Swaminathan 			    "%s did=0x%06x sbp=%p cmd=%02x tmo=%d ",
483fcf3ce44SJohn Forte 			    emlxs_error_xlate(localstat), did, sbp,
484fcf3ce44SJohn Forte 			    scsi_opcode, pkt->pkt_timeout);
485fcf3ce44SJohn Forte 			break;
486fcf3ce44SJohn Forte 
487fcf3ce44SJohn Forte 		default:
488fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT,
489fcf3ce44SJohn Forte 			    &emlxs_fcp_completion_error_msg,
490fcf3ce44SJohn Forte 			    "Local reject. %s did=0x%06x sbp=%p cmd=%02x",
491291a2b48SSukumar Swaminathan 			    emlxs_error_xlate(localstat), did, sbp,
492291a2b48SSukumar Swaminathan 			    scsi_opcode);
493fcf3ce44SJohn Forte 		}
494fcf3ce44SJohn Forte 
495fcf3ce44SJohn Forte 		break;
496fcf3ce44SJohn Forte 
497fcf3ce44SJohn Forte 	case IOSTAT_NPORT_RJT:
498fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
499291a2b48SSukumar Swaminathan 		    "Nport reject. did=0x%06x sbp=%p cmd=%02x", did, sbp,
500291a2b48SSukumar Swaminathan 		    scsi_opcode);
501fcf3ce44SJohn Forte 		break;
502fcf3ce44SJohn Forte 
503fcf3ce44SJohn Forte 	case IOSTAT_FABRIC_RJT:
504fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
505291a2b48SSukumar Swaminathan 		    "Fabric reject. did=0x%06x sbp=%p cmd=%02x", did, sbp,
506291a2b48SSukumar Swaminathan 		    scsi_opcode);
507fcf3ce44SJohn Forte 		break;
508fcf3ce44SJohn Forte 
509fcf3ce44SJohn Forte 	case IOSTAT_NPORT_BSY:
510291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
511291a2b48SSukumar Swaminathan 		ndlp = (NODELIST *)iocbq->node;
512291a2b48SSukumar Swaminathan 		emlxs_log_sd_fc_bsy_event(port, (HBA_WWN *)&ndlp->nlp_portname);
513291a2b48SSukumar Swaminathan #endif
514291a2b48SSukumar Swaminathan 
515fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
516291a2b48SSukumar Swaminathan 		    "Nport busy. did=0x%06x sbp=%p cmd=%02x", did, sbp,
517291a2b48SSukumar Swaminathan 		    scsi_opcode);
518fcf3ce44SJohn Forte 		break;
519fcf3ce44SJohn Forte 
520fcf3ce44SJohn Forte 	case IOSTAT_FABRIC_BSY:
521291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
522291a2b48SSukumar Swaminathan 		ndlp = (NODELIST *)iocbq->node;
523291a2b48SSukumar Swaminathan 		emlxs_log_sd_fc_bsy_event(port, NULL);
524291a2b48SSukumar Swaminathan #endif
525291a2b48SSukumar Swaminathan 
526fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
527291a2b48SSukumar Swaminathan 		    "Fabric busy. did=0x%06x sbp=%p cmd=%02x", did, sbp,
528291a2b48SSukumar Swaminathan 		    scsi_opcode);
529fcf3ce44SJohn Forte 		break;
530fcf3ce44SJohn Forte 
531fcf3ce44SJohn Forte 	case IOSTAT_INTERMED_RSP:
532fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
533291a2b48SSukumar Swaminathan 		    "Intermediate response. did=0x%06x sbp=%p cmd=%02x", did,
534291a2b48SSukumar Swaminathan 		    sbp, scsi_opcode);
535fcf3ce44SJohn Forte 		break;
536fcf3ce44SJohn Forte 
537fcf3ce44SJohn Forte 	case IOSTAT_LS_RJT:
538fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
539291a2b48SSukumar Swaminathan 		    "LS Reject. did=0x%06x sbp=%p cmd=%02x", did, sbp,
540291a2b48SSukumar Swaminathan 		    scsi_opcode);
541fcf3ce44SJohn Forte 		break;
542fcf3ce44SJohn Forte 
543fcf3ce44SJohn Forte 	case IOSTAT_DATA_UNDERRUN:
544fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
545291a2b48SSukumar Swaminathan 		    "Underrun. did=0x%06x sbp=%p cmd=%02x "
546291a2b48SSukumar Swaminathan 		    "dl=%d,%d rx=%d rsp=%d (%02x,%02x,%02x,%02x)",
547291a2b48SSukumar Swaminathan 		    did, sbp, scsi_opcode, pkt->pkt_datalen, scsi_dl, data_rx,
548291a2b48SSukumar Swaminathan 		    rsp_data_resid, scsi_status, sense, asc, ascq);
549fcf3ce44SJohn Forte 		break;
550fcf3ce44SJohn Forte 
551fcf3ce44SJohn Forte 	case IOSTAT_DATA_OVERRUN:
552fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
553291a2b48SSukumar Swaminathan 		    "Overrun. did=0x%06x sbp=%p cmd=%02x "
554291a2b48SSukumar Swaminathan 		    "dl=%d,%d rx=%d rsp=%d (%02x,%02x,%02x,%02x)",
555291a2b48SSukumar Swaminathan 		    did, sbp, scsi_opcode, pkt->pkt_datalen, scsi_dl, data_rx,
556291a2b48SSukumar Swaminathan 		    rsp_data_resid, scsi_status, sense, asc, ascq);
557fcf3ce44SJohn Forte 		break;
558fcf3ce44SJohn Forte 
559fcf3ce44SJohn Forte 	default:
560fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
561fcf3ce44SJohn Forte 		    "Unknown status=%x reason=%x did=0x%06x sbp=%p cmd=%02x",
562291a2b48SSukumar Swaminathan 		    iostat, cmd->un.grsp.perr.statLocalError, did, sbp,
563291a2b48SSukumar Swaminathan 		    scsi_opcode);
564fcf3ce44SJohn Forte 		break;
565fcf3ce44SJohn Forte 	}
566fcf3ce44SJohn Forte 
567fcf3ce44SJohn Forte done:
568fcf3ce44SJohn Forte 
569fcf3ce44SJohn Forte 	if (iostat == IOSTAT_SUCCESS) {
570fcf3ce44SJohn Forte 		HBASTATS.FcpGood++;
571fcf3ce44SJohn Forte 	} else {
572fcf3ce44SJohn Forte 		HBASTATS.FcpError++;
573fcf3ce44SJohn Forte 	}
574fcf3ce44SJohn Forte 
575fcf3ce44SJohn Forte 	mutex_exit(&sbp->mtx);
576fcf3ce44SJohn Forte 
577fcf3ce44SJohn Forte 	emlxs_pkt_complete(sbp, iostat, localstat, 0);
578fcf3ce44SJohn Forte 
579fcf3ce44SJohn Forte 	return;
580fcf3ce44SJohn Forte 
58182527734SSukumar Swaminathan } /* emlxs_handle_fcp_event() */
582fcf3ce44SJohn Forte 
583fcf3ce44SJohn Forte 
584fcf3ce44SJohn Forte 
585fcf3ce44SJohn Forte /*
586fcf3ce44SJohn Forte  *  emlxs_post_buffer
587fcf3ce44SJohn Forte  *
588fcf3ce44SJohn Forte  *  This routine will post count buffers to the
589fcf3ce44SJohn Forte  *  ring with the QUE_RING_BUF_CN command. This
590fcf3ce44SJohn Forte  *  allows 2 buffers / command to be posted.
591fcf3ce44SJohn Forte  *  Returns the number of buffers NOT posted.
592fcf3ce44SJohn Forte  */
59382527734SSukumar Swaminathan /* SLI3 */
594fcf3ce44SJohn Forte extern int
595fcf3ce44SJohn Forte emlxs_post_buffer(emlxs_hba_t *hba, RING *rp, int16_t cnt)
596fcf3ce44SJohn Forte {
597fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
598fcf3ce44SJohn Forte 	IOCB *icmd;
599fcf3ce44SJohn Forte 	IOCBQ *iocbq;
600fcf3ce44SJohn Forte 	MATCHMAP *mp;
601fcf3ce44SJohn Forte 	uint16_t tag;
602fcf3ce44SJohn Forte 	uint32_t maxqbuf;
603fcf3ce44SJohn Forte 	int32_t i;
604fcf3ce44SJohn Forte 	int32_t j;
605fcf3ce44SJohn Forte 	uint32_t seg;
606fcf3ce44SJohn Forte 	uint32_t size;
607fcf3ce44SJohn Forte 
608fcf3ce44SJohn Forte 	mp = 0;
609fcf3ce44SJohn Forte 	maxqbuf = 2;
610fcf3ce44SJohn Forte 	tag = (uint16_t)cnt;
611fcf3ce44SJohn Forte 	cnt += rp->fc_missbufcnt;
612fcf3ce44SJohn Forte 
61382527734SSukumar Swaminathan 	if (rp->ringno == hba->channel_els) {
614fcf3ce44SJohn Forte 		seg = MEM_BUF;
615fcf3ce44SJohn Forte 		size = MEM_ELSBUF_SIZE;
61682527734SSukumar Swaminathan 	} else if (rp->ringno == hba->channel_ip) {
617fcf3ce44SJohn Forte 		seg = MEM_IPBUF;
618fcf3ce44SJohn Forte 		size = MEM_IPBUF_SIZE;
61982527734SSukumar Swaminathan 	} else if (rp->ringno == hba->channel_ct) {
620fcf3ce44SJohn Forte 		seg = MEM_CTBUF;
621fcf3ce44SJohn Forte 		size = MEM_CTBUF_SIZE;
622fcf3ce44SJohn Forte 	}
623fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
62482527734SSukumar Swaminathan 	else if (rp->ringno == hba->CHANNEL_FCT) {
625fcf3ce44SJohn Forte 		seg = MEM_FCTBUF;
626fcf3ce44SJohn Forte 		size = MEM_FCTBUF_SIZE;
627fcf3ce44SJohn Forte 	}
628291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
629fcf3ce44SJohn Forte 	else {
630fcf3ce44SJohn Forte 		return (0);
631fcf3ce44SJohn Forte 	}
632fcf3ce44SJohn Forte 
633fcf3ce44SJohn Forte 	/*
634fcf3ce44SJohn Forte 	 * While there are buffers to post
635fcf3ce44SJohn Forte 	 */
636fcf3ce44SJohn Forte 	while (cnt) {
63782527734SSukumar Swaminathan 		if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB, 0)) == 0) {
638fcf3ce44SJohn Forte 			rp->fc_missbufcnt = cnt;
639fcf3ce44SJohn Forte 			return (cnt);
640fcf3ce44SJohn Forte 		}
641291a2b48SSukumar Swaminathan 
64282527734SSukumar Swaminathan 		iocbq->channel = (void *)&hba->chan[rp->ringno];
643fcf3ce44SJohn Forte 		iocbq->port = (void *)port;
644fcf3ce44SJohn Forte 		iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
645fcf3ce44SJohn Forte 
646fcf3ce44SJohn Forte 		icmd = &iocbq->iocb;
647fcf3ce44SJohn Forte 
648fcf3ce44SJohn Forte 		/*
649fcf3ce44SJohn Forte 		 * Max buffers can be posted per command
650fcf3ce44SJohn Forte 		 */
651fcf3ce44SJohn Forte 		for (i = 0; i < maxqbuf; i++) {
652fcf3ce44SJohn Forte 			if (cnt <= 0)
653fcf3ce44SJohn Forte 				break;
654fcf3ce44SJohn Forte 
655fcf3ce44SJohn Forte 			/* fill in BDEs for command */
65682527734SSukumar Swaminathan 			if ((mp = (MATCHMAP *)emlxs_mem_get(hba, seg, 1))
65782527734SSukumar Swaminathan 			    == 0) {
65882527734SSukumar Swaminathan 				icmd->ULPBDECOUNT = i;
659fcf3ce44SJohn Forte 				for (j = 0; j < i; j++) {
660291a2b48SSukumar Swaminathan 					mp = EMLXS_GET_VADDR(hba, rp, icmd);
661fcf3ce44SJohn Forte 					if (mp) {
662fcf3ce44SJohn Forte 						(void) emlxs_mem_put(hba, seg,
663fcf3ce44SJohn Forte 						    (uint8_t *)mp);
664fcf3ce44SJohn Forte 					}
665fcf3ce44SJohn Forte 				}
666fcf3ce44SJohn Forte 
667fcf3ce44SJohn Forte 				rp->fc_missbufcnt = cnt + i;
668fcf3ce44SJohn Forte 
669fcf3ce44SJohn Forte 				(void) emlxs_mem_put(hba, MEM_IOCB,
670fcf3ce44SJohn Forte 				    (uint8_t *)iocbq);
671fcf3ce44SJohn Forte 
672fcf3ce44SJohn Forte 				return (cnt + i);
673fcf3ce44SJohn Forte 			}
674291a2b48SSukumar Swaminathan 
675fcf3ce44SJohn Forte 			/*
676fcf3ce44SJohn Forte 			 * map that page and save the address pair for lookup
677fcf3ce44SJohn Forte 			 * later
678fcf3ce44SJohn Forte 			 */
679291a2b48SSukumar Swaminathan 			emlxs_mem_map_vaddr(hba,
680291a2b48SSukumar Swaminathan 			    rp,
681291a2b48SSukumar Swaminathan 			    mp,
682fcf3ce44SJohn Forte 			    (uint32_t *)&icmd->un.cont64[i].addrHigh,
683fcf3ce44SJohn Forte 			    (uint32_t *)&icmd->un.cont64[i].addrLow);
684fcf3ce44SJohn Forte 
685fcf3ce44SJohn Forte 			icmd->un.cont64[i].tus.f.bdeSize = size;
68682527734SSukumar Swaminathan 			icmd->ULPCOMMAND = CMD_QUE_RING_BUF64_CN;
687fcf3ce44SJohn Forte 
688291a2b48SSukumar Swaminathan 			/*
689291a2b48SSukumar Swaminathan 			 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
690291a2b48SSukumar Swaminathan 			 *    "UB Post: ring=%d addr=%08x%08x size=%d",
691291a2b48SSukumar Swaminathan 			 *    rp->ringno, icmd->un.cont64[i].addrHigh,
692291a2b48SSukumar Swaminathan 			 *    icmd->un.cont64[i].addrLow, size);
693291a2b48SSukumar Swaminathan 			 */
694fcf3ce44SJohn Forte 
695fcf3ce44SJohn Forte 			cnt--;
696fcf3ce44SJohn Forte 		}
697fcf3ce44SJohn Forte 
69882527734SSukumar Swaminathan 		icmd->ULPIOTAG = tag;
69982527734SSukumar Swaminathan 		icmd->ULPBDECOUNT = i;
70082527734SSukumar Swaminathan 		icmd->ULPLE = 1;
70182527734SSukumar Swaminathan 		icmd->ULPOWNER = OWN_CHIP;
702291a2b48SSukumar Swaminathan 		/* used for delimiter between commands */
703291a2b48SSukumar Swaminathan 		iocbq->bp = (uint8_t *)mp;
704fcf3ce44SJohn Forte 
70582527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[rp->ringno], iocbq);
706fcf3ce44SJohn Forte 	}
707fcf3ce44SJohn Forte 
708fcf3ce44SJohn Forte 	rp->fc_missbufcnt = 0;
709fcf3ce44SJohn Forte 
710fcf3ce44SJohn Forte 	return (0);
711fcf3ce44SJohn Forte 
71282527734SSukumar Swaminathan } /* emlxs_post_buffer() */
713fcf3ce44SJohn Forte 
714fcf3ce44SJohn Forte 
715fcf3ce44SJohn Forte extern int
716fcf3ce44SJohn Forte emlxs_port_offline(emlxs_port_t *port, uint32_t scope)
717fcf3ce44SJohn Forte {
718fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
719fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
720fcf3ce44SJohn Forte 	NODELIST *nlp;
721fcf3ce44SJohn Forte 	fc_affected_id_t *aid;
722fcf3ce44SJohn Forte 	uint32_t mask;
723fcf3ce44SJohn Forte 	uint32_t aff_d_id;
724fcf3ce44SJohn Forte 	uint32_t linkdown;
725fcf3ce44SJohn Forte 	uint32_t vlinkdown;
726fcf3ce44SJohn Forte 	uint32_t action;
727fcf3ce44SJohn Forte 	int i;
728fcf3ce44SJohn Forte 	uint32_t unreg_vpi;
729fcf3ce44SJohn Forte 	uint32_t update;
730fcf3ce44SJohn Forte 	uint32_t adisc_support;
7313be114edSSukumar Swaminathan 	uint8_t format;
732fcf3ce44SJohn Forte 
733fcf3ce44SJohn Forte 	/* Target mode only uses this routine for linkdowns */
734fcf3ce44SJohn Forte 	if (port->tgt_mode && (scope != 0xffffffff) && (scope != 0xfeffffff)) {
735fcf3ce44SJohn Forte 		return (0);
736fcf3ce44SJohn Forte 	}
737291a2b48SSukumar Swaminathan 
738fcf3ce44SJohn Forte 	cfg = &CFG;
739fcf3ce44SJohn Forte 	aid = (fc_affected_id_t *)&scope;
740fcf3ce44SJohn Forte 	linkdown = 0;
741fcf3ce44SJohn Forte 	vlinkdown = 0;
742fcf3ce44SJohn Forte 	unreg_vpi = 0;
743fcf3ce44SJohn Forte 	update = 0;
744fcf3ce44SJohn Forte 
745fcf3ce44SJohn Forte 	if (!(port->flag & EMLXS_PORT_BOUND)) {
746fcf3ce44SJohn Forte 		return (0);
747fcf3ce44SJohn Forte 	}
748291a2b48SSukumar Swaminathan 
7493be114edSSukumar Swaminathan 	format = aid->aff_format;
7503be114edSSukumar Swaminathan 
7513be114edSSukumar Swaminathan 	switch (format) {
752fcf3ce44SJohn Forte 	case 0:	/* Port */
753fcf3ce44SJohn Forte 		mask = 0x00ffffff;
754fcf3ce44SJohn Forte 		break;
755fcf3ce44SJohn Forte 
756fcf3ce44SJohn Forte 	case 1:	/* Area */
757fcf3ce44SJohn Forte 		mask = 0x00ffff00;
758fcf3ce44SJohn Forte 		break;
759fcf3ce44SJohn Forte 
760fcf3ce44SJohn Forte 	case 2:	/* Domain */
761fcf3ce44SJohn Forte 		mask = 0x00ff0000;
762fcf3ce44SJohn Forte 		break;
763fcf3ce44SJohn Forte 
764fcf3ce44SJohn Forte 	case 3:	/* Network */
765fcf3ce44SJohn Forte 		mask = 0x00000000;
766fcf3ce44SJohn Forte 		break;
767fcf3ce44SJohn Forte 
768fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
769fcf3ce44SJohn Forte 	case 0xfe:	/* Virtual link down */
770fcf3ce44SJohn Forte 		mask = 0x00000000;
771fcf3ce44SJohn Forte 		vlinkdown = 1;
772fcf3ce44SJohn Forte 		break;
773291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
774fcf3ce44SJohn Forte 
775fcf3ce44SJohn Forte 	case 0xff:	/* link is down */
776fcf3ce44SJohn Forte 		mask = 0x00000000;
777fcf3ce44SJohn Forte 		linkdown = 1;
778fcf3ce44SJohn Forte 		break;
779fcf3ce44SJohn Forte 
780fcf3ce44SJohn Forte 	}
781fcf3ce44SJohn Forte 
782fcf3ce44SJohn Forte 	aff_d_id = aid->aff_d_id & mask;
783fcf3ce44SJohn Forte 
784fcf3ce44SJohn Forte 
785fcf3ce44SJohn Forte 	/*
786291a2b48SSukumar Swaminathan 	 * If link is down then this is a hard shutdown and flush
787291a2b48SSukumar Swaminathan 	 * If link not down then this is a soft shutdown and flush
788291a2b48SSukumar Swaminathan 	 * (e.g. RSCN)
789fcf3ce44SJohn Forte 	 */
790fcf3ce44SJohn Forte 	if (linkdown) {
791fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
792fcf3ce44SJohn Forte 
793fcf3ce44SJohn Forte 		port->flag &= EMLXS_PORT_LINKDOWN_MASK;
794fcf3ce44SJohn Forte 		port->prev_did = port->did;
795fcf3ce44SJohn Forte 		port->did = 0;
796fcf3ce44SJohn Forte 
797fcf3ce44SJohn Forte 		if (port->ulp_statec != FC_STATE_OFFLINE) {
798fcf3ce44SJohn Forte 			port->ulp_statec = FC_STATE_OFFLINE;
799fcf3ce44SJohn Forte 			update = 1;
800fcf3ce44SJohn Forte 		}
801291a2b48SSukumar Swaminathan 
802fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
803fcf3ce44SJohn Forte 
804fcf3ce44SJohn Forte 		/* Tell ULP about it */
805fcf3ce44SJohn Forte 		if (update) {
806fcf3ce44SJohn Forte 			if (port->flag & EMLXS_PORT_BOUND) {
807fcf3ce44SJohn Forte 				if (port->vpi == 0) {
808fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
809291a2b48SSukumar Swaminathan 					    &emlxs_link_down_msg, NULL);
810fcf3ce44SJohn Forte 				}
811291a2b48SSukumar Swaminathan 
8123be114edSSukumar Swaminathan 				if (port->ini_mode) {
8133be114edSSukumar Swaminathan 					port->ulp_statec_cb(port->ulp_handle,
8143be114edSSukumar Swaminathan 					    FC_STATE_OFFLINE);
8153be114edSSukumar Swaminathan 				}
816291a2b48SSukumar Swaminathan #ifdef SFCT_SUPPORT
8173be114edSSukumar Swaminathan 				else if (port->tgt_mode) {
818fcf3ce44SJohn Forte 					emlxs_fct_link_down(port);
8193be114edSSukumar Swaminathan 				}
820291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
821fcf3ce44SJohn Forte 
822fcf3ce44SJohn Forte 			} else {
823fcf3ce44SJohn Forte 				if (port->vpi == 0) {
824fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
825291a2b48SSukumar Swaminathan 					    &emlxs_link_down_msg, "*");
826fcf3ce44SJohn Forte 				}
827fcf3ce44SJohn Forte 			}
828fcf3ce44SJohn Forte 
829fcf3ce44SJohn Forte 
830fcf3ce44SJohn Forte 		}
831291a2b48SSukumar Swaminathan 
832fcf3ce44SJohn Forte 		unreg_vpi = 1;
833fcf3ce44SJohn Forte 
834fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
835fcf3ce44SJohn Forte 		/* Stop authentication with all nodes */
836fcf3ce44SJohn Forte 		emlxs_dhc_auth_stop(port, NULL);
837291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
838fcf3ce44SJohn Forte 
839fcf3ce44SJohn Forte 		/* Flush the base node */
840fcf3ce44SJohn Forte 		(void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0);
841fcf3ce44SJohn Forte 		(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);
842fcf3ce44SJohn Forte 
843fcf3ce44SJohn Forte 		/* Flush any pending ub buffers */
844fcf3ce44SJohn Forte 		emlxs_ub_flush(port);
845fcf3ce44SJohn Forte 	}
846fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
847fcf3ce44SJohn Forte 	/* virtual link down */
848fcf3ce44SJohn Forte 	else if (vlinkdown) {
849fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
850fcf3ce44SJohn Forte 
851fcf3ce44SJohn Forte 		if (port->ulp_statec != FC_STATE_OFFLINE) {
852fcf3ce44SJohn Forte 			port->ulp_statec = FC_STATE_OFFLINE;
853fcf3ce44SJohn Forte 			update = 1;
854fcf3ce44SJohn Forte 		}
855291a2b48SSukumar Swaminathan 
856fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
857fcf3ce44SJohn Forte 
858fcf3ce44SJohn Forte 		/* Tell ULP about it */
859fcf3ce44SJohn Forte 		if (update) {
860fcf3ce44SJohn Forte 			if (port->flag & EMLXS_PORT_BOUND) {
861fcf3ce44SJohn Forte 				if (port->vpi == 0) {
862fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
863fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
864fcf3ce44SJohn Forte 					    "Switch authentication failed.");
865fcf3ce44SJohn Forte 				}
866291a2b48SSukumar Swaminathan 
867fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
868fcf3ce44SJohn Forte 				if (port->tgt_mode) {
869fcf3ce44SJohn Forte 					emlxs_fct_link_down(port);
870291a2b48SSukumar Swaminathan 
871fcf3ce44SJohn Forte 				} else if (port->ini_mode) {
872fcf3ce44SJohn Forte 					port->ulp_statec_cb(port->ulp_handle,
873fcf3ce44SJohn Forte 					    FC_STATE_OFFLINE);
874fcf3ce44SJohn Forte 				}
875fcf3ce44SJohn Forte #else
876fcf3ce44SJohn Forte 				port->ulp_statec_cb(port->ulp_handle,
877fcf3ce44SJohn Forte 				    FC_STATE_OFFLINE);
878fcf3ce44SJohn Forte #endif	/* SFCT_SUPPORT */
879fcf3ce44SJohn Forte 			} else {
880fcf3ce44SJohn Forte 				if (port->vpi == 0) {
881fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
882fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
883fcf3ce44SJohn Forte 					    "Switch authentication failed. *");
884fcf3ce44SJohn Forte 				}
885fcf3ce44SJohn Forte 			}
886fcf3ce44SJohn Forte 
887fcf3ce44SJohn Forte 
888fcf3ce44SJohn Forte 		}
889291a2b48SSukumar Swaminathan 
890fcf3ce44SJohn Forte 		/* Flush the base node */
891fcf3ce44SJohn Forte 		(void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0);
892fcf3ce44SJohn Forte 		(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);
893fcf3ce44SJohn Forte 	}
894291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
895fcf3ce44SJohn Forte 
896fcf3ce44SJohn Forte 	if (port->tgt_mode) {
897fcf3ce44SJohn Forte 		goto done;
898fcf3ce44SJohn Forte 	}
899291a2b48SSukumar Swaminathan 
900fcf3ce44SJohn Forte 	/* Set the node tags */
901fcf3ce44SJohn Forte 	/* We will process all nodes with this tag */
902fcf3ce44SJohn Forte 	rw_enter(&port->node_rwlock, RW_READER);
903fcf3ce44SJohn Forte 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
904fcf3ce44SJohn Forte 		nlp = port->node_table[i];
905fcf3ce44SJohn Forte 		while (nlp != NULL) {
906fcf3ce44SJohn Forte 			nlp->nlp_tag = 1;
907fcf3ce44SJohn Forte 			nlp = nlp->nlp_list_next;
908fcf3ce44SJohn Forte 		}
909fcf3ce44SJohn Forte 	}
910fcf3ce44SJohn Forte 	rw_exit(&port->node_rwlock);
911fcf3ce44SJohn Forte 
912fcf3ce44SJohn Forte 	if (hba->flag & FC_ONLINE_MODE) {
913fcf3ce44SJohn Forte 		adisc_support = cfg[CFG_ADISC_SUPPORT].current;
914fcf3ce44SJohn Forte 	} else {
915fcf3ce44SJohn Forte 		adisc_support = 0;
916fcf3ce44SJohn Forte 	}
917fcf3ce44SJohn Forte 
918fcf3ce44SJohn Forte 	/* Check ADISC support level */
919fcf3ce44SJohn Forte 	switch (adisc_support) {
920fcf3ce44SJohn Forte 	case 0:	/* No support - Flush all IO to all matching nodes */
921fcf3ce44SJohn Forte 
922291a2b48SSukumar Swaminathan 		for (;;) {
923fcf3ce44SJohn Forte 			/*
924fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
925291a2b48SSukumar Swaminathan 			 * emlxs_mb_unreg_did and the flush routines enter the
926291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
927291a2b48SSukumar Swaminathan 			 * can change out from under us.
928fcf3ce44SJohn Forte 			 */
929fcf3ce44SJohn Forte 
930fcf3ce44SJohn Forte 			/* Find first node */
931fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
932fcf3ce44SJohn Forte 			action = 0;
933fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
934fcf3ce44SJohn Forte 				nlp = port->node_table[i];
935fcf3ce44SJohn Forte 				while (nlp != NULL) {
936fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
937fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
938fcf3ce44SJohn Forte 						continue;
939fcf3ce44SJohn Forte 					}
940fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
941fcf3ce44SJohn Forte 
942fcf3ce44SJohn Forte 					/*
943fcf3ce44SJohn Forte 					 * Check for any device that matches
944fcf3ce44SJohn Forte 					 * our mask
945fcf3ce44SJohn Forte 					 */
946fcf3ce44SJohn Forte 					if ((nlp->nlp_DID & mask) == aff_d_id) {
947fcf3ce44SJohn Forte 						if (linkdown) {
948fcf3ce44SJohn Forte 							action = 1;
949fcf3ce44SJohn Forte 							break;
950291a2b48SSukumar Swaminathan 						} else { /* Must be an RCSN */
951291a2b48SSukumar Swaminathan 
952fcf3ce44SJohn Forte 							action = 2;
953fcf3ce44SJohn Forte 							break;
954fcf3ce44SJohn Forte 						}
955fcf3ce44SJohn Forte 					}
956fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
957fcf3ce44SJohn Forte 				}
958fcf3ce44SJohn Forte 
959fcf3ce44SJohn Forte 				if (action) {
960fcf3ce44SJohn Forte 					break;
961fcf3ce44SJohn Forte 				}
962fcf3ce44SJohn Forte 			}
963fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
964fcf3ce44SJohn Forte 
965fcf3ce44SJohn Forte 
966fcf3ce44SJohn Forte 			/* Check if nothing was found */
967fcf3ce44SJohn Forte 			if (action == 0) {
968fcf3ce44SJohn Forte 				break;
969fcf3ce44SJohn Forte 			} else if (action == 1) {
970fcf3ce44SJohn Forte 				(void) emlxs_mb_unreg_did(port, nlp->nlp_DID,
971fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
972fcf3ce44SJohn Forte 			} else if (action == 2) {
973fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
974fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
975291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
976fcf3ce44SJohn Forte 
977291a2b48SSukumar Swaminathan 				/*
978291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
979291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
980291a2b48SSukumar Swaminathan 				 */
98182527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
98282527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
98382527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
98482527734SSukumar Swaminathan 				    hba->channel_ip, 60);
985fcf3ce44SJohn Forte 
986fcf3ce44SJohn Forte 				/* Flush tx queue */
987fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
988fcf3ce44SJohn Forte 
989fcf3ce44SJohn Forte 				/* Flush chip queue */
990fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
991fcf3ce44SJohn Forte 			}
992291a2b48SSukumar Swaminathan 
993fcf3ce44SJohn Forte 		}
994fcf3ce44SJohn Forte 
995fcf3ce44SJohn Forte 		break;
996fcf3ce44SJohn Forte 
997291a2b48SSukumar Swaminathan 	case 1:	/* Partial support - Flush IO for non-FCP2 matching nodes */
998fcf3ce44SJohn Forte 
999fcf3ce44SJohn Forte 		for (;;) {
1000fcf3ce44SJohn Forte 
1001fcf3ce44SJohn Forte 			/*
1002fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
1003291a2b48SSukumar Swaminathan 			 * emlxs_mb_unreg_did and the flush routines enter the
1004291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
1005291a2b48SSukumar Swaminathan 			 * can change out from under us.
1006fcf3ce44SJohn Forte 			 */
1007fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1008fcf3ce44SJohn Forte 			action = 0;
1009fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1010fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1011fcf3ce44SJohn Forte 				while (nlp != NULL) {
1012fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1013fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1014fcf3ce44SJohn Forte 						continue;
1015fcf3ce44SJohn Forte 					}
1016fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1017fcf3ce44SJohn Forte 
1018fcf3ce44SJohn Forte 					/*
1019291a2b48SSukumar Swaminathan 					 * Check for special FCP2 target device
1020291a2b48SSukumar Swaminathan 					 * that matches our mask
1021fcf3ce44SJohn Forte 					 */
1022fcf3ce44SJohn Forte 					if ((nlp->nlp_fcp_info &
1023fcf3ce44SJohn Forte 					    NLP_FCP_TGT_DEVICE) &&
1024291a2b48SSukumar Swaminathan 					    (nlp-> nlp_fcp_info &
1025fcf3ce44SJohn Forte 					    NLP_FCP_2_DEVICE) &&
1026291a2b48SSukumar Swaminathan 					    (nlp->nlp_DID & mask) ==
1027291a2b48SSukumar Swaminathan 					    aff_d_id) {
1028fcf3ce44SJohn Forte 						action = 3;
1029fcf3ce44SJohn Forte 						break;
1030fcf3ce44SJohn Forte 					}
1031291a2b48SSukumar Swaminathan 
1032fcf3ce44SJohn Forte 					/*
1033fcf3ce44SJohn Forte 					 * Check for any other device that
1034fcf3ce44SJohn Forte 					 * matches our mask
1035fcf3ce44SJohn Forte 					 */
1036fcf3ce44SJohn Forte 					else if ((nlp->nlp_DID & mask) ==
1037fcf3ce44SJohn Forte 					    aff_d_id) {
1038fcf3ce44SJohn Forte 						if (linkdown) {
1039fcf3ce44SJohn Forte 							action = 1;
1040fcf3ce44SJohn Forte 							break;
1041291a2b48SSukumar Swaminathan 						} else { /* Must be an RSCN */
1042291a2b48SSukumar Swaminathan 
1043fcf3ce44SJohn Forte 							action = 2;
1044fcf3ce44SJohn Forte 							break;
1045fcf3ce44SJohn Forte 						}
1046fcf3ce44SJohn Forte 					}
1047291a2b48SSukumar Swaminathan 
1048fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1049fcf3ce44SJohn Forte 				}
1050fcf3ce44SJohn Forte 
1051fcf3ce44SJohn Forte 				if (action) {
1052fcf3ce44SJohn Forte 					break;
1053fcf3ce44SJohn Forte 				}
1054fcf3ce44SJohn Forte 			}
1055fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1056fcf3ce44SJohn Forte 
1057fcf3ce44SJohn Forte 			/* Check if nothing was found */
1058fcf3ce44SJohn Forte 			if (action == 0) {
1059fcf3ce44SJohn Forte 				break;
1060fcf3ce44SJohn Forte 			} else if (action == 1) {
1061fcf3ce44SJohn Forte 				(void) emlxs_mb_unreg_did(port, nlp->nlp_DID,
1062fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1063fcf3ce44SJohn Forte 			} else if (action == 2) {
1064fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1065fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1066291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1067fcf3ce44SJohn Forte 
1068291a2b48SSukumar Swaminathan 				/*
1069291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1070291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
1071291a2b48SSukumar Swaminathan 				 */
107282527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
107382527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
107482527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
107582527734SSukumar Swaminathan 				    hba->channel_ip, 60);
1076fcf3ce44SJohn Forte 
1077fcf3ce44SJohn Forte 				/* Flush tx queue */
1078fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1079fcf3ce44SJohn Forte 
1080fcf3ce44SJohn Forte 				/* Flush chip queue */
1081fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1082291a2b48SSukumar Swaminathan 
1083fcf3ce44SJohn Forte 			} else if (action == 3) {	/* FCP2 devices */
1084fcf3ce44SJohn Forte 				unreg_vpi = 0;
1085fcf3ce44SJohn Forte 
1086fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1087fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1088291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1089fcf3ce44SJohn Forte 
1090291a2b48SSukumar Swaminathan 				/*
1091291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1092291a2b48SSukumar Swaminathan 				 * An ADISC or a PLOGI with reopen the node
1093291a2b48SSukumar Swaminathan 				 */
109482527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
109582527734SSukumar Swaminathan 				    hba->channel_fcp, -1);
109682527734SSukumar Swaminathan 				emlxs_node_close(port, nlp, hba->channel_ip,
1097fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1098fcf3ce44SJohn Forte 
1099fcf3ce44SJohn Forte 				/* Flush tx queues except for FCP ring */
1100fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
110182527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], 0, 0);
1102fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
110382527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], 0, 0);
1104fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
110582527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], 0, 0);
1106fcf3ce44SJohn Forte 
1107fcf3ce44SJohn Forte 				/* Flush chip queues except for FCP ring */
1108fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
110982527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], nlp, 0);
1110fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
111182527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], nlp, 0);
1112fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
111382527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], nlp, 0);
1114fcf3ce44SJohn Forte 			}
1115fcf3ce44SJohn Forte 		}
1116fcf3ce44SJohn Forte 		break;
1117fcf3ce44SJohn Forte 
1118fcf3ce44SJohn Forte 	case 2:	/* Full support - Hold FCP IO to FCP target matching nodes */
1119fcf3ce44SJohn Forte 
1120fcf3ce44SJohn Forte 		if (!linkdown && !vlinkdown) {
1121fcf3ce44SJohn Forte 			break;
1122fcf3ce44SJohn Forte 		}
1123291a2b48SSukumar Swaminathan 
1124fcf3ce44SJohn Forte 		for (;;) {
1125fcf3ce44SJohn Forte 			/*
1126fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
1127291a2b48SSukumar Swaminathan 			 * emlxs_mb_unreg_did and the flush routines enter the
1128291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
1129291a2b48SSukumar Swaminathan 			 * can change out from under us.
1130fcf3ce44SJohn Forte 			 */
1131fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1132fcf3ce44SJohn Forte 			action = 0;
1133fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1134fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1135fcf3ce44SJohn Forte 				while (nlp != NULL) {
1136fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1137fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1138fcf3ce44SJohn Forte 						continue;
1139fcf3ce44SJohn Forte 					}
1140fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1141fcf3ce44SJohn Forte 
1142fcf3ce44SJohn Forte 					/*
1143fcf3ce44SJohn Forte 					 * Check for FCP target device that
1144fcf3ce44SJohn Forte 					 * matches our mask
1145fcf3ce44SJohn Forte 					 */
1146291a2b48SSukumar Swaminathan 					if ((nlp-> nlp_fcp_info &
1147fcf3ce44SJohn Forte 					    NLP_FCP_TGT_DEVICE) &&
1148291a2b48SSukumar Swaminathan 					    (nlp->nlp_DID & mask) ==
1149291a2b48SSukumar Swaminathan 					    aff_d_id) {
1150fcf3ce44SJohn Forte 						action = 3;
1151fcf3ce44SJohn Forte 						break;
1152fcf3ce44SJohn Forte 					}
1153291a2b48SSukumar Swaminathan 
1154fcf3ce44SJohn Forte 					/*
1155fcf3ce44SJohn Forte 					 * Check for any other device that
1156fcf3ce44SJohn Forte 					 * matches our mask
1157fcf3ce44SJohn Forte 					 */
1158fcf3ce44SJohn Forte 					else if ((nlp->nlp_DID & mask) ==
1159fcf3ce44SJohn Forte 					    aff_d_id) {
1160fcf3ce44SJohn Forte 						if (linkdown) {
1161fcf3ce44SJohn Forte 							action = 1;
1162fcf3ce44SJohn Forte 							break;
1163fcf3ce44SJohn Forte 						} else { /* Must be an RSCN */
1164291a2b48SSukumar Swaminathan 
1165fcf3ce44SJohn Forte 							action = 2;
1166fcf3ce44SJohn Forte 							break;
1167fcf3ce44SJohn Forte 						}
1168fcf3ce44SJohn Forte 					}
1169291a2b48SSukumar Swaminathan 
1170fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1171fcf3ce44SJohn Forte 				}
1172fcf3ce44SJohn Forte 				if (action) {
1173fcf3ce44SJohn Forte 					break;
1174fcf3ce44SJohn Forte 				}
1175fcf3ce44SJohn Forte 			}
1176fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1177fcf3ce44SJohn Forte 
1178fcf3ce44SJohn Forte 			/* Check if nothing was found */
1179fcf3ce44SJohn Forte 			if (action == 0) {
1180fcf3ce44SJohn Forte 				break;
1181fcf3ce44SJohn Forte 			} else if (action == 1) {
1182fcf3ce44SJohn Forte 				(void) emlxs_mb_unreg_did(port, nlp->nlp_DID,
1183fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1184fcf3ce44SJohn Forte 			} else if (action == 2) {
1185291a2b48SSukumar Swaminathan 				/*
1186291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1187291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
1188291a2b48SSukumar Swaminathan 				 */
118982527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
119082527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
119182527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
119282527734SSukumar Swaminathan 				    hba->channel_ip, 60);
1193fcf3ce44SJohn Forte 
1194fcf3ce44SJohn Forte 				/* Flush tx queue */
1195fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1196fcf3ce44SJohn Forte 
1197fcf3ce44SJohn Forte 				/* Flush chip queue */
1198fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1199fcf3ce44SJohn Forte 
1200fcf3ce44SJohn Forte 			} else if (action == 3) {	/* FCP2 devices */
1201fcf3ce44SJohn Forte 				unreg_vpi = 0;
1202fcf3ce44SJohn Forte 
1203291a2b48SSukumar Swaminathan 				/*
1204291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1205291a2b48SSukumar Swaminathan 				 * An ADISC or a PLOGI with reopen the node
1206291a2b48SSukumar Swaminathan 				 */
120782527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
120882527734SSukumar Swaminathan 				    hba->channel_fcp, -1);
120982527734SSukumar Swaminathan 				emlxs_node_close(port, nlp, hba->channel_ip,
1210fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1211fcf3ce44SJohn Forte 
1212fcf3ce44SJohn Forte 				/* Flush tx queues except for FCP ring */
1213fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
121482527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], 0, 0);
1215fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
121682527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], 0, 0);
1217fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
121882527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], 0, 0);
1219fcf3ce44SJohn Forte 
1220fcf3ce44SJohn Forte 				/* Flush chip queues except for FCP ring */
1221fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
122282527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], nlp, 0);
1223fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
122482527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], nlp, 0);
1225fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
122682527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], nlp, 0);
1227fcf3ce44SJohn Forte 			}
1228fcf3ce44SJohn Forte 		}
1229fcf3ce44SJohn Forte 
1230fcf3ce44SJohn Forte 		break;
1231fcf3ce44SJohn Forte 
1232fcf3ce44SJohn Forte 	}	/* switch() */
1233fcf3ce44SJohn Forte 
1234fcf3ce44SJohn Forte done:
1235fcf3ce44SJohn Forte 
123682527734SSukumar Swaminathan 	if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) {
123782527734SSukumar Swaminathan 		if (unreg_vpi) {
123882527734SSukumar Swaminathan 			(void) emlxs_mb_unreg_vpi(port);
123982527734SSukumar Swaminathan 		}
1240fcf3ce44SJohn Forte 	}
1241fcf3ce44SJohn Forte 
1242291a2b48SSukumar Swaminathan 	return (0);
1243fcf3ce44SJohn Forte 
124482527734SSukumar Swaminathan } /* emlxs_port_offline() */
1245fcf3ce44SJohn Forte 
1246fcf3ce44SJohn Forte 
1247fcf3ce44SJohn Forte extern void
1248fcf3ce44SJohn Forte emlxs_port_online(emlxs_port_t *vport)
1249fcf3ce44SJohn Forte {
1250fcf3ce44SJohn Forte 	emlxs_hba_t *hba = vport->hba;
1251fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1252fcf3ce44SJohn Forte 	uint32_t state;
1253fcf3ce44SJohn Forte 	uint32_t update;
1254fcf3ce44SJohn Forte 	uint32_t npiv_linkup;
1255fcf3ce44SJohn Forte 	char topology[32];
1256fcf3ce44SJohn Forte 	char linkspeed[32];
1257fcf3ce44SJohn Forte 	char mode[32];
1258fcf3ce44SJohn Forte 
1259fcf3ce44SJohn Forte 	/*
1260291a2b48SSukumar Swaminathan 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1261291a2b48SSukumar Swaminathan 	 *    "linkup_callback. vpi=%d fc_flag=%x", vport->vpi, hba->flag);
1262fcf3ce44SJohn Forte 	 */
1263fcf3ce44SJohn Forte 
1264fcf3ce44SJohn Forte 	if ((vport->vpi > 0) &&
1265fcf3ce44SJohn Forte 	    (!(hba->flag & FC_NPIV_ENABLED) ||
1266fcf3ce44SJohn Forte 	    !(hba->flag & FC_NPIV_SUPPORTED))) {
1267fcf3ce44SJohn Forte 		return;
1268fcf3ce44SJohn Forte 	}
1269291a2b48SSukumar Swaminathan 
1270fcf3ce44SJohn Forte 	if (!(vport->flag & EMLXS_PORT_BOUND) ||
1271fcf3ce44SJohn Forte 	    !(vport->flag & EMLXS_PORT_ENABLE)) {
1272fcf3ce44SJohn Forte 		return;
1273fcf3ce44SJohn Forte 	}
1274291a2b48SSukumar Swaminathan 
1275fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1276fcf3ce44SJohn Forte 
1277fcf3ce44SJohn Forte 	/* Check for mode */
1278fcf3ce44SJohn Forte 	if (port->tgt_mode) {
1279fcf3ce44SJohn Forte 		(void) strcpy(mode, ", target");
1280fcf3ce44SJohn Forte 	} else if (port->ini_mode) {
1281fcf3ce44SJohn Forte 		(void) strcpy(mode, ", initiator");
1282fcf3ce44SJohn Forte 	} else {
1283fcf3ce44SJohn Forte 		(void) strcpy(mode, "");
1284fcf3ce44SJohn Forte 	}
1285fcf3ce44SJohn Forte 
1286fcf3ce44SJohn Forte 	/* Check for loop topology */
1287fcf3ce44SJohn Forte 	if (hba->topology == TOPOLOGY_LOOP) {
1288fcf3ce44SJohn Forte 		state = FC_STATE_LOOP;
1289fcf3ce44SJohn Forte 		(void) strcpy(topology, ", loop");
1290fcf3ce44SJohn Forte 	} else {
1291fcf3ce44SJohn Forte 		state = FC_STATE_ONLINE;
1292fcf3ce44SJohn Forte 		(void) strcpy(topology, ", fabric");
1293fcf3ce44SJohn Forte 	}
1294fcf3ce44SJohn Forte 
1295fcf3ce44SJohn Forte 	/* Set the link speed */
1296fcf3ce44SJohn Forte 	switch (hba->linkspeed) {
1297fcf3ce44SJohn Forte 	case 0:
1298fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "Gb");
1299fcf3ce44SJohn Forte 		state |= FC_STATE_1GBIT_SPEED;
1300fcf3ce44SJohn Forte 		break;
1301fcf3ce44SJohn Forte 
1302fcf3ce44SJohn Forte 	case LA_1GHZ_LINK:
1303fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "1Gb");
1304fcf3ce44SJohn Forte 		state |= FC_STATE_1GBIT_SPEED;
1305fcf3ce44SJohn Forte 		break;
1306fcf3ce44SJohn Forte 	case LA_2GHZ_LINK:
1307fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "2Gb");
1308fcf3ce44SJohn Forte 		state |= FC_STATE_2GBIT_SPEED;
1309fcf3ce44SJohn Forte 		break;
1310fcf3ce44SJohn Forte 	case LA_4GHZ_LINK:
1311fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "4Gb");
1312fcf3ce44SJohn Forte 		state |= FC_STATE_4GBIT_SPEED;
1313fcf3ce44SJohn Forte 		break;
1314fcf3ce44SJohn Forte 	case LA_8GHZ_LINK:
1315fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "8Gb");
1316fcf3ce44SJohn Forte 		state |= FC_STATE_8GBIT_SPEED;
1317fcf3ce44SJohn Forte 		break;
1318fcf3ce44SJohn Forte 	case LA_10GHZ_LINK:
1319fcf3ce44SJohn Forte 		(void) strcpy(linkspeed, "10Gb");
1320fcf3ce44SJohn Forte 		state |= FC_STATE_10GBIT_SPEED;
1321fcf3ce44SJohn Forte 		break;
1322fcf3ce44SJohn Forte 	default:
1323fcf3ce44SJohn Forte 		(void) sprintf(linkspeed, "unknown(0x%x)", hba->linkspeed);
1324fcf3ce44SJohn Forte 		break;
1325fcf3ce44SJohn Forte 	}
1326fcf3ce44SJohn Forte 
1327fcf3ce44SJohn Forte 	npiv_linkup = 0;
1328fcf3ce44SJohn Forte 	update = 0;
1329fcf3ce44SJohn Forte 
1330fcf3ce44SJohn Forte 	if ((hba->state >= FC_LINK_UP) &&
1331291a2b48SSukumar Swaminathan 	    !(hba->flag & FC_LOOPBACK_MODE) && (vport->ulp_statec != state)) {
1332fcf3ce44SJohn Forte 		update = 1;
1333fcf3ce44SJohn Forte 		vport->ulp_statec = state;
1334fcf3ce44SJohn Forte 
1335fcf3ce44SJohn Forte 		if ((vport->vpi > 0) && !(hba->flag & FC_NPIV_LINKUP)) {
1336fcf3ce44SJohn Forte 			hba->flag |= FC_NPIV_LINKUP;
1337fcf3ce44SJohn Forte 			npiv_linkup = 1;
1338fcf3ce44SJohn Forte 		}
1339fcf3ce44SJohn Forte 	}
1340291a2b48SSukumar Swaminathan 
1341fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1342fcf3ce44SJohn Forte 
134382527734SSukumar Swaminathan 
1344fcf3ce44SJohn Forte 	/*
1345291a2b48SSukumar Swaminathan 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
134682527734SSukumar Swaminathan 	 *    "linkup_callback: update=%d vpi=%d flag=%d fc_flag=%x state=%x"
134782527734SSukumar Swaminathan 	 *    "statec=%x", update, vport->vpi, npiv_linkup, hba->flag,
1348291a2b48SSukumar Swaminathan 	 *    hba->state, vport->ulp_statec);
1349fcf3ce44SJohn Forte 	 */
135082527734SSukumar Swaminathan 
1351fcf3ce44SJohn Forte 	if (update) {
1352fcf3ce44SJohn Forte 		if (vport->flag & EMLXS_PORT_BOUND) {
1353fcf3ce44SJohn Forte 			if (vport->vpi == 0) {
1354fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1355291a2b48SSukumar Swaminathan 				    "%s%s%s", linkspeed, topology, mode);
1356fcf3ce44SJohn Forte 			} else if (npiv_linkup) {
1357fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT,
1358291a2b48SSukumar Swaminathan 				    &emlxs_npiv_link_up_msg, "%s%s%s",
1359fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1360fcf3ce44SJohn Forte 			}
1361291a2b48SSukumar Swaminathan 
13623be114edSSukumar Swaminathan 			if (vport->ini_mode) {
1363291a2b48SSukumar Swaminathan 				vport->ulp_statec_cb(vport->ulp_handle,
1364291a2b48SSukumar Swaminathan 				    state);
1365fcf3ce44SJohn Forte 			}
13663be114edSSukumar Swaminathan #ifdef SFCT_SUPPORT
13673be114edSSukumar Swaminathan 			else if (vport->tgt_mode) {
13683be114edSSukumar Swaminathan 				emlxs_fct_link_up(vport);
13693be114edSSukumar Swaminathan 			}
13703be114edSSukumar Swaminathan #endif /* SFCT_SUPPORT */
1371fcf3ce44SJohn Forte 		} else {
1372fcf3ce44SJohn Forte 			if (vport->vpi == 0) {
1373fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1374291a2b48SSukumar Swaminathan 				    "%s%s%s *", linkspeed, topology, mode);
1375fcf3ce44SJohn Forte 			} else if (npiv_linkup) {
1376fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT,
1377291a2b48SSukumar Swaminathan 				    &emlxs_npiv_link_up_msg, "%s%s%s *",
1378fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1379fcf3ce44SJohn Forte 			}
1380fcf3ce44SJohn Forte 		}
1381fcf3ce44SJohn Forte 
1382fcf3ce44SJohn Forte 		/* Check for waiting threads */
1383fcf3ce44SJohn Forte 		if (vport->vpi == 0) {
1384fcf3ce44SJohn Forte 			mutex_enter(&EMLXS_LINKUP_LOCK);
1385fcf3ce44SJohn Forte 			if (hba->linkup_wait_flag == TRUE) {
1386fcf3ce44SJohn Forte 				hba->linkup_wait_flag = FALSE;
1387fcf3ce44SJohn Forte 				cv_broadcast(&EMLXS_LINKUP_CV);
1388fcf3ce44SJohn Forte 			}
1389fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_LINKUP_LOCK);
1390fcf3ce44SJohn Forte 		}
1391291a2b48SSukumar Swaminathan 
1392fcf3ce44SJohn Forte 		/* Flush any pending ub buffers */
1393fcf3ce44SJohn Forte 		emlxs_ub_flush(vport);
1394fcf3ce44SJohn Forte 	}
1395291a2b48SSukumar Swaminathan 
1396fcf3ce44SJohn Forte 	return;
1397fcf3ce44SJohn Forte 
139882527734SSukumar Swaminathan } /* emlxs_port_online() */
1399fcf3ce44SJohn Forte 
1400fcf3ce44SJohn Forte 
1401fcf3ce44SJohn Forte extern void
1402fcf3ce44SJohn Forte emlxs_linkdown(emlxs_hba_t *hba)
1403fcf3ce44SJohn Forte {
1404fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
140582527734SSukumar Swaminathan 	RPIobj_t *rp;
1406fcf3ce44SJohn Forte 	int i;
1407fcf3ce44SJohn Forte 
1408fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1409fcf3ce44SJohn Forte 
141082527734SSukumar Swaminathan 	if (hba->state > FC_LINK_DOWN) {
141182527734SSukumar Swaminathan 		HBASTATS.LinkDown++;
141282527734SSukumar Swaminathan 		EMLXS_STATE_CHANGE_LOCKED(hba, FC_LINK_DOWN);
141382527734SSukumar Swaminathan 	}
1414fcf3ce44SJohn Forte 
1415fcf3ce44SJohn Forte 	/* Filter hba flags */
1416fcf3ce44SJohn Forte 	hba->flag &= FC_LINKDOWN_MASK;
1417fcf3ce44SJohn Forte 	hba->discovery_timer = 0;
1418fcf3ce44SJohn Forte 	hba->linkup_timer = 0;
1419fcf3ce44SJohn Forte 
142082527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
142182527734SSukumar Swaminathan 		rp = hba->sli.sli4.RPIp;
142282527734SSukumar Swaminathan 		for (i = 0; i < hba->sli.sli4.RPICount; i++) {
142382527734SSukumar Swaminathan 			if (rp->state & RESOURCE_ALLOCATED) {
142482527734SSukumar Swaminathan 				rp->state |= RESOURCE_RPI_PAUSED;
142582527734SSukumar Swaminathan 			}
142682527734SSukumar Swaminathan 			rp++;
142782527734SSukumar Swaminathan 		}
142882527734SSukumar Swaminathan 	}
142982527734SSukumar Swaminathan 
1430fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1431fcf3ce44SJohn Forte 
1432fcf3ce44SJohn Forte 	for (i = 0; i < MAX_VPORTS; i++) {
1433fcf3ce44SJohn Forte 		port = &VPORT(i);
1434fcf3ce44SJohn Forte 
1435fcf3ce44SJohn Forte 		if (!(port->flag & EMLXS_PORT_BOUND)) {
1436fcf3ce44SJohn Forte 			continue;
1437fcf3ce44SJohn Forte 		}
1438291a2b48SSukumar Swaminathan 
1439fcf3ce44SJohn Forte 		(void) emlxs_port_offline(port, 0xffffffff);
1440fcf3ce44SJohn Forte 
1441fcf3ce44SJohn Forte 	}
1442fcf3ce44SJohn Forte 
1443fcf3ce44SJohn Forte 	return;
1444fcf3ce44SJohn Forte 
144582527734SSukumar Swaminathan } /* emlxs_linkdown() */
1446fcf3ce44SJohn Forte 
1447fcf3ce44SJohn Forte 
1448fcf3ce44SJohn Forte extern void
1449fcf3ce44SJohn Forte emlxs_linkup(emlxs_hba_t *hba)
1450fcf3ce44SJohn Forte {
1451fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1452fcf3ce44SJohn Forte 	emlxs_config_t *cfg = &CFG;
1453fcf3ce44SJohn Forte 
1454fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1455fcf3ce44SJohn Forte 
1456fcf3ce44SJohn Forte 	HBASTATS.LinkUp++;
145782527734SSukumar Swaminathan 	EMLXS_STATE_CHANGE_LOCKED(hba, FC_LINK_UP);
1458fcf3ce44SJohn Forte 
1459fcf3ce44SJohn Forte #ifdef MENLO_SUPPORT
1460fcf3ce44SJohn Forte 	if (hba->flag & FC_MENLO_MODE) {
1461fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1462fcf3ce44SJohn Forte 
1463fcf3ce44SJohn Forte 		/*
1464fcf3ce44SJohn Forte 		 * Trigger linkup CV and don't start linkup & discovery
1465fcf3ce44SJohn Forte 		 * timers
1466fcf3ce44SJohn Forte 		 */
1467fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_LINKUP_LOCK);
1468fcf3ce44SJohn Forte 		cv_broadcast(&EMLXS_LINKUP_CV);
1469fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_LINKUP_LOCK);
1470fcf3ce44SJohn Forte 
1471fcf3ce44SJohn Forte 		return;
1472fcf3ce44SJohn Forte 	}
1473291a2b48SSukumar Swaminathan #endif /* MENLO_SUPPORT */
1474fcf3ce44SJohn Forte 
1475fcf3ce44SJohn Forte 	/* Set the linkup & discovery timers */
1476fcf3ce44SJohn Forte 	hba->linkup_timer = hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current;
1477291a2b48SSukumar Swaminathan 	hba->discovery_timer =
1478291a2b48SSukumar Swaminathan 	    hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current +
1479291a2b48SSukumar Swaminathan 	    cfg[CFG_DISC_TIMEOUT].current;
1480fcf3ce44SJohn Forte 
1481fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1482fcf3ce44SJohn Forte 
1483fcf3ce44SJohn Forte 	return;
1484fcf3ce44SJohn Forte 
148582527734SSukumar Swaminathan } /* emlxs_linkup() */
1486fcf3ce44SJohn Forte 
1487fcf3ce44SJohn Forte 
1488fcf3ce44SJohn Forte /*
1489fcf3ce44SJohn Forte  *  emlxs_reset_link
1490fcf3ce44SJohn Forte  *
1491fcf3ce44SJohn Forte  *  Description:
1492fcf3ce44SJohn Forte  *  Called to reset the link with an init_link
1493fcf3ce44SJohn Forte  *
1494fcf3ce44SJohn Forte  *    Returns:
1495fcf3ce44SJohn Forte  *
1496fcf3ce44SJohn Forte  */
1497fcf3ce44SJohn Forte extern int
149882527734SSukumar Swaminathan emlxs_reset_link(emlxs_hba_t *hba, uint32_t linkup, uint32_t wait)
1499fcf3ce44SJohn Forte {
1500fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1501fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
150282527734SSukumar Swaminathan 	MAILBOXQ *mbq = NULL;
150382527734SSukumar Swaminathan 	MAILBOX *mb = NULL;
150482527734SSukumar Swaminathan 	int rval = 0;
150582527734SSukumar Swaminathan 	int rc;
1506fcf3ce44SJohn Forte 
1507fcf3ce44SJohn Forte 	/*
1508fcf3ce44SJohn Forte 	 * Get a buffer to use for the mailbox command
1509fcf3ce44SJohn Forte 	 */
151082527734SSukumar Swaminathan 	if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))
151182527734SSukumar Swaminathan 	    == NULL) {
1512fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_failed_msg,
1513fcf3ce44SJohn Forte 		    "Unable to allocate mailbox buffer.");
151482527734SSukumar Swaminathan 		rval = 1;
151582527734SSukumar Swaminathan 		goto reset_link_fail;
151682527734SSukumar Swaminathan 	}
1517fcf3ce44SJohn Forte 
151882527734SSukumar Swaminathan 	mb = (MAILBOX *)mbq;
151982527734SSukumar Swaminathan 
152082527734SSukumar Swaminathan 	/* Bring link down first */
152182527734SSukumar Swaminathan 	emlxs_mb_down_link(hba, mbq);
152282527734SSukumar Swaminathan 
152382527734SSukumar Swaminathan #define	MBXERR_LINK_DOWN	0x33
152482527734SSukumar Swaminathan 
152582527734SSukumar Swaminathan 	if (wait) {
152682527734SSukumar Swaminathan 		wait = MBX_WAIT;
152782527734SSukumar Swaminathan 	} else {
152882527734SSukumar Swaminathan 		wait = MBX_NOWAIT;
152982527734SSukumar Swaminathan 	}
153082527734SSukumar Swaminathan 	rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, wait, 0);
153182527734SSukumar Swaminathan 	if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS) &&
153282527734SSukumar Swaminathan 	    (rc != MBXERR_LINK_DOWN)) {
153382527734SSukumar Swaminathan 		rval = 1;
153482527734SSukumar Swaminathan 		goto reset_link_fail;
1535fcf3ce44SJohn Forte 	}
1536291a2b48SSukumar Swaminathan 
153782527734SSukumar Swaminathan 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg,
153882527734SSukumar Swaminathan 	    "Disabling link...");
1539fcf3ce44SJohn Forte 
1540fcf3ce44SJohn Forte 	if (linkup) {
1541fcf3ce44SJohn Forte 		/*
1542fcf3ce44SJohn Forte 		 * Setup and issue mailbox INITIALIZE LINK command
1543fcf3ce44SJohn Forte 		 */
1544fcf3ce44SJohn Forte 
154582527734SSukumar Swaminathan 		if (wait == MBX_NOWAIT) {
154682527734SSukumar Swaminathan 			if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))
154782527734SSukumar Swaminathan 			    == NULL) {
154882527734SSukumar Swaminathan 				EMLXS_MSGF(EMLXS_CONTEXT,
154982527734SSukumar Swaminathan 				    &emlxs_link_reset_failed_msg,
155082527734SSukumar Swaminathan 				    "Unable to allocate mailbox buffer.");
155182527734SSukumar Swaminathan 				rval = 1;
155282527734SSukumar Swaminathan 				goto reset_link_fail;
155382527734SSukumar Swaminathan 			}
155482527734SSukumar Swaminathan 			mb = (MAILBOX *)mbq;
155582527734SSukumar Swaminathan 		} else {
155682527734SSukumar Swaminathan 			/* Reuse mbq from previous mbox */
155782527734SSukumar Swaminathan 			mb = (MAILBOX *)mbq;
155882527734SSukumar Swaminathan 		}
155982527734SSukumar Swaminathan 		cfg = &CFG;
156082527734SSukumar Swaminathan 
156182527734SSukumar Swaminathan 		emlxs_mb_init_link(hba, mbq,
1562fcf3ce44SJohn Forte 		    cfg[CFG_TOPOLOGY].current, cfg[CFG_LINK_SPEED].current);
1563fcf3ce44SJohn Forte 
1564fcf3ce44SJohn Forte 		mb->un.varInitLnk.lipsr_AL_PA = 0;
1565fcf3ce44SJohn Forte 
1566fcf3ce44SJohn Forte 		/* Clear the loopback mode */
1567fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1568fcf3ce44SJohn Forte 		hba->flag &= ~FC_LOOPBACK_MODE;
1569291a2b48SSukumar Swaminathan 		hba->loopback_tics = 0;
1570fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1571fcf3ce44SJohn Forte 
157282527734SSukumar Swaminathan 		rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, wait, 0);
157382527734SSukumar Swaminathan 		if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
157482527734SSukumar Swaminathan 			rval = 1;
157582527734SSukumar Swaminathan 			goto reset_link_fail;
1576fcf3ce44SJohn Forte 		}
1577291a2b48SSukumar Swaminathan 
1578fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg, NULL);
157982527734SSukumar Swaminathan 	}
1580fcf3ce44SJohn Forte 
158182527734SSukumar Swaminathan reset_link_fail:
1582291a2b48SSukumar Swaminathan 
158382527734SSukumar Swaminathan 	if ((wait == MBX_WAIT) && mbq) {
158482527734SSukumar Swaminathan 		(void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
1585fcf3ce44SJohn Forte 	}
1586fcf3ce44SJohn Forte 
158782527734SSukumar Swaminathan 	return (rval);
158882527734SSukumar Swaminathan } /* emlxs_reset_link() */
1589fcf3ce44SJohn Forte 
1590fcf3ce44SJohn Forte 
1591fcf3ce44SJohn Forte extern int
1592fcf3ce44SJohn Forte emlxs_online(emlxs_hba_t *hba)
1593fcf3ce44SJohn Forte {
1594fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1595fcf3ce44SJohn Forte 	int32_t rval = 0;
1596fcf3ce44SJohn Forte 	uint32_t i = 0;
1597fcf3ce44SJohn Forte 
1598fcf3ce44SJohn Forte 	/* Make sure adapter is offline or exit trying (30 seconds) */
1599291a2b48SSukumar Swaminathan 	while (i++ < 30) {
1600fcf3ce44SJohn Forte 		/* Check if adapter is already going online */
1601fcf3ce44SJohn Forte 		if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) {
1602fcf3ce44SJohn Forte 			return (0);
1603fcf3ce44SJohn Forte 		}
1604291a2b48SSukumar Swaminathan 
1605fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1606fcf3ce44SJohn Forte 
1607fcf3ce44SJohn Forte 		/* Check again */
1608fcf3ce44SJohn Forte 		if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) {
1609fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1610fcf3ce44SJohn Forte 			return (0);
1611fcf3ce44SJohn Forte 		}
1612291a2b48SSukumar Swaminathan 
1613fcf3ce44SJohn Forte 		/* Check if adapter is offline */
1614fcf3ce44SJohn Forte 		if (hba->flag & FC_OFFLINE_MODE) {
1615fcf3ce44SJohn Forte 			/* Mark it going online */
1616fcf3ce44SJohn Forte 			hba->flag &= ~FC_OFFLINE_MODE;
1617fcf3ce44SJohn Forte 			hba->flag |= FC_ONLINING_MODE;
1618fcf3ce44SJohn Forte 
1619fcf3ce44SJohn Forte 			/* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */
1620fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1621fcf3ce44SJohn Forte 			break;
1622fcf3ce44SJohn Forte 		}
1623291a2b48SSukumar Swaminathan 
1624fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1625fcf3ce44SJohn Forte 
1626fcf3ce44SJohn Forte 		DELAYMS(1000);
1627fcf3ce44SJohn Forte 	}
1628fcf3ce44SJohn Forte 
1629fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
1630fcf3ce44SJohn Forte 	    "Going online...");
1631fcf3ce44SJohn Forte 
163282527734SSukumar Swaminathan 	if (rval = EMLXS_SLI_ONLINE(hba)) {
1633291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg, "status=%x",
1634fcf3ce44SJohn Forte 		    rval);
1635fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL);
1636fcf3ce44SJohn Forte 
1637fcf3ce44SJohn Forte 		/* Set FC_OFFLINE_MODE */
1638fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1639fcf3ce44SJohn Forte 		emlxs_diag_state = DDI_OFFDI;
1640fcf3ce44SJohn Forte 		hba->flag |= FC_OFFLINE_MODE;
1641fcf3ce44SJohn Forte 		hba->flag &= ~FC_ONLINING_MODE;
1642fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1643fcf3ce44SJohn Forte 
1644fcf3ce44SJohn Forte 		return (rval);
1645fcf3ce44SJohn Forte 	}
1646291a2b48SSukumar Swaminathan 
1647fcf3ce44SJohn Forte 	/* Start the timer */
1648fcf3ce44SJohn Forte 	emlxs_timer_start(hba);
1649fcf3ce44SJohn Forte 
1650fcf3ce44SJohn Forte 	/* Set FC_ONLINE_MODE */
1651fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1652fcf3ce44SJohn Forte 	emlxs_diag_state = DDI_ONDI;
1653fcf3ce44SJohn Forte 	hba->flag |= FC_ONLINE_MODE;
1654fcf3ce44SJohn Forte 	hba->flag &= ~FC_ONLINING_MODE;
1655fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1656fcf3ce44SJohn Forte 
1657fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_online_msg, NULL);
1658fcf3ce44SJohn Forte 
1659fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
1660fcf3ce44SJohn Forte 	(void) emlxs_fct_port_initialize(port);
1661291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
1662fcf3ce44SJohn Forte 
1663fcf3ce44SJohn Forte 	return (rval);
1664fcf3ce44SJohn Forte 
166582527734SSukumar Swaminathan } /* emlxs_online() */
1666fcf3ce44SJohn Forte 
1667fcf3ce44SJohn Forte 
1668fcf3ce44SJohn Forte extern int
1669fcf3ce44SJohn Forte emlxs_offline(emlxs_hba_t *hba)
1670fcf3ce44SJohn Forte {
1671fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1672fcf3ce44SJohn Forte 	uint32_t i = 0;
1673fcf3ce44SJohn Forte 	int rval = 1;
1674fcf3ce44SJohn Forte 
1675fcf3ce44SJohn Forte 	/* Make sure adapter is online or exit trying (30 seconds) */
1676291a2b48SSukumar Swaminathan 	while (i++ < 30) {
1677fcf3ce44SJohn Forte 		/* Check if adapter is already going offline */
1678fcf3ce44SJohn Forte 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1679fcf3ce44SJohn Forte 			return (0);
1680fcf3ce44SJohn Forte 		}
1681291a2b48SSukumar Swaminathan 
1682fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1683fcf3ce44SJohn Forte 
1684fcf3ce44SJohn Forte 		/* Check again */
1685fcf3ce44SJohn Forte 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1686fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1687fcf3ce44SJohn Forte 			return (0);
1688fcf3ce44SJohn Forte 		}
1689291a2b48SSukumar Swaminathan 
1690fcf3ce44SJohn Forte 		/* Check if adapter is online */
1691fcf3ce44SJohn Forte 		if (hba->flag & FC_ONLINE_MODE) {
1692fcf3ce44SJohn Forte 			/* Mark it going offline */
1693fcf3ce44SJohn Forte 			hba->flag &= ~FC_ONLINE_MODE;
1694fcf3ce44SJohn Forte 			hba->flag |= FC_OFFLINING_MODE;
1695fcf3ce44SJohn Forte 
1696fcf3ce44SJohn Forte 			/* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */
1697fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1698fcf3ce44SJohn Forte 			break;
1699fcf3ce44SJohn Forte 		}
1700291a2b48SSukumar Swaminathan 
1701fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1702fcf3ce44SJohn Forte 
1703fcf3ce44SJohn Forte 		DELAYMS(1000);
1704fcf3ce44SJohn Forte 	}
1705fcf3ce44SJohn Forte 
1706291a2b48SSukumar Swaminathan 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
1707291a2b48SSukumar Swaminathan 	    "Going offline...");
1708fcf3ce44SJohn Forte 
1709fcf3ce44SJohn Forte 	if (port->ini_mode) {
1710fcf3ce44SJohn Forte 		/* Flush all IO */
1711fcf3ce44SJohn Forte 		emlxs_linkdown(hba);
1712fcf3ce44SJohn Forte 	}
1713fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
1714fcf3ce44SJohn Forte 	else {
1715fcf3ce44SJohn Forte 		(void) emlxs_fct_port_shutdown(port);
1716fcf3ce44SJohn Forte 	}
1717291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
1718fcf3ce44SJohn Forte 
1719fcf3ce44SJohn Forte 	/* Check if adapter was shutdown */
1720fcf3ce44SJohn Forte 	if (hba->flag & FC_HARDWARE_ERROR) {
1721291a2b48SSukumar Swaminathan 		/*
1722291a2b48SSukumar Swaminathan 		 * Force mailbox cleanup
1723291a2b48SSukumar Swaminathan 		 * This will wake any sleeping or polling threads
1724291a2b48SSukumar Swaminathan 		 */
1725fcf3ce44SJohn Forte 		emlxs_mb_fini(hba, NULL, MBX_HARDWARE_ERROR);
1726fcf3ce44SJohn Forte 	}
1727291a2b48SSukumar Swaminathan 
1728fcf3ce44SJohn Forte 	/* Pause here for the IO to settle */
1729fcf3ce44SJohn Forte 	delay(drv_usectohz(1000000));	/* 1 sec */
1730fcf3ce44SJohn Forte 
1731fcf3ce44SJohn Forte 	/* Unregister all nodes */
1732fcf3ce44SJohn Forte 	emlxs_ffcleanup(hba);
1733fcf3ce44SJohn Forte 
1734fcf3ce44SJohn Forte 	if (hba->bus_type == SBUS_FC) {
173582527734SSukumar Swaminathan 		WRITE_SBUS_CSR_REG(hba, FC_SHS_REG(hba), 0x9A);
17364baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
173782527734SSukumar Swaminathan 		/* Access handle validation */
173882527734SSukumar Swaminathan 		EMLXS_CHK_ACC_HANDLE(hba, hba->sli.sli3.sbus_csr_handle);
17394baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
1740fcf3ce44SJohn Forte 	}
1741291a2b48SSukumar Swaminathan 
1742fcf3ce44SJohn Forte 	/* Stop the timer */
1743fcf3ce44SJohn Forte 	emlxs_timer_stop(hba);
1744fcf3ce44SJohn Forte 
1745fcf3ce44SJohn Forte 	/* For safety flush every iotag list */
1746fcf3ce44SJohn Forte 	if (emlxs_iotag_flush(hba)) {
1747fcf3ce44SJohn Forte 		/* Pause here for the IO to flush */
1748728bdc9bSSukumar Swaminathan 		delay(drv_usectohz(1000));
1749728bdc9bSSukumar Swaminathan 	}
1750728bdc9bSSukumar Swaminathan 
1751728bdc9bSSukumar Swaminathan 	/* Wait for poll command request to settle */
1752728bdc9bSSukumar Swaminathan 	while (hba->io_poll_count > 0) {
1753728bdc9bSSukumar Swaminathan 		delay(drv_usectohz(2000000));   /* 2 sec */
1754fcf3ce44SJohn Forte 	}
1755728bdc9bSSukumar Swaminathan 
175682527734SSukumar Swaminathan 	/* Shutdown the adapter interface */
175782527734SSukumar Swaminathan 	EMLXS_SLI_OFFLINE(hba);
1758fcf3ce44SJohn Forte 
1759fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1760fcf3ce44SJohn Forte 	hba->flag |= FC_OFFLINE_MODE;
1761fcf3ce44SJohn Forte 	hba->flag &= ~FC_OFFLINING_MODE;
1762fcf3ce44SJohn Forte 	emlxs_diag_state = DDI_OFFDI;
1763fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1764fcf3ce44SJohn Forte 
1765fcf3ce44SJohn Forte 	rval = 0;
1766fcf3ce44SJohn Forte 
1767fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL);
1768fcf3ce44SJohn Forte 
1769fcf3ce44SJohn Forte done:
1770fcf3ce44SJohn Forte 
1771fcf3ce44SJohn Forte 	return (rval);
1772fcf3ce44SJohn Forte 
177382527734SSukumar Swaminathan } /* emlxs_offline() */
1774fcf3ce44SJohn Forte 
1775fcf3ce44SJohn Forte 
1776fcf3ce44SJohn Forte 
1777fcf3ce44SJohn Forte extern int
1778fcf3ce44SJohn Forte emlxs_power_down(emlxs_hba_t *hba)
1779fcf3ce44SJohn Forte {
17804baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
17814baa2c25SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
17824baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
1783fcf3ce44SJohn Forte 	int32_t rval = 0;
1784fcf3ce44SJohn Forte 	uint32_t *ptr;
1785fcf3ce44SJohn Forte 	uint32_t i;
1786fcf3ce44SJohn Forte 
1787fcf3ce44SJohn Forte 	if ((rval = emlxs_offline(hba))) {
1788fcf3ce44SJohn Forte 		return (rval);
1789fcf3ce44SJohn Forte 	}
179082527734SSukumar Swaminathan 	EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
1791291a2b48SSukumar Swaminathan 
1792fcf3ce44SJohn Forte 	/* Save pci config space */
1793fcf3ce44SJohn Forte 	ptr = (uint32_t *)hba->pm_config;
1794fcf3ce44SJohn Forte 	for (i = 0; i < PCI_CONFIG_SIZE; i += 4, ptr++) {
1795291a2b48SSukumar Swaminathan 		*ptr =
1796291a2b48SSukumar Swaminathan 		    ddi_get32(hba->pci_acc_handle,
1797fcf3ce44SJohn Forte 		    (uint32_t *)(hba->pci_addr + i));
1798fcf3ce44SJohn Forte 	}
1799fcf3ce44SJohn Forte 
1800fcf3ce44SJohn Forte 	/* Put chip in D3 state */
1801fcf3ce44SJohn Forte 	(void) ddi_put8(hba->pci_acc_handle,
1802fcf3ce44SJohn Forte 	    (uint8_t *)(hba->pci_addr + PCI_PM_CONTROL_REGISTER),
1803fcf3ce44SJohn Forte 	    (uint8_t)PCI_PM_D3_STATE);
1804fcf3ce44SJohn Forte 
18054baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
18064baa2c25SSukumar Swaminathan 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
18074baa2c25SSukumar Swaminathan 	    != DDI_FM_OK) {
18084baa2c25SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT,
18094baa2c25SSukumar Swaminathan 		    &emlxs_invalid_access_handle_msg, NULL);
18104baa2c25SSukumar Swaminathan 		return (1);
18114baa2c25SSukumar Swaminathan 	}
18124baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
18134baa2c25SSukumar Swaminathan 
1814fcf3ce44SJohn Forte 	return (0);
1815fcf3ce44SJohn Forte 
181682527734SSukumar Swaminathan } /* End emlxs_power_down */
1817fcf3ce44SJohn Forte 
1818fcf3ce44SJohn Forte 
1819fcf3ce44SJohn Forte extern int
1820fcf3ce44SJohn Forte emlxs_power_up(emlxs_hba_t *hba)
1821fcf3ce44SJohn Forte {
18224baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
18234baa2c25SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
18244baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
1825fcf3ce44SJohn Forte 	int32_t rval = 0;
1826fcf3ce44SJohn Forte 	uint32_t *ptr;
1827fcf3ce44SJohn Forte 	uint32_t i;
1828fcf3ce44SJohn Forte 
1829fcf3ce44SJohn Forte 
1830fcf3ce44SJohn Forte 	/* Take chip out of D3 state */
1831fcf3ce44SJohn Forte 	(void) ddi_put8(hba->pci_acc_handle,
1832fcf3ce44SJohn Forte 	    (uint8_t *)(hba->pci_addr + PCI_PM_CONTROL_REGISTER),
1833fcf3ce44SJohn Forte 	    (uint8_t)PCI_PM_D0_STATE);
1834fcf3ce44SJohn Forte 
1835fcf3ce44SJohn Forte 	/* Must have at least 10 ms delay here */
1836fcf3ce44SJohn Forte 	DELAYMS(100);
1837fcf3ce44SJohn Forte 
1838fcf3ce44SJohn Forte 	/* Restore pci config space */
1839fcf3ce44SJohn Forte 	ptr = (uint32_t *)hba->pm_config;
1840fcf3ce44SJohn Forte 	for (i = 0; i < PCI_CONFIG_SIZE; i += 4, ptr++) {
1841fcf3ce44SJohn Forte 		(void) ddi_put32(hba->pci_acc_handle,
1842fcf3ce44SJohn Forte 		    (uint32_t *)(hba->pci_addr + i), *ptr);
1843fcf3ce44SJohn Forte 	}
1844fcf3ce44SJohn Forte 
18454baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
18464baa2c25SSukumar Swaminathan 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
18474baa2c25SSukumar Swaminathan 	    != DDI_FM_OK) {
18484baa2c25SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT,
18494baa2c25SSukumar Swaminathan 		    &emlxs_invalid_access_handle_msg, NULL);
18504baa2c25SSukumar Swaminathan 		return (1);
18514baa2c25SSukumar Swaminathan 	}
18524baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
18534baa2c25SSukumar Swaminathan 
1854fcf3ce44SJohn Forte 	/* Bring adapter online */
1855fcf3ce44SJohn Forte 	if ((rval = emlxs_online(hba))) {
1856fcf3ce44SJohn Forte 		(void) ddi_put8(hba->pci_acc_handle,
1857fcf3ce44SJohn Forte 		    (uint8_t *)(hba->pci_addr + PCI_PM_CONTROL_REGISTER),
1858fcf3ce44SJohn Forte 		    (uint8_t)PCI_PM_D3_STATE);
1859fcf3ce44SJohn Forte 
1860fcf3ce44SJohn Forte 		return (rval);
1861fcf3ce44SJohn Forte 	}
1862291a2b48SSukumar Swaminathan 
1863fcf3ce44SJohn Forte 	return (rval);
1864fcf3ce44SJohn Forte 
186582527734SSukumar Swaminathan } /* End emlxs_power_up */
1866fcf3ce44SJohn Forte 
1867fcf3ce44SJohn Forte 
1868fcf3ce44SJohn Forte /*
1869291a2b48SSukumar Swaminathan  *
1870fcf3ce44SJohn Forte  * NAME:     emlxs_ffcleanup
1871fcf3ce44SJohn Forte  *
1872fcf3ce44SJohn Forte  * FUNCTION: Cleanup all the Firefly resources used by configuring the adapter
1873fcf3ce44SJohn Forte  *
1874fcf3ce44SJohn Forte  * EXECUTION ENVIRONMENT: process only
1875fcf3ce44SJohn Forte  *
1876fcf3ce44SJohn Forte  * CALLED FROM: CFG_TERM
1877fcf3ce44SJohn Forte  *
1878fcf3ce44SJohn Forte  * INPUT: hba       - pointer to the dev_ctl area.
1879fcf3ce44SJohn Forte  *
1880fcf3ce44SJohn Forte  * RETURNS: none
1881fcf3ce44SJohn Forte  */
1882fcf3ce44SJohn Forte extern void
1883fcf3ce44SJohn Forte emlxs_ffcleanup(emlxs_hba_t *hba)
1884fcf3ce44SJohn Forte {
1885fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1886291a2b48SSukumar Swaminathan 	uint32_t i;
1887fcf3ce44SJohn Forte 
1888fcf3ce44SJohn Forte 	/* Disable all but the mailbox interrupt */
188982527734SSukumar Swaminathan 	EMLXS_SLI_DISABLE_INTR(hba, HC_MBINT_ENA);
1890fcf3ce44SJohn Forte 
1891fcf3ce44SJohn Forte 	/* Make sure all port nodes are destroyed */
1892291a2b48SSukumar Swaminathan 	for (i = 0; i < MAX_VPORTS; i++) {
1893291a2b48SSukumar Swaminathan 		port = &VPORT(i);
1894fcf3ce44SJohn Forte 
1895fcf3ce44SJohn Forte 		if (port->node_count) {
189682527734SSukumar Swaminathan 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
189782527734SSukumar Swaminathan 				(void) emlxs_sli4_unreg_all_rpi_by_port(port);
189882527734SSukumar Swaminathan 			} else {
189982527734SSukumar Swaminathan 				(void) emlxs_mb_unreg_rpi(port, 0xffff, 0, 0,
190082527734SSukumar Swaminathan 				    0);
190182527734SSukumar Swaminathan 			}
1902fcf3ce44SJohn Forte 		}
1903fcf3ce44SJohn Forte 	}
1904fcf3ce44SJohn Forte 
1905fcf3ce44SJohn Forte 	/* Clear all interrupt enable conditions */
190682527734SSukumar Swaminathan 	EMLXS_SLI_DISABLE_INTR(hba, 0);
1907fcf3ce44SJohn Forte 
1908fcf3ce44SJohn Forte 	return;
1909fcf3ce44SJohn Forte 
191082527734SSukumar Swaminathan } /* emlxs_ffcleanup() */
1911fcf3ce44SJohn Forte 
1912fcf3ce44SJohn Forte 
1913fcf3ce44SJohn Forte extern uint16_t
191482527734SSukumar Swaminathan emlxs_register_pkt(CHANNEL *cp, emlxs_buf_t *sbp)
1915fcf3ce44SJohn Forte {
1916fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
1917fcf3ce44SJohn Forte 	emlxs_port_t *port;
1918fcf3ce44SJohn Forte 	uint16_t iotag;
1919fcf3ce44SJohn Forte 	uint32_t i;
1920fcf3ce44SJohn Forte 
192182527734SSukumar Swaminathan 	hba = cp->hba;
1922fcf3ce44SJohn Forte 
192382527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
1924fcf3ce44SJohn Forte 
1925fcf3ce44SJohn Forte 	if (sbp->iotag != 0) {
1926fcf3ce44SJohn Forte 		port = &PPORT;
1927fcf3ce44SJohn Forte 
1928fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
192982527734SSukumar Swaminathan 		    "Pkt already registered! channel=%d iotag=%d sbp=%p",
193082527734SSukumar Swaminathan 		    sbp->channel, sbp->iotag, sbp);
1931fcf3ce44SJohn Forte 	}
1932291a2b48SSukumar Swaminathan 
1933fcf3ce44SJohn Forte 	iotag = 0;
193482527734SSukumar Swaminathan 	for (i = 0; i < hba->max_iotag; i++) {
193582527734SSukumar Swaminathan 		if (!hba->fc_iotag || hba->fc_iotag >= hba->max_iotag) {
193682527734SSukumar Swaminathan 			hba->fc_iotag = 1;
1937fcf3ce44SJohn Forte 		}
193882527734SSukumar Swaminathan 		iotag = hba->fc_iotag++;
1939fcf3ce44SJohn Forte 
194082527734SSukumar Swaminathan 		if (hba->fc_table[iotag] == 0 ||
194182527734SSukumar Swaminathan 		    hba->fc_table[iotag] == STALE_PACKET) {
194282527734SSukumar Swaminathan 			hba->io_count++;
194382527734SSukumar Swaminathan 			hba->fc_table[iotag] = sbp;
1944fcf3ce44SJohn Forte 
1945fcf3ce44SJohn Forte 			sbp->iotag = iotag;
194682527734SSukumar Swaminathan 			sbp->channel = cp;
1947fcf3ce44SJohn Forte 
1948fcf3ce44SJohn Forte 			break;
1949fcf3ce44SJohn Forte 		}
1950fcf3ce44SJohn Forte 		iotag = 0;
1951fcf3ce44SJohn Forte 	}
1952fcf3ce44SJohn Forte 
195382527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
1954fcf3ce44SJohn Forte 
1955fcf3ce44SJohn Forte 	/*
1956fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
195782527734SSukumar Swaminathan 	 *    "emlxs_register_pkt: channel=%d iotag=%d sbp=%p",
195882527734SSukumar Swaminathan 	 *    cp->channelno, iotag, sbp);
1959fcf3ce44SJohn Forte 	 */
1960fcf3ce44SJohn Forte 
1961fcf3ce44SJohn Forte 	return (iotag);
1962fcf3ce44SJohn Forte 
196382527734SSukumar Swaminathan } /* emlxs_register_pkt() */
1964fcf3ce44SJohn Forte 
1965fcf3ce44SJohn Forte 
1966fcf3ce44SJohn Forte 
1967fcf3ce44SJohn Forte extern emlxs_buf_t *
196882527734SSukumar Swaminathan emlxs_unregister_pkt(CHANNEL *cp, uint16_t iotag, uint32_t forced)
1969fcf3ce44SJohn Forte {
1970fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
1971fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
197282527734SSukumar Swaminathan 
197382527734SSukumar Swaminathan 	sbp = NULL;
197482527734SSukumar Swaminathan 	hba = cp->hba;
1975fcf3ce44SJohn Forte 
1976fcf3ce44SJohn Forte 	/* Check the iotag range */
197782527734SSukumar Swaminathan 	if ((iotag == 0) || (iotag >= hba->max_iotag)) {
1978fcf3ce44SJohn Forte 		return (NULL);
1979fcf3ce44SJohn Forte 	}
1980291a2b48SSukumar Swaminathan 
1981fcf3ce44SJohn Forte 	/* Remove the sbp from the table */
198282527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
198382527734SSukumar Swaminathan 	sbp = hba->fc_table[iotag];
1984fcf3ce44SJohn Forte 
1985fcf3ce44SJohn Forte 	if (!sbp || (sbp == STALE_PACKET)) {
198682527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
1987fcf3ce44SJohn Forte 		return (sbp);
1988fcf3ce44SJohn Forte 	}
1989291a2b48SSukumar Swaminathan 
199082527734SSukumar Swaminathan 	hba->fc_table[iotag] = ((forced) ? STALE_PACKET : NULL);
199182527734SSukumar Swaminathan 	hba->io_count--;
1992fcf3ce44SJohn Forte 	sbp->iotag = 0;
1993fcf3ce44SJohn Forte 
199482527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
1995fcf3ce44SJohn Forte 
1996fcf3ce44SJohn Forte 
1997fcf3ce44SJohn Forte 	/* Clean up the sbp */
1998fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
1999fcf3ce44SJohn Forte 
2000fcf3ce44SJohn Forte 	if (sbp->pkt_flags & PACKET_IN_TXQ) {
2001fcf3ce44SJohn Forte 		sbp->pkt_flags &= ~PACKET_IN_TXQ;
200282527734SSukumar Swaminathan 		hba->channel_tx_count--;
2003fcf3ce44SJohn Forte 	}
2004291a2b48SSukumar Swaminathan 
2005fcf3ce44SJohn Forte 	if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
2006fcf3ce44SJohn Forte 		sbp->pkt_flags &= ~PACKET_IN_CHIPQ;
2007fcf3ce44SJohn Forte 	}
2008291a2b48SSukumar Swaminathan 
2009fcf3ce44SJohn Forte 	if (sbp->bmp) {
2010fcf3ce44SJohn Forte 		(void) emlxs_mem_put(hba, MEM_BPL, (uint8_t *)sbp->bmp);
2011fcf3ce44SJohn Forte 		sbp->bmp = 0;
2012fcf3ce44SJohn Forte 	}
2013fcf3ce44SJohn Forte 
2014291a2b48SSukumar Swaminathan 	mutex_exit(&sbp->mtx);
2015fcf3ce44SJohn Forte 
2016fcf3ce44SJohn Forte 	return (sbp);
2017fcf3ce44SJohn Forte 
201882527734SSukumar Swaminathan } /* emlxs_unregister_pkt() */
2019fcf3ce44SJohn Forte 
2020fcf3ce44SJohn Forte 
2021fcf3ce44SJohn Forte 
202282527734SSukumar Swaminathan /* Flush all IO's to all nodes for a given IO Channel */
2023fcf3ce44SJohn Forte extern uint32_t
202482527734SSukumar Swaminathan emlxs_tx_channel_flush(emlxs_hba_t *hba, CHANNEL *cp, emlxs_buf_t *fpkt)
2025fcf3ce44SJohn Forte {
2026fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2027fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2028fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2029fcf3ce44SJohn Forte 	IOCBQ *next;
2030fcf3ce44SJohn Forte 	IOCB *iocb;
203182527734SSukumar Swaminathan 	uint32_t channelno;
2032fcf3ce44SJohn Forte 	Q abort;
2033fcf3ce44SJohn Forte 	NODELIST *ndlp;
2034fcf3ce44SJohn Forte 	IOCB *icmd;
2035fcf3ce44SJohn Forte 	MATCHMAP *mp;
2036fcf3ce44SJohn Forte 	uint32_t i;
203782527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2038fcf3ce44SJohn Forte 
203982527734SSukumar Swaminathan 	channelno = cp->channelno;
2040fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
204182527734SSukumar Swaminathan 	bzero((void *)flag, MAX_CHANNEL * sizeof (uint8_t));
2042fcf3ce44SJohn Forte 
204382527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2044fcf3ce44SJohn Forte 
2045fcf3ce44SJohn Forte 	/* While a node needs servicing */
204682527734SSukumar Swaminathan 	while (cp->nodeq.q_first) {
204782527734SSukumar Swaminathan 		ndlp = (NODELIST *) cp->nodeq.q_first;
2048fcf3ce44SJohn Forte 
2049fcf3ce44SJohn Forte 		/* Check if priority queue is not empty */
205082527734SSukumar Swaminathan 		if (ndlp->nlp_ptx[channelno].q_first) {
2051fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2052fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
205382527734SSukumar Swaminathan 				abort.q_first =
205482527734SSukumar Swaminathan 				    ndlp->nlp_ptx[channelno].q_first;
2055fcf3ce44SJohn Forte 			} else {
2056fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
205782527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_ptx[channelno].q_first;
2058fcf3ce44SJohn Forte 			}
205982527734SSukumar Swaminathan 			flag[channelno] = 1;
2060fcf3ce44SJohn Forte 
206182527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_ptx[channelno].q_last;
206282527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_ptx[channelno].q_cnt;
2063fcf3ce44SJohn Forte 		}
2064291a2b48SSukumar Swaminathan 
2065fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
206682527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
2067fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2068fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
206982527734SSukumar Swaminathan 				abort.q_first = ndlp->nlp_tx[channelno].q_first;
2070fcf3ce44SJohn Forte 			} else {
2071fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
207282527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2073fcf3ce44SJohn Forte 			}
2074fcf3ce44SJohn Forte 
207582527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_tx[channelno].q_last;
207682527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_tx[channelno].q_cnt;
2077fcf3ce44SJohn Forte 		}
2078291a2b48SSukumar Swaminathan 
2079fcf3ce44SJohn Forte 		/* Clear the queue pointers */
208082527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_first = NULL;
208182527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_last = NULL;
208282527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_cnt = 0;
2083fcf3ce44SJohn Forte 
208482527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_first = NULL;
208582527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_last = NULL;
208682527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_cnt = 0;
2087fcf3ce44SJohn Forte 
2088fcf3ce44SJohn Forte 		/* Remove node from service queue */
2089fcf3ce44SJohn Forte 
2090fcf3ce44SJohn Forte 		/* If this is the last node on list */
209182527734SSukumar Swaminathan 		if (cp->nodeq.q_last == (void *)ndlp) {
209282527734SSukumar Swaminathan 			cp->nodeq.q_last = NULL;
209382527734SSukumar Swaminathan 			cp->nodeq.q_first = NULL;
209482527734SSukumar Swaminathan 			cp->nodeq.q_cnt = 0;
2095fcf3ce44SJohn Forte 		} else {
2096fcf3ce44SJohn Forte 			/* Remove node from head */
209782527734SSukumar Swaminathan 			cp->nodeq.q_first = ndlp->nlp_next[channelno];
209882527734SSukumar Swaminathan 			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
209982527734SSukumar Swaminathan 			    cp->nodeq.q_first;
210082527734SSukumar Swaminathan 			cp->nodeq.q_cnt--;
2101fcf3ce44SJohn Forte 		}
2102fcf3ce44SJohn Forte 
2103fcf3ce44SJohn Forte 		/* Clear node */
210482527734SSukumar Swaminathan 		ndlp->nlp_next[channelno] = NULL;
2105fcf3ce44SJohn Forte 	}
2106fcf3ce44SJohn Forte 
2107fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2108291a2b48SSukumar Swaminathan 	iocbq = (IOCBQ *) abort.q_first;
2109fcf3ce44SJohn Forte 	while (iocbq) {
2110fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2111fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
211282527734SSukumar Swaminathan 
211382527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
211482527734SSukumar Swaminathan 			sbp = iocbq->sbp;
211582527734SSukumar Swaminathan 			if (sbp) {
211682527734SSukumar Swaminathan 				hba->fc_table[sbp->iotag] = NULL;
211782527734SSukumar Swaminathan 				emlxs_sli4_free_xri(hba, sbp, sbp->xp);
211882527734SSukumar Swaminathan 			}
211982527734SSukumar Swaminathan 		} else {
212082527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
212182527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
212282527734SSukumar Swaminathan 		}
2123fcf3ce44SJohn Forte 
2124fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2125fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2126fcf3ce44SJohn Forte 
2127fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2128fcf3ce44SJohn Forte 			/*
2129fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2130291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2131291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2132fcf3ce44SJohn Forte 			 */
2133fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2134fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2135fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2136fcf3ce44SJohn Forte 				fpkt->flush_count++;
2137fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2138fcf3ce44SJohn Forte 			}
2139291a2b48SSukumar Swaminathan 
2140fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2141fcf3ce44SJohn Forte 		}
2142291a2b48SSukumar Swaminathan 
2143fcf3ce44SJohn Forte 		iocbq = (IOCBQ *)iocbq->next;
2144fcf3ce44SJohn Forte 	}	/* end of while */
2145fcf3ce44SJohn Forte 
214682527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2147fcf3ce44SJohn Forte 
2148fcf3ce44SJohn Forte 	/* Now abort the iocb's */
2149fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2150fcf3ce44SJohn Forte 	while (iocbq) {
2151fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2152fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2153fcf3ce44SJohn Forte 
2154fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2155fcf3ce44SJohn Forte 		iocbq->next = NULL;
2156fcf3ce44SJohn Forte 
2157fcf3ce44SJohn Forte 		/* Get the pkt */
2158fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2159fcf3ce44SJohn Forte 
2160fcf3ce44SJohn Forte 		if (sbp) {
2161fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2162291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2163fcf3ce44SJohn Forte 
2164fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2165fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2166fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2167fcf3ce44SJohn Forte 			} else {
2168fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2169fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2170fcf3ce44SJohn Forte 			}
2171fcf3ce44SJohn Forte 
2172fcf3ce44SJohn Forte 		}
2173fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2174fcf3ce44SJohn Forte 		else {
2175fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
217682527734SSukumar Swaminathan 
217782527734SSukumar Swaminathan 			/* SLI3 */
217882527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
217982527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
218082527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2181fcf3ce44SJohn Forte 				if ((hba->flag &
2182fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2183fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
218482527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2185fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2186291a2b48SSukumar Swaminathan 						uint8_t	*tmp;
218782527734SSukumar Swaminathan 						RING *rp;
2188fcf3ce44SJohn Forte 
218982527734SSukumar Swaminathan 						rp = &hba->sli.sli3.
219082527734SSukumar Swaminathan 						    ring[channelno];
2191fcf3ce44SJohn Forte 						for (i = 0;
219282527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2193fcf3ce44SJohn Forte 						    i++) {
2194fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2195fcf3ce44SJohn Forte 							    hba, rp, icmd);
2196fcf3ce44SJohn Forte 
2197fcf3ce44SJohn Forte 							tmp = (uint8_t *)mp;
2198fcf3ce44SJohn Forte 							if (mp) {
2199291a2b48SSukumar Swaminathan 							(void) emlxs_mem_put(
2200291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2201fcf3ce44SJohn Forte 							}
2202fcf3ce44SJohn Forte 						}
2203fcf3ce44SJohn Forte 					}
2204291a2b48SSukumar Swaminathan 
2205fcf3ce44SJohn Forte 					(void) emlxs_mem_put(hba, MEM_IOCB,
2206fcf3ce44SJohn Forte 					    (uint8_t *)iocbq);
2207fcf3ce44SJohn Forte 				} else {
2208fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
220982527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp,
2210291a2b48SSukumar Swaminathan 					    iocbq);
2211fcf3ce44SJohn Forte 				}
221282527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
221382527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
221482527734SSukumar Swaminathan 
221582527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
2216fcf3ce44SJohn Forte 			}
2217fcf3ce44SJohn Forte 		}
2218fcf3ce44SJohn Forte 
2219fcf3ce44SJohn Forte 		iocbq = next;
2220fcf3ce44SJohn Forte 
2221fcf3ce44SJohn Forte 	}	/* end of while */
2222fcf3ce44SJohn Forte 
222382527734SSukumar Swaminathan 	/* Now trigger channel service */
222482527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
222582527734SSukumar Swaminathan 		if (!flag[channelno]) {
222682527734SSukumar Swaminathan 			continue;
222782527734SSukumar Swaminathan 		}
222882527734SSukumar Swaminathan 
222982527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
223082527734SSukumar Swaminathan 	}
223182527734SSukumar Swaminathan 
2232fcf3ce44SJohn Forte 	return (abort.q_cnt);
2233fcf3ce44SJohn Forte 
223482527734SSukumar Swaminathan } /* emlxs_tx_channel_flush() */
2235fcf3ce44SJohn Forte 
2236fcf3ce44SJohn Forte 
2237fcf3ce44SJohn Forte /* Flush all IO's on all or a given ring for a given node */
2238fcf3ce44SJohn Forte extern uint32_t
223982527734SSukumar Swaminathan emlxs_tx_node_flush(emlxs_port_t *port, NODELIST *ndlp, CHANNEL *chan,
2240fcf3ce44SJohn Forte     uint32_t shutdown, emlxs_buf_t *fpkt)
2241fcf3ce44SJohn Forte {
2242fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2243fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
224482527734SSukumar Swaminathan 	uint32_t channelno;
224582527734SSukumar Swaminathan 	CHANNEL *cp;
2246fcf3ce44SJohn Forte 	IOCB *icmd;
2247fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2248fcf3ce44SJohn Forte 	NODELIST *prev;
2249fcf3ce44SJohn Forte 	IOCBQ *next;
2250fcf3ce44SJohn Forte 	IOCB *iocb;
2251fcf3ce44SJohn Forte 	Q abort;
2252fcf3ce44SJohn Forte 	uint32_t i;
2253fcf3ce44SJohn Forte 	MATCHMAP *mp;
225482527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2255fcf3ce44SJohn Forte 
2256fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
2257fcf3ce44SJohn Forte 
2258fcf3ce44SJohn Forte 	/* Flush all I/O's on tx queue to this target */
225982527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2260fcf3ce44SJohn Forte 
2261fcf3ce44SJohn Forte 	if (!ndlp->nlp_base && shutdown) {
2262fcf3ce44SJohn Forte 		ndlp->nlp_active = 0;
2263fcf3ce44SJohn Forte 	}
2264291a2b48SSukumar Swaminathan 
226582527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
226682527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
2267fcf3ce44SJohn Forte 
226882527734SSukumar Swaminathan 		if (chan && cp != chan) {
2269fcf3ce44SJohn Forte 			continue;
2270fcf3ce44SJohn Forte 		}
2271291a2b48SSukumar Swaminathan 
2272fcf3ce44SJohn Forte 		if (!ndlp->nlp_base || shutdown) {
2273fcf3ce44SJohn Forte 			/* Check if priority queue is not empty */
227482527734SSukumar Swaminathan 			if (ndlp->nlp_ptx[channelno].q_first) {
2275fcf3ce44SJohn Forte 				/* Transfer all iocb's to local queue */
2276fcf3ce44SJohn Forte 				if (abort.q_first == 0) {
2277fcf3ce44SJohn Forte 					abort.q_first =
227882527734SSukumar Swaminathan 					    ndlp->nlp_ptx[channelno].q_first;
2279fcf3ce44SJohn Forte 				} else {
228082527734SSukumar Swaminathan 					((IOCBQ *)(abort.q_last))->next =
228182527734SSukumar Swaminathan 					    (IOCBQ *)ndlp->nlp_ptx[channelno].
2282291a2b48SSukumar Swaminathan 					    q_first;
2283fcf3ce44SJohn Forte 				}
2284fcf3ce44SJohn Forte 
228582527734SSukumar Swaminathan 				flag[channelno] = 1;
228682527734SSukumar Swaminathan 
228782527734SSukumar Swaminathan 				abort.q_last = ndlp->nlp_ptx[channelno].q_last;
228882527734SSukumar Swaminathan 				abort.q_cnt += ndlp->nlp_ptx[channelno].q_cnt;
2289fcf3ce44SJohn Forte 			}
2290fcf3ce44SJohn Forte 		}
2291291a2b48SSukumar Swaminathan 
2292fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
229382527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
229482527734SSukumar Swaminathan 
2295fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2296fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
229782527734SSukumar Swaminathan 				abort.q_first = ndlp->nlp_tx[channelno].q_first;
2298fcf3ce44SJohn Forte 			} else {
2299fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
230082527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2301fcf3ce44SJohn Forte 			}
2302fcf3ce44SJohn Forte 
230382527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_tx[channelno].q_last;
230482527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_tx[channelno].q_cnt;
2305fcf3ce44SJohn Forte 		}
2306291a2b48SSukumar Swaminathan 
2307fcf3ce44SJohn Forte 		/* Clear the queue pointers */
230882527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_first = NULL;
230982527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_last = NULL;
231082527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_cnt = 0;
2311fcf3ce44SJohn Forte 
231282527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_first = NULL;
231382527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_last = NULL;
231482527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_cnt = 0;
2315fcf3ce44SJohn Forte 
231682527734SSukumar Swaminathan 		/* If this node was on the channel queue, remove it */
231782527734SSukumar Swaminathan 		if (ndlp->nlp_next[channelno]) {
2318fcf3ce44SJohn Forte 			/* If this is the only node on list */
231982527734SSukumar Swaminathan 			if (cp->nodeq.q_first == (void *)ndlp &&
232082527734SSukumar Swaminathan 			    cp->nodeq.q_last == (void *)ndlp) {
232182527734SSukumar Swaminathan 				cp->nodeq.q_last = NULL;
232282527734SSukumar Swaminathan 				cp->nodeq.q_first = NULL;
232382527734SSukumar Swaminathan 				cp->nodeq.q_cnt = 0;
232482527734SSukumar Swaminathan 			} else if (cp->nodeq.q_first == (void *)ndlp) {
232582527734SSukumar Swaminathan 				cp->nodeq.q_first = ndlp->nlp_next[channelno];
232682527734SSukumar Swaminathan 				((NODELIST *) cp->nodeq.q_last)->
232782527734SSukumar Swaminathan 				    nlp_next[channelno] = cp->nodeq.q_first;
232882527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
2329291a2b48SSukumar Swaminathan 			} else {
2330fcf3ce44SJohn Forte 				/*
2331291a2b48SSukumar Swaminathan 				 * This is a little more difficult find the
233282527734SSukumar Swaminathan 				 * previous node in the circular channel queue
2333fcf3ce44SJohn Forte 				 */
2334fcf3ce44SJohn Forte 				prev = ndlp;
233582527734SSukumar Swaminathan 				while (prev->nlp_next[channelno] != ndlp) {
233682527734SSukumar Swaminathan 					prev = prev->nlp_next[channelno];
2337fcf3ce44SJohn Forte 				}
2338fcf3ce44SJohn Forte 
233982527734SSukumar Swaminathan 				prev->nlp_next[channelno] =
234082527734SSukumar Swaminathan 				    ndlp->nlp_next[channelno];
2341fcf3ce44SJohn Forte 
234282527734SSukumar Swaminathan 				if (cp->nodeq.q_last == (void *)ndlp) {
234382527734SSukumar Swaminathan 					cp->nodeq.q_last = (void *)prev;
2344fcf3ce44SJohn Forte 				}
234582527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
2346fcf3ce44SJohn Forte 
2347fcf3ce44SJohn Forte 			}
2348fcf3ce44SJohn Forte 
2349fcf3ce44SJohn Forte 			/* Clear node */
235082527734SSukumar Swaminathan 			ndlp->nlp_next[channelno] = NULL;
2351fcf3ce44SJohn Forte 		}
2352291a2b48SSukumar Swaminathan 
2353fcf3ce44SJohn Forte 	}
2354fcf3ce44SJohn Forte 
2355fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2356291a2b48SSukumar Swaminathan 	iocbq = (IOCBQ *) abort.q_first;
2357fcf3ce44SJohn Forte 	while (iocbq) {
2358fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2359fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
236082527734SSukumar Swaminathan 
236182527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
236282527734SSukumar Swaminathan 			sbp = iocbq->sbp;
236382527734SSukumar Swaminathan 			if (sbp) {
236482527734SSukumar Swaminathan 				hba->fc_table[sbp->iotag] = NULL;
236582527734SSukumar Swaminathan 				emlxs_sli4_free_xri(hba, sbp, sbp->xp);
236682527734SSukumar Swaminathan 			}
236782527734SSukumar Swaminathan 		} else {
236882527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
236982527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
237082527734SSukumar Swaminathan 		}
2371fcf3ce44SJohn Forte 
2372fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2373fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2374fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2375fcf3ce44SJohn Forte 			/*
2376fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2377291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2378291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2379fcf3ce44SJohn Forte 			 */
2380fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2381fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2382fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2383fcf3ce44SJohn Forte 				fpkt->flush_count++;
2384fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2385fcf3ce44SJohn Forte 			}
2386291a2b48SSukumar Swaminathan 
2387fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2388fcf3ce44SJohn Forte 		}
2389291a2b48SSukumar Swaminathan 
2390291a2b48SSukumar Swaminathan 		iocbq = (IOCBQ *) iocbq->next;
2391fcf3ce44SJohn Forte 
2392fcf3ce44SJohn Forte 	}	/* end of while */
2393fcf3ce44SJohn Forte 
239482527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2395fcf3ce44SJohn Forte 
2396fcf3ce44SJohn Forte 	/* Now abort the iocb's outside the locks */
2397fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2398fcf3ce44SJohn Forte 	while (iocbq) {
2399fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2400fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2401fcf3ce44SJohn Forte 
2402fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2403fcf3ce44SJohn Forte 		iocbq->next = NULL;
2404fcf3ce44SJohn Forte 
2405fcf3ce44SJohn Forte 		/* Get the pkt */
2406fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2407fcf3ce44SJohn Forte 
2408fcf3ce44SJohn Forte 		if (sbp) {
2409fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2410291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2411fcf3ce44SJohn Forte 
2412fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2413fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2414fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2415fcf3ce44SJohn Forte 			} else {
2416fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2417fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2418fcf3ce44SJohn Forte 			}
2419fcf3ce44SJohn Forte 
2420fcf3ce44SJohn Forte 		}
2421fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2422fcf3ce44SJohn Forte 		else {
242382527734SSukumar Swaminathan 			/* CMD_CLOSE_XRI_CN should also free the memory */
2424fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
242582527734SSukumar Swaminathan 
242682527734SSukumar Swaminathan 			/* SLI3 */
242782527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
242882527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
242982527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2430fcf3ce44SJohn Forte 				if ((hba->flag &
2431fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2432fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
243382527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2434fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2435291a2b48SSukumar Swaminathan 						uint8_t	*tmp;
243682527734SSukumar Swaminathan 						RING *rp;
243782527734SSukumar Swaminathan 						int ch;
2438fcf3ce44SJohn Forte 
243982527734SSukumar Swaminathan 						ch = ((CHANNEL *)
244082527734SSukumar Swaminathan 						    iocbq->channel)->channelno;
244182527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
2442fcf3ce44SJohn Forte 						for (i = 0;
244382527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2444fcf3ce44SJohn Forte 						    i++) {
2445fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2446fcf3ce44SJohn Forte 							    hba, rp, icmd);
2447fcf3ce44SJohn Forte 
2448fcf3ce44SJohn Forte 							tmp = (uint8_t *)mp;
2449fcf3ce44SJohn Forte 							if (mp) {
2450291a2b48SSukumar Swaminathan 							(void) emlxs_mem_put(
2451291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2452fcf3ce44SJohn Forte 							}
2453fcf3ce44SJohn Forte 						}
2454fcf3ce44SJohn Forte 					}
2455291a2b48SSukumar Swaminathan 
2456fcf3ce44SJohn Forte 					(void) emlxs_mem_put(hba, MEM_IOCB,
2457fcf3ce44SJohn Forte 					    (uint8_t *)iocbq);
2458fcf3ce44SJohn Forte 				} else {
2459fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
246082527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
246182527734SSukumar Swaminathan 					    (CHANNEL *)iocbq->channel, iocbq);
2462fcf3ce44SJohn Forte 				}
246382527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
246482527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
246582527734SSukumar Swaminathan 				/*
246682527734SSukumar Swaminathan 				 * Resend the abort iocbq if any
246782527734SSukumar Swaminathan 				 */
246882527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
2469fcf3ce44SJohn Forte 			}
2470fcf3ce44SJohn Forte 		}
2471fcf3ce44SJohn Forte 
2472fcf3ce44SJohn Forte 		iocbq = next;
2473fcf3ce44SJohn Forte 
2474fcf3ce44SJohn Forte 	}	/* end of while */
2475fcf3ce44SJohn Forte 
247682527734SSukumar Swaminathan 	/* Now trigger channel service */
247782527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
247882527734SSukumar Swaminathan 		if (!flag[channelno]) {
247982527734SSukumar Swaminathan 			continue;
248082527734SSukumar Swaminathan 		}
248182527734SSukumar Swaminathan 
248282527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
248382527734SSukumar Swaminathan 	}
248482527734SSukumar Swaminathan 
2485fcf3ce44SJohn Forte 	return (abort.q_cnt);
2486fcf3ce44SJohn Forte 
248782527734SSukumar Swaminathan } /* emlxs_tx_node_flush() */
2488fcf3ce44SJohn Forte 
2489fcf3ce44SJohn Forte 
2490fcf3ce44SJohn Forte /* Check for IO's on all or a given ring for a given node */
2491fcf3ce44SJohn Forte extern uint32_t
249282527734SSukumar Swaminathan emlxs_tx_node_check(emlxs_port_t *port, NODELIST *ndlp, CHANNEL *chan)
2493fcf3ce44SJohn Forte {
2494fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
249582527734SSukumar Swaminathan 	uint32_t channelno;
249682527734SSukumar Swaminathan 	CHANNEL *cp;
2497fcf3ce44SJohn Forte 	uint32_t count;
2498fcf3ce44SJohn Forte 
2499fcf3ce44SJohn Forte 	count = 0;
2500fcf3ce44SJohn Forte 
2501fcf3ce44SJohn Forte 	/* Flush all I/O's on tx queue to this target */
250282527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2503fcf3ce44SJohn Forte 
250482527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
250582527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
2506fcf3ce44SJohn Forte 
250782527734SSukumar Swaminathan 		if (chan && cp != chan) {
2508fcf3ce44SJohn Forte 			continue;
2509fcf3ce44SJohn Forte 		}
2510291a2b48SSukumar Swaminathan 
2511fcf3ce44SJohn Forte 		/* Check if priority queue is not empty */
251282527734SSukumar Swaminathan 		if (ndlp->nlp_ptx[channelno].q_first) {
251382527734SSukumar Swaminathan 			count += ndlp->nlp_ptx[channelno].q_cnt;
2514fcf3ce44SJohn Forte 		}
2515291a2b48SSukumar Swaminathan 
2516fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
251782527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
251882527734SSukumar Swaminathan 			count += ndlp->nlp_tx[channelno].q_cnt;
2519fcf3ce44SJohn Forte 		}
2520291a2b48SSukumar Swaminathan 
2521fcf3ce44SJohn Forte 	}
2522fcf3ce44SJohn Forte 
252382527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2524fcf3ce44SJohn Forte 
2525fcf3ce44SJohn Forte 	return (count);
2526fcf3ce44SJohn Forte 
252782527734SSukumar Swaminathan } /* emlxs_tx_node_check() */
2528fcf3ce44SJohn Forte 
2529fcf3ce44SJohn Forte 
2530fcf3ce44SJohn Forte 
253182527734SSukumar Swaminathan /* Flush all IO's on the any ring for a given node's lun */
2532fcf3ce44SJohn Forte extern uint32_t
2533291a2b48SSukumar Swaminathan emlxs_tx_lun_flush(emlxs_port_t *port, NODELIST *ndlp, uint32_t lun,
2534291a2b48SSukumar Swaminathan     emlxs_buf_t *fpkt)
2535fcf3ce44SJohn Forte {
2536fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2537fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
253882527734SSukumar Swaminathan 	uint32_t channelno;
2539fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2540fcf3ce44SJohn Forte 	IOCBQ *prev;
2541fcf3ce44SJohn Forte 	IOCBQ *next;
2542fcf3ce44SJohn Forte 	IOCB *iocb;
2543fcf3ce44SJohn Forte 	IOCB *icmd;
2544fcf3ce44SJohn Forte 	Q abort;
2545fcf3ce44SJohn Forte 	uint32_t i;
2546fcf3ce44SJohn Forte 	MATCHMAP *mp;
254782527734SSukumar Swaminathan 	CHANNEL *cp;
254882527734SSukumar Swaminathan 	CHANNEL *channel;
254982527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2550fcf3ce44SJohn Forte 
2551fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
2552fcf3ce44SJohn Forte 
2553fcf3ce44SJohn Forte 	/* Flush I/O's on txQ to this target's lun */
255482527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2555fcf3ce44SJohn Forte 
255682527734SSukumar Swaminathan 	channel = &hba->chan[hba->channel_fcp];
2557fcf3ce44SJohn Forte 
255882527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
255982527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
2560fcf3ce44SJohn Forte 
256182527734SSukumar Swaminathan 		if (channel && cp != channel) {
256282527734SSukumar Swaminathan 			continue;
256382527734SSukumar Swaminathan 		}
2564291a2b48SSukumar Swaminathan 
256582527734SSukumar Swaminathan 		/* Scan the priority queue first */
256682527734SSukumar Swaminathan 		prev = NULL;
256782527734SSukumar Swaminathan 		iocbq = (IOCBQ *) ndlp->nlp_ptx[channelno].q_first;
2568fcf3ce44SJohn Forte 
256982527734SSukumar Swaminathan 		while (iocbq) {
257082527734SSukumar Swaminathan 			next = (IOCBQ *)iocbq->next;
257182527734SSukumar Swaminathan 			iocb = &iocbq->iocb;
257282527734SSukumar Swaminathan 			sbp = (emlxs_buf_t *)iocbq->sbp;
257382527734SSukumar Swaminathan 
257482527734SSukumar Swaminathan 			/* Check if this IO is for our lun */
257582527734SSukumar Swaminathan 			if (sbp && (sbp->lun == lun)) {
257682527734SSukumar Swaminathan 				/* Remove iocb from the node's ptx queue */
257782527734SSukumar Swaminathan 				if (next == 0) {
257882527734SSukumar Swaminathan 					ndlp->nlp_ptx[channelno].q_last =
257982527734SSukumar Swaminathan 					    (uint8_t *)prev;
258082527734SSukumar Swaminathan 				}
258182527734SSukumar Swaminathan 
258282527734SSukumar Swaminathan 				if (prev == 0) {
258382527734SSukumar Swaminathan 					ndlp->nlp_ptx[channelno].q_first =
258482527734SSukumar Swaminathan 					    (uint8_t *)next;
258582527734SSukumar Swaminathan 				} else {
258682527734SSukumar Swaminathan 					prev->next = next;
258782527734SSukumar Swaminathan 				}
258882527734SSukumar Swaminathan 
258982527734SSukumar Swaminathan 				iocbq->next = NULL;
259082527734SSukumar Swaminathan 				ndlp->nlp_ptx[channelno].q_cnt--;
259182527734SSukumar Swaminathan 
259282527734SSukumar Swaminathan 				/*
259382527734SSukumar Swaminathan 				 * Add this iocb to our local abort Q
259482527734SSukumar Swaminathan 				 */
259582527734SSukumar Swaminathan 				if (abort.q_first) {
259682527734SSukumar Swaminathan 					((IOCBQ *)abort.q_last)->next = iocbq;
259782527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
259882527734SSukumar Swaminathan 					abort.q_cnt++;
259982527734SSukumar Swaminathan 				} else {
260082527734SSukumar Swaminathan 					abort.q_first = (uint8_t *)iocbq;
260182527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
260282527734SSukumar Swaminathan 					abort.q_cnt = 1;
260382527734SSukumar Swaminathan 				}
260482527734SSukumar Swaminathan 				iocbq->next = NULL;
260582527734SSukumar Swaminathan 				flag[channelno] = 1;
2606fcf3ce44SJohn Forte 
2607fcf3ce44SJohn Forte 			} else {
260882527734SSukumar Swaminathan 				prev = iocbq;
2609fcf3ce44SJohn Forte 			}
2610fcf3ce44SJohn Forte 
261182527734SSukumar Swaminathan 			iocbq = next;
2612fcf3ce44SJohn Forte 
261382527734SSukumar Swaminathan 		}	/* while (iocbq) */
2614fcf3ce44SJohn Forte 
2615fcf3ce44SJohn Forte 
261682527734SSukumar Swaminathan 		/* Scan the regular queue */
261782527734SSukumar Swaminathan 		prev = NULL;
261882527734SSukumar Swaminathan 		iocbq = (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2619fcf3ce44SJohn Forte 
262082527734SSukumar Swaminathan 		while (iocbq) {
262182527734SSukumar Swaminathan 			next = (IOCBQ *)iocbq->next;
262282527734SSukumar Swaminathan 			iocb = &iocbq->iocb;
262382527734SSukumar Swaminathan 			sbp = (emlxs_buf_t *)iocbq->sbp;
262482527734SSukumar Swaminathan 
262582527734SSukumar Swaminathan 			/* Check if this IO is for our lun */
262682527734SSukumar Swaminathan 			if (sbp && (sbp->lun == lun)) {
262782527734SSukumar Swaminathan 				/* Remove iocb from the node's tx queue */
262882527734SSukumar Swaminathan 				if (next == 0) {
262982527734SSukumar Swaminathan 					ndlp->nlp_tx[channelno].q_last =
263082527734SSukumar Swaminathan 					    (uint8_t *)prev;
263182527734SSukumar Swaminathan 				}
2632291a2b48SSukumar Swaminathan 
263382527734SSukumar Swaminathan 				if (prev == 0) {
263482527734SSukumar Swaminathan 					ndlp->nlp_tx[channelno].q_first =
263582527734SSukumar Swaminathan 					    (uint8_t *)next;
263682527734SSukumar Swaminathan 				} else {
263782527734SSukumar Swaminathan 					prev->next = next;
263882527734SSukumar Swaminathan 				}
2639fcf3ce44SJohn Forte 
264082527734SSukumar Swaminathan 				iocbq->next = NULL;
264182527734SSukumar Swaminathan 				ndlp->nlp_tx[channelno].q_cnt--;
2642fcf3ce44SJohn Forte 
264382527734SSukumar Swaminathan 				/*
264482527734SSukumar Swaminathan 				 * Add this iocb to our local abort Q
264582527734SSukumar Swaminathan 				 */
264682527734SSukumar Swaminathan 				if (abort.q_first) {
264782527734SSukumar Swaminathan 					((IOCBQ *) abort.q_last)->next = iocbq;
264882527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
264982527734SSukumar Swaminathan 					abort.q_cnt++;
265082527734SSukumar Swaminathan 				} else {
265182527734SSukumar Swaminathan 					abort.q_first = (uint8_t *)iocbq;
265282527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
265382527734SSukumar Swaminathan 					abort.q_cnt = 1;
265482527734SSukumar Swaminathan 				}
265582527734SSukumar Swaminathan 				iocbq->next = NULL;
2656fcf3ce44SJohn Forte 			} else {
265782527734SSukumar Swaminathan 				prev = iocbq;
2658fcf3ce44SJohn Forte 			}
2659fcf3ce44SJohn Forte 
266082527734SSukumar Swaminathan 			iocbq = next;
2661fcf3ce44SJohn Forte 
266282527734SSukumar Swaminathan 		}	/* while (iocbq) */
266382527734SSukumar Swaminathan 	}	/* for loop */
2664fcf3ce44SJohn Forte 
2665fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2666fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2667fcf3ce44SJohn Forte 	while (iocbq) {
2668fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2669fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
267082527734SSukumar Swaminathan 
267182527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
267282527734SSukumar Swaminathan 			sbp = iocbq->sbp;
267382527734SSukumar Swaminathan 			if (sbp) {
267482527734SSukumar Swaminathan 				hba->fc_table[sbp->iotag] = NULL;
267582527734SSukumar Swaminathan 				emlxs_sli4_free_xri(hba, sbp, sbp->xp);
267682527734SSukumar Swaminathan 			}
267782527734SSukumar Swaminathan 		} else {
267882527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
267982527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
268082527734SSukumar Swaminathan 		}
2681fcf3ce44SJohn Forte 
2682fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2683fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2684fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2685fcf3ce44SJohn Forte 			/*
2686fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2687291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2688291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2689fcf3ce44SJohn Forte 			 */
2690fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2691fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2692fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2693fcf3ce44SJohn Forte 				fpkt->flush_count++;
2694fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2695fcf3ce44SJohn Forte 			}
2696291a2b48SSukumar Swaminathan 
2697fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2698fcf3ce44SJohn Forte 		}
2699291a2b48SSukumar Swaminathan 
2700291a2b48SSukumar Swaminathan 		iocbq = (IOCBQ *) iocbq->next;
2701fcf3ce44SJohn Forte 
2702fcf3ce44SJohn Forte 	}	/* end of while */
2703fcf3ce44SJohn Forte 
270482527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2705fcf3ce44SJohn Forte 
2706fcf3ce44SJohn Forte 	/* Now abort the iocb's outside the locks */
2707fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2708fcf3ce44SJohn Forte 	while (iocbq) {
2709fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2710fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2711fcf3ce44SJohn Forte 
2712fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2713fcf3ce44SJohn Forte 		iocbq->next = NULL;
2714fcf3ce44SJohn Forte 
2715fcf3ce44SJohn Forte 		/* Get the pkt */
2716fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2717fcf3ce44SJohn Forte 
2718fcf3ce44SJohn Forte 		if (sbp) {
2719fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2720291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2721fcf3ce44SJohn Forte 
2722fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2723fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2724fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2725fcf3ce44SJohn Forte 			} else {
2726fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2727fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2728fcf3ce44SJohn Forte 			}
2729fcf3ce44SJohn Forte 		}
2730291a2b48SSukumar Swaminathan 
2731fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2732fcf3ce44SJohn Forte 		else {
273382527734SSukumar Swaminathan 			/* Should never happen! */
2734fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
2735fcf3ce44SJohn Forte 
273682527734SSukumar Swaminathan 			/* SLI3 */
273782527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
273882527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
273982527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2740fcf3ce44SJohn Forte 				if ((hba->flag &
2741fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2742fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
274382527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2744fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2745291a2b48SSukumar Swaminathan 						uint8_t	*tmp;
274682527734SSukumar Swaminathan 						RING *rp;
274782527734SSukumar Swaminathan 						int ch;
2748fcf3ce44SJohn Forte 
274982527734SSukumar Swaminathan 						ch = ((CHANNEL *)
275082527734SSukumar Swaminathan 						    iocbq->channel)->channelno;
275182527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
2752fcf3ce44SJohn Forte 						for (i = 0;
275382527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2754fcf3ce44SJohn Forte 						    i++) {
2755fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2756fcf3ce44SJohn Forte 							    hba, rp, icmd);
2757fcf3ce44SJohn Forte 
2758fcf3ce44SJohn Forte 							tmp = (uint8_t *)mp;
2759fcf3ce44SJohn Forte 							if (mp) {
2760291a2b48SSukumar Swaminathan 							(void) emlxs_mem_put(
2761291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2762fcf3ce44SJohn Forte 							}
2763fcf3ce44SJohn Forte 						}
2764fcf3ce44SJohn Forte 					}
2765291a2b48SSukumar Swaminathan 
2766fcf3ce44SJohn Forte 					(void) emlxs_mem_put(hba, MEM_IOCB,
2767fcf3ce44SJohn Forte 					    (uint8_t *)iocbq);
2768fcf3ce44SJohn Forte 				} else {
2769fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
277082527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
277182527734SSukumar Swaminathan 					    (CHANNEL *)iocbq->channel, iocbq);
2772fcf3ce44SJohn Forte 				}
277382527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
277482527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
277582527734SSukumar Swaminathan 				/*
277682527734SSukumar Swaminathan 				 * Resend the abort iocbq if any
277782527734SSukumar Swaminathan 				 */
277882527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
2779fcf3ce44SJohn Forte 			}
2780fcf3ce44SJohn Forte 		}
2781fcf3ce44SJohn Forte 
2782fcf3ce44SJohn Forte 		iocbq = next;
2783fcf3ce44SJohn Forte 
2784fcf3ce44SJohn Forte 	}	/* end of while */
2785fcf3ce44SJohn Forte 
278682527734SSukumar Swaminathan 	/* Now trigger channel service */
278782527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
278882527734SSukumar Swaminathan 		if (!flag[channelno]) {
278982527734SSukumar Swaminathan 			continue;
279082527734SSukumar Swaminathan 		}
279182527734SSukumar Swaminathan 
279282527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
279382527734SSukumar Swaminathan 	}
2794fcf3ce44SJohn Forte 
2795fcf3ce44SJohn Forte 	return (abort.q_cnt);
2796fcf3ce44SJohn Forte 
279782527734SSukumar Swaminathan } /* emlxs_tx_lun_flush() */
2798fcf3ce44SJohn Forte 
2799fcf3ce44SJohn Forte 
2800fcf3ce44SJohn Forte extern void
2801fcf3ce44SJohn Forte emlxs_tx_put(IOCBQ *iocbq, uint32_t lock)
2802fcf3ce44SJohn Forte {
2803fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
2804fcf3ce44SJohn Forte 	emlxs_port_t *port;
280582527734SSukumar Swaminathan 	uint32_t channelno;
2806fcf3ce44SJohn Forte 	NODELIST *nlp;
280782527734SSukumar Swaminathan 	CHANNEL *cp;
2808fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2809fcf3ce44SJohn Forte 
2810fcf3ce44SJohn Forte 	port = (emlxs_port_t *)iocbq->port;
2811fcf3ce44SJohn Forte 	hba = HBA;
281282527734SSukumar Swaminathan 	cp = (CHANNEL *)iocbq->channel;
2813fcf3ce44SJohn Forte 	nlp = (NODELIST *)iocbq->node;
281482527734SSukumar Swaminathan 	channelno = cp->channelno;
2815fcf3ce44SJohn Forte 	sbp = (emlxs_buf_t *)iocbq->sbp;
2816fcf3ce44SJohn Forte 
281782527734SSukumar Swaminathan 	/* under what cases, nlp is NULL */
2818fcf3ce44SJohn Forte 	if (nlp == NULL) {
2819fcf3ce44SJohn Forte 		/* Set node to base node by default */
2820fcf3ce44SJohn Forte 		nlp = &port->node_base;
2821fcf3ce44SJohn Forte 
2822fcf3ce44SJohn Forte 		iocbq->node = (void *)nlp;
2823fcf3ce44SJohn Forte 
2824fcf3ce44SJohn Forte 		if (sbp) {
2825fcf3ce44SJohn Forte 			sbp->node = (void *)nlp;
2826fcf3ce44SJohn Forte 		}
2827fcf3ce44SJohn Forte 	}
2828291a2b48SSukumar Swaminathan 
2829fcf3ce44SJohn Forte 	if (lock) {
283082527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2831fcf3ce44SJohn Forte 	}
2832291a2b48SSukumar Swaminathan 
2833fcf3ce44SJohn Forte 	if (!nlp->nlp_active || (sbp && (sbp->pkt_flags & PACKET_IN_ABORT))) {
2834fcf3ce44SJohn Forte 		if (sbp) {
2835fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2836fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2837fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2838fcf3ce44SJohn Forte 
283982527734SSukumar Swaminathan 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
284082527734SSukumar Swaminathan 				hba->fc_table[sbp->iotag] = NULL;
284182527734SSukumar Swaminathan 				emlxs_sli4_free_xri(hba, sbp, sbp->xp);
284282527734SSukumar Swaminathan 			} else {
284382527734SSukumar Swaminathan 				(void) emlxs_unregister_pkt(cp, sbp->iotag, 0);
284482527734SSukumar Swaminathan 			}
2845fcf3ce44SJohn Forte 
2846fcf3ce44SJohn Forte 			if (lock) {
284782527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2848fcf3ce44SJohn Forte 			}
2849291a2b48SSukumar Swaminathan 
2850fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2851fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2852fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2853fcf3ce44SJohn Forte 			} else {
2854fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2855fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2856fcf3ce44SJohn Forte 			}
2857fcf3ce44SJohn Forte 			return;
2858fcf3ce44SJohn Forte 		} else {
2859fcf3ce44SJohn Forte 			if (lock) {
286082527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2861fcf3ce44SJohn Forte 			}
2862291a2b48SSukumar Swaminathan 
2863fcf3ce44SJohn Forte 			(void) emlxs_mem_put(hba, MEM_IOCB, (uint8_t *)iocbq);
2864fcf3ce44SJohn Forte 		}
2865fcf3ce44SJohn Forte 
2866fcf3ce44SJohn Forte 		return;
2867fcf3ce44SJohn Forte 	}
2868291a2b48SSukumar Swaminathan 
2869fcf3ce44SJohn Forte 	if (sbp) {
2870fcf3ce44SJohn Forte 
2871fcf3ce44SJohn Forte 		mutex_enter(&sbp->mtx);
2872fcf3ce44SJohn Forte 
2873291a2b48SSukumar Swaminathan 		if (sbp->pkt_flags &
2874291a2b48SSukumar Swaminathan 		    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ | PACKET_IN_TXQ)) {
2875fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2876fcf3ce44SJohn Forte 			if (lock) {
287782527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2878fcf3ce44SJohn Forte 			}
2879fcf3ce44SJohn Forte 			return;
2880fcf3ce44SJohn Forte 		}
2881291a2b48SSukumar Swaminathan 
2882fcf3ce44SJohn Forte 		sbp->pkt_flags |= PACKET_IN_TXQ;
288382527734SSukumar Swaminathan 		hba->channel_tx_count++;
2884fcf3ce44SJohn Forte 
2885fcf3ce44SJohn Forte 		mutex_exit(&sbp->mtx);
2886fcf3ce44SJohn Forte 	}
2887291a2b48SSukumar Swaminathan 
2888291a2b48SSukumar Swaminathan 
2889fcf3ce44SJohn Forte 	/* Check iocbq priority */
289082527734SSukumar Swaminathan 	/* Some IOCB has the high priority like reset/close xri etc */
2891fcf3ce44SJohn Forte 	if (iocbq->flag & IOCB_PRIORITY) {
2892fcf3ce44SJohn Forte 		/* Add the iocb to the bottom of the node's ptx queue */
289382527734SSukumar Swaminathan 		if (nlp->nlp_ptx[channelno].q_first) {
289482527734SSukumar Swaminathan 			((IOCBQ *)nlp->nlp_ptx[channelno].q_last)->next = iocbq;
289582527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_last = (uint8_t *)iocbq;
289682527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_cnt++;
2897fcf3ce44SJohn Forte 		} else {
289882527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_first = (uint8_t *)iocbq;
289982527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_last = (uint8_t *)iocbq;
290082527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_cnt = 1;
2901fcf3ce44SJohn Forte 		}
2902fcf3ce44SJohn Forte 
2903fcf3ce44SJohn Forte 		iocbq->next = NULL;
2904fcf3ce44SJohn Forte 	} else {	/* Normal priority */
2905fcf3ce44SJohn Forte 
2906291a2b48SSukumar Swaminathan 
2907fcf3ce44SJohn Forte 		/* Add the iocb to the bottom of the node's tx queue */
290882527734SSukumar Swaminathan 		if (nlp->nlp_tx[channelno].q_first) {
290982527734SSukumar Swaminathan 			((IOCBQ *)nlp->nlp_tx[channelno].q_last)->next = iocbq;
291082527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_last = (uint8_t *)iocbq;
291182527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_cnt++;
2912fcf3ce44SJohn Forte 		} else {
291382527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_first = (uint8_t *)iocbq;
291482527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_last = (uint8_t *)iocbq;
291582527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_cnt = 1;
2916fcf3ce44SJohn Forte 		}
2917fcf3ce44SJohn Forte 
2918fcf3ce44SJohn Forte 		iocbq->next = NULL;
2919fcf3ce44SJohn Forte 	}
2920fcf3ce44SJohn Forte 
2921fcf3ce44SJohn Forte 
2922fcf3ce44SJohn Forte 	/*
292382527734SSukumar Swaminathan 	 * Check if the node is not already on channel queue and
2924291a2b48SSukumar Swaminathan 	 * (is not closed or  is a priority request)
2925fcf3ce44SJohn Forte 	 */
292682527734SSukumar Swaminathan 	if (!nlp->nlp_next[channelno] &&
292782527734SSukumar Swaminathan 	    (!(nlp->nlp_flag[channelno] & NLP_CLOSED) ||
2928fcf3ce44SJohn Forte 	    (iocbq->flag & IOCB_PRIORITY))) {
292982527734SSukumar Swaminathan 		/* If so, then add it to the channel queue */
293082527734SSukumar Swaminathan 		if (cp->nodeq.q_first) {
293182527734SSukumar Swaminathan 			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
2932fcf3ce44SJohn Forte 			    (uint8_t *)nlp;
293382527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = cp->nodeq.q_first;
2934fcf3ce44SJohn Forte 
2935fcf3ce44SJohn Forte 			/*
2936291a2b48SSukumar Swaminathan 			 * If this is not the base node then add it
2937291a2b48SSukumar Swaminathan 			 * to the tail
2938fcf3ce44SJohn Forte 			 */
2939fcf3ce44SJohn Forte 			if (!nlp->nlp_base) {
294082527734SSukumar Swaminathan 				cp->nodeq.q_last = (uint8_t *)nlp;
2941fcf3ce44SJohn Forte 			} else {	/* Otherwise, add it to the head */
2942291a2b48SSukumar Swaminathan 
2943fcf3ce44SJohn Forte 				/* The command node always gets priority */
294482527734SSukumar Swaminathan 				cp->nodeq.q_first = (uint8_t *)nlp;
2945fcf3ce44SJohn Forte 			}
2946fcf3ce44SJohn Forte 
294782527734SSukumar Swaminathan 			cp->nodeq.q_cnt++;
2948fcf3ce44SJohn Forte 		} else {
294982527734SSukumar Swaminathan 			cp->nodeq.q_first = (uint8_t *)nlp;
295082527734SSukumar Swaminathan 			cp->nodeq.q_last = (uint8_t *)nlp;
295182527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = nlp;
295282527734SSukumar Swaminathan 			cp->nodeq.q_cnt = 1;
2953fcf3ce44SJohn Forte 		}
2954fcf3ce44SJohn Forte 	}
2955291a2b48SSukumar Swaminathan 
295682527734SSukumar Swaminathan 	HBASTATS.IocbTxPut[channelno]++;
2957fcf3ce44SJohn Forte 
295882527734SSukumar Swaminathan 	/* Adjust the channel timeout timer */
295982527734SSukumar Swaminathan 	cp->timeout = hba->timer_tics + 5;
2960fcf3ce44SJohn Forte 
2961fcf3ce44SJohn Forte 	if (lock) {
296282527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2963fcf3ce44SJohn Forte 	}
2964291a2b48SSukumar Swaminathan 
2965fcf3ce44SJohn Forte 	return;
2966fcf3ce44SJohn Forte 
296782527734SSukumar Swaminathan } /* emlxs_tx_put() */
2968fcf3ce44SJohn Forte 
2969fcf3ce44SJohn Forte 
2970fcf3ce44SJohn Forte extern IOCBQ *
297182527734SSukumar Swaminathan emlxs_tx_get(CHANNEL *cp, uint32_t lock)
2972fcf3ce44SJohn Forte {
2973fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
297482527734SSukumar Swaminathan 	uint32_t channelno;
2975fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2976fcf3ce44SJohn Forte 	NODELIST *nlp;
2977fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2978fcf3ce44SJohn Forte 
297982527734SSukumar Swaminathan 	hba = cp->hba;
298082527734SSukumar Swaminathan 	channelno = cp->channelno;
2981fcf3ce44SJohn Forte 
2982fcf3ce44SJohn Forte 	if (lock) {
298382527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2984fcf3ce44SJohn Forte 	}
2985291a2b48SSukumar Swaminathan 
2986fcf3ce44SJohn Forte begin:
2987fcf3ce44SJohn Forte 
2988fcf3ce44SJohn Forte 	iocbq = NULL;
2989fcf3ce44SJohn Forte 
2990fcf3ce44SJohn Forte 	/* Check if a node needs servicing */
299182527734SSukumar Swaminathan 	if (cp->nodeq.q_first) {
299282527734SSukumar Swaminathan 		nlp = (NODELIST *)cp->nodeq.q_first;
2993fcf3ce44SJohn Forte 
2994fcf3ce44SJohn Forte 		/* Get next iocb from node's priority queue */
2995fcf3ce44SJohn Forte 
299682527734SSukumar Swaminathan 		if (nlp->nlp_ptx[channelno].q_first) {
299782527734SSukumar Swaminathan 			iocbq = (IOCBQ *)nlp->nlp_ptx[channelno].q_first;
2998fcf3ce44SJohn Forte 
2999fcf3ce44SJohn Forte 			/* Check if this is last entry */
300082527734SSukumar Swaminathan 			if (nlp->nlp_ptx[channelno].q_last == (void *)iocbq) {
300182527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_first = NULL;
300282527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_last = NULL;
300382527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_cnt = 0;
3004fcf3ce44SJohn Forte 			} else {
3005fcf3ce44SJohn Forte 				/* Remove iocb from head */
300682527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_first =
3007fcf3ce44SJohn Forte 				    (void *)iocbq->next;
300882527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_cnt--;
3009fcf3ce44SJohn Forte 			}
3010fcf3ce44SJohn Forte 
3011fcf3ce44SJohn Forte 			iocbq->next = NULL;
3012fcf3ce44SJohn Forte 		}
3013291a2b48SSukumar Swaminathan 
3014fcf3ce44SJohn Forte 		/* Get next iocb from node tx queue if node not closed */
301582527734SSukumar Swaminathan 		else if (nlp->nlp_tx[channelno].q_first &&
301682527734SSukumar Swaminathan 		    !(nlp->nlp_flag[channelno] & NLP_CLOSED)) {
301782527734SSukumar Swaminathan 			iocbq = (IOCBQ *)nlp->nlp_tx[channelno].q_first;
3018fcf3ce44SJohn Forte 
3019fcf3ce44SJohn Forte 			/* Check if this is last entry */
302082527734SSukumar Swaminathan 			if (nlp->nlp_tx[channelno].q_last == (void *)iocbq) {
302182527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_first = NULL;
302282527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_last = NULL;
302382527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_cnt = 0;
3024fcf3ce44SJohn Forte 			} else {
3025fcf3ce44SJohn Forte 				/* Remove iocb from head */
302682527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_first =
3027fcf3ce44SJohn Forte 				    (void *)iocbq->next;
302882527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_cnt--;
3029fcf3ce44SJohn Forte 			}
3030fcf3ce44SJohn Forte 
3031fcf3ce44SJohn Forte 			iocbq->next = NULL;
3032fcf3ce44SJohn Forte 		}
3033291a2b48SSukumar Swaminathan 
3034fcf3ce44SJohn Forte 		/* Now deal with node itself */
3035fcf3ce44SJohn Forte 
3036fcf3ce44SJohn Forte 		/* Check if node still needs servicing */
303782527734SSukumar Swaminathan 		if ((nlp->nlp_ptx[channelno].q_first) ||
303882527734SSukumar Swaminathan 		    (nlp->nlp_tx[channelno].q_first &&
303982527734SSukumar Swaminathan 		    !(nlp->nlp_flag[channelno] & NLP_CLOSED))) {
3040fcf3ce44SJohn Forte 
3041fcf3ce44SJohn Forte 			/*
3042fcf3ce44SJohn Forte 			 * If this is the base node, then don't shift the
3043291a2b48SSukumar Swaminathan 			 * pointers. We want to drain the base node before
3044291a2b48SSukumar Swaminathan 			 * moving on
3045fcf3ce44SJohn Forte 			 */
3046fcf3ce44SJohn Forte 			if (!nlp->nlp_base) {
3047fcf3ce44SJohn Forte 				/*
304882527734SSukumar Swaminathan 				 * Just shift channel queue pointers to next
3049fcf3ce44SJohn Forte 				 * node
3050fcf3ce44SJohn Forte 				 */
305182527734SSukumar Swaminathan 				cp->nodeq.q_last = (void *)nlp;
305282527734SSukumar Swaminathan 				cp->nodeq.q_first = nlp->nlp_next[channelno];
3053fcf3ce44SJohn Forte 			}
3054fcf3ce44SJohn Forte 		} else {
305582527734SSukumar Swaminathan 			/* Remove node from channel queue */
3056fcf3ce44SJohn Forte 
3057fcf3ce44SJohn Forte 			/* If this is the last node on list */
305882527734SSukumar Swaminathan 			if (cp->nodeq.q_last == (void *)nlp) {
305982527734SSukumar Swaminathan 				cp->nodeq.q_last = NULL;
306082527734SSukumar Swaminathan 				cp->nodeq.q_first = NULL;
306182527734SSukumar Swaminathan 				cp->nodeq.q_cnt = 0;
3062fcf3ce44SJohn Forte 			} else {
3063fcf3ce44SJohn Forte 				/* Remove node from head */
306482527734SSukumar Swaminathan 				cp->nodeq.q_first = nlp->nlp_next[channelno];
306582527734SSukumar Swaminathan 				((NODELIST *)cp->nodeq.q_last)->
306682527734SSukumar Swaminathan 				    nlp_next[channelno] = cp->nodeq.q_first;
306782527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
3068fcf3ce44SJohn Forte 
3069fcf3ce44SJohn Forte 			}
3070fcf3ce44SJohn Forte 
3071fcf3ce44SJohn Forte 			/* Clear node */
307282527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = NULL;
3073fcf3ce44SJohn Forte 		}
3074fcf3ce44SJohn Forte 
3075fcf3ce44SJohn Forte 		/*
3076291a2b48SSukumar Swaminathan 		 * If no iocbq was found on this node, then it will have
3077291a2b48SSukumar Swaminathan 		 * been removed. So try again.
3078fcf3ce44SJohn Forte 		 */
3079fcf3ce44SJohn Forte 		if (!iocbq) {
3080fcf3ce44SJohn Forte 			goto begin;
3081fcf3ce44SJohn Forte 		}
3082291a2b48SSukumar Swaminathan 
3083fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
3084fcf3ce44SJohn Forte 
3085fcf3ce44SJohn Forte 		if (sbp) {
3086fcf3ce44SJohn Forte 			/*
3087291a2b48SSukumar Swaminathan 			 * Check flags before we enter mutex in case this
3088291a2b48SSukumar Swaminathan 			 * has been flushed and destroyed
3089fcf3ce44SJohn Forte 			 */
3090fcf3ce44SJohn Forte 			if ((sbp->pkt_flags &
3091fcf3ce44SJohn Forte 			    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) ||
3092fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_IN_TXQ)) {
3093fcf3ce44SJohn Forte 				goto begin;
3094fcf3ce44SJohn Forte 			}
3095291a2b48SSukumar Swaminathan 
3096fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
3097fcf3ce44SJohn Forte 
3098fcf3ce44SJohn Forte 			if ((sbp->pkt_flags &
3099fcf3ce44SJohn Forte 			    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) ||
3100fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_IN_TXQ)) {
3101fcf3ce44SJohn Forte 				mutex_exit(&sbp->mtx);
3102fcf3ce44SJohn Forte 				goto begin;
3103fcf3ce44SJohn Forte 			}
3104291a2b48SSukumar Swaminathan 
3105fcf3ce44SJohn Forte 			sbp->pkt_flags &= ~PACKET_IN_TXQ;
310682527734SSukumar Swaminathan 			hba->channel_tx_count--;
3107fcf3ce44SJohn Forte 
3108fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3109fcf3ce44SJohn Forte 		}
3110fcf3ce44SJohn Forte 	}
3111291a2b48SSukumar Swaminathan 
3112fcf3ce44SJohn Forte 	if (iocbq) {
311382527734SSukumar Swaminathan 		HBASTATS.IocbTxGet[channelno]++;
3114fcf3ce44SJohn Forte 	}
3115291a2b48SSukumar Swaminathan 
3116fcf3ce44SJohn Forte 	/* Adjust the ring timeout timer */
311782527734SSukumar Swaminathan 	cp->timeout = (cp->nodeq.q_first) ? (hba->timer_tics + 5) : 0;
3118fcf3ce44SJohn Forte 
3119fcf3ce44SJohn Forte 	if (lock) {
312082527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3121fcf3ce44SJohn Forte 	}
3122291a2b48SSukumar Swaminathan 
3123fcf3ce44SJohn Forte 	return (iocbq);
3124fcf3ce44SJohn Forte 
312582527734SSukumar Swaminathan } /* emlxs_tx_get() */
312682527734SSukumar Swaminathan 
3127fcf3ce44SJohn Forte 
312882527734SSukumar Swaminathan /*
312982527734SSukumar Swaminathan  * Remove all cmd from from_rp's txq to to_rp's txq for ndlp.
313082527734SSukumar Swaminathan  * The old IoTag has to be released, the new one has to be
313182527734SSukumar Swaminathan  * allocated.  Others no change
313282527734SSukumar Swaminathan  * TX_CHANNEL lock is held
313382527734SSukumar Swaminathan  */
313482527734SSukumar Swaminathan extern void
313582527734SSukumar Swaminathan emlxs_tx_move(NODELIST *ndlp, CHANNEL *from_chan, CHANNEL *to_chan,
313682527734SSukumar Swaminathan     uint32_t cmd, emlxs_buf_t *fpkt, uint32_t lock)
313782527734SSukumar Swaminathan {
313882527734SSukumar Swaminathan 	emlxs_hba_t *hba;
313982527734SSukumar Swaminathan 	emlxs_port_t *port;
314082527734SSukumar Swaminathan 	uint32_t fchanno, tchanno, i;
314182527734SSukumar Swaminathan 
314282527734SSukumar Swaminathan 	IOCBQ *iocbq;
314382527734SSukumar Swaminathan 	IOCBQ *prev;
314482527734SSukumar Swaminathan 	IOCBQ *next;
314582527734SSukumar Swaminathan 	IOCB *iocb, *icmd;
314682527734SSukumar Swaminathan 	Q tbm;		/* To Be Moved Q */
314782527734SSukumar Swaminathan 	MATCHMAP *mp;
314882527734SSukumar Swaminathan 
314982527734SSukumar Swaminathan 	NODELIST *nlp = ndlp;
315082527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
315182527734SSukumar Swaminathan 
315282527734SSukumar Swaminathan 	NODELIST *n_prev = NULL;
315382527734SSukumar Swaminathan 	NODELIST *n_next = NULL;
315482527734SSukumar Swaminathan 	uint16_t count = 0;
315582527734SSukumar Swaminathan 
315682527734SSukumar Swaminathan 	hba = from_chan->hba;
315782527734SSukumar Swaminathan 	port = &PPORT;
315882527734SSukumar Swaminathan 	cmd = cmd; /* To pass lint */
315982527734SSukumar Swaminathan 
316082527734SSukumar Swaminathan 	fchanno = from_chan->channelno;
316182527734SSukumar Swaminathan 	tchanno = to_chan->channelno;
316282527734SSukumar Swaminathan 
316382527734SSukumar Swaminathan 	if (lock) {
316482527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
316582527734SSukumar Swaminathan 	}
316682527734SSukumar Swaminathan 
316782527734SSukumar Swaminathan 	bzero((void *)&tbm, sizeof (Q));
316882527734SSukumar Swaminathan 
316982527734SSukumar Swaminathan 	/* Scan the ndlp's fchanno txq to get the iocb of fcp cmd */
317082527734SSukumar Swaminathan 	prev = NULL;
317182527734SSukumar Swaminathan 	iocbq = (IOCBQ *)nlp->nlp_tx[fchanno].q_first;
317282527734SSukumar Swaminathan 
317382527734SSukumar Swaminathan 	while (iocbq) {
317482527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
317582527734SSukumar Swaminathan 		/* Check if this iocb is fcp cmd */
317682527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
317782527734SSukumar Swaminathan 
317882527734SSukumar Swaminathan 		switch (iocb->ULPCOMMAND) {
317982527734SSukumar Swaminathan 		/* FCP commands */
318082527734SSukumar Swaminathan 		case CMD_FCP_ICMND_CR:
318182527734SSukumar Swaminathan 		case CMD_FCP_ICMND_CX:
318282527734SSukumar Swaminathan 		case CMD_FCP_IREAD_CR:
318382527734SSukumar Swaminathan 		case CMD_FCP_IREAD_CX:
318482527734SSukumar Swaminathan 		case CMD_FCP_IWRITE_CR:
318582527734SSukumar Swaminathan 		case CMD_FCP_IWRITE_CX:
318682527734SSukumar Swaminathan 		case CMD_FCP_ICMND64_CR:
318782527734SSukumar Swaminathan 		case CMD_FCP_ICMND64_CX:
318882527734SSukumar Swaminathan 		case CMD_FCP_IREAD64_CR:
318982527734SSukumar Swaminathan 		case CMD_FCP_IREAD64_CX:
319082527734SSukumar Swaminathan 		case CMD_FCP_IWRITE64_CR:
319182527734SSukumar Swaminathan 		case CMD_FCP_IWRITE64_CX:
319282527734SSukumar Swaminathan 			/* We found a fcp cmd */
319382527734SSukumar Swaminathan 			break;
319482527734SSukumar Swaminathan 		default:
319582527734SSukumar Swaminathan 			/* this is not fcp cmd continue */
319682527734SSukumar Swaminathan 			prev = iocbq;
319782527734SSukumar Swaminathan 			iocbq = next;
319882527734SSukumar Swaminathan 			continue;
319982527734SSukumar Swaminathan 		}
320082527734SSukumar Swaminathan 
320182527734SSukumar Swaminathan 		/* found a fcp cmd iocb in fchanno txq, now deque it */
320282527734SSukumar Swaminathan 		if (next == NULL) {
320382527734SSukumar Swaminathan 			/* This is the last iocbq */
320482527734SSukumar Swaminathan 			nlp->nlp_tx[fchanno].q_last =
320582527734SSukumar Swaminathan 			    (uint8_t *)prev;
320682527734SSukumar Swaminathan 		}
320782527734SSukumar Swaminathan 
320882527734SSukumar Swaminathan 		if (prev == NULL) {
320982527734SSukumar Swaminathan 			/* This is the first one then remove it from head */
321082527734SSukumar Swaminathan 			nlp->nlp_tx[fchanno].q_first =
321182527734SSukumar Swaminathan 			    (uint8_t *)next;
321282527734SSukumar Swaminathan 		} else {
321382527734SSukumar Swaminathan 			prev->next = next;
321482527734SSukumar Swaminathan 		}
321582527734SSukumar Swaminathan 
321682527734SSukumar Swaminathan 		iocbq->next = NULL;
321782527734SSukumar Swaminathan 		nlp->nlp_tx[fchanno].q_cnt--;
321882527734SSukumar Swaminathan 
321982527734SSukumar Swaminathan 		/* Add this iocb to our local toberemovedq */
322082527734SSukumar Swaminathan 		/* This way we donot hold the TX_CHANNEL lock too long */
322182527734SSukumar Swaminathan 
322282527734SSukumar Swaminathan 		if (tbm.q_first) {
322382527734SSukumar Swaminathan 			((IOCBQ *)tbm.q_last)->next = iocbq;
322482527734SSukumar Swaminathan 			tbm.q_last = (uint8_t *)iocbq;
322582527734SSukumar Swaminathan 			tbm.q_cnt++;
322682527734SSukumar Swaminathan 		} else {
322782527734SSukumar Swaminathan 			tbm.q_first = (uint8_t *)iocbq;
322882527734SSukumar Swaminathan 			tbm.q_last = (uint8_t *)iocbq;
322982527734SSukumar Swaminathan 			tbm.q_cnt = 1;
323082527734SSukumar Swaminathan 		}
323182527734SSukumar Swaminathan 
323282527734SSukumar Swaminathan 		iocbq = next;
323382527734SSukumar Swaminathan 
323482527734SSukumar Swaminathan 	}	/* While (iocbq) */
323582527734SSukumar Swaminathan 
323682527734SSukumar Swaminathan 	if ((tchanno == hba->channel_fcp) && (tbm.q_cnt != 0)) {
323782527734SSukumar Swaminathan 
323882527734SSukumar Swaminathan 		/* from_chan->nodeq.q_first must be non NULL */
323982527734SSukumar Swaminathan 		if (from_chan->nodeq.q_first) {
324082527734SSukumar Swaminathan 
324182527734SSukumar Swaminathan 			/* nodeq is not empty, now deal with the node itself */
324282527734SSukumar Swaminathan 			if ((nlp->nlp_tx[fchanno].q_first)) {
324382527734SSukumar Swaminathan 
324482527734SSukumar Swaminathan 				if (!nlp->nlp_base) {
324582527734SSukumar Swaminathan 					from_chan->nodeq.q_last =
324682527734SSukumar Swaminathan 					    (void *)nlp;
324782527734SSukumar Swaminathan 					from_chan->nodeq.q_first =
324882527734SSukumar Swaminathan 					    nlp->nlp_next[fchanno];
324982527734SSukumar Swaminathan 				}
325082527734SSukumar Swaminathan 
325182527734SSukumar Swaminathan 			} else {
325282527734SSukumar Swaminathan 				n_prev = (NODELIST *)from_chan->nodeq.q_first;
325382527734SSukumar Swaminathan 				count = from_chan->nodeq.q_cnt;
325482527734SSukumar Swaminathan 
325582527734SSukumar Swaminathan 				if (n_prev == nlp) {
325682527734SSukumar Swaminathan 
325782527734SSukumar Swaminathan 					/* If this is the only node on list */
325882527734SSukumar Swaminathan 					if (from_chan->nodeq.q_last ==
325982527734SSukumar Swaminathan 					    (void *)nlp) {
326082527734SSukumar Swaminathan 						from_chan->nodeq.q_last =
326182527734SSukumar Swaminathan 						    NULL;
326282527734SSukumar Swaminathan 						from_chan->nodeq.q_first =
326382527734SSukumar Swaminathan 						    NULL;
326482527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt = 0;
326582527734SSukumar Swaminathan 					} else {
326682527734SSukumar Swaminathan 						from_chan->nodeq.q_first =
326782527734SSukumar Swaminathan 						    nlp->nlp_next[fchanno];
326882527734SSukumar Swaminathan 						((NODELIST *)from_chan->
326982527734SSukumar Swaminathan 						    nodeq.q_last)->
327082527734SSukumar Swaminathan 						    nlp_next[fchanno] =
327182527734SSukumar Swaminathan 						    from_chan->nodeq.q_first;
327282527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt--;
327382527734SSukumar Swaminathan 					}
327482527734SSukumar Swaminathan 					/* Clear node */
327582527734SSukumar Swaminathan 					nlp->nlp_next[fchanno] = NULL;
327682527734SSukumar Swaminathan 				} else {
327782527734SSukumar Swaminathan 					count--;
327882527734SSukumar Swaminathan 					do {
327982527734SSukumar Swaminathan 						n_next =
328082527734SSukumar Swaminathan 						    n_prev->nlp_next[fchanno];
328182527734SSukumar Swaminathan 						if (n_next == nlp) {
328282527734SSukumar Swaminathan 							break;
328382527734SSukumar Swaminathan 						}
328482527734SSukumar Swaminathan 						n_prev = n_next;
328582527734SSukumar Swaminathan 					} while (count--);
328682527734SSukumar Swaminathan 
328782527734SSukumar Swaminathan 					if (count != 0) {
328882527734SSukumar Swaminathan 
328982527734SSukumar Swaminathan 						if (n_next ==
329082527734SSukumar Swaminathan 						    (NODELIST *)from_chan->
329182527734SSukumar Swaminathan 						    nodeq.q_last) {
329282527734SSukumar Swaminathan 							n_prev->
329382527734SSukumar Swaminathan 							    nlp_next[fchanno]
329482527734SSukumar Swaminathan 							    =
329582527734SSukumar Swaminathan 							    ((NODELIST *)
329682527734SSukumar Swaminathan 							    from_chan->
329782527734SSukumar Swaminathan 							    nodeq.q_last)->
329882527734SSukumar Swaminathan 							    nlp_next
329982527734SSukumar Swaminathan 							    [fchanno];
330082527734SSukumar Swaminathan 							from_chan->nodeq.q_last
330182527734SSukumar Swaminathan 							    = (uint8_t *)n_prev;
330282527734SSukumar Swaminathan 						} else {
330382527734SSukumar Swaminathan 
330482527734SSukumar Swaminathan 							n_prev->
330582527734SSukumar Swaminathan 							    nlp_next[fchanno]
330682527734SSukumar Swaminathan 							    =
330782527734SSukumar Swaminathan 							    n_next-> nlp_next
330882527734SSukumar Swaminathan 							    [fchanno];
330982527734SSukumar Swaminathan 						}
331082527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt--;
331182527734SSukumar Swaminathan 						/* Clear node */
331282527734SSukumar Swaminathan 						nlp->nlp_next[fchanno] =
331382527734SSukumar Swaminathan 						    NULL;
331482527734SSukumar Swaminathan 					}
331582527734SSukumar Swaminathan 				}
331682527734SSukumar Swaminathan 			}
331782527734SSukumar Swaminathan 		}
331882527734SSukumar Swaminathan 	}
331982527734SSukumar Swaminathan 
332082527734SSukumar Swaminathan 	/* Now cleanup the iocb's */
332182527734SSukumar Swaminathan 	prev = NULL;
332282527734SSukumar Swaminathan 	iocbq = (IOCBQ *)tbm.q_first;
332382527734SSukumar Swaminathan 
332482527734SSukumar Swaminathan 	while (iocbq) {
332582527734SSukumar Swaminathan 
332682527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
332782527734SSukumar Swaminathan 
332882527734SSukumar Swaminathan 		/* Free the IoTag and the bmp */
332982527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
333082527734SSukumar Swaminathan 
333182527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
333282527734SSukumar Swaminathan 			sbp = iocbq->sbp;
333382527734SSukumar Swaminathan 			if (sbp) {
333482527734SSukumar Swaminathan 				hba->fc_table[sbp->iotag] = NULL;
333582527734SSukumar Swaminathan 				emlxs_sli4_free_xri(hba, sbp, sbp->xp);
333682527734SSukumar Swaminathan 			}
333782527734SSukumar Swaminathan 		} else {
333882527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
333982527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
334082527734SSukumar Swaminathan 		}
334182527734SSukumar Swaminathan 
334282527734SSukumar Swaminathan 		if (sbp && (sbp != STALE_PACKET)) {
334382527734SSukumar Swaminathan 			mutex_enter(&sbp->mtx);
334482527734SSukumar Swaminathan 			sbp->pkt_flags |= PACKET_IN_FLUSH;
334582527734SSukumar Swaminathan 
334682527734SSukumar Swaminathan 			/*
334782527734SSukumar Swaminathan 			 * If the fpkt is already set, then we will leave it
334882527734SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
334982527734SSukumar Swaminathan 			 * for on one fpkt->flush_count
335082527734SSukumar Swaminathan 			 */
335182527734SSukumar Swaminathan 			if (!sbp->fpkt && fpkt) {
335282527734SSukumar Swaminathan 				mutex_enter(&fpkt->mtx);
335382527734SSukumar Swaminathan 				sbp->fpkt = fpkt;
335482527734SSukumar Swaminathan 				fpkt->flush_count++;
335582527734SSukumar Swaminathan 				mutex_exit(&fpkt->mtx);
335682527734SSukumar Swaminathan 			}
335782527734SSukumar Swaminathan 			mutex_exit(&sbp->mtx);
335882527734SSukumar Swaminathan 		}
335982527734SSukumar Swaminathan 		iocbq = next;
336082527734SSukumar Swaminathan 
336182527734SSukumar Swaminathan 	}	/* end of while */
336282527734SSukumar Swaminathan 
336382527734SSukumar Swaminathan 	iocbq = (IOCBQ *)tbm.q_first;
336482527734SSukumar Swaminathan 	while (iocbq) {
336582527734SSukumar Swaminathan 		/* Save the next iocbq for now */
336682527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
336782527734SSukumar Swaminathan 
336882527734SSukumar Swaminathan 		/* Unlink this iocbq */
336982527734SSukumar Swaminathan 		iocbq->next = NULL;
337082527734SSukumar Swaminathan 
337182527734SSukumar Swaminathan 		/* Get the pkt */
337282527734SSukumar Swaminathan 		sbp = (emlxs_buf_t *)iocbq->sbp;
337382527734SSukumar Swaminathan 
337482527734SSukumar Swaminathan 		if (sbp) {
337582527734SSukumar Swaminathan 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
337682527734SSukumar Swaminathan 			"tx: sbp=%p node=%p", sbp, sbp->node);
337782527734SSukumar Swaminathan 
337882527734SSukumar Swaminathan 			if (hba->state >= FC_LINK_UP) {
337982527734SSukumar Swaminathan 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
338082527734SSukumar Swaminathan 				    IOERR_ABORT_REQUESTED, 1);
338182527734SSukumar Swaminathan 			} else {
338282527734SSukumar Swaminathan 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
338382527734SSukumar Swaminathan 				    IOERR_LINK_DOWN, 1);
338482527734SSukumar Swaminathan 			}
338582527734SSukumar Swaminathan 
338682527734SSukumar Swaminathan 		}
338782527734SSukumar Swaminathan 		/* Free the iocb and its associated buffers */
338882527734SSukumar Swaminathan 		else {
338982527734SSukumar Swaminathan 			icmd = &iocbq->iocb;
339082527734SSukumar Swaminathan 
339182527734SSukumar Swaminathan 			/* SLI3 */
339282527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
339382527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
339482527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
339582527734SSukumar Swaminathan 				if ((hba->flag &
339682527734SSukumar Swaminathan 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
339782527734SSukumar Swaminathan 					/* HBA is detaching or offlining */
339882527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
339982527734SSukumar Swaminathan 					    CMD_QUE_RING_LIST64_CN) {
340082527734SSukumar Swaminathan 						uint8_t *tmp;
340182527734SSukumar Swaminathan 						RING *rp;
340282527734SSukumar Swaminathan 						int ch;
340382527734SSukumar Swaminathan 
340482527734SSukumar Swaminathan 						ch = from_chan->channelno;
340582527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
340682527734SSukumar Swaminathan 
340782527734SSukumar Swaminathan 						for (i = 0;
340882527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
340982527734SSukumar Swaminathan 						    i++) {
341082527734SSukumar Swaminathan 							mp = EMLXS_GET_VADDR(
341182527734SSukumar Swaminathan 							    hba, rp, icmd);
341282527734SSukumar Swaminathan 
341382527734SSukumar Swaminathan 							tmp = (uint8_t *)mp;
341482527734SSukumar Swaminathan 							if (mp) {
341582527734SSukumar Swaminathan 							(void) emlxs_mem_put(
341682527734SSukumar Swaminathan 							    hba,
341782527734SSukumar Swaminathan 							    MEM_BUF,
341882527734SSukumar Swaminathan 							    tmp);
341982527734SSukumar Swaminathan 							}
342082527734SSukumar Swaminathan 						}
342182527734SSukumar Swaminathan 
342282527734SSukumar Swaminathan 					}
342382527734SSukumar Swaminathan 
342482527734SSukumar Swaminathan 					(void) emlxs_mem_put(hba, MEM_IOCB,
342582527734SSukumar Swaminathan 					    (uint8_t *)iocbq);
342682527734SSukumar Swaminathan 				} else {
342782527734SSukumar Swaminathan 					/* repost the unsolicited buffer */
342882527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
342982527734SSukumar Swaminathan 					    from_chan, iocbq);
343082527734SSukumar Swaminathan 				}
343182527734SSukumar Swaminathan 			}
343282527734SSukumar Swaminathan 		}
343382527734SSukumar Swaminathan 
343482527734SSukumar Swaminathan 		iocbq = next;
343582527734SSukumar Swaminathan 
343682527734SSukumar Swaminathan 	}	/* end of while */
343782527734SSukumar Swaminathan 
343882527734SSukumar Swaminathan 	/* Now flush the chipq if any */
343982527734SSukumar Swaminathan 	if (!(nlp->nlp_flag[fchanno] & NLP_CLOSED)) {
344082527734SSukumar Swaminathan 
344182527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
344282527734SSukumar Swaminathan 
344382527734SSukumar Swaminathan 		(void) emlxs_chipq_node_flush(port, from_chan, nlp, 0);
344482527734SSukumar Swaminathan 
344582527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
344682527734SSukumar Swaminathan 	}
344782527734SSukumar Swaminathan 
344882527734SSukumar Swaminathan 	if (lock) {
344982527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
345082527734SSukumar Swaminathan 	}
345182527734SSukumar Swaminathan 
345282527734SSukumar Swaminathan 	return;
345382527734SSukumar Swaminathan 
345482527734SSukumar Swaminathan } /* emlxs_tx_move */
3455fcf3ce44SJohn Forte 
3456fcf3ce44SJohn Forte 
3457fcf3ce44SJohn Forte extern uint32_t
345882527734SSukumar Swaminathan emlxs_chipq_node_flush(emlxs_port_t *port, CHANNEL *chan, NODELIST *ndlp,
3459291a2b48SSukumar Swaminathan     emlxs_buf_t *fpkt)
3460fcf3ce44SJohn Forte {
3461fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3462fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3463fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3464fcf3ce44SJohn Forte 	IOCBQ *next;
3465fcf3ce44SJohn Forte 	Q abort;
346682527734SSukumar Swaminathan 	CHANNEL *cp;
346782527734SSukumar Swaminathan 	uint32_t channelno;
346882527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
3469fcf3ce44SJohn Forte 	uint32_t iotag;
3470fcf3ce44SJohn Forte 
3471fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
3472fcf3ce44SJohn Forte 	bzero((void *)flag, sizeof (flag));
3473fcf3ce44SJohn Forte 
347482527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
347582527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3476fcf3ce44SJohn Forte 
347782527734SSukumar Swaminathan 		if (chan && cp != chan) {
3478fcf3ce44SJohn Forte 			continue;
3479fcf3ce44SJohn Forte 		}
3480291a2b48SSukumar Swaminathan 
348182527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3482fcf3ce44SJohn Forte 
348382527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
348482527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3485fcf3ce44SJohn Forte 
3486fcf3ce44SJohn Forte 			if (sbp && (sbp != STALE_PACKET) &&
3487fcf3ce44SJohn Forte 			    (sbp->pkt_flags & PACKET_IN_CHIPQ) &&
3488fcf3ce44SJohn Forte 			    (sbp->node == ndlp) &&
348982527734SSukumar Swaminathan 			    (sbp->channel == cp) &&
3490fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
3491291a2b48SSukumar Swaminathan 				emlxs_sbp_abort_add(port, sbp, &abort, flag,
3492291a2b48SSukumar Swaminathan 				    fpkt);
3493fcf3ce44SJohn Forte 			}
3494291a2b48SSukumar Swaminathan 
3495fcf3ce44SJohn Forte 		}
349682527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3497fcf3ce44SJohn Forte 
3498fcf3ce44SJohn Forte 	}	/* for */
3499fcf3ce44SJohn Forte 
3500fcf3ce44SJohn Forte 	/* Now put the iocb's on the tx queue */
3501fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
3502fcf3ce44SJohn Forte 	while (iocbq) {
3503fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
3504fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
3505fcf3ce44SJohn Forte 
3506fcf3ce44SJohn Forte 		/* Unlink this iocbq */
3507fcf3ce44SJohn Forte 		iocbq->next = NULL;
3508fcf3ce44SJohn Forte 
3509fcf3ce44SJohn Forte 		/* Send this iocbq */
3510fcf3ce44SJohn Forte 		emlxs_tx_put(iocbq, 1);
3511fcf3ce44SJohn Forte 
3512fcf3ce44SJohn Forte 		iocbq = next;
3513fcf3ce44SJohn Forte 	}
3514fcf3ce44SJohn Forte 
351582527734SSukumar Swaminathan 	/* Now trigger channel service */
351682527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
351782527734SSukumar Swaminathan 		if (!flag[channelno]) {
3518fcf3ce44SJohn Forte 			continue;
3519fcf3ce44SJohn Forte 		}
3520291a2b48SSukumar Swaminathan 
352182527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
3522fcf3ce44SJohn Forte 	}
3523fcf3ce44SJohn Forte 
3524fcf3ce44SJohn Forte 	return (abort.q_cnt);
3525fcf3ce44SJohn Forte 
352682527734SSukumar Swaminathan } /* emlxs_chipq_node_flush() */
3527fcf3ce44SJohn Forte 
3528fcf3ce44SJohn Forte 
3529fcf3ce44SJohn Forte /* Flush all IO's left on all iotag lists */
353082527734SSukumar Swaminathan extern uint32_t
3531fcf3ce44SJohn Forte emlxs_iotag_flush(emlxs_hba_t *hba)
3532fcf3ce44SJohn Forte {
3533fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
3534fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3535fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3536fcf3ce44SJohn Forte 	IOCB *iocb;
3537fcf3ce44SJohn Forte 	Q abort;
353882527734SSukumar Swaminathan 	CHANNEL *cp;
353982527734SSukumar Swaminathan 	uint32_t channelno;
3540fcf3ce44SJohn Forte 	uint32_t iotag;
3541fcf3ce44SJohn Forte 	uint32_t count;
3542fcf3ce44SJohn Forte 
3543fcf3ce44SJohn Forte 	count = 0;
354482527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
354582527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3546fcf3ce44SJohn Forte 
3547fcf3ce44SJohn Forte 		bzero((void *)&abort, sizeof (Q));
3548fcf3ce44SJohn Forte 
354982527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3550fcf3ce44SJohn Forte 
355182527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
355282527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3553fcf3ce44SJohn Forte 
355482527734SSukumar Swaminathan 			/* Check if the slot is empty */
3555fcf3ce44SJohn Forte 			if (!sbp || (sbp == STALE_PACKET)) {
3556fcf3ce44SJohn Forte 				continue;
3557fcf3ce44SJohn Forte 			}
3558291a2b48SSukumar Swaminathan 
355982527734SSukumar Swaminathan 			/* We are building an abort list per channel */
356082527734SSukumar Swaminathan 			if (sbp->channel != cp) {
356182527734SSukumar Swaminathan 				continue;
356282527734SSukumar Swaminathan 			}
3563fcf3ce44SJohn Forte 
3564fcf3ce44SJohn Forte 			/* Set IOCB status */
3565fcf3ce44SJohn Forte 			iocbq = &sbp->iocbq;
3566fcf3ce44SJohn Forte 			iocb = &iocbq->iocb;
3567fcf3ce44SJohn Forte 
356882527734SSukumar Swaminathan 			iocb->ULPSTATUS = IOSTAT_LOCAL_REJECT;
3569fcf3ce44SJohn Forte 			iocb->un.grsp.perr.statLocalError = IOERR_LINK_DOWN;
357082527734SSukumar Swaminathan 			iocb->ULPLE = 1;
3571fcf3ce44SJohn Forte 			iocbq->next = NULL;
3572fcf3ce44SJohn Forte 
357382527734SSukumar Swaminathan 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
357482527734SSukumar Swaminathan 				hba->fc_table[iotag] = NULL;
357582527734SSukumar Swaminathan 				emlxs_sli4_free_xri(hba, sbp, sbp->xp);
357682527734SSukumar Swaminathan 			} else {
357782527734SSukumar Swaminathan 				hba->fc_table[iotag] = STALE_PACKET;
357882527734SSukumar Swaminathan 				hba->io_count --;
357982527734SSukumar Swaminathan 				sbp->iotag = 0;
3580291a2b48SSukumar Swaminathan 
358182527734SSukumar Swaminathan 				/* Clean up the sbp */
358282527734SSukumar Swaminathan 				mutex_enter(&sbp->mtx);
358382527734SSukumar Swaminathan 
358482527734SSukumar Swaminathan 				if (sbp->pkt_flags & PACKET_IN_TXQ) {
358582527734SSukumar Swaminathan 					sbp->pkt_flags &= ~PACKET_IN_TXQ;
358682527734SSukumar Swaminathan 					hba->channel_tx_count --;
358782527734SSukumar Swaminathan 				}
358882527734SSukumar Swaminathan 
358982527734SSukumar Swaminathan 				if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
359082527734SSukumar Swaminathan 					sbp->pkt_flags &= ~PACKET_IN_CHIPQ;
359182527734SSukumar Swaminathan 				}
3592291a2b48SSukumar Swaminathan 
359382527734SSukumar Swaminathan 				if (sbp->bmp) {
359482527734SSukumar Swaminathan 					(void) emlxs_mem_put(hba, MEM_BPL,
359582527734SSukumar Swaminathan 					    (uint8_t *)sbp->bmp);
359682527734SSukumar Swaminathan 					sbp->bmp = 0;
359782527734SSukumar Swaminathan 				}
359882527734SSukumar Swaminathan 
359982527734SSukumar Swaminathan 				mutex_exit(&sbp->mtx);
3600fcf3ce44SJohn Forte 			}
3601291a2b48SSukumar Swaminathan 
3602fcf3ce44SJohn Forte 			/* At this point all nodes are assumed destroyed */
360382527734SSukumar Swaminathan 			mutex_enter(&sbp->mtx);
3604fcf3ce44SJohn Forte 			sbp->node = 0;
3605fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3606fcf3ce44SJohn Forte 
3607fcf3ce44SJohn Forte 			/* Add this iocb to our local abort Q */
3608fcf3ce44SJohn Forte 			if (abort.q_first) {
3609291a2b48SSukumar Swaminathan 				((IOCBQ *)abort.q_last)->next = iocbq;
3610fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
3611fcf3ce44SJohn Forte 				abort.q_cnt++;
3612fcf3ce44SJohn Forte 			} else {
3613fcf3ce44SJohn Forte 				abort.q_first = (uint8_t *)iocbq;
3614fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
3615fcf3ce44SJohn Forte 				abort.q_cnt = 1;
3616fcf3ce44SJohn Forte 			}
3617fcf3ce44SJohn Forte 		}
3618fcf3ce44SJohn Forte 
361982527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3620fcf3ce44SJohn Forte 
3621fcf3ce44SJohn Forte 		/* Trigger deferred completion */
3622fcf3ce44SJohn Forte 		if (abort.q_first) {
362382527734SSukumar Swaminathan 			mutex_enter(&cp->rsp_lock);
362482527734SSukumar Swaminathan 			if (cp->rsp_head == NULL) {
362582527734SSukumar Swaminathan 				cp->rsp_head = (IOCBQ *)abort.q_first;
362682527734SSukumar Swaminathan 				cp->rsp_tail = (IOCBQ *)abort.q_last;
3627fcf3ce44SJohn Forte 			} else {
362882527734SSukumar Swaminathan 				cp->rsp_tail->next = (IOCBQ *)abort.q_first;
362982527734SSukumar Swaminathan 				cp->rsp_tail = (IOCBQ *)abort.q_last;
3630fcf3ce44SJohn Forte 			}
363182527734SSukumar Swaminathan 			mutex_exit(&cp->rsp_lock);
3632fcf3ce44SJohn Forte 
363382527734SSukumar Swaminathan 			emlxs_thread_trigger2(&cp->intr_thread,
363482527734SSukumar Swaminathan 			    emlxs_proc_channel, cp);
3635fcf3ce44SJohn Forte 
363682527734SSukumar Swaminathan 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_err_msg,
363782527734SSukumar Swaminathan 			    "Forced iotag completion. channel=%d count=%d",
363882527734SSukumar Swaminathan 			    channelno, abort.q_cnt);
3639fcf3ce44SJohn Forte 
3640fcf3ce44SJohn Forte 			count += abort.q_cnt;
3641fcf3ce44SJohn Forte 		}
3642fcf3ce44SJohn Forte 	}
3643fcf3ce44SJohn Forte 
3644fcf3ce44SJohn Forte 	return (count);
3645fcf3ce44SJohn Forte 
364682527734SSukumar Swaminathan } /* emlxs_iotag_flush() */
3647fcf3ce44SJohn Forte 
3648fcf3ce44SJohn Forte 
3649fcf3ce44SJohn Forte 
365082527734SSukumar Swaminathan /* Checks for IO's on all or a given channel for a given node */
3651fcf3ce44SJohn Forte extern uint32_t
365282527734SSukumar Swaminathan emlxs_chipq_node_check(emlxs_port_t *port, CHANNEL *chan, NODELIST *ndlp)
3653fcf3ce44SJohn Forte {
3654fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3655fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
365682527734SSukumar Swaminathan 	CHANNEL *cp;
365782527734SSukumar Swaminathan 	uint32_t channelno;
3658fcf3ce44SJohn Forte 	uint32_t count;
3659fcf3ce44SJohn Forte 	uint32_t iotag;
3660fcf3ce44SJohn Forte 
3661fcf3ce44SJohn Forte 	count = 0;
3662fcf3ce44SJohn Forte 
366382527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
366482527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3665fcf3ce44SJohn Forte 
366682527734SSukumar Swaminathan 		if (chan && cp != chan) {
3667fcf3ce44SJohn Forte 			continue;
3668fcf3ce44SJohn Forte 		}
3669291a2b48SSukumar Swaminathan 
367082527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3671fcf3ce44SJohn Forte 
367282527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
367382527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3674fcf3ce44SJohn Forte 
3675fcf3ce44SJohn Forte 			if (sbp && (sbp != STALE_PACKET) &&
3676fcf3ce44SJohn Forte 			    (sbp->pkt_flags & PACKET_IN_CHIPQ) &&
3677fcf3ce44SJohn Forte 			    (sbp->node == ndlp) &&
367882527734SSukumar Swaminathan 			    (sbp->channel == cp) &&
3679fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
3680fcf3ce44SJohn Forte 				count++;
3681fcf3ce44SJohn Forte 			}
3682291a2b48SSukumar Swaminathan 
3683fcf3ce44SJohn Forte 		}
368482527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3685fcf3ce44SJohn Forte 
3686fcf3ce44SJohn Forte 	}	/* for */
3687fcf3ce44SJohn Forte 
3688fcf3ce44SJohn Forte 	return (count);
3689fcf3ce44SJohn Forte 
369082527734SSukumar Swaminathan } /* emlxs_chipq_node_check() */
3691fcf3ce44SJohn Forte 
3692fcf3ce44SJohn Forte 
3693fcf3ce44SJohn Forte 
369482527734SSukumar Swaminathan /* Flush all IO's for a given node's lun (on any channel) */
3695fcf3ce44SJohn Forte extern uint32_t
369682527734SSukumar Swaminathan emlxs_chipq_lun_flush(emlxs_port_t *port, NODELIST *ndlp,
369782527734SSukumar Swaminathan     uint32_t lun, emlxs_buf_t *fpkt)
3698fcf3ce44SJohn Forte {
3699fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3700fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3701fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3702fcf3ce44SJohn Forte 	IOCBQ *next;
3703fcf3ce44SJohn Forte 	Q abort;
3704fcf3ce44SJohn Forte 	uint32_t iotag;
370582527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
370682527734SSukumar Swaminathan 	uint32_t channelno;
3707fcf3ce44SJohn Forte 
3708fcf3ce44SJohn Forte 	bzero((void *)flag, sizeof (flag));
3709fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
3710fcf3ce44SJohn Forte 
371182527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
371282527734SSukumar Swaminathan 	for (iotag = 1; iotag < hba->max_iotag; iotag++) {
371382527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
3714fcf3ce44SJohn Forte 
3715fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET) &&
3716fcf3ce44SJohn Forte 		    sbp->pkt_flags & PACKET_IN_CHIPQ &&
3717fcf3ce44SJohn Forte 		    sbp->node == ndlp &&
3718fcf3ce44SJohn Forte 		    sbp->lun == lun &&
3719fcf3ce44SJohn Forte 		    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
372082527734SSukumar Swaminathan 			emlxs_sbp_abort_add(port, sbp,
372182527734SSukumar Swaminathan 			    &abort, flag, fpkt);
3722fcf3ce44SJohn Forte 		}
3723fcf3ce44SJohn Forte 	}
372482527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
3725fcf3ce44SJohn Forte 
3726fcf3ce44SJohn Forte 	/* Now put the iocb's on the tx queue */
3727fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
3728fcf3ce44SJohn Forte 	while (iocbq) {
3729fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
3730fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
3731fcf3ce44SJohn Forte 
3732fcf3ce44SJohn Forte 		/* Unlink this iocbq */
3733fcf3ce44SJohn Forte 		iocbq->next = NULL;
3734fcf3ce44SJohn Forte 
3735fcf3ce44SJohn Forte 		/* Send this iocbq */
3736fcf3ce44SJohn Forte 		emlxs_tx_put(iocbq, 1);
3737fcf3ce44SJohn Forte 
3738fcf3ce44SJohn Forte 		iocbq = next;
3739fcf3ce44SJohn Forte 	}
3740fcf3ce44SJohn Forte 
374182527734SSukumar Swaminathan 	/* Now trigger channel service */
374282527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
374382527734SSukumar Swaminathan 		if (!flag[channelno]) {
374482527734SSukumar Swaminathan 			continue;
374582527734SSukumar Swaminathan 		}
374682527734SSukumar Swaminathan 
374782527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
3748fcf3ce44SJohn Forte 	}
3749291a2b48SSukumar Swaminathan 
3750fcf3ce44SJohn Forte 	return (abort.q_cnt);
3751fcf3ce44SJohn Forte 
375282527734SSukumar Swaminathan } /* emlxs_chipq_lun_flush() */
3753fcf3ce44SJohn Forte 
3754fcf3ce44SJohn Forte 
3755fcf3ce44SJohn Forte 
3756fcf3ce44SJohn Forte /*
3757fcf3ce44SJohn Forte  * Issue an ABORT_XRI_CN iocb command to abort an FCP command already issued.
3758fe199829SSukumar Swaminathan  * This must be called while holding the EMLXS_FCTAB_LOCK
3759fcf3ce44SJohn Forte  */
3760fcf3ce44SJohn Forte extern IOCBQ *
3761291a2b48SSukumar Swaminathan emlxs_create_abort_xri_cn(emlxs_port_t *port, NODELIST *ndlp,
376282527734SSukumar Swaminathan     uint16_t iotag, CHANNEL *cp, uint8_t class, int32_t flag)
3763fcf3ce44SJohn Forte {
3764fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3765fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3766fcf3ce44SJohn Forte 	IOCB *iocb;
376782527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
376882527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
3769fcf3ce44SJohn Forte 	uint16_t abort_iotag;
3770fcf3ce44SJohn Forte 
377182527734SSukumar Swaminathan 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB, 0)) == NULL) {
3772fcf3ce44SJohn Forte 		return (NULL);
3773fcf3ce44SJohn Forte 	}
3774291a2b48SSukumar Swaminathan 
377582527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
3776fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
3777fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
3778fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
3779fcf3ce44SJohn Forte 
3780fcf3ce44SJohn Forte 	/*
3781fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
3782fcf3ce44SJohn Forte 	 */
378382527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
378482527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
3785fcf3ce44SJohn Forte 	}
378682527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
3787291a2b48SSukumar Swaminathan 
3788fcf3ce44SJohn Forte 
378982527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
379082527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
379182527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
3792fcf3ce44SJohn Forte 
379382527734SSukumar Swaminathan 		/* Try to issue abort by XRI if possible */
379482527734SSukumar Swaminathan 		if (sbp == NULL || sbp == STALE_PACKET || sbp->xp == NULL) {
379582527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_REQ_TAG;
379682527734SSukumar Swaminathan 			wqe->AbortTag = iotag;
379782527734SSukumar Swaminathan 		} else {
379882527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_XRI_TAG;
379982527734SSukumar Swaminathan 			wqe->AbortTag = sbp->xp->XRI;
380082527734SSukumar Swaminathan 		}
380182527734SSukumar Swaminathan 		wqe->un.Abort.IA = 0;
380282527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
380382527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
380482527734SSukumar Swaminathan 		wqe->Class = CLASS3;
380582527734SSukumar Swaminathan 		wqe->CQId = 0x3ff;
380682527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
380782527734SSukumar Swaminathan 	} else {
380882527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
380982527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
381082527734SSukumar Swaminathan 		iocb->un.acxri.abortType = flag;
381182527734SSukumar Swaminathan 		iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi;
381282527734SSukumar Swaminathan 		iocb->un.acxri.abortIoTag = iotag;
381382527734SSukumar Swaminathan 		iocb->ULPLE = 1;
381482527734SSukumar Swaminathan 		iocb->ULPCLASS = class;
381582527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_ABORT_XRI_CN;
381682527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
381782527734SSukumar Swaminathan 	}
3818fcf3ce44SJohn Forte 
3819fcf3ce44SJohn Forte 	return (iocbq);
3820fcf3ce44SJohn Forte 
382182527734SSukumar Swaminathan } /* emlxs_create_abort_xri_cn() */
3822fcf3ce44SJohn Forte 
3823fcf3ce44SJohn Forte 
3824fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
3825fcf3ce44SJohn Forte extern IOCBQ *
3826fcf3ce44SJohn Forte emlxs_create_abort_xri_cx(emlxs_port_t *port, NODELIST *ndlp, uint16_t xid,
382782527734SSukumar Swaminathan     CHANNEL *cp, uint8_t class, int32_t flag)
3828fcf3ce44SJohn Forte {
3829fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3830fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3831fcf3ce44SJohn Forte 	IOCB *iocb;
383282527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
3833fcf3ce44SJohn Forte 	uint16_t abort_iotag;
3834fcf3ce44SJohn Forte 
383582527734SSukumar Swaminathan 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB, 0)) == NULL) {
3836fcf3ce44SJohn Forte 		return (NULL);
3837fcf3ce44SJohn Forte 	}
3838291a2b48SSukumar Swaminathan 
383982527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
3840fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
3841fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
3842fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
3843fcf3ce44SJohn Forte 
3844fcf3ce44SJohn Forte 	/*
3845fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
3846fcf3ce44SJohn Forte 	 */
384782527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
384882527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
384982527734SSukumar Swaminathan 	}
385082527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
385182527734SSukumar Swaminathan 
385282527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
385382527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
385482527734SSukumar Swaminathan 		wqe->un.Abort.Criteria = ABORT_XRI_TAG;
385582527734SSukumar Swaminathan 		wqe->un.Abort.IA = 0;
385682527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
385782527734SSukumar Swaminathan 		wqe->AbortTag = xid;
385882527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
385982527734SSukumar Swaminathan 		wqe->Class = CLASS3;
386082527734SSukumar Swaminathan 		wqe->CQId = 0x3ff;
386182527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
386282527734SSukumar Swaminathan 	} else {
386382527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
386482527734SSukumar Swaminathan 		iocb->ULPCONTEXT = xid;
386582527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
386682527734SSukumar Swaminathan 		iocb->un.acxri.abortType = flag;
386782527734SSukumar Swaminathan 		iocb->ULPLE = 1;
386882527734SSukumar Swaminathan 		iocb->ULPCLASS = class;
386982527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_ABORT_XRI_CX;
387082527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
3871fcf3ce44SJohn Forte 	}
3872291a2b48SSukumar Swaminathan 
3873fcf3ce44SJohn Forte 	return (iocbq);
3874fcf3ce44SJohn Forte 
387582527734SSukumar Swaminathan } /* emlxs_create_abort_xri_cx() */
3876fcf3ce44SJohn Forte 
3877fcf3ce44SJohn Forte 
3878fcf3ce44SJohn Forte 
3879fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
3880fcf3ce44SJohn Forte extern IOCBQ *
3881fcf3ce44SJohn Forte emlxs_create_close_xri_cn(emlxs_port_t *port, NODELIST *ndlp,
388282527734SSukumar Swaminathan     uint16_t iotag, CHANNEL *cp)
3883fcf3ce44SJohn Forte {
3884fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3885fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3886fcf3ce44SJohn Forte 	IOCB *iocb;
388782527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
388882527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
3889fcf3ce44SJohn Forte 	uint16_t abort_iotag;
3890fcf3ce44SJohn Forte 
389182527734SSukumar Swaminathan 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB, 0)) == NULL) {
3892fcf3ce44SJohn Forte 		return (NULL);
3893fcf3ce44SJohn Forte 	}
3894291a2b48SSukumar Swaminathan 
389582527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
3896fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
3897fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
3898fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
3899fcf3ce44SJohn Forte 
3900fcf3ce44SJohn Forte 	/*
3901fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
3902fcf3ce44SJohn Forte 	 */
390382527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
390482527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
3905fcf3ce44SJohn Forte 	}
390682527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
3907291a2b48SSukumar Swaminathan 
390882527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
390982527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
391082527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
3911fcf3ce44SJohn Forte 
391282527734SSukumar Swaminathan 		/* Try to issue close by XRI if possible */
391382527734SSukumar Swaminathan 		if (sbp == NULL || sbp == STALE_PACKET || sbp->xp == NULL) {
391482527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_REQ_TAG;
391582527734SSukumar Swaminathan 			wqe->AbortTag = iotag;
391682527734SSukumar Swaminathan 		} else {
391782527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_XRI_TAG;
391882527734SSukumar Swaminathan 			wqe->AbortTag = sbp->xp->XRI;
391982527734SSukumar Swaminathan 		}
392082527734SSukumar Swaminathan 		wqe->un.Abort.IA = 1;
392182527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
392282527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
392382527734SSukumar Swaminathan 		wqe->Class = CLASS3;
392482527734SSukumar Swaminathan 		wqe->CQId = 0x3ff;
392582527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
392682527734SSukumar Swaminathan 	} else {
392782527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
392882527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
392982527734SSukumar Swaminathan 		iocb->un.acxri.abortType = 0;
393082527734SSukumar Swaminathan 		iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi;
393182527734SSukumar Swaminathan 		iocb->un.acxri.abortIoTag = iotag;
393282527734SSukumar Swaminathan 		iocb->ULPLE = 1;
393382527734SSukumar Swaminathan 		iocb->ULPCLASS = 0;
393482527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_CLOSE_XRI_CN;
393582527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
393682527734SSukumar Swaminathan 	}
3937fcf3ce44SJohn Forte 
3938fcf3ce44SJohn Forte 	return (iocbq);
3939fcf3ce44SJohn Forte 
394082527734SSukumar Swaminathan } /* emlxs_create_close_xri_cn() */
3941fcf3ce44SJohn Forte 
3942fcf3ce44SJohn Forte 
3943fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
3944fcf3ce44SJohn Forte extern IOCBQ *
3945291a2b48SSukumar Swaminathan emlxs_create_close_xri_cx(emlxs_port_t *port, NODELIST *ndlp, uint16_t xid,
394682527734SSukumar Swaminathan     CHANNEL *cp)
3947fcf3ce44SJohn Forte {
3948fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3949fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3950fcf3ce44SJohn Forte 	IOCB *iocb;
395182527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
3952fcf3ce44SJohn Forte 	uint16_t abort_iotag;
3953fcf3ce44SJohn Forte 
395482527734SSukumar Swaminathan 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB, 0)) == NULL) {
3955fcf3ce44SJohn Forte 		return (NULL);
3956fcf3ce44SJohn Forte 	}
3957291a2b48SSukumar Swaminathan 
395882527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
3959fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
3960fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
3961fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
3962fcf3ce44SJohn Forte 
3963fcf3ce44SJohn Forte 	/*
3964fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
3965fcf3ce44SJohn Forte 	 */
396682527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
396782527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
396882527734SSukumar Swaminathan 	}
396982527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
397082527734SSukumar Swaminathan 
397182527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
397282527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
397382527734SSukumar Swaminathan 		wqe->un.Abort.Criteria = ABORT_XRI_TAG;
397482527734SSukumar Swaminathan 		wqe->un.Abort.IA = 1;
397582527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
397682527734SSukumar Swaminathan 		wqe->AbortTag = xid;
397782527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
397882527734SSukumar Swaminathan 		wqe->Class = CLASS3;
397982527734SSukumar Swaminathan 		wqe->CQId = 0x3ff;
398082527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
398182527734SSukumar Swaminathan 	} else {
398282527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
398382527734SSukumar Swaminathan 		iocb->ULPCONTEXT = xid;
398482527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
398582527734SSukumar Swaminathan 		iocb->ULPLE = 1;
398682527734SSukumar Swaminathan 		iocb->ULPCLASS = 0;
398782527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_CLOSE_XRI_CX;
398882527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
3989fcf3ce44SJohn Forte 	}
3990291a2b48SSukumar Swaminathan 
3991fcf3ce44SJohn Forte 	return (iocbq);
3992fcf3ce44SJohn Forte 
399382527734SSukumar Swaminathan } /* emlxs_create_close_xri_cx() */
3994fcf3ce44SJohn Forte 
3995fcf3ce44SJohn Forte 
3996fe199829SSukumar Swaminathan #ifdef SFCT_SUPPORT
3997fe199829SSukumar Swaminathan void
3998fe199829SSukumar Swaminathan emlxs_abort_fct_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
3999fe199829SSukumar Swaminathan {
4000fe199829SSukumar Swaminathan 	CHANNEL *cp;
4001fe199829SSukumar Swaminathan 	IOCBQ *iocbq;
4002fe199829SSukumar Swaminathan 	IOCB *iocb;
4003fe199829SSukumar Swaminathan 
4004fe199829SSukumar Swaminathan 	if (rxid == 0 || rxid == 0xFFFF) {
4005fe199829SSukumar Swaminathan 		return;
4006fe199829SSukumar Swaminathan 	}
4007fe199829SSukumar Swaminathan 
4008fe199829SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4009fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4010fe199829SSukumar Swaminathan 		    "Aborting FCT exchange: xid=%x", rxid);
4011fe199829SSukumar Swaminathan 
4012fe199829SSukumar Swaminathan 		if (emlxs_sli4_unreserve_xri(hba, rxid) == 0) {
4013fe199829SSukumar Swaminathan 			/* We have no way to abort unsolicited exchanges */
4014fe199829SSukumar Swaminathan 			/* that we have not responded to at this time */
4015fe199829SSukumar Swaminathan 			/* So we will return for now */
4016fe199829SSukumar Swaminathan 			return;
4017fe199829SSukumar Swaminathan 		}
4018fe199829SSukumar Swaminathan 	}
4019fe199829SSukumar Swaminathan 
4020fe199829SSukumar Swaminathan 	cp = &hba->chan[hba->channel_fcp];
4021fe199829SSukumar Swaminathan 
4022fe199829SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
4023fe199829SSukumar Swaminathan 
4024fe199829SSukumar Swaminathan 	/* Create the abort IOCB */
4025fe199829SSukumar Swaminathan 	if (hba->state >= FC_LINK_UP) {
4026fe199829SSukumar Swaminathan 		iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4027fe199829SSukumar Swaminathan 		    CLASS3, ABORT_TYPE_ABTS);
4028fe199829SSukumar Swaminathan 	} else {
4029fe199829SSukumar Swaminathan 		iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4030fe199829SSukumar Swaminathan 	}
4031fe199829SSukumar Swaminathan 
4032fe199829SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
4033fe199829SSukumar Swaminathan 
4034fe199829SSukumar Swaminathan 	if (iocbq) {
4035fe199829SSukumar Swaminathan 		iocb = &iocbq->iocb;
4036fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4037fe199829SSukumar Swaminathan 		    "Aborting FCT exchange: xid=%x iotag=%x", rxid,
4038fe199829SSukumar Swaminathan 		    iocb->ULPIOTAG);
4039fe199829SSukumar Swaminathan 
4040fe199829SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4041fe199829SSukumar Swaminathan 	}
4042fe199829SSukumar Swaminathan 
4043fe199829SSukumar Swaminathan } /* emlxs_abort_fct_exchange() */
4044fe199829SSukumar Swaminathan #endif /* SFCT_SUPPORT */
4045fe199829SSukumar Swaminathan 
4046fe199829SSukumar Swaminathan 
4047fe199829SSukumar Swaminathan void
4048fe199829SSukumar Swaminathan emlxs_abort_els_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4049fe199829SSukumar Swaminathan {
4050fe199829SSukumar Swaminathan 	CHANNEL *cp;
4051fe199829SSukumar Swaminathan 	IOCBQ *iocbq;
4052fe199829SSukumar Swaminathan 	IOCB *iocb;
4053fe199829SSukumar Swaminathan 
4054fe199829SSukumar Swaminathan 	if (rxid == 0 || rxid == 0xFFFF) {
4055fe199829SSukumar Swaminathan 		return;
4056fe199829SSukumar Swaminathan 	}
4057fe199829SSukumar Swaminathan 
4058fe199829SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4059fe199829SSukumar Swaminathan 
4060fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4061fe199829SSukumar Swaminathan 		    "Aborting ELS exchange: xid=%x", rxid);
4062fe199829SSukumar Swaminathan 
4063fe199829SSukumar Swaminathan 		if (emlxs_sli4_unreserve_xri(hba, rxid) == 0) {
4064fe199829SSukumar Swaminathan 			/* We have no way to abort unsolicited exchanges */
4065fe199829SSukumar Swaminathan 			/* that we have not responded to at this time */
4066fe199829SSukumar Swaminathan 			/* So we will return for now */
4067fe199829SSukumar Swaminathan 			return;
4068fe199829SSukumar Swaminathan 		}
4069fe199829SSukumar Swaminathan 	}
4070fe199829SSukumar Swaminathan 
4071fe199829SSukumar Swaminathan 	cp = &hba->chan[hba->channel_els];
4072fe199829SSukumar Swaminathan 
4073fe199829SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
4074fe199829SSukumar Swaminathan 
4075fe199829SSukumar Swaminathan 	/* Create the abort IOCB */
4076fe199829SSukumar Swaminathan 	if (hba->state >= FC_LINK_UP) {
4077fe199829SSukumar Swaminathan 		iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4078fe199829SSukumar Swaminathan 		    CLASS3, ABORT_TYPE_ABTS);
4079fe199829SSukumar Swaminathan 	} else {
4080fe199829SSukumar Swaminathan 		iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4081fe199829SSukumar Swaminathan 	}
4082fe199829SSukumar Swaminathan 
4083fe199829SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
4084fe199829SSukumar Swaminathan 
4085fe199829SSukumar Swaminathan 	if (iocbq) {
4086fe199829SSukumar Swaminathan 		iocb = &iocbq->iocb;
4087fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4088fe199829SSukumar Swaminathan 		    "Aborting ELS exchange: xid=%x iotag=%x", rxid,
4089fe199829SSukumar Swaminathan 		    iocb->ULPIOTAG);
4090fe199829SSukumar Swaminathan 
4091fe199829SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4092fe199829SSukumar Swaminathan 	}
4093fe199829SSukumar Swaminathan 
4094fe199829SSukumar Swaminathan } /* emlxs_abort_els_exchange() */
4095fe199829SSukumar Swaminathan 
4096fe199829SSukumar Swaminathan 
4097728bdc9bSSukumar Swaminathan void
4098bb63f56eSSukumar Swaminathan emlxs_abort_ct_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4099728bdc9bSSukumar Swaminathan {
410082527734SSukumar Swaminathan 	CHANNEL *cp;
4101728bdc9bSSukumar Swaminathan 	IOCBQ *iocbq;
4102fe199829SSukumar Swaminathan 	IOCB *iocb;
4103728bdc9bSSukumar Swaminathan 
4104fe199829SSukumar Swaminathan 	if (rxid == 0 || rxid == 0xFFFF) {
4105fe199829SSukumar Swaminathan 		return;
4106fe199829SSukumar Swaminathan 	}
410782527734SSukumar Swaminathan 
410882527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4109fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ct_msg,
4110fe199829SSukumar Swaminathan 		    "Aborting CT exchange: xid=%x", rxid);
4111fe199829SSukumar Swaminathan 
411282527734SSukumar Swaminathan 		if (emlxs_sli4_unreserve_xri(hba, rxid) == 0) {
411382527734SSukumar Swaminathan 			/* We have no way to abort unsolicited exchanges */
411482527734SSukumar Swaminathan 			/* that we have not responded to at this time */
411582527734SSukumar Swaminathan 			/* So we will return for now */
411682527734SSukumar Swaminathan 			return;
411782527734SSukumar Swaminathan 		}
411882527734SSukumar Swaminathan 	}
411982527734SSukumar Swaminathan 
412082527734SSukumar Swaminathan 	cp = &hba->chan[hba->channel_ct];
4121728bdc9bSSukumar Swaminathan 
4122fe199829SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
4123fe199829SSukumar Swaminathan 
4124728bdc9bSSukumar Swaminathan 	/* Create the abort IOCB */
4125728bdc9bSSukumar Swaminathan 	if (hba->state >= FC_LINK_UP) {
4126fe199829SSukumar Swaminathan 		iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4127fe199829SSukumar Swaminathan 		    CLASS3, ABORT_TYPE_ABTS);
4128291a2b48SSukumar Swaminathan 	} else {
412982527734SSukumar Swaminathan 		iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4130728bdc9bSSukumar Swaminathan 	}
413182527734SSukumar Swaminathan 
4132fe199829SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
4133fe199829SSukumar Swaminathan 
4134bb63f56eSSukumar Swaminathan 	if (iocbq) {
4135fe199829SSukumar Swaminathan 		iocb = &iocbq->iocb;
4136fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4137fe199829SSukumar Swaminathan 		    "Aborting CT exchange: xid=%x iotag=%x", rxid,
4138fe199829SSukumar Swaminathan 		    iocb->ULPIOTAG);
4139fe199829SSukumar Swaminathan 
414082527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4141bb63f56eSSukumar Swaminathan 	}
414282527734SSukumar Swaminathan 
414382527734SSukumar Swaminathan } /* emlxs_abort_ct_exchange() */
4144728bdc9bSSukumar Swaminathan 
4145fcf3ce44SJohn Forte 
4146fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4147fcf3ce44SJohn Forte static void
4148fcf3ce44SJohn Forte emlxs_sbp_abort_add(emlxs_port_t *port, emlxs_buf_t *sbp, Q *abort,
4149fcf3ce44SJohn Forte     uint8_t *flag, emlxs_buf_t *fpkt)
4150fcf3ce44SJohn Forte {
4151fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4152fcf3ce44SJohn Forte 	IOCBQ *iocbq;
415382527734SSukumar Swaminathan 	CHANNEL *cp;
4154fcf3ce44SJohn Forte 	NODELIST *ndlp;
4155fcf3ce44SJohn Forte 
415682527734SSukumar Swaminathan 	cp = (CHANNEL *)sbp->channel;
4157fcf3ce44SJohn Forte 	ndlp = sbp->node;
4158fcf3ce44SJohn Forte 
4159fcf3ce44SJohn Forte 	/* Create the close XRI IOCB */
416082527734SSukumar Swaminathan 	iocbq = emlxs_create_close_xri_cn(port, ndlp, sbp->iotag, cp);
4161fcf3ce44SJohn Forte 
4162291a2b48SSukumar Swaminathan 	/*
4163291a2b48SSukumar Swaminathan 	 * Add this iocb to our local abort Q
4164291a2b48SSukumar Swaminathan 	 * This way we don't hold the CHIPQ lock too long
4165291a2b48SSukumar Swaminathan 	 */
4166fcf3ce44SJohn Forte 	if (iocbq) {
4167fcf3ce44SJohn Forte 		if (abort->q_first) {
4168291a2b48SSukumar Swaminathan 			((IOCBQ *)abort->q_last)->next = iocbq;
4169fcf3ce44SJohn Forte 			abort->q_last = (uint8_t *)iocbq;
4170fcf3ce44SJohn Forte 			abort->q_cnt++;
4171fcf3ce44SJohn Forte 		} else {
4172fcf3ce44SJohn Forte 			abort->q_first = (uint8_t *)iocbq;
4173fcf3ce44SJohn Forte 			abort->q_last = (uint8_t *)iocbq;
4174fcf3ce44SJohn Forte 			abort->q_cnt = 1;
4175fcf3ce44SJohn Forte 		}
4176fcf3ce44SJohn Forte 		iocbq->next = NULL;
4177fcf3ce44SJohn Forte 	}
4178291a2b48SSukumar Swaminathan 
4179fcf3ce44SJohn Forte 	/* set the flags */
4180fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
4181fcf3ce44SJohn Forte 
4182fcf3ce44SJohn Forte 	sbp->pkt_flags |= (PACKET_IN_FLUSH | PACKET_XRI_CLOSED);
418382527734SSukumar Swaminathan 
4184fcf3ce44SJohn Forte 	sbp->ticks = hba->timer_tics + 10;
4185fcf3ce44SJohn Forte 	sbp->abort_attempts++;
4186fcf3ce44SJohn Forte 
418782527734SSukumar Swaminathan 	flag[cp->channelno] = 1;
4188fcf3ce44SJohn Forte 
4189fcf3ce44SJohn Forte 	/*
4190291a2b48SSukumar Swaminathan 	 * If the fpkt is already set, then we will leave it alone
4191fcf3ce44SJohn Forte 	 * This ensures that this pkt is only accounted for on one
4192fcf3ce44SJohn Forte 	 * fpkt->flush_count
4193fcf3ce44SJohn Forte 	 */
4194fcf3ce44SJohn Forte 	if (!sbp->fpkt && fpkt) {
4195fcf3ce44SJohn Forte 		mutex_enter(&fpkt->mtx);
4196fcf3ce44SJohn Forte 		sbp->fpkt = fpkt;
4197fcf3ce44SJohn Forte 		fpkt->flush_count++;
4198fcf3ce44SJohn Forte 		mutex_exit(&fpkt->mtx);
4199fcf3ce44SJohn Forte 	}
4200291a2b48SSukumar Swaminathan 
4201fcf3ce44SJohn Forte 	mutex_exit(&sbp->mtx);
4202fcf3ce44SJohn Forte 
4203fcf3ce44SJohn Forte 	return;
4204fcf3ce44SJohn Forte 
420582527734SSukumar Swaminathan }	/* emlxs_sbp_abort_add() */
4206