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  *
8*8f23e9faSHans Rosenfeld  * You can obtain a copy of the license at
9*8f23e9faSHans Rosenfeld  * http://www.opensource.org/licenses/cddl1.txt.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte 
22fcf3ce44SJohn Forte /*
23*8f23e9faSHans Rosenfeld  * Copyright (c) 2004-2012 Emulex. All rights reserved.
2482527734SSukumar Swaminathan  * Use is subject to license terms.
25fcf3ce44SJohn Forte  */
26fcf3ce44SJohn Forte 
27291a2b48SSukumar Swaminathan #include <emlxs.h>
28fcf3ce44SJohn Forte 
29fcf3ce44SJohn Forte /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
30fcf3ce44SJohn Forte EMLXS_MSG_DEF(EMLXS_FCP_C);
31fcf3ce44SJohn Forte 
32fcf3ce44SJohn Forte #define	EMLXS_GET_VADDR(hba, rp, icmd) emlxs_mem_get_vaddr(hba, rp, \
3382527734SSukumar Swaminathan 	PADDR(icmd->un.cont64[i].addrHigh, icmd->un.cont64[i].addrLow));
34fcf3ce44SJohn Forte 
35291a2b48SSukumar Swaminathan static void	emlxs_sbp_abort_add(emlxs_port_t *port, emlxs_buf_t *sbp,
36291a2b48SSukumar Swaminathan     Q *abort, uint8_t *flag, emlxs_buf_t *fpkt);
37fcf3ce44SJohn Forte 
38fcf3ce44SJohn Forte #define	SCSI3_PERSISTENT_RESERVE_IN	0x5e
39291a2b48SSukumar Swaminathan #define	SCSI_INQUIRY			0x12
40291a2b48SSukumar Swaminathan #define	SCSI_RX_DIAG    		0x1C
41fcf3ce44SJohn Forte 
42fcf3ce44SJohn Forte 
43fcf3ce44SJohn Forte /*
44fcf3ce44SJohn Forte  *  emlxs_handle_fcp_event
45fcf3ce44SJohn Forte  *
46fcf3ce44SJohn Forte  *  Description: Process an FCP Rsp Ring completion
47fcf3ce44SJohn Forte  *
48fcf3ce44SJohn Forte  */
49fcf3ce44SJohn Forte /* ARGSUSED */
50fcf3ce44SJohn Forte extern void
5182527734SSukumar Swaminathan emlxs_handle_fcp_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
52fcf3ce44SJohn Forte {
53fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
5482527734SSukumar Swaminathan 	emlxs_config_t	*cfg = &CFG;
55fcf3ce44SJohn Forte 	IOCB *cmd;
56fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
57fcf3ce44SJohn Forte 	fc_packet_t *pkt = NULL;
58291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
59291a2b48SSukumar Swaminathan 	NODELIST *ndlp;
60291a2b48SSukumar Swaminathan #endif
61fcf3ce44SJohn Forte 	uint32_t iostat;
62fcf3ce44SJohn Forte 	uint8_t localstat;
63fcf3ce44SJohn Forte 	fcp_rsp_t *rsp;
64fcf3ce44SJohn Forte 	uint32_t rsp_data_resid;
65fcf3ce44SJohn Forte 	uint32_t check_underrun;
66fcf3ce44SJohn Forte 	uint8_t asc;
67fcf3ce44SJohn Forte 	uint8_t ascq;
68fcf3ce44SJohn Forte 	uint8_t scsi_status;
69fcf3ce44SJohn Forte 	uint8_t sense;
70fcf3ce44SJohn Forte 	uint32_t did;
71fcf3ce44SJohn Forte 	uint32_t fix_it;
72fcf3ce44SJohn Forte 	uint8_t *scsi_cmd;
73fcf3ce44SJohn Forte 	uint8_t scsi_opcode;
74fcf3ce44SJohn Forte 	uint16_t scsi_dl;
75fcf3ce44SJohn Forte 	uint32_t data_rx;
76*8f23e9faSHans Rosenfeld 	uint32_t length;
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,
99*8f23e9faSHans Rosenfeld 		    "cmd=%x iotag=%d", cmd->ULPCOMMAND, cmd->ULPIOTAG);
100fcf3ce44SJohn Forte 
101fcf3ce44SJohn Forte 		return;
102fcf3ce44SJohn Forte 	}
103291a2b48SSukumar Swaminathan 
104fcf3ce44SJohn Forte 	HBASTATS.FcpCompleted++;
105fcf3ce44SJohn Forte 
106291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
107291a2b48SSukumar Swaminathan 	emlxs_update_sd_bucket(sbp);
108291a2b48SSukumar Swaminathan #endif /* SAN_DIAG_SUPPORT */
109291a2b48SSukumar Swaminathan 
110fcf3ce44SJohn Forte 	pkt = PRIV2PKT(sbp);
111fcf3ce44SJohn Forte 
11282527734SSukumar Swaminathan 	did = LE_SWAP24_LO(pkt->pkt_cmd_fhdr.d_id);
113fcf3ce44SJohn Forte 	scsi_cmd = (uint8_t *)pkt->pkt_cmd;
114fcf3ce44SJohn Forte 	scsi_opcode = scsi_cmd[12];
115fcf3ce44SJohn Forte 	data_rx = 0;
116fcf3ce44SJohn Forte 
117fcf3ce44SJohn Forte 	/* Sync data in data buffer only on FC_PKT_FCP_READ */
118fcf3ce44SJohn Forte 	if (pkt->pkt_datalen && (pkt->pkt_tran_type == FC_PKT_FCP_READ)) {
11982527734SSukumar Swaminathan 		EMLXS_MPDATA_SYNC(pkt->pkt_data_dma, 0, pkt->pkt_datalen,
120fcf3ce44SJohn Forte 		    DDI_DMA_SYNC_FORKERNEL);
121fcf3ce44SJohn Forte 
122fcf3ce44SJohn Forte #ifdef TEST_SUPPORT
123fcf3ce44SJohn Forte 		if (hba->underrun_counter && (iostat == IOSTAT_SUCCESS) &&
124fcf3ce44SJohn Forte 		    (pkt->pkt_datalen >= 512)) {
125fcf3ce44SJohn Forte 			hba->underrun_counter--;
126fcf3ce44SJohn Forte 			iostat = IOSTAT_FCP_RSP_ERROR;
127fcf3ce44SJohn Forte 
128fcf3ce44SJohn Forte 			/* Report 512 bytes missing by adapter */
129fcf3ce44SJohn Forte 			cmd->un.fcpi.fcpi_parm = pkt->pkt_datalen - 512;
130fcf3ce44SJohn Forte 
131fcf3ce44SJohn Forte 			/* Corrupt 512 bytes of Data buffer */
132fcf3ce44SJohn Forte 			bzero((uint8_t *)pkt->pkt_data, 512);
133fcf3ce44SJohn Forte 
134fcf3ce44SJohn Forte 			/* Set FCP response to STATUS_GOOD */
135fcf3ce44SJohn Forte 			bzero((uint8_t *)pkt->pkt_resp, pkt->pkt_rsplen);
136fcf3ce44SJohn Forte 		}
137291a2b48SSukumar Swaminathan #endif /* TEST_SUPPORT */
138fcf3ce44SJohn Forte 	}
139291a2b48SSukumar Swaminathan 
140fcf3ce44SJohn Forte 	/* Process the pkt */
141fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
142fcf3ce44SJohn Forte 
143fcf3ce44SJohn Forte 	/* Check for immediate return */
144fcf3ce44SJohn Forte 	if ((iostat == IOSTAT_SUCCESS) &&
145fcf3ce44SJohn Forte 	    (pkt->pkt_comp) &&
146291a2b48SSukumar Swaminathan 	    !(sbp->pkt_flags &
14782527734SSukumar Swaminathan 	    (PACKET_ULP_OWNED | PACKET_COMPLETED |
148fcf3ce44SJohn Forte 	    PACKET_IN_COMPLETION | PACKET_IN_TXQ | PACKET_IN_CHIPQ |
149fcf3ce44SJohn Forte 	    PACKET_IN_DONEQ | PACKET_IN_TIMEOUT | PACKET_IN_FLUSH |
150fcf3ce44SJohn Forte 	    PACKET_IN_ABORT | PACKET_POLLED))) {
151fcf3ce44SJohn Forte 		HBASTATS.FcpGood++;
152fcf3ce44SJohn Forte 
153291a2b48SSukumar Swaminathan 		sbp->pkt_flags |=
154291a2b48SSukumar Swaminathan 		    (PACKET_STATE_VALID | PACKET_IN_COMPLETION |
15582527734SSukumar Swaminathan 		    PACKET_COMPLETED | PACKET_ULP_OWNED);
156fcf3ce44SJohn Forte 		mutex_exit(&sbp->mtx);
157fcf3ce44SJohn Forte 
158fcf3ce44SJohn Forte #if (EMLXS_MODREVX == EMLXS_MODREV2X)
159fcf3ce44SJohn Forte 		emlxs_unswap_pkt(sbp);
160291a2b48SSukumar Swaminathan #endif /* EMLXS_MODREV2X */
161b3660a96SSukumar Swaminathan 
162b3660a96SSukumar Swaminathan #ifdef FMA_SUPPORT
163b3660a96SSukumar Swaminathan 		emlxs_check_dma(hba, sbp);
164b3660a96SSukumar Swaminathan #endif  /* FMA_SUPPORT */
165b3660a96SSukumar Swaminathan 
16682527734SSukumar Swaminathan 		cp->ulpCmplCmd++;
167fcf3ce44SJohn Forte 		(*pkt->pkt_comp) (pkt);
168fcf3ce44SJohn Forte 
169b3660a96SSukumar Swaminathan #ifdef FMA_SUPPORT
170b3660a96SSukumar Swaminathan 		if (hba->flag & FC_DMA_CHECK_ERROR) {
171b3660a96SSukumar Swaminathan 			emlxs_thread_spawn(hba, emlxs_restart_thread,
172b3660a96SSukumar Swaminathan 			    NULL, NULL);
173b3660a96SSukumar Swaminathan 		}
174b3660a96SSukumar Swaminathan #endif  /* FMA_SUPPORT */
175b3660a96SSukumar Swaminathan 
176fcf3ce44SJohn Forte 		return;
177fcf3ce44SJohn Forte 	}
178291a2b48SSukumar Swaminathan 
179fcf3ce44SJohn Forte 	/*
180291a2b48SSukumar Swaminathan 	 * A response is only placed in the resp buffer if IOSTAT_FCP_RSP_ERROR
181291a2b48SSukumar Swaminathan 	 * is reported.
182fcf3ce44SJohn Forte 	 */
183fcf3ce44SJohn Forte 
184*8f23e9faSHans Rosenfeld 	/* Check if a response buffer was not provided */
185*8f23e9faSHans Rosenfeld 	if ((iostat != IOSTAT_FCP_RSP_ERROR) || (pkt->pkt_rsplen == 0)) {
186*8f23e9faSHans Rosenfeld 		goto done;
187*8f23e9faSHans Rosenfeld 	}
188*8f23e9faSHans Rosenfeld 
189*8f23e9faSHans Rosenfeld 	EMLXS_MPDATA_SYNC(pkt->pkt_resp_dma, 0, pkt->pkt_rsplen,
190*8f23e9faSHans Rosenfeld 	    DDI_DMA_SYNC_FORKERNEL);
191*8f23e9faSHans Rosenfeld 
192*8f23e9faSHans Rosenfeld 	/* Get the response buffer pointer */
193*8f23e9faSHans Rosenfeld 	rsp = (fcp_rsp_t *)pkt->pkt_resp;
194*8f23e9faSHans Rosenfeld 
195*8f23e9faSHans Rosenfeld 	/* Validate the response payload */
196*8f23e9faSHans Rosenfeld 	if (!rsp->fcp_u.fcp_status.resid_under &&
197*8f23e9faSHans Rosenfeld 	    !rsp->fcp_u.fcp_status.resid_over) {
198*8f23e9faSHans Rosenfeld 		rsp->fcp_resid = 0;
199*8f23e9faSHans Rosenfeld 	}
200*8f23e9faSHans Rosenfeld 
201*8f23e9faSHans Rosenfeld 	if (!rsp->fcp_u.fcp_status.rsp_len_set) {
202*8f23e9faSHans Rosenfeld 		rsp->fcp_response_len = 0;
203*8f23e9faSHans Rosenfeld 	}
204fcf3ce44SJohn Forte 
205*8f23e9faSHans Rosenfeld 	if (!rsp->fcp_u.fcp_status.sense_len_set) {
206*8f23e9faSHans Rosenfeld 		rsp->fcp_sense_len = 0;
207*8f23e9faSHans Rosenfeld 	}
208*8f23e9faSHans Rosenfeld 
209*8f23e9faSHans Rosenfeld 	length = sizeof (fcp_rsp_t) + LE_SWAP32(rsp->fcp_response_len) +
210*8f23e9faSHans Rosenfeld 	    LE_SWAP32(rsp->fcp_sense_len);
211*8f23e9faSHans Rosenfeld 
212*8f23e9faSHans Rosenfeld 	if (length > pkt->pkt_rsplen) {
213*8f23e9faSHans Rosenfeld 		iostat = IOSTAT_RSP_INVALID;
214*8f23e9faSHans Rosenfeld 		pkt->pkt_data_resid = pkt->pkt_datalen;
215*8f23e9faSHans Rosenfeld 		goto done;
216*8f23e9faSHans Rosenfeld 	}
217fcf3ce44SJohn Forte 
218*8f23e9faSHans Rosenfeld 	/* Set the valid response flag */
219*8f23e9faSHans Rosenfeld 	sbp->pkt_flags |= PACKET_FCP_RSP_VALID;
220fcf3ce44SJohn Forte 
221*8f23e9faSHans Rosenfeld 	scsi_status = rsp->fcp_u.fcp_status.scsi_status;
222fcf3ce44SJohn Forte 
223291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
224*8f23e9faSHans Rosenfeld 	ndlp = (NODELIST *)iocbq->node;
225*8f23e9faSHans Rosenfeld 	if (scsi_status == SCSI_STAT_QUE_FULL) {
226*8f23e9faSHans Rosenfeld 		emlxs_log_sd_scsi_event(port, SD_SCSI_SUBCATEGORY_QFULL,
227*8f23e9faSHans Rosenfeld 		    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun);
228*8f23e9faSHans Rosenfeld 	} else if (scsi_status == SCSI_STAT_BUSY) {
229*8f23e9faSHans Rosenfeld 		emlxs_log_sd_scsi_event(port,
230*8f23e9faSHans Rosenfeld 		    SD_SCSI_SUBCATEGORY_DEVBSY,
231*8f23e9faSHans Rosenfeld 		    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun);
232*8f23e9faSHans Rosenfeld 	}
233291a2b48SSukumar Swaminathan #endif
234291a2b48SSukumar Swaminathan 
235*8f23e9faSHans Rosenfeld 	/*
236*8f23e9faSHans Rosenfeld 	 * Convert a task abort to a check condition with no data
237*8f23e9faSHans Rosenfeld 	 * transferred. We saw a data corruption when Solaris received
238*8f23e9faSHans Rosenfeld 	 * a Task Abort from a tape.
239*8f23e9faSHans Rosenfeld 	 */
240a9800bebSGarrett D'Amore 
241*8f23e9faSHans Rosenfeld 	if (scsi_status == SCSI_STAT_TASK_ABORT) {
242*8f23e9faSHans Rosenfeld 		EMLXS_MSGF(EMLXS_CONTEXT,
243*8f23e9faSHans Rosenfeld 		    &emlxs_fcp_completion_error_msg,
244*8f23e9faSHans Rosenfeld 		    "Task Abort. "
245*8f23e9faSHans Rosenfeld 		    "Fixed. did=0x%06x sbp=%p cmd=%02x dl=%d",
246*8f23e9faSHans Rosenfeld 		    did, sbp, scsi_opcode, pkt->pkt_datalen);
247*8f23e9faSHans Rosenfeld 
248*8f23e9faSHans Rosenfeld 		rsp->fcp_u.fcp_status.scsi_status =
249*8f23e9faSHans Rosenfeld 		    SCSI_STAT_CHECK_COND;
250*8f23e9faSHans Rosenfeld 		rsp->fcp_u.fcp_status.rsp_len_set = 0;
251*8f23e9faSHans Rosenfeld 		rsp->fcp_u.fcp_status.sense_len_set = 0;
252*8f23e9faSHans Rosenfeld 		rsp->fcp_u.fcp_status.resid_over = 0;
253*8f23e9faSHans Rosenfeld 
254*8f23e9faSHans Rosenfeld 		if (pkt->pkt_datalen) {
255*8f23e9faSHans Rosenfeld 			rsp->fcp_u.fcp_status.resid_under = 1;
256*8f23e9faSHans Rosenfeld 			rsp->fcp_resid =
257*8f23e9faSHans Rosenfeld 			    LE_SWAP32(pkt->pkt_datalen);
258*8f23e9faSHans Rosenfeld 		} else {
259*8f23e9faSHans Rosenfeld 			rsp->fcp_u.fcp_status.resid_under = 0;
260*8f23e9faSHans Rosenfeld 			rsp->fcp_resid = 0;
261*8f23e9faSHans Rosenfeld 		}
262fcf3ce44SJohn Forte 
263*8f23e9faSHans Rosenfeld 		scsi_status = SCSI_STAT_CHECK_COND;
264*8f23e9faSHans Rosenfeld 	}
265fcf3ce44SJohn Forte 
266*8f23e9faSHans Rosenfeld 	/*
267*8f23e9faSHans Rosenfeld 	 * We only need to check underrun if data could
268*8f23e9faSHans Rosenfeld 	 * have been sent
269*8f23e9faSHans Rosenfeld 	 */
270fcf3ce44SJohn Forte 
271*8f23e9faSHans Rosenfeld 	/* Always check underrun if status is good */
272*8f23e9faSHans Rosenfeld 	if (scsi_status == SCSI_STAT_GOOD) {
273*8f23e9faSHans Rosenfeld 		check_underrun = 1;
274*8f23e9faSHans Rosenfeld 	}
275*8f23e9faSHans Rosenfeld 	/* Check the sense codes if this is a check condition */
276*8f23e9faSHans Rosenfeld 	else if (scsi_status == SCSI_STAT_CHECK_COND) {
277*8f23e9faSHans Rosenfeld 		check_underrun = 1;
278*8f23e9faSHans Rosenfeld 
279*8f23e9faSHans Rosenfeld 		/* Check if sense data was provided */
280*8f23e9faSHans Rosenfeld 		if (LE_SWAP32(rsp->fcp_sense_len) >= 14) {
281*8f23e9faSHans Rosenfeld 			sense = *((uint8_t *)rsp + 32 + 2);
282*8f23e9faSHans Rosenfeld 			asc = *((uint8_t *)rsp + 32 + 12);
283*8f23e9faSHans Rosenfeld 			ascq = *((uint8_t *)rsp + 32 + 13);
284fcf3ce44SJohn Forte 		}
285291a2b48SSukumar Swaminathan 
286*8f23e9faSHans Rosenfeld #ifdef SAN_DIAG_SUPPORT
287*8f23e9faSHans Rosenfeld 		emlxs_log_sd_scsi_check_event(port,
288*8f23e9faSHans Rosenfeld 		    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun,
289*8f23e9faSHans Rosenfeld 		    scsi_opcode, sense, asc, ascq);
290*8f23e9faSHans Rosenfeld #endif
291*8f23e9faSHans Rosenfeld 	}
292*8f23e9faSHans Rosenfeld 	/* Status is not good and this is not a check condition */
293*8f23e9faSHans Rosenfeld 	/* No data should have been sent */
294*8f23e9faSHans Rosenfeld 	else {
295*8f23e9faSHans Rosenfeld 		check_underrun = 0;
296*8f23e9faSHans Rosenfeld 	}
297*8f23e9faSHans Rosenfeld 
298*8f23e9faSHans Rosenfeld 	/* Initialize the resids */
299*8f23e9faSHans Rosenfeld 	pkt->pkt_resp_resid = 0;
300*8f23e9faSHans Rosenfeld 	pkt->pkt_data_resid = 0;
301*8f23e9faSHans Rosenfeld 
302*8f23e9faSHans Rosenfeld 	/* Check if no data was to be transferred */
303*8f23e9faSHans Rosenfeld 	if (pkt->pkt_datalen == 0) {
304*8f23e9faSHans Rosenfeld 		goto done;
305*8f23e9faSHans Rosenfeld 	}
306*8f23e9faSHans Rosenfeld 
307*8f23e9faSHans Rosenfeld 	/* Get the residual underrun count reported by the SCSI reply */
308*8f23e9faSHans Rosenfeld 	rsp_data_resid = (rsp->fcp_u.fcp_status.resid_under) ?
309*8f23e9faSHans Rosenfeld 	    LE_SWAP32(rsp->fcp_resid) : 0;
310*8f23e9faSHans Rosenfeld 
311*8f23e9faSHans Rosenfeld 	/* Set the pkt_data_resid to what the scsi response resid */
312*8f23e9faSHans Rosenfeld 	pkt->pkt_data_resid = rsp_data_resid;
313*8f23e9faSHans Rosenfeld 
314*8f23e9faSHans Rosenfeld 	/* Adjust the pkt_data_resid field if needed */
315*8f23e9faSHans Rosenfeld 	if (pkt->pkt_tran_type == FC_PKT_FCP_READ) {
316fcf3ce44SJohn Forte 		/*
317*8f23e9faSHans Rosenfeld 		 * Get the residual underrun count reported by
318*8f23e9faSHans Rosenfeld 		 * our adapter
319fcf3ce44SJohn Forte 		 */
320*8f23e9faSHans Rosenfeld 		pkt->pkt_data_resid = cmd->un.fcpi.fcpi_parm;
321291a2b48SSukumar Swaminathan 
322291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
323*8f23e9faSHans Rosenfeld 		if ((rsp_data_resid == 0) && (pkt->pkt_data_resid)) {
324*8f23e9faSHans Rosenfeld 			emlxs_log_sd_fc_rdchk_event(port,
325291a2b48SSukumar Swaminathan 			    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun,
326*8f23e9faSHans Rosenfeld 			    scsi_opcode, pkt->pkt_data_resid);
327fcf3ce44SJohn Forte 		}
328*8f23e9faSHans Rosenfeld #endif
329*8f23e9faSHans Rosenfeld 
330*8f23e9faSHans Rosenfeld 		/* Get the actual amount of data transferred */
331*8f23e9faSHans Rosenfeld 		data_rx = pkt->pkt_datalen - pkt->pkt_data_resid;
332fcf3ce44SJohn Forte 
333*8f23e9faSHans Rosenfeld 		/*
334*8f23e9faSHans Rosenfeld 		 * If the residual being reported by the adapter is
335*8f23e9faSHans Rosenfeld 		 * greater than the residual being reported in the
336*8f23e9faSHans Rosenfeld 		 * reply, then we have a true underrun.
337*8f23e9faSHans Rosenfeld 		 */
338*8f23e9faSHans Rosenfeld 		if (check_underrun && (pkt->pkt_data_resid > rsp_data_resid)) {
339*8f23e9faSHans Rosenfeld 			switch (scsi_opcode) {
340*8f23e9faSHans Rosenfeld 			case SCSI_INQUIRY:
341*8f23e9faSHans Rosenfeld 				scsi_dl = scsi_cmd[16];
342*8f23e9faSHans Rosenfeld 				break;
343*8f23e9faSHans Rosenfeld 
344*8f23e9faSHans Rosenfeld 			case SCSI_RX_DIAG:
345*8f23e9faSHans Rosenfeld 				scsi_dl =
346*8f23e9faSHans Rosenfeld 				    (scsi_cmd[15] * 0x100) +
347*8f23e9faSHans Rosenfeld 				    scsi_cmd[16];
348*8f23e9faSHans Rosenfeld 				break;
349fcf3ce44SJohn Forte 
350*8f23e9faSHans Rosenfeld 			default:
351*8f23e9faSHans Rosenfeld 				scsi_dl = pkt->pkt_datalen;
352*8f23e9faSHans Rosenfeld 			}
353fcf3ce44SJohn Forte 
354*8f23e9faSHans Rosenfeld #ifdef FCP_UNDERRUN_PATCH1
355*8f23e9faSHans Rosenfeld if (cfg[CFG_ENABLE_PATCH].current & FCP_UNDERRUN_PATCH1) {
356fcf3ce44SJohn Forte 			/*
357*8f23e9faSHans Rosenfeld 			 * If status is not good and no data was
358*8f23e9faSHans Rosenfeld 			 * actually transferred, then we must fix
359*8f23e9faSHans Rosenfeld 			 * the issue
360fcf3ce44SJohn Forte 			 */
361*8f23e9faSHans Rosenfeld 			if ((scsi_status != SCSI_STAT_GOOD) && (data_rx == 0)) {
362*8f23e9faSHans Rosenfeld 				fix_it = 1;
363*8f23e9faSHans Rosenfeld 
364*8f23e9faSHans Rosenfeld 				EMLXS_MSGF(EMLXS_CONTEXT,
365*8f23e9faSHans Rosenfeld 				    &emlxs_fcp_completion_error_msg,
366*8f23e9faSHans Rosenfeld 				    "Underrun(1). Fixed. "
367*8f23e9faSHans Rosenfeld 				    "did=0x%06x sbp=%p cmd=%02x "
368*8f23e9faSHans Rosenfeld 				    "dl=%d,%d rx=%d rsp=%d",
369*8f23e9faSHans Rosenfeld 				    did, sbp, scsi_opcode,
370*8f23e9faSHans Rosenfeld 				    pkt->pkt_datalen, scsi_dl,
371*8f23e9faSHans Rosenfeld 				    (pkt->pkt_datalen -
372*8f23e9faSHans Rosenfeld 				    pkt->pkt_data_resid),
373*8f23e9faSHans Rosenfeld 				    rsp_data_resid);
374fcf3ce44SJohn Forte 
375291a2b48SSukumar Swaminathan 			}
376*8f23e9faSHans Rosenfeld }
377*8f23e9faSHans Rosenfeld #endif /* FCP_UNDERRUN_PATCH1 */
378291a2b48SSukumar Swaminathan 
379fcf3ce44SJohn Forte 
380*8f23e9faSHans Rosenfeld #ifdef FCP_UNDERRUN_PATCH2
381*8f23e9faSHans Rosenfeld if (cfg[CFG_ENABLE_PATCH].current & FCP_UNDERRUN_PATCH2) {
382*8f23e9faSHans Rosenfeld 			if (scsi_status == SCSI_STAT_GOOD) {
383*8f23e9faSHans Rosenfeld 				emlxs_msg_t	*msg;
384fcf3ce44SJohn Forte 
385*8f23e9faSHans Rosenfeld 				msg = &emlxs_fcp_completion_error_msg;
386*8f23e9faSHans Rosenfeld 				/*
387*8f23e9faSHans Rosenfeld 				 * If status is good and this is an
388*8f23e9faSHans Rosenfeld 				 * inquiry request and the amount of
389*8f23e9faSHans Rosenfeld 				 * data
390*8f23e9faSHans Rosenfeld 				 */
391*8f23e9faSHans Rosenfeld 				/*
392*8f23e9faSHans Rosenfeld 				 * requested <= data received, then we
393*8f23e9faSHans Rosenfeld 				 * must fix the issue.
394*8f23e9faSHans Rosenfeld 				 */
395*8f23e9faSHans Rosenfeld 
396*8f23e9faSHans Rosenfeld 				if ((scsi_opcode == SCSI_INQUIRY) &&
397*8f23e9faSHans Rosenfeld 				    (pkt->pkt_datalen >= data_rx) &&
398*8f23e9faSHans Rosenfeld 				    (scsi_dl <= data_rx)) {
399*8f23e9faSHans Rosenfeld 					fix_it = 1;
400*8f23e9faSHans Rosenfeld 
401*8f23e9faSHans Rosenfeld 					EMLXS_MSGF(EMLXS_CONTEXT, msg,
402*8f23e9faSHans Rosenfeld 					    "Underrun(2). Fixed. "
403*8f23e9faSHans Rosenfeld 					    "did=0x%06x sbp=%p "
404*8f23e9faSHans Rosenfeld 					    "cmd=%02x dl=%d,%d "
405*8f23e9faSHans Rosenfeld 					    "rx=%d rsp=%d",
406*8f23e9faSHans Rosenfeld 					    did, sbp, scsi_opcode,
407*8f23e9faSHans Rosenfeld 					    pkt->pkt_datalen, scsi_dl,
408*8f23e9faSHans Rosenfeld 					    data_rx, rsp_data_resid);
409fcf3ce44SJohn Forte 
410fcf3ce44SJohn Forte 				}
411fcf3ce44SJohn Forte 
412fcf3ce44SJohn Forte 				/*
413*8f23e9faSHans Rosenfeld 				 * If status is good and this is an
414*8f23e9faSHans Rosenfeld 				 * inquiry request and the amount of
415*8f23e9faSHans Rosenfeld 				 * data requested >= 128 bytes, but
416*8f23e9faSHans Rosenfeld 				 * only 128 bytes were received,
417*8f23e9faSHans Rosenfeld 				 * then we must fix the issue.
418fcf3ce44SJohn Forte 				 */
419*8f23e9faSHans Rosenfeld 				else if ((scsi_opcode == SCSI_INQUIRY) &&
420*8f23e9faSHans Rosenfeld 				    (pkt->pkt_datalen >= 128) &&
421*8f23e9faSHans Rosenfeld 				    (scsi_dl >= 128) && (data_rx == 128)) {
422fcf3ce44SJohn Forte 					fix_it = 1;
423fcf3ce44SJohn Forte 
424*8f23e9faSHans Rosenfeld 					EMLXS_MSGF(EMLXS_CONTEXT, msg,
425*8f23e9faSHans Rosenfeld 					    "Underrun(3). Fixed. "
426*8f23e9faSHans Rosenfeld 					    "did=0x%06x sbp=%p "
427*8f23e9faSHans Rosenfeld 					    "cmd=%02x dl=%d,%d "
428*8f23e9faSHans Rosenfeld 					    "rx=%d rsp=%d",
429fcf3ce44SJohn Forte 					    did, sbp, scsi_opcode,
430fcf3ce44SJohn Forte 					    pkt->pkt_datalen, scsi_dl,
431*8f23e9faSHans Rosenfeld 					    data_rx, rsp_data_resid);
432fcf3ce44SJohn Forte 
433fcf3ce44SJohn Forte 				}
434*8f23e9faSHans Rosenfeld 			}
43582527734SSukumar Swaminathan }
436*8f23e9faSHans Rosenfeld #endif /* FCP_UNDERRUN_PATCH2 */
437fcf3ce44SJohn Forte 
438*8f23e9faSHans Rosenfeld 			/*
439*8f23e9faSHans Rosenfeld 			 * Check if SCSI response payload should be
440*8f23e9faSHans Rosenfeld 			 * fixed or if a DATA_UNDERRUN should be
441*8f23e9faSHans Rosenfeld 			 * reported
442*8f23e9faSHans Rosenfeld 			 */
443*8f23e9faSHans Rosenfeld 			if (fix_it) {
444*8f23e9faSHans Rosenfeld 				/*
445*8f23e9faSHans Rosenfeld 				 * Fix the SCSI response payload itself
446*8f23e9faSHans Rosenfeld 				 */
447*8f23e9faSHans Rosenfeld 				rsp->fcp_u.fcp_status.resid_under = 1;
448*8f23e9faSHans Rosenfeld 				rsp->fcp_resid =
449*8f23e9faSHans Rosenfeld 				    LE_SWAP32(pkt->pkt_data_resid);
450*8f23e9faSHans Rosenfeld 			} else {
451*8f23e9faSHans Rosenfeld 				/*
452*8f23e9faSHans Rosenfeld 				 * Change the status from
453*8f23e9faSHans Rosenfeld 				 * IOSTAT_FCP_RSP_ERROR to
454*8f23e9faSHans Rosenfeld 				 * IOSTAT_DATA_UNDERRUN
455*8f23e9faSHans Rosenfeld 				 */
456*8f23e9faSHans Rosenfeld 				iostat = IOSTAT_DATA_UNDERRUN;
457*8f23e9faSHans Rosenfeld 				pkt->pkt_data_resid =
458*8f23e9faSHans Rosenfeld 				    pkt->pkt_datalen;
459*8f23e9faSHans Rosenfeld 			}
460*8f23e9faSHans Rosenfeld 		}
461fcf3ce44SJohn Forte 
462*8f23e9faSHans Rosenfeld 		/*
463*8f23e9faSHans Rosenfeld 		 * If the residual being reported by the adapter is
464*8f23e9faSHans Rosenfeld 		 * less than the residual being reported in the reply,
465*8f23e9faSHans Rosenfeld 		 * then we have a true overrun. Since we don't know
466*8f23e9faSHans Rosenfeld 		 * where the extra data came from or went to then we
467*8f23e9faSHans Rosenfeld 		 * cannot trust anything we received
468*8f23e9faSHans Rosenfeld 		 */
469*8f23e9faSHans Rosenfeld 		else if (rsp_data_resid > pkt->pkt_data_resid) {
470*8f23e9faSHans Rosenfeld 			/*
471*8f23e9faSHans Rosenfeld 			 * Change the status from
472*8f23e9faSHans Rosenfeld 			 * IOSTAT_FCP_RSP_ERROR to
473*8f23e9faSHans Rosenfeld 			 * IOSTAT_DATA_OVERRUN
474*8f23e9faSHans Rosenfeld 			 */
475*8f23e9faSHans Rosenfeld 			iostat = IOSTAT_DATA_OVERRUN;
476*8f23e9faSHans Rosenfeld 			pkt->pkt_data_resid = pkt->pkt_datalen;
477*8f23e9faSHans Rosenfeld 		}
478fcf3ce44SJohn Forte 
479*8f23e9faSHans Rosenfeld 	} else if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) &&
480*8f23e9faSHans Rosenfeld 	    (pkt->pkt_tran_type == FC_PKT_FCP_WRITE)) {
481*8f23e9faSHans Rosenfeld 		/*
482*8f23e9faSHans Rosenfeld 		 * Get the residual underrun count reported by
483*8f23e9faSHans Rosenfeld 		 * our adapter
484*8f23e9faSHans Rosenfeld 		 */
485*8f23e9faSHans Rosenfeld 		pkt->pkt_data_resid = cmd->un.fcpi.fcpi_parm;
486fcf3ce44SJohn Forte 
487*8f23e9faSHans Rosenfeld #ifdef SAN_DIAG_SUPPORT
488*8f23e9faSHans Rosenfeld 		if ((rsp_data_resid == 0) && (pkt->pkt_data_resid)) {
489*8f23e9faSHans Rosenfeld 			emlxs_log_sd_fc_rdchk_event(port,
490*8f23e9faSHans Rosenfeld 			    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun,
491*8f23e9faSHans Rosenfeld 			    scsi_opcode, pkt->pkt_data_resid);
492*8f23e9faSHans Rosenfeld 		}
493*8f23e9faSHans Rosenfeld #endif /* SAN_DIAG_SUPPORT */
494fcf3ce44SJohn Forte 
495*8f23e9faSHans Rosenfeld 		/* Get the actual amount of data transferred */
496*8f23e9faSHans Rosenfeld 		data_rx = pkt->pkt_datalen - pkt->pkt_data_resid;
497fcf3ce44SJohn Forte 
498*8f23e9faSHans Rosenfeld 		/*
499*8f23e9faSHans Rosenfeld 		 * If the residual being reported by the adapter is
500*8f23e9faSHans Rosenfeld 		 * greater than the residual being reported in the
501*8f23e9faSHans Rosenfeld 		 * reply, then we have a true underrun.
502*8f23e9faSHans Rosenfeld 		 */
503*8f23e9faSHans Rosenfeld 		if (check_underrun && (pkt->pkt_data_resid > rsp_data_resid)) {
504291a2b48SSukumar Swaminathan 
505*8f23e9faSHans Rosenfeld 			scsi_dl = pkt->pkt_datalen;
506fcf3ce44SJohn Forte 
507*8f23e9faSHans Rosenfeld #ifdef FCP_UNDERRUN_PATCH1
508*8f23e9faSHans Rosenfeld if (cfg[CFG_ENABLE_PATCH].current & FCP_UNDERRUN_PATCH1) {
509*8f23e9faSHans Rosenfeld 			/*
510*8f23e9faSHans Rosenfeld 			 * If status is not good and no data was
511*8f23e9faSHans Rosenfeld 			 * actually transferred, then we must fix
512*8f23e9faSHans Rosenfeld 			 * the issue
513*8f23e9faSHans Rosenfeld 			 */
514*8f23e9faSHans Rosenfeld 			if ((scsi_status != SCSI_STAT_GOOD) && (data_rx == 0)) {
515*8f23e9faSHans Rosenfeld 				fix_it = 1;
516291a2b48SSukumar Swaminathan 
517*8f23e9faSHans Rosenfeld 				EMLXS_MSGF(EMLXS_CONTEXT,
518*8f23e9faSHans Rosenfeld 				    &emlxs_fcp_completion_error_msg,
519*8f23e9faSHans Rosenfeld 				    "Underrun(1). Fixed. "
520*8f23e9faSHans Rosenfeld 				    "did=0x%06x sbp=%p cmd=%02x "
521*8f23e9faSHans Rosenfeld 				    "dl=%d,%d rx=%d rsp=%d",
522*8f23e9faSHans Rosenfeld 				    did, sbp, scsi_opcode,
523*8f23e9faSHans Rosenfeld 				    pkt->pkt_datalen, scsi_dl,
524*8f23e9faSHans Rosenfeld 				    (pkt->pkt_datalen -
525*8f23e9faSHans Rosenfeld 				    pkt->pkt_data_resid),
526*8f23e9faSHans Rosenfeld 				    rsp_data_resid);
527fcf3ce44SJohn Forte 
528fcf3ce44SJohn Forte 			}
529*8f23e9faSHans Rosenfeld }
530*8f23e9faSHans Rosenfeld #endif /* FCP_UNDERRUN_PATCH1 */
531291a2b48SSukumar Swaminathan 
532fcf3ce44SJohn Forte 			/*
533*8f23e9faSHans Rosenfeld 			 * Check if SCSI response payload should be
534*8f23e9faSHans Rosenfeld 			 * fixed or if a DATA_UNDERRUN should be
535*8f23e9faSHans Rosenfeld 			 * reported
536fcf3ce44SJohn Forte 			 */
537*8f23e9faSHans Rosenfeld 			if (fix_it) {
538*8f23e9faSHans Rosenfeld 				/*
539*8f23e9faSHans Rosenfeld 				 * Fix the SCSI response payload itself
540*8f23e9faSHans Rosenfeld 				 */
541*8f23e9faSHans Rosenfeld 				rsp->fcp_u.fcp_status.resid_under = 1;
542*8f23e9faSHans Rosenfeld 				rsp->fcp_resid =
543*8f23e9faSHans Rosenfeld 				    LE_SWAP32(pkt->pkt_data_resid);
544*8f23e9faSHans Rosenfeld 			} else {
545fcf3ce44SJohn Forte 				/*
546fcf3ce44SJohn Forte 				 * Change the status from
547fcf3ce44SJohn Forte 				 * IOSTAT_FCP_RSP_ERROR to
548*8f23e9faSHans Rosenfeld 				 * IOSTAT_DATA_UNDERRUN
549fcf3ce44SJohn Forte 				 */
550*8f23e9faSHans Rosenfeld 				iostat = IOSTAT_DATA_UNDERRUN;
551*8f23e9faSHans Rosenfeld 				pkt->pkt_data_resid =
552*8f23e9faSHans Rosenfeld 				    pkt->pkt_datalen;
553fcf3ce44SJohn Forte 			}
554*8f23e9faSHans Rosenfeld 		}
555291a2b48SSukumar Swaminathan 
556*8f23e9faSHans Rosenfeld 		/*
557*8f23e9faSHans Rosenfeld 		 * If the residual being reported by the adapter is
558*8f23e9faSHans Rosenfeld 		 * less than the residual being reported in the reply,
559*8f23e9faSHans Rosenfeld 		 * then we have a true overrun. Since we don't know
560*8f23e9faSHans Rosenfeld 		 * where the extra data came from or went to then we
561*8f23e9faSHans Rosenfeld 		 * cannot trust anything we received
562*8f23e9faSHans Rosenfeld 		 */
563*8f23e9faSHans Rosenfeld 		else if (rsp_data_resid > pkt->pkt_data_resid) {
564*8f23e9faSHans Rosenfeld 			/*
565*8f23e9faSHans Rosenfeld 			 * Change the status from
566*8f23e9faSHans Rosenfeld 			 * IOSTAT_FCP_RSP_ERROR to
567*8f23e9faSHans Rosenfeld 			 * IOSTAT_DATA_OVERRUN
568*8f23e9faSHans Rosenfeld 			 */
569*8f23e9faSHans Rosenfeld 			iostat = IOSTAT_DATA_OVERRUN;
570*8f23e9faSHans Rosenfeld 			pkt->pkt_data_resid = pkt->pkt_datalen;
571fcf3ce44SJohn Forte 		}
572fcf3ce44SJohn Forte 	}
573291a2b48SSukumar Swaminathan 
574*8f23e9faSHans Rosenfeld done:
575*8f23e9faSHans Rosenfeld 
576fcf3ce44SJohn Forte 	/* Print completion message */
577fcf3ce44SJohn Forte 	switch (iostat) {
578fcf3ce44SJohn Forte 	case IOSTAT_SUCCESS:
579fcf3ce44SJohn Forte 		/* Build SCSI GOOD status */
580fcf3ce44SJohn Forte 		if (pkt->pkt_rsplen) {
581fcf3ce44SJohn Forte 			bzero((uint8_t *)pkt->pkt_resp, pkt->pkt_rsplen);
582fcf3ce44SJohn Forte 		}
583fcf3ce44SJohn Forte 		break;
584fcf3ce44SJohn Forte 
585fcf3ce44SJohn Forte 	case IOSTAT_FCP_RSP_ERROR:
586fcf3ce44SJohn Forte 		break;
587fcf3ce44SJohn Forte 
588fcf3ce44SJohn Forte 	case IOSTAT_REMOTE_STOP:
589fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
590291a2b48SSukumar Swaminathan 		    "Remote Stop. did=0x%06x sbp=%p cmd=%02x", did, sbp,
591291a2b48SSukumar Swaminathan 		    scsi_opcode);
592fcf3ce44SJohn Forte 		break;
593fcf3ce44SJohn Forte 
594fcf3ce44SJohn Forte 	case IOSTAT_LOCAL_REJECT:
595fcf3ce44SJohn Forte 		localstat = cmd->un.grsp.perr.statLocalError;
596fcf3ce44SJohn Forte 
597fcf3ce44SJohn Forte 		switch (localstat) {
598fcf3ce44SJohn Forte 		case IOERR_SEQUENCE_TIMEOUT:
599fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT,
600fcf3ce44SJohn Forte 			    &emlxs_fcp_completion_error_msg,
601291a2b48SSukumar Swaminathan 			    "Local reject. "
602291a2b48SSukumar Swaminathan 			    "%s did=0x%06x sbp=%p cmd=%02x tmo=%d ",
603fcf3ce44SJohn Forte 			    emlxs_error_xlate(localstat), did, sbp,
604fcf3ce44SJohn Forte 			    scsi_opcode, pkt->pkt_timeout);
605fcf3ce44SJohn Forte 			break;
606fcf3ce44SJohn Forte 
607fcf3ce44SJohn Forte 		default:
608fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT,
609fcf3ce44SJohn Forte 			    &emlxs_fcp_completion_error_msg,
610a9800bebSGarrett D'Amore 			    "Local reject. %s 0x%06x %p %02x (%x)(%x)",
611291a2b48SSukumar Swaminathan 			    emlxs_error_xlate(localstat), did, sbp,
612a9800bebSGarrett D'Amore 			    scsi_opcode, (uint16_t)cmd->ULPIOTAG,
613a9800bebSGarrett D'Amore 			    (uint16_t)cmd->ULPCONTEXT);
614fcf3ce44SJohn Forte 		}
615fcf3ce44SJohn Forte 
616fcf3ce44SJohn Forte 		break;
617fcf3ce44SJohn Forte 
618fcf3ce44SJohn Forte 	case IOSTAT_NPORT_RJT:
619fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
620291a2b48SSukumar Swaminathan 		    "Nport reject. did=0x%06x sbp=%p cmd=%02x", did, sbp,
621291a2b48SSukumar Swaminathan 		    scsi_opcode);
622fcf3ce44SJohn Forte 		break;
623fcf3ce44SJohn Forte 
624fcf3ce44SJohn Forte 	case IOSTAT_FABRIC_RJT:
625fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
626291a2b48SSukumar Swaminathan 		    "Fabric reject. did=0x%06x sbp=%p cmd=%02x", did, sbp,
627291a2b48SSukumar Swaminathan 		    scsi_opcode);
628fcf3ce44SJohn Forte 		break;
629fcf3ce44SJohn Forte 
630fcf3ce44SJohn Forte 	case IOSTAT_NPORT_BSY:
631291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
632291a2b48SSukumar Swaminathan 		ndlp = (NODELIST *)iocbq->node;
633291a2b48SSukumar Swaminathan 		emlxs_log_sd_fc_bsy_event(port, (HBA_WWN *)&ndlp->nlp_portname);
634291a2b48SSukumar Swaminathan #endif
635291a2b48SSukumar Swaminathan 
636fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
637291a2b48SSukumar Swaminathan 		    "Nport busy. did=0x%06x sbp=%p cmd=%02x", did, sbp,
638291a2b48SSukumar Swaminathan 		    scsi_opcode);
639fcf3ce44SJohn Forte 		break;
640fcf3ce44SJohn Forte 
641fcf3ce44SJohn Forte 	case IOSTAT_FABRIC_BSY:
642291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
643291a2b48SSukumar Swaminathan 		ndlp = (NODELIST *)iocbq->node;
644291a2b48SSukumar Swaminathan 		emlxs_log_sd_fc_bsy_event(port, NULL);
645291a2b48SSukumar Swaminathan #endif
646291a2b48SSukumar Swaminathan 
647fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
648291a2b48SSukumar Swaminathan 		    "Fabric busy. did=0x%06x sbp=%p cmd=%02x", did, sbp,
649291a2b48SSukumar Swaminathan 		    scsi_opcode);
650fcf3ce44SJohn Forte 		break;
651fcf3ce44SJohn Forte 
652fcf3ce44SJohn Forte 	case IOSTAT_INTERMED_RSP:
653fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
654291a2b48SSukumar Swaminathan 		    "Intermediate response. did=0x%06x sbp=%p cmd=%02x", did,
655291a2b48SSukumar Swaminathan 		    sbp, scsi_opcode);
656fcf3ce44SJohn Forte 		break;
657fcf3ce44SJohn Forte 
658fcf3ce44SJohn Forte 	case IOSTAT_LS_RJT:
659fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
660291a2b48SSukumar Swaminathan 		    "LS Reject. did=0x%06x sbp=%p cmd=%02x", did, sbp,
661291a2b48SSukumar Swaminathan 		    scsi_opcode);
662fcf3ce44SJohn Forte 		break;
663fcf3ce44SJohn Forte 
664fcf3ce44SJohn Forte 	case IOSTAT_DATA_UNDERRUN:
665fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
666291a2b48SSukumar Swaminathan 		    "Underrun. did=0x%06x sbp=%p cmd=%02x "
667291a2b48SSukumar Swaminathan 		    "dl=%d,%d rx=%d rsp=%d (%02x,%02x,%02x,%02x)",
668291a2b48SSukumar Swaminathan 		    did, sbp, scsi_opcode, pkt->pkt_datalen, scsi_dl, data_rx,
669291a2b48SSukumar Swaminathan 		    rsp_data_resid, scsi_status, sense, asc, ascq);
670fcf3ce44SJohn Forte 		break;
671fcf3ce44SJohn Forte 
672fcf3ce44SJohn Forte 	case IOSTAT_DATA_OVERRUN:
673fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
674291a2b48SSukumar Swaminathan 		    "Overrun. did=0x%06x sbp=%p cmd=%02x "
675291a2b48SSukumar Swaminathan 		    "dl=%d,%d rx=%d rsp=%d (%02x,%02x,%02x,%02x)",
676291a2b48SSukumar Swaminathan 		    did, sbp, scsi_opcode, pkt->pkt_datalen, scsi_dl, data_rx,
677291a2b48SSukumar Swaminathan 		    rsp_data_resid, scsi_status, sense, asc, ascq);
678fcf3ce44SJohn Forte 		break;
679fcf3ce44SJohn Forte 
680*8f23e9faSHans Rosenfeld 	case IOSTAT_RSP_INVALID:
681*8f23e9faSHans Rosenfeld 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
682*8f23e9faSHans Rosenfeld 		    "Rsp Invalid. did=0x%06x sbp=%p cmd=%02x dl=%d rl=%d"
683*8f23e9faSHans Rosenfeld 		    "(%d, %d, %d)",
684*8f23e9faSHans Rosenfeld 		    did, sbp, scsi_opcode, pkt->pkt_datalen, pkt->pkt_rsplen,
685*8f23e9faSHans Rosenfeld 		    LE_SWAP32(rsp->fcp_resid),
686*8f23e9faSHans Rosenfeld 		    LE_SWAP32(rsp->fcp_sense_len),
687*8f23e9faSHans Rosenfeld 		    LE_SWAP32(rsp->fcp_response_len));
688*8f23e9faSHans Rosenfeld 		break;
689*8f23e9faSHans Rosenfeld 
690fcf3ce44SJohn Forte 	default:
691fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
692fcf3ce44SJohn Forte 		    "Unknown status=%x reason=%x did=0x%06x sbp=%p cmd=%02x",
693291a2b48SSukumar Swaminathan 		    iostat, cmd->un.grsp.perr.statLocalError, did, sbp,
694291a2b48SSukumar Swaminathan 		    scsi_opcode);
695fcf3ce44SJohn Forte 		break;
696fcf3ce44SJohn Forte 	}
697fcf3ce44SJohn Forte 
698fcf3ce44SJohn Forte 	if (iostat == IOSTAT_SUCCESS) {
699fcf3ce44SJohn Forte 		HBASTATS.FcpGood++;
700fcf3ce44SJohn Forte 	} else {
701fcf3ce44SJohn Forte 		HBASTATS.FcpError++;
702fcf3ce44SJohn Forte 	}
703fcf3ce44SJohn Forte 
704fcf3ce44SJohn Forte 	mutex_exit(&sbp->mtx);
705fcf3ce44SJohn Forte 
706fcf3ce44SJohn Forte 	emlxs_pkt_complete(sbp, iostat, localstat, 0);
707fcf3ce44SJohn Forte 
708fcf3ce44SJohn Forte 	return;
709fcf3ce44SJohn Forte 
71082527734SSukumar Swaminathan } /* emlxs_handle_fcp_event() */
711fcf3ce44SJohn Forte 
712fcf3ce44SJohn Forte 
713fcf3ce44SJohn Forte /*
714fcf3ce44SJohn Forte  *  emlxs_post_buffer
715fcf3ce44SJohn Forte  *
716fcf3ce44SJohn Forte  *  This routine will post count buffers to the
717fcf3ce44SJohn Forte  *  ring with the QUE_RING_BUF_CN command. This
718fcf3ce44SJohn Forte  *  allows 2 buffers / command to be posted.
719fcf3ce44SJohn Forte  *  Returns the number of buffers NOT posted.
720fcf3ce44SJohn Forte  */
72182527734SSukumar Swaminathan /* SLI3 */
722fcf3ce44SJohn Forte extern int
723fcf3ce44SJohn Forte emlxs_post_buffer(emlxs_hba_t *hba, RING *rp, int16_t cnt)
724fcf3ce44SJohn Forte {
725fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
726fcf3ce44SJohn Forte 	IOCB *icmd;
727fcf3ce44SJohn Forte 	IOCBQ *iocbq;
728fcf3ce44SJohn Forte 	MATCHMAP *mp;
729fcf3ce44SJohn Forte 	uint16_t tag;
730fcf3ce44SJohn Forte 	uint32_t maxqbuf;
731fcf3ce44SJohn Forte 	int32_t i;
732fcf3ce44SJohn Forte 	int32_t j;
733fcf3ce44SJohn Forte 	uint32_t seg;
734fcf3ce44SJohn Forte 	uint32_t size;
735fcf3ce44SJohn Forte 
736fcf3ce44SJohn Forte 	mp = 0;
737fcf3ce44SJohn Forte 	maxqbuf = 2;
738fcf3ce44SJohn Forte 	tag = (uint16_t)cnt;
739fcf3ce44SJohn Forte 	cnt += rp->fc_missbufcnt;
740fcf3ce44SJohn Forte 
74182527734SSukumar Swaminathan 	if (rp->ringno == hba->channel_els) {
742fcf3ce44SJohn Forte 		seg = MEM_BUF;
743fcf3ce44SJohn Forte 		size = MEM_ELSBUF_SIZE;
74482527734SSukumar Swaminathan 	} else if (rp->ringno == hba->channel_ip) {
745fcf3ce44SJohn Forte 		seg = MEM_IPBUF;
746fcf3ce44SJohn Forte 		size = MEM_IPBUF_SIZE;
74782527734SSukumar Swaminathan 	} else if (rp->ringno == hba->channel_ct) {
748fcf3ce44SJohn Forte 		seg = MEM_CTBUF;
749fcf3ce44SJohn Forte 		size = MEM_CTBUF_SIZE;
750fcf3ce44SJohn Forte 	}
751fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
75282527734SSukumar Swaminathan 	else if (rp->ringno == hba->CHANNEL_FCT) {
753fcf3ce44SJohn Forte 		seg = MEM_FCTBUF;
754fcf3ce44SJohn Forte 		size = MEM_FCTBUF_SIZE;
755fcf3ce44SJohn Forte 	}
756291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
757fcf3ce44SJohn Forte 	else {
758fcf3ce44SJohn Forte 		return (0);
759fcf3ce44SJohn Forte 	}
760fcf3ce44SJohn Forte 
761fcf3ce44SJohn Forte 	/*
762fcf3ce44SJohn Forte 	 * While there are buffers to post
763fcf3ce44SJohn Forte 	 */
764fcf3ce44SJohn Forte 	while (cnt) {
765*8f23e9faSHans Rosenfeld 		if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == 0) {
766fcf3ce44SJohn Forte 			rp->fc_missbufcnt = cnt;
767fcf3ce44SJohn Forte 			return (cnt);
768fcf3ce44SJohn Forte 		}
769291a2b48SSukumar Swaminathan 
77082527734SSukumar Swaminathan 		iocbq->channel = (void *)&hba->chan[rp->ringno];
771fcf3ce44SJohn Forte 		iocbq->port = (void *)port;
772fcf3ce44SJohn Forte 		iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
773fcf3ce44SJohn Forte 
774fcf3ce44SJohn Forte 		icmd = &iocbq->iocb;
775fcf3ce44SJohn Forte 
776fcf3ce44SJohn Forte 		/*
777fcf3ce44SJohn Forte 		 * Max buffers can be posted per command
778fcf3ce44SJohn Forte 		 */
779fcf3ce44SJohn Forte 		for (i = 0; i < maxqbuf; i++) {
780fcf3ce44SJohn Forte 			if (cnt <= 0)
781fcf3ce44SJohn Forte 				break;
782fcf3ce44SJohn Forte 
783fcf3ce44SJohn Forte 			/* fill in BDEs for command */
784*8f23e9faSHans Rosenfeld 			if ((mp = (MATCHMAP *)emlxs_mem_get(hba, seg))
78582527734SSukumar Swaminathan 			    == 0) {
78682527734SSukumar Swaminathan 				icmd->ULPBDECOUNT = i;
787fcf3ce44SJohn Forte 				for (j = 0; j < i; j++) {
788291a2b48SSukumar Swaminathan 					mp = EMLXS_GET_VADDR(hba, rp, icmd);
789fcf3ce44SJohn Forte 					if (mp) {
790a9800bebSGarrett D'Amore 						emlxs_mem_put(hba, seg,
791a9800bebSGarrett D'Amore 						    (void *)mp);
792fcf3ce44SJohn Forte 					}
793fcf3ce44SJohn Forte 				}
794fcf3ce44SJohn Forte 
795fcf3ce44SJohn Forte 				rp->fc_missbufcnt = cnt + i;
796fcf3ce44SJohn Forte 
797a9800bebSGarrett D'Amore 				emlxs_mem_put(hba, MEM_IOCB, (void *)iocbq);
798fcf3ce44SJohn Forte 
799fcf3ce44SJohn Forte 				return (cnt + i);
800fcf3ce44SJohn Forte 			}
801291a2b48SSukumar Swaminathan 
802fcf3ce44SJohn Forte 			/*
803fcf3ce44SJohn Forte 			 * map that page and save the address pair for lookup
804fcf3ce44SJohn Forte 			 * later
805fcf3ce44SJohn Forte 			 */
806291a2b48SSukumar Swaminathan 			emlxs_mem_map_vaddr(hba,
807291a2b48SSukumar Swaminathan 			    rp,
808291a2b48SSukumar Swaminathan 			    mp,
809fcf3ce44SJohn Forte 			    (uint32_t *)&icmd->un.cont64[i].addrHigh,
810fcf3ce44SJohn Forte 			    (uint32_t *)&icmd->un.cont64[i].addrLow);
811fcf3ce44SJohn Forte 
812fcf3ce44SJohn Forte 			icmd->un.cont64[i].tus.f.bdeSize = size;
81382527734SSukumar Swaminathan 			icmd->ULPCOMMAND = CMD_QUE_RING_BUF64_CN;
814fcf3ce44SJohn Forte 
815291a2b48SSukumar Swaminathan 			/*
816291a2b48SSukumar Swaminathan 			 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
817291a2b48SSukumar Swaminathan 			 *    "UB Post: ring=%d addr=%08x%08x size=%d",
818291a2b48SSukumar Swaminathan 			 *    rp->ringno, icmd->un.cont64[i].addrHigh,
819291a2b48SSukumar Swaminathan 			 *    icmd->un.cont64[i].addrLow, size);
820291a2b48SSukumar Swaminathan 			 */
821fcf3ce44SJohn Forte 
822fcf3ce44SJohn Forte 			cnt--;
823fcf3ce44SJohn Forte 		}
824fcf3ce44SJohn Forte 
82582527734SSukumar Swaminathan 		icmd->ULPIOTAG = tag;
82682527734SSukumar Swaminathan 		icmd->ULPBDECOUNT = i;
82782527734SSukumar Swaminathan 		icmd->ULPLE = 1;
82882527734SSukumar Swaminathan 		icmd->ULPOWNER = OWN_CHIP;
829291a2b48SSukumar Swaminathan 		/* used for delimiter between commands */
830a9800bebSGarrett D'Amore 		iocbq->bp = (void *)mp;
831fcf3ce44SJohn Forte 
83282527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[rp->ringno], iocbq);
833fcf3ce44SJohn Forte 	}
834fcf3ce44SJohn Forte 
835fcf3ce44SJohn Forte 	rp->fc_missbufcnt = 0;
836fcf3ce44SJohn Forte 
837fcf3ce44SJohn Forte 	return (0);
838fcf3ce44SJohn Forte 
83982527734SSukumar Swaminathan } /* emlxs_post_buffer() */
840fcf3ce44SJohn Forte 
841fcf3ce44SJohn Forte 
842*8f23e9faSHans Rosenfeld static void
843*8f23e9faSHans Rosenfeld emlxs_fcp_tag_nodes(emlxs_port_t *port)
844*8f23e9faSHans Rosenfeld {
845*8f23e9faSHans Rosenfeld 	NODELIST *nlp;
846*8f23e9faSHans Rosenfeld 	int i;
847*8f23e9faSHans Rosenfeld 
848*8f23e9faSHans Rosenfeld 	/* We will process all nodes with this tag later */
849*8f23e9faSHans Rosenfeld 	rw_enter(&port->node_rwlock, RW_READER);
850*8f23e9faSHans Rosenfeld 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
851*8f23e9faSHans Rosenfeld 		nlp = port->node_table[i];
852*8f23e9faSHans Rosenfeld 		while (nlp != NULL) {
853*8f23e9faSHans Rosenfeld 			nlp->nlp_tag = 1;
854*8f23e9faSHans Rosenfeld 			nlp = nlp->nlp_list_next;
855*8f23e9faSHans Rosenfeld 		}
856*8f23e9faSHans Rosenfeld 	}
857*8f23e9faSHans Rosenfeld 	rw_exit(&port->node_rwlock);
858*8f23e9faSHans Rosenfeld }
859*8f23e9faSHans Rosenfeld 
860*8f23e9faSHans Rosenfeld 
861*8f23e9faSHans Rosenfeld static NODELIST *
862*8f23e9faSHans Rosenfeld emlxs_find_tagged_node(emlxs_port_t *port)
863*8f23e9faSHans Rosenfeld {
864*8f23e9faSHans Rosenfeld 	NODELIST *nlp;
865*8f23e9faSHans Rosenfeld 	NODELIST *tagged;
866*8f23e9faSHans Rosenfeld 	int i;
867*8f23e9faSHans Rosenfeld 
868*8f23e9faSHans Rosenfeld 	/* Find first node */
869*8f23e9faSHans Rosenfeld 	rw_enter(&port->node_rwlock, RW_READER);
870*8f23e9faSHans Rosenfeld 	tagged = 0;
871*8f23e9faSHans Rosenfeld 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
872*8f23e9faSHans Rosenfeld 		nlp = port->node_table[i];
873*8f23e9faSHans Rosenfeld 		while (nlp != NULL) {
874*8f23e9faSHans Rosenfeld 			if (!nlp->nlp_tag) {
875*8f23e9faSHans Rosenfeld 				nlp = nlp->nlp_list_next;
876*8f23e9faSHans Rosenfeld 				continue;
877*8f23e9faSHans Rosenfeld 			}
878*8f23e9faSHans Rosenfeld 			nlp->nlp_tag = 0;
879*8f23e9faSHans Rosenfeld 
880*8f23e9faSHans Rosenfeld 			if (nlp->nlp_Rpi == FABRIC_RPI) {
881*8f23e9faSHans Rosenfeld 				nlp = nlp->nlp_list_next;
882*8f23e9faSHans Rosenfeld 				continue;
883*8f23e9faSHans Rosenfeld 			}
884*8f23e9faSHans Rosenfeld 			tagged = nlp;
885*8f23e9faSHans Rosenfeld 			break;
886*8f23e9faSHans Rosenfeld 		}
887*8f23e9faSHans Rosenfeld 		if (tagged) {
888*8f23e9faSHans Rosenfeld 			break;
889*8f23e9faSHans Rosenfeld 		}
890*8f23e9faSHans Rosenfeld 	}
891*8f23e9faSHans Rosenfeld 	rw_exit(&port->node_rwlock);
892*8f23e9faSHans Rosenfeld 	return (tagged);
893*8f23e9faSHans Rosenfeld }
894*8f23e9faSHans Rosenfeld 
895*8f23e9faSHans Rosenfeld 
896fcf3ce44SJohn Forte extern int
897fcf3ce44SJohn Forte emlxs_port_offline(emlxs_port_t *port, uint32_t scope)
898fcf3ce44SJohn Forte {
899fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
900fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
901fcf3ce44SJohn Forte 	NODELIST *nlp;
902fcf3ce44SJohn Forte 	fc_affected_id_t *aid;
903fcf3ce44SJohn Forte 	uint32_t mask;
904fcf3ce44SJohn Forte 	uint32_t aff_d_id;
905fcf3ce44SJohn Forte 	uint32_t linkdown;
906fcf3ce44SJohn Forte 	uint32_t vlinkdown;
907fcf3ce44SJohn Forte 	uint32_t action;
908fcf3ce44SJohn Forte 	int i;
909fcf3ce44SJohn Forte 	uint32_t unreg_vpi;
910fcf3ce44SJohn Forte 	uint32_t update;
911fcf3ce44SJohn Forte 	uint32_t adisc_support;
912a9800bebSGarrett D'Amore 	uint32_t clear_all;
9133be114edSSukumar Swaminathan 	uint8_t format;
914fcf3ce44SJohn Forte 
915fcf3ce44SJohn Forte 	/* Target mode only uses this routine for linkdowns */
916*8f23e9faSHans Rosenfeld 	if ((port->mode == MODE_TARGET) && (scope != 0xffffffff) &&
917*8f23e9faSHans Rosenfeld 	    (scope != 0xfeffffff) && (scope != 0xfdffffff)) {
918fcf3ce44SJohn Forte 		return (0);
919fcf3ce44SJohn Forte 	}
920291a2b48SSukumar Swaminathan 
921fcf3ce44SJohn Forte 	cfg = &CFG;
922fcf3ce44SJohn Forte 	aid = (fc_affected_id_t *)&scope;
923fcf3ce44SJohn Forte 	linkdown = 0;
924fcf3ce44SJohn Forte 	vlinkdown = 0;
925fcf3ce44SJohn Forte 	unreg_vpi = 0;
926fcf3ce44SJohn Forte 	update = 0;
927a9800bebSGarrett D'Amore 	clear_all = 0;
928fcf3ce44SJohn Forte 
929fcf3ce44SJohn Forte 	if (!(port->flag & EMLXS_PORT_BOUND)) {
930fcf3ce44SJohn Forte 		return (0);
931fcf3ce44SJohn Forte 	}
932291a2b48SSukumar Swaminathan 
9333be114edSSukumar Swaminathan 	format = aid->aff_format;
9343be114edSSukumar Swaminathan 
9353be114edSSukumar Swaminathan 	switch (format) {
936fcf3ce44SJohn Forte 	case 0:	/* Port */
937fcf3ce44SJohn Forte 		mask = 0x00ffffff;
938fcf3ce44SJohn Forte 		break;
939fcf3ce44SJohn Forte 
940fcf3ce44SJohn Forte 	case 1:	/* Area */
941fcf3ce44SJohn Forte 		mask = 0x00ffff00;
942fcf3ce44SJohn Forte 		break;
943fcf3ce44SJohn Forte 
944fcf3ce44SJohn Forte 	case 2:	/* Domain */
945fcf3ce44SJohn Forte 		mask = 0x00ff0000;
946fcf3ce44SJohn Forte 		break;
947fcf3ce44SJohn Forte 
948fcf3ce44SJohn Forte 	case 3:	/* Network */
949fcf3ce44SJohn Forte 		mask = 0x00000000;
950fcf3ce44SJohn Forte 		break;
951fcf3ce44SJohn Forte 
952fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
953fcf3ce44SJohn Forte 	case 0xfe:	/* Virtual link down */
954fcf3ce44SJohn Forte 		mask = 0x00000000;
955fcf3ce44SJohn Forte 		vlinkdown = 1;
956fcf3ce44SJohn Forte 		break;
957291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
958fcf3ce44SJohn Forte 
959fcf3ce44SJohn Forte 	case 0xff:	/* link is down */
960fcf3ce44SJohn Forte 		mask = 0x00000000;
961fcf3ce44SJohn Forte 		linkdown = 1;
962fcf3ce44SJohn Forte 		break;
963fcf3ce44SJohn Forte 
964*8f23e9faSHans Rosenfeld 	case 0xfd:	/* New fabric */
965*8f23e9faSHans Rosenfeld 	default:
966*8f23e9faSHans Rosenfeld 		mask = 0x00000000;
967*8f23e9faSHans Rosenfeld 		linkdown = 1;
968*8f23e9faSHans Rosenfeld 		clear_all = 1;
969*8f23e9faSHans Rosenfeld 		break;
970fcf3ce44SJohn Forte 	}
971fcf3ce44SJohn Forte 
972fcf3ce44SJohn Forte 	aff_d_id = aid->aff_d_id & mask;
973fcf3ce44SJohn Forte 
974fcf3ce44SJohn Forte 
975fcf3ce44SJohn Forte 	/*
976291a2b48SSukumar Swaminathan 	 * If link is down then this is a hard shutdown and flush
977291a2b48SSukumar Swaminathan 	 * If link not down then this is a soft shutdown and flush
978291a2b48SSukumar Swaminathan 	 * (e.g. RSCN)
979fcf3ce44SJohn Forte 	 */
980fcf3ce44SJohn Forte 	if (linkdown) {
981fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
982fcf3ce44SJohn Forte 
983fcf3ce44SJohn Forte 		port->flag &= EMLXS_PORT_LINKDOWN_MASK;
984fcf3ce44SJohn Forte 
985fcf3ce44SJohn Forte 		if (port->ulp_statec != FC_STATE_OFFLINE) {
986fcf3ce44SJohn Forte 			port->ulp_statec = FC_STATE_OFFLINE;
987*8f23e9faSHans Rosenfeld 
988a9800bebSGarrett D'Amore 			port->prev_did = port->did;
989*8f23e9faSHans Rosenfeld 			port->did = 0;
990*8f23e9faSHans Rosenfeld 			port->rdid = 0;
991*8f23e9faSHans Rosenfeld 
992a9800bebSGarrett D'Amore 			bcopy(&port->fabric_sparam, &port->prev_fabric_sparam,
993a9800bebSGarrett D'Amore 			    sizeof (SERV_PARM));
994*8f23e9faSHans Rosenfeld 			bzero(&port->fabric_sparam, sizeof (SERV_PARM));
995*8f23e9faSHans Rosenfeld 
996fcf3ce44SJohn Forte 			update = 1;
997fcf3ce44SJohn Forte 		}
998291a2b48SSukumar Swaminathan 
999fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1000fcf3ce44SJohn Forte 
1001*8f23e9faSHans Rosenfeld 		emlxs_timer_cancel_clean_address(port);
1002*8f23e9faSHans Rosenfeld 
1003fcf3ce44SJohn Forte 		/* Tell ULP about it */
1004fcf3ce44SJohn Forte 		if (update) {
1005fcf3ce44SJohn Forte 			if (port->flag & EMLXS_PORT_BOUND) {
1006fcf3ce44SJohn Forte 				if (port->vpi == 0) {
1007fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1008291a2b48SSukumar Swaminathan 					    &emlxs_link_down_msg, NULL);
1009fcf3ce44SJohn Forte 				}
1010291a2b48SSukumar Swaminathan 
1011*8f23e9faSHans Rosenfeld 				if (port->mode == MODE_INITIATOR) {
1012*8f23e9faSHans Rosenfeld 					emlxs_fca_link_down(port);
10133be114edSSukumar Swaminathan 				}
1014291a2b48SSukumar Swaminathan #ifdef SFCT_SUPPORT
1015*8f23e9faSHans Rosenfeld 				else if (port->mode == MODE_TARGET) {
1016fcf3ce44SJohn Forte 					emlxs_fct_link_down(port);
10173be114edSSukumar Swaminathan 				}
1018291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
1019fcf3ce44SJohn Forte 
1020fcf3ce44SJohn Forte 			} else {
1021fcf3ce44SJohn Forte 				if (port->vpi == 0) {
1022fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1023291a2b48SSukumar Swaminathan 					    &emlxs_link_down_msg, "*");
1024fcf3ce44SJohn Forte 				}
1025fcf3ce44SJohn Forte 			}
1026fcf3ce44SJohn Forte 
1027fcf3ce44SJohn Forte 
1028fcf3ce44SJohn Forte 		}
1029291a2b48SSukumar Swaminathan 
1030fcf3ce44SJohn Forte 		unreg_vpi = 1;
1031fcf3ce44SJohn Forte 
1032fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1033fcf3ce44SJohn Forte 		/* Stop authentication with all nodes */
1034fcf3ce44SJohn Forte 		emlxs_dhc_auth_stop(port, NULL);
1035291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1036fcf3ce44SJohn Forte 
1037fcf3ce44SJohn Forte 		/* Flush the base node */
1038fcf3ce44SJohn Forte 		(void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0);
1039fcf3ce44SJohn Forte 		(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);
1040fcf3ce44SJohn Forte 
1041fcf3ce44SJohn Forte 		/* Flush any pending ub buffers */
1042fcf3ce44SJohn Forte 		emlxs_ub_flush(port);
1043fcf3ce44SJohn Forte 	}
1044fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1045fcf3ce44SJohn Forte 	/* virtual link down */
1046fcf3ce44SJohn Forte 	else if (vlinkdown) {
1047fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1048fcf3ce44SJohn Forte 
1049fcf3ce44SJohn Forte 		if (port->ulp_statec != FC_STATE_OFFLINE) {
1050fcf3ce44SJohn Forte 			port->ulp_statec = FC_STATE_OFFLINE;
1051fcf3ce44SJohn Forte 			update = 1;
1052fcf3ce44SJohn Forte 		}
1053291a2b48SSukumar Swaminathan 
1054fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1055fcf3ce44SJohn Forte 
1056*8f23e9faSHans Rosenfeld 		emlxs_timer_cancel_clean_address(port);
1057*8f23e9faSHans Rosenfeld 
1058fcf3ce44SJohn Forte 		/* Tell ULP about it */
1059fcf3ce44SJohn Forte 		if (update) {
1060fcf3ce44SJohn Forte 			if (port->flag & EMLXS_PORT_BOUND) {
1061fcf3ce44SJohn Forte 				if (port->vpi == 0) {
1062fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1063fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
1064fcf3ce44SJohn Forte 					    "Switch authentication failed.");
1065fcf3ce44SJohn Forte 				}
1066291a2b48SSukumar Swaminathan 
1067*8f23e9faSHans Rosenfeld 				if (port->mode == MODE_INITIATOR) {
1068*8f23e9faSHans Rosenfeld 					emlxs_fca_link_down(port);
1069*8f23e9faSHans Rosenfeld 				}
1070fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
1071*8f23e9faSHans Rosenfeld 				else if (port->mode == MODE_TARGET) {
1072fcf3ce44SJohn Forte 					emlxs_fct_link_down(port);
1073fcf3ce44SJohn Forte 				}
1074*8f23e9faSHans Rosenfeld #endif /* SFCT_SUPPORT */
1075fcf3ce44SJohn Forte 			} else {
1076fcf3ce44SJohn Forte 				if (port->vpi == 0) {
1077fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1078fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
1079fcf3ce44SJohn Forte 					    "Switch authentication failed. *");
1080fcf3ce44SJohn Forte 				}
1081fcf3ce44SJohn Forte 			}
1082fcf3ce44SJohn Forte 
1083fcf3ce44SJohn Forte 
1084fcf3ce44SJohn Forte 		}
1085291a2b48SSukumar Swaminathan 
1086fcf3ce44SJohn Forte 		/* Flush the base node */
1087fcf3ce44SJohn Forte 		(void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0);
1088fcf3ce44SJohn Forte 		(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);
1089fcf3ce44SJohn Forte 	}
1090291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1091*8f23e9faSHans Rosenfeld 	else {
1092*8f23e9faSHans Rosenfeld 		emlxs_timer_cancel_clean_address(port);
1093*8f23e9faSHans Rosenfeld 	}
1094fcf3ce44SJohn Forte 
1095*8f23e9faSHans Rosenfeld 	if (port->mode == MODE_TARGET) {
1096*8f23e9faSHans Rosenfeld 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1097*8f23e9faSHans Rosenfeld 			/* Set the node tags */
1098*8f23e9faSHans Rosenfeld 			emlxs_fcp_tag_nodes(port);
1099*8f23e9faSHans Rosenfeld 			unreg_vpi = 0;
1100*8f23e9faSHans Rosenfeld 			while ((nlp = emlxs_find_tagged_node(port))) {
1101*8f23e9faSHans Rosenfeld 				(void) emlxs_rpi_pause_notify(port,
1102*8f23e9faSHans Rosenfeld 				    nlp->rpip);
1103*8f23e9faSHans Rosenfeld 				/*
1104*8f23e9faSHans Rosenfeld 				 * In port_online we need to resume
1105*8f23e9faSHans Rosenfeld 				 * these RPIs before we can use them.
1106*8f23e9faSHans Rosenfeld 				 */
1107*8f23e9faSHans Rosenfeld 			}
1108*8f23e9faSHans Rosenfeld 		}
1109fcf3ce44SJohn Forte 		goto done;
1110fcf3ce44SJohn Forte 	}
1111291a2b48SSukumar Swaminathan 
1112fcf3ce44SJohn Forte 	/* Set the node tags */
1113*8f23e9faSHans Rosenfeld 	emlxs_fcp_tag_nodes(port);
1114fcf3ce44SJohn Forte 
1115a9800bebSGarrett D'Amore 	if (!clear_all && (hba->flag & FC_ONLINE_MODE)) {
1116fcf3ce44SJohn Forte 		adisc_support = cfg[CFG_ADISC_SUPPORT].current;
1117fcf3ce44SJohn Forte 	} else {
1118fcf3ce44SJohn Forte 		adisc_support = 0;
1119fcf3ce44SJohn Forte 	}
1120fcf3ce44SJohn Forte 
1121fcf3ce44SJohn Forte 	/* Check ADISC support level */
1122fcf3ce44SJohn Forte 	switch (adisc_support) {
1123fcf3ce44SJohn Forte 	case 0:	/* No support - Flush all IO to all matching nodes */
1124fcf3ce44SJohn Forte 
1125291a2b48SSukumar Swaminathan 		for (;;) {
1126fcf3ce44SJohn Forte 			/*
1127fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
1128*8f23e9faSHans Rosenfeld 			 * EMLXS_SLI_UNREG_NODE and the flush routines enter the
1129291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
1130291a2b48SSukumar Swaminathan 			 * can change out from under us.
1131fcf3ce44SJohn Forte 			 */
1132fcf3ce44SJohn Forte 
1133fcf3ce44SJohn Forte 			/* Find first node */
1134fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1135fcf3ce44SJohn Forte 			action = 0;
1136fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1137fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1138fcf3ce44SJohn Forte 				while (nlp != NULL) {
1139fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1140fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1141fcf3ce44SJohn Forte 						continue;
1142fcf3ce44SJohn Forte 					}
1143fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1144fcf3ce44SJohn Forte 
1145fcf3ce44SJohn Forte 					/*
1146fcf3ce44SJohn Forte 					 * Check for any device that matches
1147fcf3ce44SJohn Forte 					 * our mask
1148fcf3ce44SJohn Forte 					 */
1149fcf3ce44SJohn Forte 					if ((nlp->nlp_DID & mask) == aff_d_id) {
1150fcf3ce44SJohn Forte 						if (linkdown) {
1151fcf3ce44SJohn Forte 							action = 1;
1152fcf3ce44SJohn Forte 							break;
1153291a2b48SSukumar Swaminathan 						} else { /* Must be an RCSN */
1154291a2b48SSukumar Swaminathan 
1155fcf3ce44SJohn Forte 							action = 2;
1156fcf3ce44SJohn Forte 							break;
1157fcf3ce44SJohn Forte 						}
1158fcf3ce44SJohn Forte 					}
1159fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1160fcf3ce44SJohn Forte 				}
1161fcf3ce44SJohn Forte 
1162fcf3ce44SJohn Forte 				if (action) {
1163fcf3ce44SJohn Forte 					break;
1164fcf3ce44SJohn Forte 				}
1165fcf3ce44SJohn Forte 			}
1166fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1167fcf3ce44SJohn Forte 
1168fcf3ce44SJohn Forte 
1169fcf3ce44SJohn Forte 			/* Check if nothing was found */
1170fcf3ce44SJohn Forte 			if (action == 0) {
1171fcf3ce44SJohn Forte 				break;
1172fcf3ce44SJohn Forte 			} else if (action == 1) {
1173*8f23e9faSHans Rosenfeld 				(void) EMLXS_SLI_UNREG_NODE(port, nlp,
1174fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1175fcf3ce44SJohn Forte 			} else if (action == 2) {
1176*8f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
1177*8f23e9faSHans Rosenfeld 
1178fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1179fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1180291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1181fcf3ce44SJohn Forte 
1182291a2b48SSukumar Swaminathan 				/*
1183291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1184291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
1185291a2b48SSukumar Swaminathan 				 */
118682527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
118782527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
118882527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
118982527734SSukumar Swaminathan 				    hba->channel_ip, 60);
1190fcf3ce44SJohn Forte 
1191fcf3ce44SJohn Forte 				/* Flush tx queue */
1192fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1193fcf3ce44SJohn Forte 
1194fcf3ce44SJohn Forte 				/* Flush chip queue */
1195fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1196fcf3ce44SJohn Forte 			}
1197291a2b48SSukumar Swaminathan 
1198fcf3ce44SJohn Forte 		}
1199fcf3ce44SJohn Forte 
1200fcf3ce44SJohn Forte 		break;
1201fcf3ce44SJohn Forte 
1202291a2b48SSukumar Swaminathan 	case 1:	/* Partial support - Flush IO for non-FCP2 matching nodes */
1203fcf3ce44SJohn Forte 
1204fcf3ce44SJohn Forte 		for (;;) {
1205fcf3ce44SJohn Forte 
1206fcf3ce44SJohn Forte 			/*
1207fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
1208*8f23e9faSHans Rosenfeld 			 * EMLXS_SLI_UNREG_NODE and the flush routines enter the
1209291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
1210291a2b48SSukumar Swaminathan 			 * can change out from under us.
1211fcf3ce44SJohn Forte 			 */
1212fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1213fcf3ce44SJohn Forte 			action = 0;
1214fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1215fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1216fcf3ce44SJohn Forte 				while (nlp != NULL) {
1217fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1218fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1219fcf3ce44SJohn Forte 						continue;
1220fcf3ce44SJohn Forte 					}
1221fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1222fcf3ce44SJohn Forte 
1223fcf3ce44SJohn Forte 					/*
1224291a2b48SSukumar Swaminathan 					 * Check for special FCP2 target device
1225291a2b48SSukumar Swaminathan 					 * that matches our mask
1226fcf3ce44SJohn Forte 					 */
1227fcf3ce44SJohn Forte 					if ((nlp->nlp_fcp_info &
1228fcf3ce44SJohn Forte 					    NLP_FCP_TGT_DEVICE) &&
1229291a2b48SSukumar Swaminathan 					    (nlp-> nlp_fcp_info &
1230fcf3ce44SJohn Forte 					    NLP_FCP_2_DEVICE) &&
1231291a2b48SSukumar Swaminathan 					    (nlp->nlp_DID & mask) ==
1232291a2b48SSukumar Swaminathan 					    aff_d_id) {
1233fcf3ce44SJohn Forte 						action = 3;
1234fcf3ce44SJohn Forte 						break;
1235fcf3ce44SJohn Forte 					}
1236291a2b48SSukumar Swaminathan 
1237fcf3ce44SJohn Forte 					/*
1238fcf3ce44SJohn Forte 					 * Check for any other device that
1239fcf3ce44SJohn Forte 					 * matches our mask
1240fcf3ce44SJohn Forte 					 */
1241fcf3ce44SJohn Forte 					else if ((nlp->nlp_DID & mask) ==
1242fcf3ce44SJohn Forte 					    aff_d_id) {
1243fcf3ce44SJohn Forte 						if (linkdown) {
1244fcf3ce44SJohn Forte 							action = 1;
1245fcf3ce44SJohn Forte 							break;
1246291a2b48SSukumar Swaminathan 						} else { /* Must be an RSCN */
1247291a2b48SSukumar Swaminathan 
1248fcf3ce44SJohn Forte 							action = 2;
1249fcf3ce44SJohn Forte 							break;
1250fcf3ce44SJohn Forte 						}
1251fcf3ce44SJohn Forte 					}
1252291a2b48SSukumar Swaminathan 
1253fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1254fcf3ce44SJohn Forte 				}
1255fcf3ce44SJohn Forte 
1256fcf3ce44SJohn Forte 				if (action) {
1257fcf3ce44SJohn Forte 					break;
1258fcf3ce44SJohn Forte 				}
1259fcf3ce44SJohn Forte 			}
1260fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1261fcf3ce44SJohn Forte 
1262fcf3ce44SJohn Forte 			/* Check if nothing was found */
1263fcf3ce44SJohn Forte 			if (action == 0) {
1264fcf3ce44SJohn Forte 				break;
1265fcf3ce44SJohn Forte 			} else if (action == 1) {
1266*8f23e9faSHans Rosenfeld 				(void) EMLXS_SLI_UNREG_NODE(port, nlp,
1267fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1268fcf3ce44SJohn Forte 			} else if (action == 2) {
1269*8f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
1270*8f23e9faSHans Rosenfeld 
1271fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1272fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1273291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1274fcf3ce44SJohn Forte 
1275291a2b48SSukumar Swaminathan 				/*
1276291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1277291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
1278291a2b48SSukumar Swaminathan 				 */
127982527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
128082527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
128182527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
128282527734SSukumar Swaminathan 				    hba->channel_ip, 60);
1283fcf3ce44SJohn Forte 
1284fcf3ce44SJohn Forte 				/* Flush tx queue */
1285fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1286fcf3ce44SJohn Forte 
1287fcf3ce44SJohn Forte 				/* Flush chip queue */
1288fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1289291a2b48SSukumar Swaminathan 
1290fcf3ce44SJohn Forte 			} else if (action == 3) {	/* FCP2 devices */
1291*8f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
1292*8f23e9faSHans Rosenfeld 
1293fcf3ce44SJohn Forte 				unreg_vpi = 0;
1294fcf3ce44SJohn Forte 
1295a9800bebSGarrett D'Amore 				if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1296a9800bebSGarrett D'Amore 					(void) emlxs_rpi_pause_notify(port,
1297a9800bebSGarrett D'Amore 					    nlp->rpip);
1298a9800bebSGarrett D'Amore 				}
1299a9800bebSGarrett D'Amore 
1300fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1301fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1302291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1303fcf3ce44SJohn Forte 
1304291a2b48SSukumar Swaminathan 				/*
1305291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1306291a2b48SSukumar Swaminathan 				 * An ADISC or a PLOGI with reopen the node
1307291a2b48SSukumar Swaminathan 				 */
130882527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
130982527734SSukumar Swaminathan 				    hba->channel_fcp, -1);
131082527734SSukumar Swaminathan 				emlxs_node_close(port, nlp, hba->channel_ip,
1311fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1312fcf3ce44SJohn Forte 
1313fcf3ce44SJohn Forte 				/* Flush tx queues except for FCP ring */
1314fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
131582527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], 0, 0);
1316fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
131782527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], 0, 0);
1318fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
131982527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], 0, 0);
1320fcf3ce44SJohn Forte 
1321fcf3ce44SJohn Forte 				/* Flush chip queues except for FCP ring */
1322fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
132382527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], nlp, 0);
1324fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
132582527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], nlp, 0);
1326fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
132782527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], nlp, 0);
1328fcf3ce44SJohn Forte 			}
1329fcf3ce44SJohn Forte 		}
1330fcf3ce44SJohn Forte 		break;
1331fcf3ce44SJohn Forte 
1332fcf3ce44SJohn Forte 	case 2:	/* Full support - Hold FCP IO to FCP target matching nodes */
1333fcf3ce44SJohn Forte 
1334fcf3ce44SJohn Forte 		if (!linkdown && !vlinkdown) {
1335fcf3ce44SJohn Forte 			break;
1336fcf3ce44SJohn Forte 		}
1337291a2b48SSukumar Swaminathan 
1338fcf3ce44SJohn Forte 		for (;;) {
1339fcf3ce44SJohn Forte 			/*
1340fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
1341*8f23e9faSHans Rosenfeld 			 * EMLXS_SLI_UNREG_NODE and the flush routines enter the
1342291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
1343291a2b48SSukumar Swaminathan 			 * can change out from under us.
1344fcf3ce44SJohn Forte 			 */
1345fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1346fcf3ce44SJohn Forte 			action = 0;
1347fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1348fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1349fcf3ce44SJohn Forte 				while (nlp != NULL) {
1350fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1351fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1352fcf3ce44SJohn Forte 						continue;
1353fcf3ce44SJohn Forte 					}
1354fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1355fcf3ce44SJohn Forte 
1356fcf3ce44SJohn Forte 					/*
1357fcf3ce44SJohn Forte 					 * Check for FCP target device that
1358fcf3ce44SJohn Forte 					 * matches our mask
1359fcf3ce44SJohn Forte 					 */
1360291a2b48SSukumar Swaminathan 					if ((nlp-> nlp_fcp_info &
1361fcf3ce44SJohn Forte 					    NLP_FCP_TGT_DEVICE) &&
1362291a2b48SSukumar Swaminathan 					    (nlp->nlp_DID & mask) ==
1363291a2b48SSukumar Swaminathan 					    aff_d_id) {
1364fcf3ce44SJohn Forte 						action = 3;
1365fcf3ce44SJohn Forte 						break;
1366fcf3ce44SJohn Forte 					}
1367291a2b48SSukumar Swaminathan 
1368fcf3ce44SJohn Forte 					/*
1369fcf3ce44SJohn Forte 					 * Check for any other device that
1370fcf3ce44SJohn Forte 					 * matches our mask
1371fcf3ce44SJohn Forte 					 */
1372fcf3ce44SJohn Forte 					else if ((nlp->nlp_DID & mask) ==
1373fcf3ce44SJohn Forte 					    aff_d_id) {
1374fcf3ce44SJohn Forte 						if (linkdown) {
1375fcf3ce44SJohn Forte 							action = 1;
1376fcf3ce44SJohn Forte 							break;
1377fcf3ce44SJohn Forte 						} else { /* Must be an RSCN */
1378291a2b48SSukumar Swaminathan 
1379fcf3ce44SJohn Forte 							action = 2;
1380fcf3ce44SJohn Forte 							break;
1381fcf3ce44SJohn Forte 						}
1382fcf3ce44SJohn Forte 					}
1383291a2b48SSukumar Swaminathan 
1384fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1385fcf3ce44SJohn Forte 				}
1386fcf3ce44SJohn Forte 				if (action) {
1387fcf3ce44SJohn Forte 					break;
1388fcf3ce44SJohn Forte 				}
1389fcf3ce44SJohn Forte 			}
1390fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1391fcf3ce44SJohn Forte 
1392fcf3ce44SJohn Forte 			/* Check if nothing was found */
1393fcf3ce44SJohn Forte 			if (action == 0) {
1394fcf3ce44SJohn Forte 				break;
1395fcf3ce44SJohn Forte 			} else if (action == 1) {
1396*8f23e9faSHans Rosenfeld 				(void) EMLXS_SLI_UNREG_NODE(port, nlp,
1397fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1398fcf3ce44SJohn Forte 			} else if (action == 2) {
1399*8f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
1400*8f23e9faSHans Rosenfeld 
1401291a2b48SSukumar Swaminathan 				/*
1402291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1403291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
1404291a2b48SSukumar Swaminathan 				 */
140582527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
140682527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
140782527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
140882527734SSukumar Swaminathan 				    hba->channel_ip, 60);
1409fcf3ce44SJohn Forte 
1410fcf3ce44SJohn Forte 				/* Flush tx queue */
1411fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1412fcf3ce44SJohn Forte 
1413fcf3ce44SJohn Forte 				/* Flush chip queue */
1414fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1415fcf3ce44SJohn Forte 
1416fcf3ce44SJohn Forte 			} else if (action == 3) {	/* FCP2 devices */
1417*8f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
1418*8f23e9faSHans Rosenfeld 
1419fcf3ce44SJohn Forte 				unreg_vpi = 0;
1420fcf3ce44SJohn Forte 
1421a9800bebSGarrett D'Amore 				if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1422a9800bebSGarrett D'Amore 					(void) emlxs_rpi_pause_notify(port,
1423a9800bebSGarrett D'Amore 					    nlp->rpip);
1424a9800bebSGarrett D'Amore 				}
1425a9800bebSGarrett D'Amore 
1426291a2b48SSukumar Swaminathan 				/*
1427291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1428291a2b48SSukumar Swaminathan 				 * An ADISC or a PLOGI with reopen the node
1429291a2b48SSukumar Swaminathan 				 */
143082527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
143182527734SSukumar Swaminathan 				    hba->channel_fcp, -1);
143282527734SSukumar Swaminathan 				emlxs_node_close(port, nlp, hba->channel_ip,
1433fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1434fcf3ce44SJohn Forte 
1435fcf3ce44SJohn Forte 				/* Flush tx queues except for FCP ring */
1436fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
143782527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], 0, 0);
1438fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
143982527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], 0, 0);
1440fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
144182527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], 0, 0);
1442fcf3ce44SJohn Forte 
1443fcf3ce44SJohn Forte 				/* Flush chip queues except for FCP ring */
1444fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
144582527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], nlp, 0);
1446fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
144782527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], nlp, 0);
1448fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
144982527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], nlp, 0);
1450fcf3ce44SJohn Forte 			}
1451fcf3ce44SJohn Forte 		}
1452fcf3ce44SJohn Forte 
1453fcf3ce44SJohn Forte 		break;
1454fcf3ce44SJohn Forte 
1455fcf3ce44SJohn Forte 	}	/* switch() */
1456fcf3ce44SJohn Forte 
1457fcf3ce44SJohn Forte done:
1458fcf3ce44SJohn Forte 
1459a9800bebSGarrett D'Amore 	if (unreg_vpi) {
1460a9800bebSGarrett D'Amore 		(void) emlxs_mb_unreg_vpi(port);
1461fcf3ce44SJohn Forte 	}
1462fcf3ce44SJohn Forte 
1463291a2b48SSukumar Swaminathan 	return (0);
1464fcf3ce44SJohn Forte 
146582527734SSukumar Swaminathan } /* emlxs_port_offline() */
1466fcf3ce44SJohn Forte 
1467fcf3ce44SJohn Forte 
1468fcf3ce44SJohn Forte extern void
1469fcf3ce44SJohn Forte emlxs_port_online(emlxs_port_t *vport)
1470fcf3ce44SJohn Forte {
1471fcf3ce44SJohn Forte 	emlxs_hba_t *hba = vport->hba;
1472fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1473*8f23e9faSHans Rosenfeld 	NODELIST *nlp;
1474fcf3ce44SJohn Forte 	uint32_t state;
1475fcf3ce44SJohn Forte 	uint32_t update;
1476fcf3ce44SJohn Forte 	uint32_t npiv_linkup;
1477fcf3ce44SJohn Forte 	char topology[32];
1478fcf3ce44SJohn Forte 	char linkspeed[32];
1479fcf3ce44SJohn Forte 	char mode[32];
1480fcf3ce44SJohn Forte 
1481fcf3ce44SJohn Forte 	/*
1482291a2b48SSukumar Swaminathan 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1483291a2b48SSukumar Swaminathan 	 *    "linkup_callback. vpi=%d fc_flag=%x", vport->vpi, hba->flag);
1484fcf3ce44SJohn Forte 	 */
1485fcf3ce44SJohn Forte 
1486fcf3ce44SJohn Forte 	if ((vport->vpi > 0) &&
1487fcf3ce44SJohn Forte 	    (!(hba->flag & FC_NPIV_ENABLED) ||
1488fcf3ce44SJohn Forte 	    !(hba->flag & FC_NPIV_SUPPORTED))) {
1489fcf3ce44SJohn Forte 		return;
1490fcf3ce44SJohn Forte 	}
1491291a2b48SSukumar Swaminathan 
1492fcf3ce44SJohn Forte 	if (!(vport->flag & EMLXS_PORT_BOUND) ||
1493*8f23e9faSHans Rosenfeld 	    !(vport->flag & EMLXS_PORT_ENABLED)) {
1494fcf3ce44SJohn Forte 		return;
1495fcf3ce44SJohn Forte 	}
1496291a2b48SSukumar Swaminathan 
1497fcf3ce44SJohn Forte 	/* Check for mode */
1498*8f23e9faSHans Rosenfeld 	if (port->mode == MODE_TARGET) {
1499*8f23e9faSHans Rosenfeld 		(void) strlcpy(mode, ", target", sizeof (mode));
1500*8f23e9faSHans Rosenfeld 
1501*8f23e9faSHans Rosenfeld 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1502*8f23e9faSHans Rosenfeld 			/* Set the node tags */
1503*8f23e9faSHans Rosenfeld 			emlxs_fcp_tag_nodes(vport);
1504*8f23e9faSHans Rosenfeld 			while ((nlp = emlxs_find_tagged_node(vport))) {
1505*8f23e9faSHans Rosenfeld 				/* The RPI was paused in port_offline */
1506*8f23e9faSHans Rosenfeld 				(void) emlxs_rpi_resume_notify(vport,
1507*8f23e9faSHans Rosenfeld 				    nlp->rpip, 0);
1508*8f23e9faSHans Rosenfeld 			}
1509*8f23e9faSHans Rosenfeld 		}
1510*8f23e9faSHans Rosenfeld 	} else if (port->mode == MODE_INITIATOR) {
1511*8f23e9faSHans Rosenfeld 		(void) strlcpy(mode, ", initiator", sizeof (mode));
1512fcf3ce44SJohn Forte 	} else {
1513*8f23e9faSHans Rosenfeld 		(void) strlcpy(mode, "unknown", sizeof (mode));
1514fcf3ce44SJohn Forte 	}
1515*8f23e9faSHans Rosenfeld 	mutex_enter(&EMLXS_PORT_LOCK);
1516fcf3ce44SJohn Forte 
1517fcf3ce44SJohn Forte 	/* Check for loop topology */
1518fcf3ce44SJohn Forte 	if (hba->topology == TOPOLOGY_LOOP) {
1519fcf3ce44SJohn Forte 		state = FC_STATE_LOOP;
1520*8f23e9faSHans Rosenfeld 		(void) strlcpy(topology, ", loop", sizeof (topology));
1521fcf3ce44SJohn Forte 	} else {
1522fcf3ce44SJohn Forte 		state = FC_STATE_ONLINE;
1523*8f23e9faSHans Rosenfeld 		(void) strlcpy(topology, ", fabric", sizeof (topology));
1524fcf3ce44SJohn Forte 	}
1525fcf3ce44SJohn Forte 
1526fcf3ce44SJohn Forte 	/* Set the link speed */
1527fcf3ce44SJohn Forte 	switch (hba->linkspeed) {
1528fcf3ce44SJohn Forte 	case 0:
1529*8f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "Gb", sizeof (linkspeed));
1530fcf3ce44SJohn Forte 		state |= FC_STATE_1GBIT_SPEED;
1531fcf3ce44SJohn Forte 		break;
1532fcf3ce44SJohn Forte 
1533fcf3ce44SJohn Forte 	case LA_1GHZ_LINK:
1534*8f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "1Gb", sizeof (linkspeed));
1535fcf3ce44SJohn Forte 		state |= FC_STATE_1GBIT_SPEED;
1536fcf3ce44SJohn Forte 		break;
1537fcf3ce44SJohn Forte 	case LA_2GHZ_LINK:
1538*8f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "2Gb", sizeof (linkspeed));
1539fcf3ce44SJohn Forte 		state |= FC_STATE_2GBIT_SPEED;
1540fcf3ce44SJohn Forte 		break;
1541fcf3ce44SJohn Forte 	case LA_4GHZ_LINK:
1542*8f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "4Gb", sizeof (linkspeed));
1543fcf3ce44SJohn Forte 		state |= FC_STATE_4GBIT_SPEED;
1544fcf3ce44SJohn Forte 		break;
1545fcf3ce44SJohn Forte 	case LA_8GHZ_LINK:
1546*8f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "8Gb", sizeof (linkspeed));
1547fcf3ce44SJohn Forte 		state |= FC_STATE_8GBIT_SPEED;
1548fcf3ce44SJohn Forte 		break;
1549fcf3ce44SJohn Forte 	case LA_10GHZ_LINK:
1550*8f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "10Gb", sizeof (linkspeed));
1551fcf3ce44SJohn Forte 		state |= FC_STATE_10GBIT_SPEED;
1552fcf3ce44SJohn Forte 		break;
1553*8f23e9faSHans Rosenfeld 	case LA_16GHZ_LINK:
1554*8f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "16Gb", sizeof (linkspeed));
1555*8f23e9faSHans Rosenfeld 		state |= FC_STATE_16GBIT_SPEED;
1556*8f23e9faSHans Rosenfeld 		break;
1557fcf3ce44SJohn Forte 	default:
1558*8f23e9faSHans Rosenfeld 		(void) snprintf(linkspeed, sizeof (linkspeed), "unknown(0x%x)",
1559*8f23e9faSHans Rosenfeld 		    hba->linkspeed);
1560fcf3ce44SJohn Forte 		break;
1561fcf3ce44SJohn Forte 	}
1562fcf3ce44SJohn Forte 
1563fcf3ce44SJohn Forte 	npiv_linkup = 0;
1564fcf3ce44SJohn Forte 	update = 0;
1565fcf3ce44SJohn Forte 
1566fcf3ce44SJohn Forte 	if ((hba->state >= FC_LINK_UP) &&
1567291a2b48SSukumar Swaminathan 	    !(hba->flag & FC_LOOPBACK_MODE) && (vport->ulp_statec != state)) {
1568fcf3ce44SJohn Forte 		update = 1;
1569fcf3ce44SJohn Forte 		vport->ulp_statec = state;
1570fcf3ce44SJohn Forte 
1571fcf3ce44SJohn Forte 		if ((vport->vpi > 0) && !(hba->flag & FC_NPIV_LINKUP)) {
1572fcf3ce44SJohn Forte 			hba->flag |= FC_NPIV_LINKUP;
1573fcf3ce44SJohn Forte 			npiv_linkup = 1;
1574fcf3ce44SJohn Forte 		}
1575fcf3ce44SJohn Forte 	}
1576291a2b48SSukumar Swaminathan 
1577fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1578fcf3ce44SJohn Forte 
1579fcf3ce44SJohn Forte 	if (update) {
1580fcf3ce44SJohn Forte 		if (vport->flag & EMLXS_PORT_BOUND) {
1581fcf3ce44SJohn Forte 			if (vport->vpi == 0) {
1582fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1583291a2b48SSukumar Swaminathan 				    "%s%s%s", linkspeed, topology, mode);
15846a573d82SSukumar Swaminathan 
1585fcf3ce44SJohn Forte 			} else if (npiv_linkup) {
1586fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT,
1587291a2b48SSukumar Swaminathan 				    &emlxs_npiv_link_up_msg, "%s%s%s",
1588fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1589fcf3ce44SJohn Forte 			}
1590291a2b48SSukumar Swaminathan 
1591*8f23e9faSHans Rosenfeld 			if (vport->mode == MODE_INITIATOR) {
1592*8f23e9faSHans Rosenfeld 				emlxs_fca_link_up(vport);
1593fcf3ce44SJohn Forte 			}
15943be114edSSukumar Swaminathan #ifdef SFCT_SUPPORT
1595*8f23e9faSHans Rosenfeld 			else if (vport->mode == MODE_TARGET) {
15963be114edSSukumar Swaminathan 				emlxs_fct_link_up(vport);
15973be114edSSukumar Swaminathan 			}
15983be114edSSukumar Swaminathan #endif /* SFCT_SUPPORT */
1599fcf3ce44SJohn Forte 		} else {
1600fcf3ce44SJohn Forte 			if (vport->vpi == 0) {
1601fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1602291a2b48SSukumar Swaminathan 				    "%s%s%s *", linkspeed, topology, mode);
16036a573d82SSukumar Swaminathan 
1604fcf3ce44SJohn Forte 			} else if (npiv_linkup) {
1605fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT,
1606291a2b48SSukumar Swaminathan 				    &emlxs_npiv_link_up_msg, "%s%s%s *",
1607fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1608fcf3ce44SJohn Forte 			}
1609fcf3ce44SJohn Forte 		}
1610fcf3ce44SJohn Forte 
1611fcf3ce44SJohn Forte 		/* Check for waiting threads */
1612fcf3ce44SJohn Forte 		if (vport->vpi == 0) {
1613fcf3ce44SJohn Forte 			mutex_enter(&EMLXS_LINKUP_LOCK);
1614fcf3ce44SJohn Forte 			if (hba->linkup_wait_flag == TRUE) {
1615fcf3ce44SJohn Forte 				hba->linkup_wait_flag = FALSE;
1616fcf3ce44SJohn Forte 				cv_broadcast(&EMLXS_LINKUP_CV);
1617fcf3ce44SJohn Forte 			}
1618fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_LINKUP_LOCK);
1619fcf3ce44SJohn Forte 		}
1620291a2b48SSukumar Swaminathan 
1621fcf3ce44SJohn Forte 		/* Flush any pending ub buffers */
1622fcf3ce44SJohn Forte 		emlxs_ub_flush(vport);
1623fcf3ce44SJohn Forte 	}
1624291a2b48SSukumar Swaminathan 
1625fcf3ce44SJohn Forte 	return;
1626fcf3ce44SJohn Forte 
162782527734SSukumar Swaminathan } /* emlxs_port_online() */
1628fcf3ce44SJohn Forte 
1629fcf3ce44SJohn Forte 
1630a9800bebSGarrett D'Amore /* SLI3 */
1631fcf3ce44SJohn Forte extern void
1632fcf3ce44SJohn Forte emlxs_linkdown(emlxs_hba_t *hba)
1633fcf3ce44SJohn Forte {
1634fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1635fcf3ce44SJohn Forte 	int i;
1636a9800bebSGarrett D'Amore 	uint32_t scope;
1637fcf3ce44SJohn Forte 
1638fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1639fcf3ce44SJohn Forte 
164082527734SSukumar Swaminathan 	if (hba->state > FC_LINK_DOWN) {
164182527734SSukumar Swaminathan 		HBASTATS.LinkDown++;
164282527734SSukumar Swaminathan 		EMLXS_STATE_CHANGE_LOCKED(hba, FC_LINK_DOWN);
164382527734SSukumar Swaminathan 	}
1644fcf3ce44SJohn Forte 
1645a9800bebSGarrett D'Amore 	/* Set scope */
1646a9800bebSGarrett D'Amore 	scope = (hba->flag & FC_NEW_FABRIC)? 0xFDFFFFFF:0xFFFFFFFF;
1647a9800bebSGarrett D'Amore 
1648fcf3ce44SJohn Forte 	/* Filter hba flags */
1649fcf3ce44SJohn Forte 	hba->flag &= FC_LINKDOWN_MASK;
1650fcf3ce44SJohn Forte 	hba->discovery_timer = 0;
1651fcf3ce44SJohn Forte 	hba->linkup_timer = 0;
1652fcf3ce44SJohn Forte 
1653fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1654fcf3ce44SJohn Forte 
1655fcf3ce44SJohn Forte 	for (i = 0; i < MAX_VPORTS; i++) {
1656fcf3ce44SJohn Forte 		port = &VPORT(i);
1657fcf3ce44SJohn Forte 
1658fcf3ce44SJohn Forte 		if (!(port->flag & EMLXS_PORT_BOUND)) {
1659fcf3ce44SJohn Forte 			continue;
1660fcf3ce44SJohn Forte 		}
1661291a2b48SSukumar Swaminathan 
1662a9800bebSGarrett D'Amore 		(void) emlxs_port_offline(port, scope);
1663fcf3ce44SJohn Forte 
1664fcf3ce44SJohn Forte 	}
1665fcf3ce44SJohn Forte 
1666a9800bebSGarrett D'Amore 	emlxs_log_link_event(port);
1667a9800bebSGarrett D'Amore 
1668fcf3ce44SJohn Forte 	return;
1669fcf3ce44SJohn Forte 
167082527734SSukumar Swaminathan } /* emlxs_linkdown() */
1671fcf3ce44SJohn Forte 
1672fcf3ce44SJohn Forte 
1673a9800bebSGarrett D'Amore /* SLI3 */
1674fcf3ce44SJohn Forte extern void
1675fcf3ce44SJohn Forte emlxs_linkup(emlxs_hba_t *hba)
1676fcf3ce44SJohn Forte {
1677fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1678fcf3ce44SJohn Forte 	emlxs_config_t *cfg = &CFG;
1679fcf3ce44SJohn Forte 
1680fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1681fcf3ce44SJohn Forte 
1682*8f23e9faSHans Rosenfeld 	/* Check for any mode changes */
1683*8f23e9faSHans Rosenfeld 	emlxs_mode_set(hba);
1684*8f23e9faSHans Rosenfeld 
1685fcf3ce44SJohn Forte 	HBASTATS.LinkUp++;
168682527734SSukumar Swaminathan 	EMLXS_STATE_CHANGE_LOCKED(hba, FC_LINK_UP);
1687fcf3ce44SJohn Forte 
1688fcf3ce44SJohn Forte #ifdef MENLO_SUPPORT
1689fcf3ce44SJohn Forte 	if (hba->flag & FC_MENLO_MODE) {
1690fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1691fcf3ce44SJohn Forte 
1692fcf3ce44SJohn Forte 		/*
1693fcf3ce44SJohn Forte 		 * Trigger linkup CV and don't start linkup & discovery
1694fcf3ce44SJohn Forte 		 * timers
1695fcf3ce44SJohn Forte 		 */
1696fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_LINKUP_LOCK);
1697fcf3ce44SJohn Forte 		cv_broadcast(&EMLXS_LINKUP_CV);
1698fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_LINKUP_LOCK);
1699fcf3ce44SJohn Forte 
1700a9800bebSGarrett D'Amore 		emlxs_log_link_event(port);
1701a9800bebSGarrett D'Amore 
1702fcf3ce44SJohn Forte 		return;
1703fcf3ce44SJohn Forte 	}
1704291a2b48SSukumar Swaminathan #endif /* MENLO_SUPPORT */
1705fcf3ce44SJohn Forte 
1706fcf3ce44SJohn Forte 	/* Set the linkup & discovery timers */
1707fcf3ce44SJohn Forte 	hba->linkup_timer = hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current;
1708291a2b48SSukumar Swaminathan 	hba->discovery_timer =
1709291a2b48SSukumar Swaminathan 	    hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current +
1710291a2b48SSukumar Swaminathan 	    cfg[CFG_DISC_TIMEOUT].current;
1711fcf3ce44SJohn Forte 
1712fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1713fcf3ce44SJohn Forte 
1714a9800bebSGarrett D'Amore 	emlxs_log_link_event(port);
1715a9800bebSGarrett D'Amore 
1716fcf3ce44SJohn Forte 	return;
1717fcf3ce44SJohn Forte 
171882527734SSukumar Swaminathan } /* emlxs_linkup() */
1719fcf3ce44SJohn Forte 
1720fcf3ce44SJohn Forte 
1721fcf3ce44SJohn Forte /*
1722fcf3ce44SJohn Forte  *  emlxs_reset_link
1723fcf3ce44SJohn Forte  *
1724fcf3ce44SJohn Forte  *  Description:
1725fcf3ce44SJohn Forte  *  Called to reset the link with an init_link
1726fcf3ce44SJohn Forte  *
1727fcf3ce44SJohn Forte  *    Returns:
1728fcf3ce44SJohn Forte  *
1729fcf3ce44SJohn Forte  */
1730fcf3ce44SJohn Forte extern int
173182527734SSukumar Swaminathan emlxs_reset_link(emlxs_hba_t *hba, uint32_t linkup, uint32_t wait)
1732fcf3ce44SJohn Forte {
1733fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1734fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
173582527734SSukumar Swaminathan 	MAILBOXQ *mbq = NULL;
173682527734SSukumar Swaminathan 	MAILBOX *mb = NULL;
173782527734SSukumar Swaminathan 	int rval = 0;
1738*8f23e9faSHans Rosenfeld 	int tmo;
173982527734SSukumar Swaminathan 	int rc;
1740fcf3ce44SJohn Forte 
1741fcf3ce44SJohn Forte 	/*
1742fcf3ce44SJohn Forte 	 * Get a buffer to use for the mailbox command
1743fcf3ce44SJohn Forte 	 */
1744*8f23e9faSHans Rosenfeld 	if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))
174582527734SSukumar Swaminathan 	    == NULL) {
1746fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_failed_msg,
1747fcf3ce44SJohn Forte 		    "Unable to allocate mailbox buffer.");
174882527734SSukumar Swaminathan 		rval = 1;
174982527734SSukumar Swaminathan 		goto reset_link_fail;
175082527734SSukumar Swaminathan 	}
1751fcf3ce44SJohn Forte 
1752a9800bebSGarrett D'Amore 	if (linkup) {
1753a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg,
1754a9800bebSGarrett D'Amore 		    "Resetting link...");
1755a9800bebSGarrett D'Amore 	} else {
1756a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg,
1757a9800bebSGarrett D'Amore 		    "Disabling link...");
1758a9800bebSGarrett D'Amore 	}
1759a9800bebSGarrett D'Amore 
176082527734SSukumar Swaminathan 	mb = (MAILBOX *)mbq;
176182527734SSukumar Swaminathan 
176282527734SSukumar Swaminathan 	/* Bring link down first */
176382527734SSukumar Swaminathan 	emlxs_mb_down_link(hba, mbq);
176482527734SSukumar Swaminathan 
176582527734SSukumar Swaminathan #define	MBXERR_LINK_DOWN	0x33
176682527734SSukumar Swaminathan 
176782527734SSukumar Swaminathan 	if (wait) {
176882527734SSukumar Swaminathan 		wait = MBX_WAIT;
176982527734SSukumar Swaminathan 	} else {
177082527734SSukumar Swaminathan 		wait = MBX_NOWAIT;
177182527734SSukumar Swaminathan 	}
177282527734SSukumar Swaminathan 	rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, wait, 0);
177382527734SSukumar Swaminathan 	if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS) &&
177482527734SSukumar Swaminathan 	    (rc != MBXERR_LINK_DOWN)) {
177582527734SSukumar Swaminathan 		rval = 1;
177682527734SSukumar Swaminathan 		goto reset_link_fail;
1777fcf3ce44SJohn Forte 	}
1778291a2b48SSukumar Swaminathan 
1779*8f23e9faSHans Rosenfeld 	tmo = 120;
1780*8f23e9faSHans Rosenfeld 	do {
1781*8f23e9faSHans Rosenfeld 		delay(drv_usectohz(500000));
1782*8f23e9faSHans Rosenfeld 		tmo--;
1783*8f23e9faSHans Rosenfeld 
1784*8f23e9faSHans Rosenfeld 		if (!tmo)   {
1785*8f23e9faSHans Rosenfeld 			rval = 1;
1786*8f23e9faSHans Rosenfeld 
1787*8f23e9faSHans Rosenfeld 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg,
1788*8f23e9faSHans Rosenfeld 			    "Linkdown timeout.");
1789*8f23e9faSHans Rosenfeld 
1790*8f23e9faSHans Rosenfeld 			goto reset_link_fail;
1791*8f23e9faSHans Rosenfeld 		}
1792*8f23e9faSHans Rosenfeld 	} while ((hba->state >= FC_LINK_UP) && (hba->state != FC_ERROR));
1793*8f23e9faSHans Rosenfeld 
1794fcf3ce44SJohn Forte 	if (linkup) {
1795fcf3ce44SJohn Forte 		/*
1796fcf3ce44SJohn Forte 		 * Setup and issue mailbox INITIALIZE LINK command
1797fcf3ce44SJohn Forte 		 */
1798fcf3ce44SJohn Forte 
179982527734SSukumar Swaminathan 		if (wait == MBX_NOWAIT) {
1800*8f23e9faSHans Rosenfeld 			if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))
180182527734SSukumar Swaminathan 			    == NULL) {
180282527734SSukumar Swaminathan 				EMLXS_MSGF(EMLXS_CONTEXT,
180382527734SSukumar Swaminathan 				    &emlxs_link_reset_failed_msg,
180482527734SSukumar Swaminathan 				    "Unable to allocate mailbox buffer.");
180582527734SSukumar Swaminathan 				rval = 1;
180682527734SSukumar Swaminathan 				goto reset_link_fail;
180782527734SSukumar Swaminathan 			}
180882527734SSukumar Swaminathan 			mb = (MAILBOX *)mbq;
180982527734SSukumar Swaminathan 		} else {
181082527734SSukumar Swaminathan 			/* Reuse mbq from previous mbox */
181182527734SSukumar Swaminathan 			mb = (MAILBOX *)mbq;
181282527734SSukumar Swaminathan 		}
181382527734SSukumar Swaminathan 		cfg = &CFG;
181482527734SSukumar Swaminathan 
181582527734SSukumar Swaminathan 		emlxs_mb_init_link(hba, mbq,
1816fcf3ce44SJohn Forte 		    cfg[CFG_TOPOLOGY].current, cfg[CFG_LINK_SPEED].current);
1817fcf3ce44SJohn Forte 
1818fcf3ce44SJohn Forte 		mb->un.varInitLnk.lipsr_AL_PA = 0;
1819fcf3ce44SJohn Forte 
1820fcf3ce44SJohn Forte 		/* Clear the loopback mode */
1821fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1822fcf3ce44SJohn Forte 		hba->flag &= ~FC_LOOPBACK_MODE;
1823291a2b48SSukumar Swaminathan 		hba->loopback_tics = 0;
1824fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1825fcf3ce44SJohn Forte 
182682527734SSukumar Swaminathan 		rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, wait, 0);
182782527734SSukumar Swaminathan 		if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
182882527734SSukumar Swaminathan 			rval = 1;
182982527734SSukumar Swaminathan 			goto reset_link_fail;
1830fcf3ce44SJohn Forte 		}
1831291a2b48SSukumar Swaminathan 
1832fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg, NULL);
183382527734SSukumar Swaminathan 	}
1834fcf3ce44SJohn Forte 
183582527734SSukumar Swaminathan reset_link_fail:
1836291a2b48SSukumar Swaminathan 
183782527734SSukumar Swaminathan 	if ((wait == MBX_WAIT) && mbq) {
1838a9800bebSGarrett D'Amore 		emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
1839fcf3ce44SJohn Forte 	}
1840fcf3ce44SJohn Forte 
184182527734SSukumar Swaminathan 	return (rval);
184282527734SSukumar Swaminathan } /* emlxs_reset_link() */
1843fcf3ce44SJohn Forte 
1844fcf3ce44SJohn Forte 
1845fcf3ce44SJohn Forte extern int
1846fcf3ce44SJohn Forte emlxs_online(emlxs_hba_t *hba)
1847fcf3ce44SJohn Forte {
1848fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1849fcf3ce44SJohn Forte 	int32_t rval = 0;
1850fcf3ce44SJohn Forte 	uint32_t i = 0;
1851fcf3ce44SJohn Forte 
1852fcf3ce44SJohn Forte 	/* Make sure adapter is offline or exit trying (30 seconds) */
1853291a2b48SSukumar Swaminathan 	while (i++ < 30) {
1854fcf3ce44SJohn Forte 		/* Check if adapter is already going online */
1855fcf3ce44SJohn Forte 		if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) {
1856fcf3ce44SJohn Forte 			return (0);
1857fcf3ce44SJohn Forte 		}
1858291a2b48SSukumar Swaminathan 
1859fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1860fcf3ce44SJohn Forte 
1861fcf3ce44SJohn Forte 		/* Check again */
1862fcf3ce44SJohn Forte 		if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) {
1863fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1864fcf3ce44SJohn Forte 			return (0);
1865fcf3ce44SJohn Forte 		}
1866291a2b48SSukumar Swaminathan 
1867fcf3ce44SJohn Forte 		/* Check if adapter is offline */
1868fcf3ce44SJohn Forte 		if (hba->flag & FC_OFFLINE_MODE) {
1869fcf3ce44SJohn Forte 			/* Mark it going online */
1870fcf3ce44SJohn Forte 			hba->flag &= ~FC_OFFLINE_MODE;
1871fcf3ce44SJohn Forte 			hba->flag |= FC_ONLINING_MODE;
1872fcf3ce44SJohn Forte 
1873fcf3ce44SJohn Forte 			/* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */
1874fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1875fcf3ce44SJohn Forte 			break;
1876fcf3ce44SJohn Forte 		}
1877291a2b48SSukumar Swaminathan 
1878fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1879fcf3ce44SJohn Forte 
1880*8f23e9faSHans Rosenfeld 		BUSYWAIT_MS(1000);
1881fcf3ce44SJohn Forte 	}
1882fcf3ce44SJohn Forte 
1883fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
1884fcf3ce44SJohn Forte 	    "Going online...");
1885fcf3ce44SJohn Forte 
188682527734SSukumar Swaminathan 	if (rval = EMLXS_SLI_ONLINE(hba)) {
1887291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg, "status=%x",
1888fcf3ce44SJohn Forte 		    rval);
1889fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL);
1890fcf3ce44SJohn Forte 
1891fcf3ce44SJohn Forte 		/* Set FC_OFFLINE_MODE */
1892fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1893fcf3ce44SJohn Forte 		hba->flag |= FC_OFFLINE_MODE;
1894fcf3ce44SJohn Forte 		hba->flag &= ~FC_ONLINING_MODE;
1895fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1896fcf3ce44SJohn Forte 
1897fcf3ce44SJohn Forte 		return (rval);
1898fcf3ce44SJohn Forte 	}
1899291a2b48SSukumar Swaminathan 
1900fcf3ce44SJohn Forte 	/* Start the timer */
1901fcf3ce44SJohn Forte 	emlxs_timer_start(hba);
1902fcf3ce44SJohn Forte 
1903fcf3ce44SJohn Forte 	/* Set FC_ONLINE_MODE */
1904fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1905fcf3ce44SJohn Forte 	hba->flag |= FC_ONLINE_MODE;
1906fcf3ce44SJohn Forte 	hba->flag &= ~FC_ONLINING_MODE;
1907fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1908fcf3ce44SJohn Forte 
1909fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_online_msg, NULL);
1910fcf3ce44SJohn Forte 
1911fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
1912*8f23e9faSHans Rosenfeld 	if (port->flag & EMLXS_TGT_ENABLED) {
1913*8f23e9faSHans Rosenfeld 		(void) emlxs_fct_port_initialize(port);
1914*8f23e9faSHans Rosenfeld 	}
1915291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
1916fcf3ce44SJohn Forte 
1917fcf3ce44SJohn Forte 	return (rval);
1918fcf3ce44SJohn Forte 
191982527734SSukumar Swaminathan } /* emlxs_online() */
1920fcf3ce44SJohn Forte 
1921fcf3ce44SJohn Forte 
1922fcf3ce44SJohn Forte extern int
1923*8f23e9faSHans Rosenfeld emlxs_offline(emlxs_hba_t *hba, uint32_t reset_requested)
1924fcf3ce44SJohn Forte {
1925fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1926fcf3ce44SJohn Forte 	uint32_t i = 0;
1927fcf3ce44SJohn Forte 	int rval = 1;
1928fcf3ce44SJohn Forte 
1929fcf3ce44SJohn Forte 	/* Make sure adapter is online or exit trying (30 seconds) */
1930291a2b48SSukumar Swaminathan 	while (i++ < 30) {
1931fcf3ce44SJohn Forte 		/* Check if adapter is already going offline */
1932fcf3ce44SJohn Forte 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1933fcf3ce44SJohn Forte 			return (0);
1934fcf3ce44SJohn Forte 		}
1935291a2b48SSukumar Swaminathan 
1936fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1937fcf3ce44SJohn Forte 
1938fcf3ce44SJohn Forte 		/* Check again */
1939fcf3ce44SJohn Forte 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1940fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1941fcf3ce44SJohn Forte 			return (0);
1942fcf3ce44SJohn Forte 		}
1943291a2b48SSukumar Swaminathan 
1944fcf3ce44SJohn Forte 		/* Check if adapter is online */
1945fcf3ce44SJohn Forte 		if (hba->flag & FC_ONLINE_MODE) {
1946fcf3ce44SJohn Forte 			/* Mark it going offline */
1947fcf3ce44SJohn Forte 			hba->flag &= ~FC_ONLINE_MODE;
1948fcf3ce44SJohn Forte 			hba->flag |= FC_OFFLINING_MODE;
1949fcf3ce44SJohn Forte 
1950fcf3ce44SJohn Forte 			/* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */
1951fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1952fcf3ce44SJohn Forte 			break;
1953fcf3ce44SJohn Forte 		}
1954291a2b48SSukumar Swaminathan 
1955fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1956fcf3ce44SJohn Forte 
1957*8f23e9faSHans Rosenfeld 		BUSYWAIT_MS(1000);
1958fcf3ce44SJohn Forte 	}
1959fcf3ce44SJohn Forte 
1960291a2b48SSukumar Swaminathan 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
1961291a2b48SSukumar Swaminathan 	    "Going offline...");
1962fcf3ce44SJohn Forte 
1963*8f23e9faSHans Rosenfeld 	/* Declare link down */
1964*8f23e9faSHans Rosenfeld 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1965*8f23e9faSHans Rosenfeld 		(void) emlxs_fcf_shutdown_notify(port, 1);
1966*8f23e9faSHans Rosenfeld 	} else {
1967*8f23e9faSHans Rosenfeld 		emlxs_linkdown(hba);
1968fcf3ce44SJohn Forte 	}
1969*8f23e9faSHans Rosenfeld 
1970fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
1971*8f23e9faSHans Rosenfeld 	if (port->flag & EMLXS_TGT_ENABLED) {
1972fcf3ce44SJohn Forte 		(void) emlxs_fct_port_shutdown(port);
1973fcf3ce44SJohn Forte 	}
1974291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
1975fcf3ce44SJohn Forte 
1976fcf3ce44SJohn Forte 	/* Check if adapter was shutdown */
1977fcf3ce44SJohn Forte 	if (hba->flag & FC_HARDWARE_ERROR) {
1978291a2b48SSukumar Swaminathan 		/*
1979291a2b48SSukumar Swaminathan 		 * Force mailbox cleanup
1980291a2b48SSukumar Swaminathan 		 * This will wake any sleeping or polling threads
1981291a2b48SSukumar Swaminathan 		 */
1982fcf3ce44SJohn Forte 		emlxs_mb_fini(hba, NULL, MBX_HARDWARE_ERROR);
1983fcf3ce44SJohn Forte 	}
1984291a2b48SSukumar Swaminathan 
1985fcf3ce44SJohn Forte 	/* Pause here for the IO to settle */
1986fcf3ce44SJohn Forte 	delay(drv_usectohz(1000000));	/* 1 sec */
1987fcf3ce44SJohn Forte 
1988fcf3ce44SJohn Forte 	/* Unregister all nodes */
1989fcf3ce44SJohn Forte 	emlxs_ffcleanup(hba);
1990fcf3ce44SJohn Forte 
1991fcf3ce44SJohn Forte 	if (hba->bus_type == SBUS_FC) {
199282527734SSukumar Swaminathan 		WRITE_SBUS_CSR_REG(hba, FC_SHS_REG(hba), 0x9A);
19934baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
199482527734SSukumar Swaminathan 		/* Access handle validation */
199582527734SSukumar Swaminathan 		EMLXS_CHK_ACC_HANDLE(hba, hba->sli.sli3.sbus_csr_handle);
19964baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
1997fcf3ce44SJohn Forte 	}
1998291a2b48SSukumar Swaminathan 
1999fcf3ce44SJohn Forte 	/* Stop the timer */
2000fcf3ce44SJohn Forte 	emlxs_timer_stop(hba);
2001fcf3ce44SJohn Forte 
2002fcf3ce44SJohn Forte 	/* For safety flush every iotag list */
2003fcf3ce44SJohn Forte 	if (emlxs_iotag_flush(hba)) {
2004fcf3ce44SJohn Forte 		/* Pause here for the IO to flush */
2005728bdc9bSSukumar Swaminathan 		delay(drv_usectohz(1000));
2006728bdc9bSSukumar Swaminathan 	}
2007728bdc9bSSukumar Swaminathan 
2008728bdc9bSSukumar Swaminathan 	/* Wait for poll command request to settle */
2009728bdc9bSSukumar Swaminathan 	while (hba->io_poll_count > 0) {
2010728bdc9bSSukumar Swaminathan 		delay(drv_usectohz(2000000));   /* 2 sec */
2011fcf3ce44SJohn Forte 	}
2012728bdc9bSSukumar Swaminathan 
201382527734SSukumar Swaminathan 	/* Shutdown the adapter interface */
2014*8f23e9faSHans Rosenfeld 	EMLXS_SLI_OFFLINE(hba, reset_requested);
2015fcf3ce44SJohn Forte 
2016fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
2017fcf3ce44SJohn Forte 	hba->flag |= FC_OFFLINE_MODE;
2018fcf3ce44SJohn Forte 	hba->flag &= ~FC_OFFLINING_MODE;
2019fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
2020fcf3ce44SJohn Forte 
2021fcf3ce44SJohn Forte 	rval = 0;
2022fcf3ce44SJohn Forte 
2023fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL);
2024fcf3ce44SJohn Forte 
2025fcf3ce44SJohn Forte done:
2026fcf3ce44SJohn Forte 
2027fcf3ce44SJohn Forte 	return (rval);
2028fcf3ce44SJohn Forte 
202982527734SSukumar Swaminathan } /* emlxs_offline() */
2030fcf3ce44SJohn Forte 
2031fcf3ce44SJohn Forte 
2032fcf3ce44SJohn Forte 
2033fcf3ce44SJohn Forte extern int
2034fcf3ce44SJohn Forte emlxs_power_down(emlxs_hba_t *hba)
2035fcf3ce44SJohn Forte {
20364baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
20374baa2c25SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
20384baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
2039fcf3ce44SJohn Forte 	int32_t rval = 0;
2040fcf3ce44SJohn Forte 
2041*8f23e9faSHans Rosenfeld 	if ((rval = emlxs_offline(hba, 0))) {
2042fcf3ce44SJohn Forte 		return (rval);
2043fcf3ce44SJohn Forte 	}
204482527734SSukumar Swaminathan 	EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
2045291a2b48SSukumar Swaminathan 
2046fcf3ce44SJohn Forte 
20474baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
20484baa2c25SSukumar Swaminathan 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
20494baa2c25SSukumar Swaminathan 	    != DDI_FM_OK) {
20504baa2c25SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT,
20514baa2c25SSukumar Swaminathan 		    &emlxs_invalid_access_handle_msg, NULL);
20524baa2c25SSukumar Swaminathan 		return (1);
20534baa2c25SSukumar Swaminathan 	}
20544baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
20554baa2c25SSukumar Swaminathan 
2056fcf3ce44SJohn Forte 	return (0);
2057fcf3ce44SJohn Forte 
205882527734SSukumar Swaminathan } /* End emlxs_power_down */
2059fcf3ce44SJohn Forte 
2060fcf3ce44SJohn Forte 
2061fcf3ce44SJohn Forte extern int
2062fcf3ce44SJohn Forte emlxs_power_up(emlxs_hba_t *hba)
2063fcf3ce44SJohn Forte {
20644baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
20654baa2c25SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
20664baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
2067fcf3ce44SJohn Forte 	int32_t rval = 0;
2068fcf3ce44SJohn Forte 
2069fcf3ce44SJohn Forte 
20704baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
20714baa2c25SSukumar Swaminathan 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
20724baa2c25SSukumar Swaminathan 	    != DDI_FM_OK) {
20734baa2c25SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT,
20744baa2c25SSukumar Swaminathan 		    &emlxs_invalid_access_handle_msg, NULL);
20754baa2c25SSukumar Swaminathan 		return (1);
20764baa2c25SSukumar Swaminathan 	}
20774baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
20784baa2c25SSukumar Swaminathan 
2079fcf3ce44SJohn Forte 	/* Bring adapter online */
2080fcf3ce44SJohn Forte 	if ((rval = emlxs_online(hba))) {
2081a9800bebSGarrett D'Amore 		if (hba->pci_cap_offset[PCI_CAP_ID_PM]) {
2082a9800bebSGarrett D'Amore 			/* Put chip in D3 state */
2083a9800bebSGarrett D'Amore 			(void) ddi_put8(hba->pci_acc_handle,
2084a9800bebSGarrett D'Amore 			    (uint8_t *)(hba->pci_addr +
2085a9800bebSGarrett D'Amore 			    hba->pci_cap_offset[PCI_CAP_ID_PM] +
2086a9800bebSGarrett D'Amore 			    PCI_PMCSR),
2087a9800bebSGarrett D'Amore 			    (uint8_t)PCI_PMCSR_D3HOT);
2088a9800bebSGarrett D'Amore 		}
2089fcf3ce44SJohn Forte 		return (rval);
2090fcf3ce44SJohn Forte 	}
2091291a2b48SSukumar Swaminathan 
2092fcf3ce44SJohn Forte 	return (rval);
2093fcf3ce44SJohn Forte 
2094*8f23e9faSHans Rosenfeld } /* emlxs_power_up() */
2095fcf3ce44SJohn Forte 
2096fcf3ce44SJohn Forte 
2097fcf3ce44SJohn Forte /*
2098291a2b48SSukumar Swaminathan  *
2099fcf3ce44SJohn Forte  * NAME:     emlxs_ffcleanup
2100fcf3ce44SJohn Forte  *
2101fcf3ce44SJohn Forte  * FUNCTION: Cleanup all the Firefly resources used by configuring the adapter
2102fcf3ce44SJohn Forte  *
2103fcf3ce44SJohn Forte  * EXECUTION ENVIRONMENT: process only
2104fcf3ce44SJohn Forte  *
2105fcf3ce44SJohn Forte  * CALLED FROM: CFG_TERM
2106fcf3ce44SJohn Forte  *
2107fcf3ce44SJohn Forte  * INPUT: hba       - pointer to the dev_ctl area.
2108fcf3ce44SJohn Forte  *
2109fcf3ce44SJohn Forte  * RETURNS: none
2110fcf3ce44SJohn Forte  */
2111fcf3ce44SJohn Forte extern void
2112fcf3ce44SJohn Forte emlxs_ffcleanup(emlxs_hba_t *hba)
2113fcf3ce44SJohn Forte {
2114fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2115291a2b48SSukumar Swaminathan 	uint32_t i;
2116fcf3ce44SJohn Forte 
2117fcf3ce44SJohn Forte 	/* Disable all but the mailbox interrupt */
211882527734SSukumar Swaminathan 	EMLXS_SLI_DISABLE_INTR(hba, HC_MBINT_ENA);
2119fcf3ce44SJohn Forte 
2120fcf3ce44SJohn Forte 	/* Make sure all port nodes are destroyed */
2121291a2b48SSukumar Swaminathan 	for (i = 0; i < MAX_VPORTS; i++) {
2122291a2b48SSukumar Swaminathan 		port = &VPORT(i);
2123fcf3ce44SJohn Forte 
2124fcf3ce44SJohn Forte 		if (port->node_count) {
2125*8f23e9faSHans Rosenfeld 			(void) EMLXS_SLI_UNREG_NODE(port, 0, 0, 0, 0);
2126fcf3ce44SJohn Forte 		}
2127fcf3ce44SJohn Forte 	}
2128fcf3ce44SJohn Forte 
2129fcf3ce44SJohn Forte 	/* Clear all interrupt enable conditions */
213082527734SSukumar Swaminathan 	EMLXS_SLI_DISABLE_INTR(hba, 0);
2131fcf3ce44SJohn Forte 
2132fcf3ce44SJohn Forte 	return;
2133fcf3ce44SJohn Forte 
213482527734SSukumar Swaminathan } /* emlxs_ffcleanup() */
2135fcf3ce44SJohn Forte 
2136fcf3ce44SJohn Forte 
2137fcf3ce44SJohn Forte extern uint16_t
213882527734SSukumar Swaminathan emlxs_register_pkt(CHANNEL *cp, emlxs_buf_t *sbp)
2139fcf3ce44SJohn Forte {
2140fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
2141fcf3ce44SJohn Forte 	emlxs_port_t *port;
2142fcf3ce44SJohn Forte 	uint16_t iotag;
2143fcf3ce44SJohn Forte 	uint32_t i;
2144fcf3ce44SJohn Forte 
214582527734SSukumar Swaminathan 	hba = cp->hba;
2146fcf3ce44SJohn Forte 
214782527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
2148fcf3ce44SJohn Forte 
2149fcf3ce44SJohn Forte 	if (sbp->iotag != 0) {
2150fcf3ce44SJohn Forte 		port = &PPORT;
2151fcf3ce44SJohn Forte 
2152fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
215382527734SSukumar Swaminathan 		    "Pkt already registered! channel=%d iotag=%d sbp=%p",
215482527734SSukumar Swaminathan 		    sbp->channel, sbp->iotag, sbp);
2155fcf3ce44SJohn Forte 	}
2156291a2b48SSukumar Swaminathan 
2157fcf3ce44SJohn Forte 	iotag = 0;
215882527734SSukumar Swaminathan 	for (i = 0; i < hba->max_iotag; i++) {
215982527734SSukumar Swaminathan 		if (!hba->fc_iotag || hba->fc_iotag >= hba->max_iotag) {
216082527734SSukumar Swaminathan 			hba->fc_iotag = 1;
2161fcf3ce44SJohn Forte 		}
216282527734SSukumar Swaminathan 		iotag = hba->fc_iotag++;
2163fcf3ce44SJohn Forte 
216482527734SSukumar Swaminathan 		if (hba->fc_table[iotag] == 0 ||
216582527734SSukumar Swaminathan 		    hba->fc_table[iotag] == STALE_PACKET) {
216682527734SSukumar Swaminathan 			hba->io_count++;
216782527734SSukumar Swaminathan 			hba->fc_table[iotag] = sbp;
2168fcf3ce44SJohn Forte 
2169fcf3ce44SJohn Forte 			sbp->iotag = iotag;
217082527734SSukumar Swaminathan 			sbp->channel = cp;
2171fcf3ce44SJohn Forte 
2172fcf3ce44SJohn Forte 			break;
2173fcf3ce44SJohn Forte 		}
2174fcf3ce44SJohn Forte 		iotag = 0;
2175fcf3ce44SJohn Forte 	}
2176fcf3ce44SJohn Forte 
217782527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
2178fcf3ce44SJohn Forte 
2179fcf3ce44SJohn Forte 	/*
2180fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
2181*8f23e9faSHans Rosenfeld 	 *    "register_pkt: channel=%d iotag=%d sbp=%p",
218282527734SSukumar Swaminathan 	 *    cp->channelno, iotag, sbp);
2183fcf3ce44SJohn Forte 	 */
2184fcf3ce44SJohn Forte 
2185fcf3ce44SJohn Forte 	return (iotag);
2186fcf3ce44SJohn Forte 
218782527734SSukumar Swaminathan } /* emlxs_register_pkt() */
2188fcf3ce44SJohn Forte 
2189fcf3ce44SJohn Forte 
2190fcf3ce44SJohn Forte 
2191fcf3ce44SJohn Forte extern emlxs_buf_t *
219282527734SSukumar Swaminathan emlxs_unregister_pkt(CHANNEL *cp, uint16_t iotag, uint32_t forced)
2193fcf3ce44SJohn Forte {
2194fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
2195fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
219682527734SSukumar Swaminathan 
219782527734SSukumar Swaminathan 	sbp = NULL;
219882527734SSukumar Swaminathan 	hba = cp->hba;
2199fcf3ce44SJohn Forte 
2200fcf3ce44SJohn Forte 	/* Check the iotag range */
220182527734SSukumar Swaminathan 	if ((iotag == 0) || (iotag >= hba->max_iotag)) {
2202fcf3ce44SJohn Forte 		return (NULL);
2203fcf3ce44SJohn Forte 	}
2204291a2b48SSukumar Swaminathan 
2205fcf3ce44SJohn Forte 	/* Remove the sbp from the table */
220682527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
220782527734SSukumar Swaminathan 	sbp = hba->fc_table[iotag];
2208fcf3ce44SJohn Forte 
2209fcf3ce44SJohn Forte 	if (!sbp || (sbp == STALE_PACKET)) {
221082527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
2211fcf3ce44SJohn Forte 		return (sbp);
2212fcf3ce44SJohn Forte 	}
2213291a2b48SSukumar Swaminathan 
221482527734SSukumar Swaminathan 	hba->fc_table[iotag] = ((forced) ? STALE_PACKET : NULL);
221582527734SSukumar Swaminathan 	hba->io_count--;
2216fcf3ce44SJohn Forte 	sbp->iotag = 0;
2217fcf3ce44SJohn Forte 
221882527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
2219fcf3ce44SJohn Forte 
2220fcf3ce44SJohn Forte 
2221fcf3ce44SJohn Forte 	/* Clean up the sbp */
2222fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
2223fcf3ce44SJohn Forte 
2224fcf3ce44SJohn Forte 	if (sbp->pkt_flags & PACKET_IN_TXQ) {
2225fcf3ce44SJohn Forte 		sbp->pkt_flags &= ~PACKET_IN_TXQ;
222682527734SSukumar Swaminathan 		hba->channel_tx_count--;
2227fcf3ce44SJohn Forte 	}
2228291a2b48SSukumar Swaminathan 
2229fcf3ce44SJohn Forte 	if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
2230fcf3ce44SJohn Forte 		sbp->pkt_flags &= ~PACKET_IN_CHIPQ;
2231fcf3ce44SJohn Forte 	}
2232291a2b48SSukumar Swaminathan 
2233fcf3ce44SJohn Forte 	if (sbp->bmp) {
2234a9800bebSGarrett D'Amore 		emlxs_mem_put(hba, MEM_BPL, (void *)sbp->bmp);
2235fcf3ce44SJohn Forte 		sbp->bmp = 0;
2236fcf3ce44SJohn Forte 	}
2237fcf3ce44SJohn Forte 
2238291a2b48SSukumar Swaminathan 	mutex_exit(&sbp->mtx);
2239fcf3ce44SJohn Forte 
2240fcf3ce44SJohn Forte 	return (sbp);
2241fcf3ce44SJohn Forte 
224282527734SSukumar Swaminathan } /* emlxs_unregister_pkt() */
2243fcf3ce44SJohn Forte 
2244fcf3ce44SJohn Forte 
2245fcf3ce44SJohn Forte 
224682527734SSukumar Swaminathan /* Flush all IO's to all nodes for a given IO Channel */
2247fcf3ce44SJohn Forte extern uint32_t
224882527734SSukumar Swaminathan emlxs_tx_channel_flush(emlxs_hba_t *hba, CHANNEL *cp, emlxs_buf_t *fpkt)
2249fcf3ce44SJohn Forte {
2250fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2251fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2252fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2253fcf3ce44SJohn Forte 	IOCBQ *next;
2254fcf3ce44SJohn Forte 	IOCB *iocb;
225582527734SSukumar Swaminathan 	uint32_t channelno;
2256fcf3ce44SJohn Forte 	Q abort;
2257fcf3ce44SJohn Forte 	NODELIST *ndlp;
2258fcf3ce44SJohn Forte 	IOCB *icmd;
2259fcf3ce44SJohn Forte 	MATCHMAP *mp;
2260fcf3ce44SJohn Forte 	uint32_t i;
226182527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2262fcf3ce44SJohn Forte 
226382527734SSukumar Swaminathan 	channelno = cp->channelno;
2264fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
226582527734SSukumar Swaminathan 	bzero((void *)flag, MAX_CHANNEL * sizeof (uint8_t));
2266fcf3ce44SJohn Forte 
226782527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2268fcf3ce44SJohn Forte 
2269fcf3ce44SJohn Forte 	/* While a node needs servicing */
227082527734SSukumar Swaminathan 	while (cp->nodeq.q_first) {
227182527734SSukumar Swaminathan 		ndlp = (NODELIST *) cp->nodeq.q_first;
2272fcf3ce44SJohn Forte 
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) {
227782527734SSukumar Swaminathan 				abort.q_first =
227882527734SSukumar Swaminathan 				    ndlp->nlp_ptx[channelno].q_first;
2279fcf3ce44SJohn Forte 			} else {
2280fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
228182527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_ptx[channelno].q_first;
2282fcf3ce44SJohn Forte 			}
228382527734SSukumar Swaminathan 			flag[channelno] = 1;
2284fcf3ce44SJohn Forte 
228582527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_ptx[channelno].q_last;
228682527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_ptx[channelno].q_cnt;
2287fcf3ce44SJohn Forte 		}
2288291a2b48SSukumar Swaminathan 
2289fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
229082527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
2291fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2292fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
229382527734SSukumar Swaminathan 				abort.q_first = ndlp->nlp_tx[channelno].q_first;
2294fcf3ce44SJohn Forte 			} else {
2295fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
229682527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2297fcf3ce44SJohn Forte 			}
2298fcf3ce44SJohn Forte 
229982527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_tx[channelno].q_last;
230082527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_tx[channelno].q_cnt;
2301fcf3ce44SJohn Forte 		}
2302291a2b48SSukumar Swaminathan 
2303fcf3ce44SJohn Forte 		/* Clear the queue pointers */
230482527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_first = NULL;
230582527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_last = NULL;
230682527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_cnt = 0;
2307fcf3ce44SJohn Forte 
230882527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_first = NULL;
230982527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_last = NULL;
231082527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_cnt = 0;
2311fcf3ce44SJohn Forte 
2312fcf3ce44SJohn Forte 		/* Remove node from service queue */
2313fcf3ce44SJohn Forte 
2314fcf3ce44SJohn Forte 		/* If this is the last node on list */
231582527734SSukumar Swaminathan 		if (cp->nodeq.q_last == (void *)ndlp) {
231682527734SSukumar Swaminathan 			cp->nodeq.q_last = NULL;
231782527734SSukumar Swaminathan 			cp->nodeq.q_first = NULL;
231882527734SSukumar Swaminathan 			cp->nodeq.q_cnt = 0;
2319fcf3ce44SJohn Forte 		} else {
2320fcf3ce44SJohn Forte 			/* Remove node from head */
232182527734SSukumar Swaminathan 			cp->nodeq.q_first = ndlp->nlp_next[channelno];
232282527734SSukumar Swaminathan 			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
232382527734SSukumar Swaminathan 			    cp->nodeq.q_first;
232482527734SSukumar Swaminathan 			cp->nodeq.q_cnt--;
2325fcf3ce44SJohn Forte 		}
2326fcf3ce44SJohn Forte 
2327fcf3ce44SJohn Forte 		/* Clear node */
232882527734SSukumar Swaminathan 		ndlp->nlp_next[channelno] = NULL;
2329fcf3ce44SJohn Forte 	}
2330fcf3ce44SJohn Forte 
2331fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2332291a2b48SSukumar Swaminathan 	iocbq = (IOCBQ *) abort.q_first;
2333fcf3ce44SJohn Forte 	while (iocbq) {
2334fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2335fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
233682527734SSukumar Swaminathan 
233782527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
233882527734SSukumar Swaminathan 			sbp = iocbq->sbp;
233982527734SSukumar Swaminathan 			if (sbp) {
2340*8f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
234182527734SSukumar Swaminathan 			}
234282527734SSukumar Swaminathan 		} else {
234382527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
234482527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
234582527734SSukumar Swaminathan 		}
2346fcf3ce44SJohn Forte 
2347fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2348fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2349fcf3ce44SJohn Forte 
2350fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2351fcf3ce44SJohn Forte 			/*
2352fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2353291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2354291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2355fcf3ce44SJohn Forte 			 */
2356fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2357fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2358fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2359fcf3ce44SJohn Forte 				fpkt->flush_count++;
2360fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2361fcf3ce44SJohn Forte 			}
2362291a2b48SSukumar Swaminathan 
2363fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2364fcf3ce44SJohn Forte 		}
2365291a2b48SSukumar Swaminathan 
2366fcf3ce44SJohn Forte 		iocbq = (IOCBQ *)iocbq->next;
2367fcf3ce44SJohn Forte 	}	/* end of while */
2368fcf3ce44SJohn Forte 
236982527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2370fcf3ce44SJohn Forte 
2371fcf3ce44SJohn Forte 	/* Now abort the iocb's */
2372fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2373fcf3ce44SJohn Forte 	while (iocbq) {
2374fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2375fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2376fcf3ce44SJohn Forte 
2377fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2378fcf3ce44SJohn Forte 		iocbq->next = NULL;
2379fcf3ce44SJohn Forte 
2380fcf3ce44SJohn Forte 		/* Get the pkt */
2381fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2382fcf3ce44SJohn Forte 
2383fcf3ce44SJohn Forte 		if (sbp) {
2384fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2385291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2386fcf3ce44SJohn Forte 
2387fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2388fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2389fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2390fcf3ce44SJohn Forte 			} else {
2391fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2392fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2393fcf3ce44SJohn Forte 			}
2394fcf3ce44SJohn Forte 
2395fcf3ce44SJohn Forte 		}
2396fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2397fcf3ce44SJohn Forte 		else {
2398fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
239982527734SSukumar Swaminathan 
240082527734SSukumar Swaminathan 			/* SLI3 */
240182527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
240282527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
240382527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2404fcf3ce44SJohn Forte 				if ((hba->flag &
2405fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2406fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
240782527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2408fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2409a9800bebSGarrett D'Amore 						void	*tmp;
241082527734SSukumar Swaminathan 						RING *rp;
2411fcf3ce44SJohn Forte 
241282527734SSukumar Swaminathan 						rp = &hba->sli.sli3.
241382527734SSukumar Swaminathan 						    ring[channelno];
2414fcf3ce44SJohn Forte 						for (i = 0;
241582527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2416fcf3ce44SJohn Forte 						    i++) {
2417fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2418fcf3ce44SJohn Forte 							    hba, rp, icmd);
2419fcf3ce44SJohn Forte 
2420a9800bebSGarrett D'Amore 							tmp = (void *)mp;
2421fcf3ce44SJohn Forte 							if (mp) {
2422a9800bebSGarrett D'Amore 							emlxs_mem_put(
2423291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2424fcf3ce44SJohn Forte 							}
2425fcf3ce44SJohn Forte 						}
2426fcf3ce44SJohn Forte 					}
2427291a2b48SSukumar Swaminathan 
2428a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
2429a9800bebSGarrett D'Amore 					    (void *)iocbq);
2430fcf3ce44SJohn Forte 				} else {
2431fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
243282527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp,
2433291a2b48SSukumar Swaminathan 					    iocbq);
2434fcf3ce44SJohn Forte 				}
243582527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
243682527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
243782527734SSukumar Swaminathan 
243882527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
2439fcf3ce44SJohn Forte 			}
2440fcf3ce44SJohn Forte 		}
2441fcf3ce44SJohn Forte 
2442fcf3ce44SJohn Forte 		iocbq = next;
2443fcf3ce44SJohn Forte 
2444fcf3ce44SJohn Forte 	}	/* end of while */
2445fcf3ce44SJohn Forte 
244682527734SSukumar Swaminathan 	/* Now trigger channel service */
244782527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
244882527734SSukumar Swaminathan 		if (!flag[channelno]) {
244982527734SSukumar Swaminathan 			continue;
245082527734SSukumar Swaminathan 		}
245182527734SSukumar Swaminathan 
245282527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
245382527734SSukumar Swaminathan 	}
245482527734SSukumar Swaminathan 
2455fcf3ce44SJohn Forte 	return (abort.q_cnt);
2456fcf3ce44SJohn Forte 
245782527734SSukumar Swaminathan } /* emlxs_tx_channel_flush() */
2458fcf3ce44SJohn Forte 
2459fcf3ce44SJohn Forte 
2460fcf3ce44SJohn Forte /* Flush all IO's on all or a given ring for a given node */
2461fcf3ce44SJohn Forte extern uint32_t
246282527734SSukumar Swaminathan emlxs_tx_node_flush(emlxs_port_t *port, NODELIST *ndlp, CHANNEL *chan,
2463fcf3ce44SJohn Forte     uint32_t shutdown, emlxs_buf_t *fpkt)
2464fcf3ce44SJohn Forte {
2465fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2466fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
246782527734SSukumar Swaminathan 	uint32_t channelno;
246882527734SSukumar Swaminathan 	CHANNEL *cp;
2469fcf3ce44SJohn Forte 	IOCB *icmd;
2470fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2471fcf3ce44SJohn Forte 	NODELIST *prev;
2472fcf3ce44SJohn Forte 	IOCBQ *next;
2473fcf3ce44SJohn Forte 	IOCB *iocb;
2474fcf3ce44SJohn Forte 	Q abort;
2475fcf3ce44SJohn Forte 	uint32_t i;
2476fcf3ce44SJohn Forte 	MATCHMAP *mp;
247782527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2478fcf3ce44SJohn Forte 
2479fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
2480fcf3ce44SJohn Forte 
2481fcf3ce44SJohn Forte 	/* Flush all I/O's on tx queue to this target */
248282527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2483fcf3ce44SJohn Forte 
2484fcf3ce44SJohn Forte 	if (!ndlp->nlp_base && shutdown) {
2485fcf3ce44SJohn Forte 		ndlp->nlp_active = 0;
2486fcf3ce44SJohn Forte 	}
2487291a2b48SSukumar Swaminathan 
248882527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
248982527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
2490fcf3ce44SJohn Forte 
249182527734SSukumar Swaminathan 		if (chan && cp != chan) {
2492fcf3ce44SJohn Forte 			continue;
2493fcf3ce44SJohn Forte 		}
2494291a2b48SSukumar Swaminathan 
2495fcf3ce44SJohn Forte 		if (!ndlp->nlp_base || shutdown) {
2496fcf3ce44SJohn Forte 			/* Check if priority queue is not empty */
249782527734SSukumar Swaminathan 			if (ndlp->nlp_ptx[channelno].q_first) {
2498fcf3ce44SJohn Forte 				/* Transfer all iocb's to local queue */
2499fcf3ce44SJohn Forte 				if (abort.q_first == 0) {
2500fcf3ce44SJohn Forte 					abort.q_first =
250182527734SSukumar Swaminathan 					    ndlp->nlp_ptx[channelno].q_first;
2502fcf3ce44SJohn Forte 				} else {
250382527734SSukumar Swaminathan 					((IOCBQ *)(abort.q_last))->next =
250482527734SSukumar Swaminathan 					    (IOCBQ *)ndlp->nlp_ptx[channelno].
2505291a2b48SSukumar Swaminathan 					    q_first;
2506fcf3ce44SJohn Forte 				}
2507fcf3ce44SJohn Forte 
250882527734SSukumar Swaminathan 				flag[channelno] = 1;
250982527734SSukumar Swaminathan 
251082527734SSukumar Swaminathan 				abort.q_last = ndlp->nlp_ptx[channelno].q_last;
251182527734SSukumar Swaminathan 				abort.q_cnt += ndlp->nlp_ptx[channelno].q_cnt;
2512fcf3ce44SJohn Forte 			}
2513fcf3ce44SJohn Forte 		}
2514291a2b48SSukumar Swaminathan 
2515fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
251682527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
251782527734SSukumar Swaminathan 
2518fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2519fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
252082527734SSukumar Swaminathan 				abort.q_first = ndlp->nlp_tx[channelno].q_first;
2521fcf3ce44SJohn Forte 			} else {
2522fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
252382527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2524fcf3ce44SJohn Forte 			}
2525fcf3ce44SJohn Forte 
252682527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_tx[channelno].q_last;
252782527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_tx[channelno].q_cnt;
2528fcf3ce44SJohn Forte 		}
2529291a2b48SSukumar Swaminathan 
2530fcf3ce44SJohn Forte 		/* Clear the queue pointers */
253182527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_first = NULL;
253282527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_last = NULL;
253382527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_cnt = 0;
2534fcf3ce44SJohn Forte 
253582527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_first = NULL;
253682527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_last = NULL;
253782527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_cnt = 0;
2538fcf3ce44SJohn Forte 
253982527734SSukumar Swaminathan 		/* If this node was on the channel queue, remove it */
254082527734SSukumar Swaminathan 		if (ndlp->nlp_next[channelno]) {
2541fcf3ce44SJohn Forte 			/* If this is the only node on list */
254282527734SSukumar Swaminathan 			if (cp->nodeq.q_first == (void *)ndlp &&
254382527734SSukumar Swaminathan 			    cp->nodeq.q_last == (void *)ndlp) {
254482527734SSukumar Swaminathan 				cp->nodeq.q_last = NULL;
254582527734SSukumar Swaminathan 				cp->nodeq.q_first = NULL;
254682527734SSukumar Swaminathan 				cp->nodeq.q_cnt = 0;
254782527734SSukumar Swaminathan 			} else if (cp->nodeq.q_first == (void *)ndlp) {
254882527734SSukumar Swaminathan 				cp->nodeq.q_first = ndlp->nlp_next[channelno];
254982527734SSukumar Swaminathan 				((NODELIST *) cp->nodeq.q_last)->
255082527734SSukumar Swaminathan 				    nlp_next[channelno] = cp->nodeq.q_first;
255182527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
2552291a2b48SSukumar Swaminathan 			} else {
2553fcf3ce44SJohn Forte 				/*
2554291a2b48SSukumar Swaminathan 				 * This is a little more difficult find the
255582527734SSukumar Swaminathan 				 * previous node in the circular channel queue
2556fcf3ce44SJohn Forte 				 */
2557fcf3ce44SJohn Forte 				prev = ndlp;
255882527734SSukumar Swaminathan 				while (prev->nlp_next[channelno] != ndlp) {
255982527734SSukumar Swaminathan 					prev = prev->nlp_next[channelno];
2560fcf3ce44SJohn Forte 				}
2561fcf3ce44SJohn Forte 
256282527734SSukumar Swaminathan 				prev->nlp_next[channelno] =
256382527734SSukumar Swaminathan 				    ndlp->nlp_next[channelno];
2564fcf3ce44SJohn Forte 
256582527734SSukumar Swaminathan 				if (cp->nodeq.q_last == (void *)ndlp) {
256682527734SSukumar Swaminathan 					cp->nodeq.q_last = (void *)prev;
2567fcf3ce44SJohn Forte 				}
256882527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
2569fcf3ce44SJohn Forte 
2570fcf3ce44SJohn Forte 			}
2571fcf3ce44SJohn Forte 
2572fcf3ce44SJohn Forte 			/* Clear node */
257382527734SSukumar Swaminathan 			ndlp->nlp_next[channelno] = NULL;
2574fcf3ce44SJohn Forte 		}
2575291a2b48SSukumar Swaminathan 
2576fcf3ce44SJohn Forte 	}
2577fcf3ce44SJohn Forte 
2578fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2579291a2b48SSukumar Swaminathan 	iocbq = (IOCBQ *) abort.q_first;
2580fcf3ce44SJohn Forte 	while (iocbq) {
2581fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2582fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
258382527734SSukumar Swaminathan 
258482527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
258582527734SSukumar Swaminathan 			sbp = iocbq->sbp;
258682527734SSukumar Swaminathan 			if (sbp) {
2587*8f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
258882527734SSukumar Swaminathan 			}
258982527734SSukumar Swaminathan 		} else {
259082527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
259182527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
259282527734SSukumar Swaminathan 		}
2593fcf3ce44SJohn Forte 
2594fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2595fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2596fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2597fcf3ce44SJohn Forte 			/*
2598fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2599291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2600291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2601fcf3ce44SJohn Forte 			 */
2602fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2603fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2604fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2605fcf3ce44SJohn Forte 				fpkt->flush_count++;
2606fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2607fcf3ce44SJohn Forte 			}
2608291a2b48SSukumar Swaminathan 
2609fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2610fcf3ce44SJohn Forte 		}
2611291a2b48SSukumar Swaminathan 
2612291a2b48SSukumar Swaminathan 		iocbq = (IOCBQ *) iocbq->next;
2613fcf3ce44SJohn Forte 
2614fcf3ce44SJohn Forte 	}	/* end of while */
2615fcf3ce44SJohn Forte 
261682527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2617fcf3ce44SJohn Forte 
2618fcf3ce44SJohn Forte 	/* Now abort the iocb's outside the locks */
2619fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2620fcf3ce44SJohn Forte 	while (iocbq) {
2621fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2622fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2623fcf3ce44SJohn Forte 
2624fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2625fcf3ce44SJohn Forte 		iocbq->next = NULL;
2626fcf3ce44SJohn Forte 
2627fcf3ce44SJohn Forte 		/* Get the pkt */
2628fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2629fcf3ce44SJohn Forte 
2630fcf3ce44SJohn Forte 		if (sbp) {
2631fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2632291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2633fcf3ce44SJohn Forte 
2634fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2635fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2636fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2637fcf3ce44SJohn Forte 			} else {
2638fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2639fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2640fcf3ce44SJohn Forte 			}
2641fcf3ce44SJohn Forte 
2642fcf3ce44SJohn Forte 		}
2643fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2644fcf3ce44SJohn Forte 		else {
264582527734SSukumar Swaminathan 			/* CMD_CLOSE_XRI_CN should also free the memory */
2646fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
264782527734SSukumar Swaminathan 
264882527734SSukumar Swaminathan 			/* SLI3 */
264982527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
265082527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
265182527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2652fcf3ce44SJohn Forte 				if ((hba->flag &
2653fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2654fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
265582527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2656fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2657a9800bebSGarrett D'Amore 						void	*tmp;
265882527734SSukumar Swaminathan 						RING *rp;
265982527734SSukumar Swaminathan 						int ch;
2660fcf3ce44SJohn Forte 
266182527734SSukumar Swaminathan 						ch = ((CHANNEL *)
266282527734SSukumar Swaminathan 						    iocbq->channel)->channelno;
266382527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
2664fcf3ce44SJohn Forte 						for (i = 0;
266582527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2666fcf3ce44SJohn Forte 						    i++) {
2667fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2668fcf3ce44SJohn Forte 							    hba, rp, icmd);
2669fcf3ce44SJohn Forte 
2670a9800bebSGarrett D'Amore 							tmp = (void *)mp;
2671fcf3ce44SJohn Forte 							if (mp) {
2672a9800bebSGarrett D'Amore 							emlxs_mem_put(
2673291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2674fcf3ce44SJohn Forte 							}
2675fcf3ce44SJohn Forte 						}
2676fcf3ce44SJohn Forte 					}
2677291a2b48SSukumar Swaminathan 
2678a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
2679a9800bebSGarrett D'Amore 					    (void *)iocbq);
2680fcf3ce44SJohn Forte 				} else {
2681fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
268282527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
268382527734SSukumar Swaminathan 					    (CHANNEL *)iocbq->channel, iocbq);
2684fcf3ce44SJohn Forte 				}
268582527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
268682527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
268782527734SSukumar Swaminathan 				/*
268882527734SSukumar Swaminathan 				 * Resend the abort iocbq if any
268982527734SSukumar Swaminathan 				 */
269082527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
2691fcf3ce44SJohn Forte 			}
2692fcf3ce44SJohn Forte 		}
2693fcf3ce44SJohn Forte 
2694fcf3ce44SJohn Forte 		iocbq = next;
2695fcf3ce44SJohn Forte 
2696fcf3ce44SJohn Forte 	}	/* end of while */
2697fcf3ce44SJohn Forte 
269882527734SSukumar Swaminathan 	/* Now trigger channel service */
269982527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
270082527734SSukumar Swaminathan 		if (!flag[channelno]) {
270182527734SSukumar Swaminathan 			continue;
270282527734SSukumar Swaminathan 		}
270382527734SSukumar Swaminathan 
270482527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
270582527734SSukumar Swaminathan 	}
270682527734SSukumar Swaminathan 
2707fcf3ce44SJohn Forte 	return (abort.q_cnt);
2708fcf3ce44SJohn Forte 
270982527734SSukumar Swaminathan } /* emlxs_tx_node_flush() */
2710fcf3ce44SJohn Forte 
2711fcf3ce44SJohn Forte 
2712fcf3ce44SJohn Forte /* Check for IO's on all or a given ring for a given node */
2713fcf3ce44SJohn Forte extern uint32_t
271482527734SSukumar Swaminathan emlxs_tx_node_check(emlxs_port_t *port, NODELIST *ndlp, CHANNEL *chan)
2715fcf3ce44SJohn Forte {
2716fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
271782527734SSukumar Swaminathan 	uint32_t channelno;
271882527734SSukumar Swaminathan 	CHANNEL *cp;
2719fcf3ce44SJohn Forte 	uint32_t count;
2720fcf3ce44SJohn Forte 
2721fcf3ce44SJohn Forte 	count = 0;
2722fcf3ce44SJohn Forte 
2723fcf3ce44SJohn Forte 	/* Flush all I/O's on tx queue to this target */
272482527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2725fcf3ce44SJohn Forte 
272682527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
272782527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
2728fcf3ce44SJohn Forte 
272982527734SSukumar Swaminathan 		if (chan && cp != chan) {
2730fcf3ce44SJohn Forte 			continue;
2731fcf3ce44SJohn Forte 		}
2732291a2b48SSukumar Swaminathan 
2733fcf3ce44SJohn Forte 		/* Check if priority queue is not empty */
273482527734SSukumar Swaminathan 		if (ndlp->nlp_ptx[channelno].q_first) {
273582527734SSukumar Swaminathan 			count += ndlp->nlp_ptx[channelno].q_cnt;
2736fcf3ce44SJohn Forte 		}
2737291a2b48SSukumar Swaminathan 
2738fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
273982527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
274082527734SSukumar Swaminathan 			count += ndlp->nlp_tx[channelno].q_cnt;
2741fcf3ce44SJohn Forte 		}
2742291a2b48SSukumar Swaminathan 
2743fcf3ce44SJohn Forte 	}
2744fcf3ce44SJohn Forte 
274582527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2746fcf3ce44SJohn Forte 
2747fcf3ce44SJohn Forte 	return (count);
2748fcf3ce44SJohn Forte 
274982527734SSukumar Swaminathan } /* emlxs_tx_node_check() */
2750fcf3ce44SJohn Forte 
2751fcf3ce44SJohn Forte 
2752fcf3ce44SJohn Forte 
275382527734SSukumar Swaminathan /* Flush all IO's on the any ring for a given node's lun */
2754fcf3ce44SJohn Forte extern uint32_t
2755291a2b48SSukumar Swaminathan emlxs_tx_lun_flush(emlxs_port_t *port, NODELIST *ndlp, uint32_t lun,
2756291a2b48SSukumar Swaminathan     emlxs_buf_t *fpkt)
2757fcf3ce44SJohn Forte {
2758fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2759fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
276082527734SSukumar Swaminathan 	uint32_t channelno;
2761fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2762fcf3ce44SJohn Forte 	IOCBQ *prev;
2763fcf3ce44SJohn Forte 	IOCBQ *next;
2764fcf3ce44SJohn Forte 	IOCB *iocb;
2765fcf3ce44SJohn Forte 	IOCB *icmd;
2766fcf3ce44SJohn Forte 	Q abort;
2767fcf3ce44SJohn Forte 	uint32_t i;
2768fcf3ce44SJohn Forte 	MATCHMAP *mp;
276982527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2770fcf3ce44SJohn Forte 
2771a9800bebSGarrett D'Amore 	if (lun == EMLXS_LUN_NONE) {
2772a9800bebSGarrett D'Amore 		return (0);
2773a9800bebSGarrett D'Amore 	}
2774a9800bebSGarrett D'Amore 
2775fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
2776fcf3ce44SJohn Forte 
2777fcf3ce44SJohn Forte 	/* Flush I/O's on txQ to this target's lun */
277882527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2779fcf3ce44SJohn Forte 
278082527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
2781291a2b48SSukumar Swaminathan 
278282527734SSukumar Swaminathan 		/* Scan the priority queue first */
278382527734SSukumar Swaminathan 		prev = NULL;
278482527734SSukumar Swaminathan 		iocbq = (IOCBQ *) ndlp->nlp_ptx[channelno].q_first;
2785fcf3ce44SJohn Forte 
278682527734SSukumar Swaminathan 		while (iocbq) {
278782527734SSukumar Swaminathan 			next = (IOCBQ *)iocbq->next;
278882527734SSukumar Swaminathan 			iocb = &iocbq->iocb;
278982527734SSukumar Swaminathan 			sbp = (emlxs_buf_t *)iocbq->sbp;
279082527734SSukumar Swaminathan 
279182527734SSukumar Swaminathan 			/* Check if this IO is for our lun */
279282527734SSukumar Swaminathan 			if (sbp && (sbp->lun == lun)) {
279382527734SSukumar Swaminathan 				/* Remove iocb from the node's ptx queue */
279482527734SSukumar Swaminathan 				if (next == 0) {
279582527734SSukumar Swaminathan 					ndlp->nlp_ptx[channelno].q_last =
279682527734SSukumar Swaminathan 					    (uint8_t *)prev;
279782527734SSukumar Swaminathan 				}
279882527734SSukumar Swaminathan 
279982527734SSukumar Swaminathan 				if (prev == 0) {
280082527734SSukumar Swaminathan 					ndlp->nlp_ptx[channelno].q_first =
280182527734SSukumar Swaminathan 					    (uint8_t *)next;
280282527734SSukumar Swaminathan 				} else {
280382527734SSukumar Swaminathan 					prev->next = next;
280482527734SSukumar Swaminathan 				}
280582527734SSukumar Swaminathan 
280682527734SSukumar Swaminathan 				iocbq->next = NULL;
280782527734SSukumar Swaminathan 				ndlp->nlp_ptx[channelno].q_cnt--;
280882527734SSukumar Swaminathan 
280982527734SSukumar Swaminathan 				/*
281082527734SSukumar Swaminathan 				 * Add this iocb to our local abort Q
281182527734SSukumar Swaminathan 				 */
281282527734SSukumar Swaminathan 				if (abort.q_first) {
281382527734SSukumar Swaminathan 					((IOCBQ *)abort.q_last)->next = iocbq;
281482527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
281582527734SSukumar Swaminathan 					abort.q_cnt++;
281682527734SSukumar Swaminathan 				} else {
281782527734SSukumar Swaminathan 					abort.q_first = (uint8_t *)iocbq;
281882527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
281982527734SSukumar Swaminathan 					abort.q_cnt = 1;
282082527734SSukumar Swaminathan 				}
282182527734SSukumar Swaminathan 				iocbq->next = NULL;
282282527734SSukumar Swaminathan 				flag[channelno] = 1;
2823fcf3ce44SJohn Forte 
2824fcf3ce44SJohn Forte 			} else {
282582527734SSukumar Swaminathan 				prev = iocbq;
2826fcf3ce44SJohn Forte 			}
2827fcf3ce44SJohn Forte 
282882527734SSukumar Swaminathan 			iocbq = next;
2829fcf3ce44SJohn Forte 
283082527734SSukumar Swaminathan 		}	/* while (iocbq) */
2831fcf3ce44SJohn Forte 
2832fcf3ce44SJohn Forte 
283382527734SSukumar Swaminathan 		/* Scan the regular queue */
283482527734SSukumar Swaminathan 		prev = NULL;
283582527734SSukumar Swaminathan 		iocbq = (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2836fcf3ce44SJohn Forte 
283782527734SSukumar Swaminathan 		while (iocbq) {
283882527734SSukumar Swaminathan 			next = (IOCBQ *)iocbq->next;
283982527734SSukumar Swaminathan 			iocb = &iocbq->iocb;
284082527734SSukumar Swaminathan 			sbp = (emlxs_buf_t *)iocbq->sbp;
284182527734SSukumar Swaminathan 
284282527734SSukumar Swaminathan 			/* Check if this IO is for our lun */
284382527734SSukumar Swaminathan 			if (sbp && (sbp->lun == lun)) {
284482527734SSukumar Swaminathan 				/* Remove iocb from the node's tx queue */
284582527734SSukumar Swaminathan 				if (next == 0) {
284682527734SSukumar Swaminathan 					ndlp->nlp_tx[channelno].q_last =
284782527734SSukumar Swaminathan 					    (uint8_t *)prev;
284882527734SSukumar Swaminathan 				}
2849291a2b48SSukumar Swaminathan 
285082527734SSukumar Swaminathan 				if (prev == 0) {
285182527734SSukumar Swaminathan 					ndlp->nlp_tx[channelno].q_first =
285282527734SSukumar Swaminathan 					    (uint8_t *)next;
285382527734SSukumar Swaminathan 				} else {
285482527734SSukumar Swaminathan 					prev->next = next;
285582527734SSukumar Swaminathan 				}
2856fcf3ce44SJohn Forte 
285782527734SSukumar Swaminathan 				iocbq->next = NULL;
285882527734SSukumar Swaminathan 				ndlp->nlp_tx[channelno].q_cnt--;
2859fcf3ce44SJohn Forte 
286082527734SSukumar Swaminathan 				/*
286182527734SSukumar Swaminathan 				 * Add this iocb to our local abort Q
286282527734SSukumar Swaminathan 				 */
286382527734SSukumar Swaminathan 				if (abort.q_first) {
286482527734SSukumar Swaminathan 					((IOCBQ *) abort.q_last)->next = iocbq;
286582527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
286682527734SSukumar Swaminathan 					abort.q_cnt++;
286782527734SSukumar Swaminathan 				} else {
286882527734SSukumar Swaminathan 					abort.q_first = (uint8_t *)iocbq;
286982527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
287082527734SSukumar Swaminathan 					abort.q_cnt = 1;
287182527734SSukumar Swaminathan 				}
287282527734SSukumar Swaminathan 				iocbq->next = NULL;
2873fcf3ce44SJohn Forte 			} else {
287482527734SSukumar Swaminathan 				prev = iocbq;
2875fcf3ce44SJohn Forte 			}
2876fcf3ce44SJohn Forte 
287782527734SSukumar Swaminathan 			iocbq = next;
2878fcf3ce44SJohn Forte 
287982527734SSukumar Swaminathan 		}	/* while (iocbq) */
288082527734SSukumar Swaminathan 	}	/* for loop */
2881fcf3ce44SJohn Forte 
2882fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2883fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2884fcf3ce44SJohn Forte 	while (iocbq) {
2885fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2886fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
288782527734SSukumar Swaminathan 
288882527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
288982527734SSukumar Swaminathan 			sbp = iocbq->sbp;
289082527734SSukumar Swaminathan 			if (sbp) {
2891*8f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
289282527734SSukumar Swaminathan 			}
289382527734SSukumar Swaminathan 		} else {
289482527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
289582527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
289682527734SSukumar Swaminathan 		}
2897fcf3ce44SJohn Forte 
2898fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2899fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2900fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2901fcf3ce44SJohn Forte 			/*
2902fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2903291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2904291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2905fcf3ce44SJohn Forte 			 */
2906fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2907fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2908fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2909fcf3ce44SJohn Forte 				fpkt->flush_count++;
2910fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2911fcf3ce44SJohn Forte 			}
2912291a2b48SSukumar Swaminathan 
2913fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2914fcf3ce44SJohn Forte 		}
2915291a2b48SSukumar Swaminathan 
2916291a2b48SSukumar Swaminathan 		iocbq = (IOCBQ *) iocbq->next;
2917fcf3ce44SJohn Forte 
2918fcf3ce44SJohn Forte 	}	/* end of while */
2919fcf3ce44SJohn Forte 
292082527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2921fcf3ce44SJohn Forte 
2922fcf3ce44SJohn Forte 	/* Now abort the iocb's outside the locks */
2923fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2924fcf3ce44SJohn Forte 	while (iocbq) {
2925fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2926fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2927fcf3ce44SJohn Forte 
2928fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2929fcf3ce44SJohn Forte 		iocbq->next = NULL;
2930fcf3ce44SJohn Forte 
2931fcf3ce44SJohn Forte 		/* Get the pkt */
2932fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2933fcf3ce44SJohn Forte 
2934fcf3ce44SJohn Forte 		if (sbp) {
2935fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2936291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2937fcf3ce44SJohn Forte 
2938fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2939fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2940fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2941fcf3ce44SJohn Forte 			} else {
2942fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2943fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2944fcf3ce44SJohn Forte 			}
2945fcf3ce44SJohn Forte 		}
2946291a2b48SSukumar Swaminathan 
2947fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2948fcf3ce44SJohn Forte 		else {
294982527734SSukumar Swaminathan 			/* Should never happen! */
2950fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
2951fcf3ce44SJohn Forte 
295282527734SSukumar Swaminathan 			/* SLI3 */
295382527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
295482527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
295582527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2956fcf3ce44SJohn Forte 				if ((hba->flag &
2957fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2958fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
295982527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2960fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2961a9800bebSGarrett D'Amore 						void	*tmp;
296282527734SSukumar Swaminathan 						RING *rp;
296382527734SSukumar Swaminathan 						int ch;
2964fcf3ce44SJohn Forte 
296582527734SSukumar Swaminathan 						ch = ((CHANNEL *)
296682527734SSukumar Swaminathan 						    iocbq->channel)->channelno;
296782527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
2968fcf3ce44SJohn Forte 						for (i = 0;
296982527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2970fcf3ce44SJohn Forte 						    i++) {
2971fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2972fcf3ce44SJohn Forte 							    hba, rp, icmd);
2973fcf3ce44SJohn Forte 
2974a9800bebSGarrett D'Amore 							tmp = (void *)mp;
2975fcf3ce44SJohn Forte 							if (mp) {
2976a9800bebSGarrett D'Amore 							emlxs_mem_put(
2977291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2978fcf3ce44SJohn Forte 							}
2979fcf3ce44SJohn Forte 						}
2980fcf3ce44SJohn Forte 					}
2981291a2b48SSukumar Swaminathan 
2982a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
2983a9800bebSGarrett D'Amore 					    (void *)iocbq);
2984fcf3ce44SJohn Forte 				} else {
2985fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
298682527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
298782527734SSukumar Swaminathan 					    (CHANNEL *)iocbq->channel, iocbq);
2988fcf3ce44SJohn Forte 				}
298982527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
299082527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
299182527734SSukumar Swaminathan 				/*
299282527734SSukumar Swaminathan 				 * Resend the abort iocbq if any
299382527734SSukumar Swaminathan 				 */
299482527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
2995fcf3ce44SJohn Forte 			}
2996fcf3ce44SJohn Forte 		}
2997fcf3ce44SJohn Forte 
2998fcf3ce44SJohn Forte 		iocbq = next;
2999fcf3ce44SJohn Forte 
3000fcf3ce44SJohn Forte 	}	/* end of while */
3001fcf3ce44SJohn Forte 
300282527734SSukumar Swaminathan 	/* Now trigger channel service */
300382527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
300482527734SSukumar Swaminathan 		if (!flag[channelno]) {
300582527734SSukumar Swaminathan 			continue;
300682527734SSukumar Swaminathan 		}
300782527734SSukumar Swaminathan 
300882527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
300982527734SSukumar Swaminathan 	}
3010fcf3ce44SJohn Forte 
3011fcf3ce44SJohn Forte 	return (abort.q_cnt);
3012fcf3ce44SJohn Forte 
301382527734SSukumar Swaminathan } /* emlxs_tx_lun_flush() */
3014fcf3ce44SJohn Forte 
3015fcf3ce44SJohn Forte 
3016fcf3ce44SJohn Forte extern void
3017fcf3ce44SJohn Forte emlxs_tx_put(IOCBQ *iocbq, uint32_t lock)
3018fcf3ce44SJohn Forte {
3019fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
3020fcf3ce44SJohn Forte 	emlxs_port_t *port;
302182527734SSukumar Swaminathan 	uint32_t channelno;
3022fcf3ce44SJohn Forte 	NODELIST *nlp;
302382527734SSukumar Swaminathan 	CHANNEL *cp;
3024fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3025fcf3ce44SJohn Forte 
3026fcf3ce44SJohn Forte 	port = (emlxs_port_t *)iocbq->port;
3027fcf3ce44SJohn Forte 	hba = HBA;
302882527734SSukumar Swaminathan 	cp = (CHANNEL *)iocbq->channel;
3029fcf3ce44SJohn Forte 	nlp = (NODELIST *)iocbq->node;
303082527734SSukumar Swaminathan 	channelno = cp->channelno;
3031fcf3ce44SJohn Forte 	sbp = (emlxs_buf_t *)iocbq->sbp;
3032fcf3ce44SJohn Forte 
3033fcf3ce44SJohn Forte 	if (nlp == NULL) {
3034fcf3ce44SJohn Forte 		/* Set node to base node by default */
3035fcf3ce44SJohn Forte 		nlp = &port->node_base;
3036fcf3ce44SJohn Forte 
3037fcf3ce44SJohn Forte 		iocbq->node = (void *)nlp;
3038fcf3ce44SJohn Forte 
3039fcf3ce44SJohn Forte 		if (sbp) {
3040fcf3ce44SJohn Forte 			sbp->node = (void *)nlp;
3041fcf3ce44SJohn Forte 		}
3042fcf3ce44SJohn Forte 	}
3043291a2b48SSukumar Swaminathan 
3044fcf3ce44SJohn Forte 	if (lock) {
304582527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
3046fcf3ce44SJohn Forte 	}
3047291a2b48SSukumar Swaminathan 
3048fcf3ce44SJohn Forte 	if (!nlp->nlp_active || (sbp && (sbp->pkt_flags & PACKET_IN_ABORT))) {
3049fcf3ce44SJohn Forte 		if (sbp) {
3050fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
3051fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
3052fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3053fcf3ce44SJohn Forte 
305482527734SSukumar Swaminathan 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3055*8f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
305682527734SSukumar Swaminathan 			} else {
305782527734SSukumar Swaminathan 				(void) emlxs_unregister_pkt(cp, sbp->iotag, 0);
305882527734SSukumar Swaminathan 			}
3059fcf3ce44SJohn Forte 
3060fcf3ce44SJohn Forte 			if (lock) {
306182527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3062fcf3ce44SJohn Forte 			}
3063291a2b48SSukumar Swaminathan 
3064fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
3065fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
3066fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
3067fcf3ce44SJohn Forte 			} else {
3068fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
3069fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
3070fcf3ce44SJohn Forte 			}
3071fcf3ce44SJohn Forte 			return;
3072fcf3ce44SJohn Forte 		} else {
3073fcf3ce44SJohn Forte 			if (lock) {
307482527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3075fcf3ce44SJohn Forte 			}
3076291a2b48SSukumar Swaminathan 
3077a9800bebSGarrett D'Amore 			emlxs_mem_put(hba, MEM_IOCB, (void *)iocbq);
3078fcf3ce44SJohn Forte 		}
3079fcf3ce44SJohn Forte 
3080fcf3ce44SJohn Forte 		return;
3081fcf3ce44SJohn Forte 	}
3082291a2b48SSukumar Swaminathan 
3083fcf3ce44SJohn Forte 	if (sbp) {
3084fcf3ce44SJohn Forte 
3085fcf3ce44SJohn Forte 		mutex_enter(&sbp->mtx);
3086fcf3ce44SJohn Forte 
3087291a2b48SSukumar Swaminathan 		if (sbp->pkt_flags &
3088291a2b48SSukumar Swaminathan 		    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ | PACKET_IN_TXQ)) {
3089fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3090fcf3ce44SJohn Forte 			if (lock) {
309182527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3092fcf3ce44SJohn Forte 			}
3093fcf3ce44SJohn Forte 			return;
3094fcf3ce44SJohn Forte 		}
3095291a2b48SSukumar Swaminathan 
3096fcf3ce44SJohn Forte 		sbp->pkt_flags |= PACKET_IN_TXQ;
309782527734SSukumar Swaminathan 		hba->channel_tx_count++;
3098fcf3ce44SJohn Forte 
3099fcf3ce44SJohn Forte 		mutex_exit(&sbp->mtx);
3100fcf3ce44SJohn Forte 	}
3101291a2b48SSukumar Swaminathan 
3102291a2b48SSukumar Swaminathan 
3103fcf3ce44SJohn Forte 	/* Check iocbq priority */
310482527734SSukumar Swaminathan 	/* Some IOCB has the high priority like reset/close xri etc */
3105fcf3ce44SJohn Forte 	if (iocbq->flag & IOCB_PRIORITY) {
3106fcf3ce44SJohn Forte 		/* Add the iocb to the bottom of the node's ptx queue */
310782527734SSukumar Swaminathan 		if (nlp->nlp_ptx[channelno].q_first) {
310882527734SSukumar Swaminathan 			((IOCBQ *)nlp->nlp_ptx[channelno].q_last)->next = iocbq;
310982527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_last = (uint8_t *)iocbq;
311082527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_cnt++;
3111fcf3ce44SJohn Forte 		} else {
311282527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_first = (uint8_t *)iocbq;
311382527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_last = (uint8_t *)iocbq;
311482527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_cnt = 1;
3115fcf3ce44SJohn Forte 		}
3116fcf3ce44SJohn Forte 
3117fcf3ce44SJohn Forte 		iocbq->next = NULL;
3118fcf3ce44SJohn Forte 	} else {	/* Normal priority */
3119fcf3ce44SJohn Forte 
3120291a2b48SSukumar Swaminathan 
3121fcf3ce44SJohn Forte 		/* Add the iocb to the bottom of the node's tx queue */
312282527734SSukumar Swaminathan 		if (nlp->nlp_tx[channelno].q_first) {
312382527734SSukumar Swaminathan 			((IOCBQ *)nlp->nlp_tx[channelno].q_last)->next = iocbq;
312482527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_last = (uint8_t *)iocbq;
312582527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_cnt++;
3126fcf3ce44SJohn Forte 		} else {
312782527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_first = (uint8_t *)iocbq;
312882527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_last = (uint8_t *)iocbq;
312982527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_cnt = 1;
3130fcf3ce44SJohn Forte 		}
3131fcf3ce44SJohn Forte 
3132fcf3ce44SJohn Forte 		iocbq->next = NULL;
3133fcf3ce44SJohn Forte 	}
3134fcf3ce44SJohn Forte 
3135fcf3ce44SJohn Forte 
3136fcf3ce44SJohn Forte 	/*
313782527734SSukumar Swaminathan 	 * Check if the node is not already on channel queue and
3138291a2b48SSukumar Swaminathan 	 * (is not closed or  is a priority request)
3139fcf3ce44SJohn Forte 	 */
314082527734SSukumar Swaminathan 	if (!nlp->nlp_next[channelno] &&
314182527734SSukumar Swaminathan 	    (!(nlp->nlp_flag[channelno] & NLP_CLOSED) ||
3142fcf3ce44SJohn Forte 	    (iocbq->flag & IOCB_PRIORITY))) {
314382527734SSukumar Swaminathan 		/* If so, then add it to the channel queue */
314482527734SSukumar Swaminathan 		if (cp->nodeq.q_first) {
314582527734SSukumar Swaminathan 			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
3146fcf3ce44SJohn Forte 			    (uint8_t *)nlp;
314782527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = cp->nodeq.q_first;
3148fcf3ce44SJohn Forte 
3149fcf3ce44SJohn Forte 			/*
3150291a2b48SSukumar Swaminathan 			 * If this is not the base node then add it
3151291a2b48SSukumar Swaminathan 			 * to the tail
3152fcf3ce44SJohn Forte 			 */
3153fcf3ce44SJohn Forte 			if (!nlp->nlp_base) {
315482527734SSukumar Swaminathan 				cp->nodeq.q_last = (uint8_t *)nlp;
3155fcf3ce44SJohn Forte 			} else {	/* Otherwise, add it to the head */
3156291a2b48SSukumar Swaminathan 
3157fcf3ce44SJohn Forte 				/* The command node always gets priority */
315882527734SSukumar Swaminathan 				cp->nodeq.q_first = (uint8_t *)nlp;
3159fcf3ce44SJohn Forte 			}
3160fcf3ce44SJohn Forte 
316182527734SSukumar Swaminathan 			cp->nodeq.q_cnt++;
3162fcf3ce44SJohn Forte 		} else {
316382527734SSukumar Swaminathan 			cp->nodeq.q_first = (uint8_t *)nlp;
316482527734SSukumar Swaminathan 			cp->nodeq.q_last = (uint8_t *)nlp;
316582527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = nlp;
316682527734SSukumar Swaminathan 			cp->nodeq.q_cnt = 1;
3167fcf3ce44SJohn Forte 		}
3168fcf3ce44SJohn Forte 	}
3169291a2b48SSukumar Swaminathan 
317082527734SSukumar Swaminathan 	HBASTATS.IocbTxPut[channelno]++;
3171fcf3ce44SJohn Forte 
317282527734SSukumar Swaminathan 	/* Adjust the channel timeout timer */
317382527734SSukumar Swaminathan 	cp->timeout = hba->timer_tics + 5;
3174fcf3ce44SJohn Forte 
3175fcf3ce44SJohn Forte 	if (lock) {
317682527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3177fcf3ce44SJohn Forte 	}
3178291a2b48SSukumar Swaminathan 
3179fcf3ce44SJohn Forte 	return;
3180fcf3ce44SJohn Forte 
318182527734SSukumar Swaminathan } /* emlxs_tx_put() */
3182fcf3ce44SJohn Forte 
3183fcf3ce44SJohn Forte 
3184fcf3ce44SJohn Forte extern IOCBQ *
318582527734SSukumar Swaminathan emlxs_tx_get(CHANNEL *cp, uint32_t lock)
3186fcf3ce44SJohn Forte {
3187fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
318882527734SSukumar Swaminathan 	uint32_t channelno;
3189fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3190fcf3ce44SJohn Forte 	NODELIST *nlp;
3191fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3192fcf3ce44SJohn Forte 
319382527734SSukumar Swaminathan 	hba = cp->hba;
319482527734SSukumar Swaminathan 	channelno = cp->channelno;
3195fcf3ce44SJohn Forte 
3196fcf3ce44SJohn Forte 	if (lock) {
319782527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
3198fcf3ce44SJohn Forte 	}
3199291a2b48SSukumar Swaminathan 
3200fcf3ce44SJohn Forte begin:
3201fcf3ce44SJohn Forte 
3202fcf3ce44SJohn Forte 	iocbq = NULL;
3203fcf3ce44SJohn Forte 
3204fcf3ce44SJohn Forte 	/* Check if a node needs servicing */
320582527734SSukumar Swaminathan 	if (cp->nodeq.q_first) {
320682527734SSukumar Swaminathan 		nlp = (NODELIST *)cp->nodeq.q_first;
3207fcf3ce44SJohn Forte 
3208fcf3ce44SJohn Forte 		/* Get next iocb from node's priority queue */
3209fcf3ce44SJohn Forte 
321082527734SSukumar Swaminathan 		if (nlp->nlp_ptx[channelno].q_first) {
321182527734SSukumar Swaminathan 			iocbq = (IOCBQ *)nlp->nlp_ptx[channelno].q_first;
3212fcf3ce44SJohn Forte 
3213fcf3ce44SJohn Forte 			/* Check if this is last entry */
321482527734SSukumar Swaminathan 			if (nlp->nlp_ptx[channelno].q_last == (void *)iocbq) {
321582527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_first = NULL;
321682527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_last = NULL;
321782527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_cnt = 0;
3218fcf3ce44SJohn Forte 			} else {
3219fcf3ce44SJohn Forte 				/* Remove iocb from head */
322082527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_first =
3221fcf3ce44SJohn Forte 				    (void *)iocbq->next;
322282527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_cnt--;
3223fcf3ce44SJohn Forte 			}
3224fcf3ce44SJohn Forte 
3225fcf3ce44SJohn Forte 			iocbq->next = NULL;
3226fcf3ce44SJohn Forte 		}
3227291a2b48SSukumar Swaminathan 
3228fcf3ce44SJohn Forte 		/* Get next iocb from node tx queue if node not closed */
322982527734SSukumar Swaminathan 		else if (nlp->nlp_tx[channelno].q_first &&
323082527734SSukumar Swaminathan 		    !(nlp->nlp_flag[channelno] & NLP_CLOSED)) {
323182527734SSukumar Swaminathan 			iocbq = (IOCBQ *)nlp->nlp_tx[channelno].q_first;
3232fcf3ce44SJohn Forte 
3233fcf3ce44SJohn Forte 			/* Check if this is last entry */
323482527734SSukumar Swaminathan 			if (nlp->nlp_tx[channelno].q_last == (void *)iocbq) {
323582527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_first = NULL;
323682527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_last = NULL;
323782527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_cnt = 0;
3238fcf3ce44SJohn Forte 			} else {
3239fcf3ce44SJohn Forte 				/* Remove iocb from head */
324082527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_first =
3241fcf3ce44SJohn Forte 				    (void *)iocbq->next;
324282527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_cnt--;
3243fcf3ce44SJohn Forte 			}
3244fcf3ce44SJohn Forte 
3245fcf3ce44SJohn Forte 			iocbq->next = NULL;
3246fcf3ce44SJohn Forte 		}
3247291a2b48SSukumar Swaminathan 
3248fcf3ce44SJohn Forte 		/* Now deal with node itself */
3249fcf3ce44SJohn Forte 
3250fcf3ce44SJohn Forte 		/* Check if node still needs servicing */
325182527734SSukumar Swaminathan 		if ((nlp->nlp_ptx[channelno].q_first) ||
325282527734SSukumar Swaminathan 		    (nlp->nlp_tx[channelno].q_first &&
325382527734SSukumar Swaminathan 		    !(nlp->nlp_flag[channelno] & NLP_CLOSED))) {
3254fcf3ce44SJohn Forte 
3255fcf3ce44SJohn Forte 			/*
3256fcf3ce44SJohn Forte 			 * If this is the base node, then don't shift the
3257291a2b48SSukumar Swaminathan 			 * pointers. We want to drain the base node before
3258291a2b48SSukumar Swaminathan 			 * moving on
3259fcf3ce44SJohn Forte 			 */
3260fcf3ce44SJohn Forte 			if (!nlp->nlp_base) {
3261fcf3ce44SJohn Forte 				/*
326282527734SSukumar Swaminathan 				 * Just shift channel queue pointers to next
3263fcf3ce44SJohn Forte 				 * node
3264fcf3ce44SJohn Forte 				 */
326582527734SSukumar Swaminathan 				cp->nodeq.q_last = (void *)nlp;
326682527734SSukumar Swaminathan 				cp->nodeq.q_first = nlp->nlp_next[channelno];
3267fcf3ce44SJohn Forte 			}
3268fcf3ce44SJohn Forte 		} else {
326982527734SSukumar Swaminathan 			/* Remove node from channel queue */
3270fcf3ce44SJohn Forte 
3271fcf3ce44SJohn Forte 			/* If this is the last node on list */
327282527734SSukumar Swaminathan 			if (cp->nodeq.q_last == (void *)nlp) {
327382527734SSukumar Swaminathan 				cp->nodeq.q_last = NULL;
327482527734SSukumar Swaminathan 				cp->nodeq.q_first = NULL;
327582527734SSukumar Swaminathan 				cp->nodeq.q_cnt = 0;
3276fcf3ce44SJohn Forte 			} else {
3277fcf3ce44SJohn Forte 				/* Remove node from head */
327882527734SSukumar Swaminathan 				cp->nodeq.q_first = nlp->nlp_next[channelno];
327982527734SSukumar Swaminathan 				((NODELIST *)cp->nodeq.q_last)->
328082527734SSukumar Swaminathan 				    nlp_next[channelno] = cp->nodeq.q_first;
328182527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
3282fcf3ce44SJohn Forte 
3283fcf3ce44SJohn Forte 			}
3284fcf3ce44SJohn Forte 
3285fcf3ce44SJohn Forte 			/* Clear node */
328682527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = NULL;
3287fcf3ce44SJohn Forte 		}
3288fcf3ce44SJohn Forte 
3289fcf3ce44SJohn Forte 		/*
3290291a2b48SSukumar Swaminathan 		 * If no iocbq was found on this node, then it will have
3291291a2b48SSukumar Swaminathan 		 * been removed. So try again.
3292fcf3ce44SJohn Forte 		 */
3293fcf3ce44SJohn Forte 		if (!iocbq) {
3294fcf3ce44SJohn Forte 			goto begin;
3295fcf3ce44SJohn Forte 		}
3296291a2b48SSukumar Swaminathan 
3297fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
3298fcf3ce44SJohn Forte 
3299fcf3ce44SJohn Forte 		if (sbp) {
3300fcf3ce44SJohn Forte 			/*
3301291a2b48SSukumar Swaminathan 			 * Check flags before we enter mutex in case this
3302291a2b48SSukumar Swaminathan 			 * has been flushed and destroyed
3303fcf3ce44SJohn Forte 			 */
3304fcf3ce44SJohn Forte 			if ((sbp->pkt_flags &
3305fcf3ce44SJohn Forte 			    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) ||
3306fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_IN_TXQ)) {
3307fcf3ce44SJohn Forte 				goto begin;
3308fcf3ce44SJohn Forte 			}
3309291a2b48SSukumar Swaminathan 
3310fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
3311fcf3ce44SJohn Forte 
3312fcf3ce44SJohn Forte 			if ((sbp->pkt_flags &
3313fcf3ce44SJohn Forte 			    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) ||
3314fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_IN_TXQ)) {
3315fcf3ce44SJohn Forte 				mutex_exit(&sbp->mtx);
3316fcf3ce44SJohn Forte 				goto begin;
3317fcf3ce44SJohn Forte 			}
3318291a2b48SSukumar Swaminathan 
3319fcf3ce44SJohn Forte 			sbp->pkt_flags &= ~PACKET_IN_TXQ;
332082527734SSukumar Swaminathan 			hba->channel_tx_count--;
3321fcf3ce44SJohn Forte 
3322fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3323fcf3ce44SJohn Forte 		}
3324fcf3ce44SJohn Forte 	}
3325291a2b48SSukumar Swaminathan 
3326fcf3ce44SJohn Forte 	if (iocbq) {
332782527734SSukumar Swaminathan 		HBASTATS.IocbTxGet[channelno]++;
3328fcf3ce44SJohn Forte 	}
3329291a2b48SSukumar Swaminathan 
3330fcf3ce44SJohn Forte 	/* Adjust the ring timeout timer */
333182527734SSukumar Swaminathan 	cp->timeout = (cp->nodeq.q_first) ? (hba->timer_tics + 5) : 0;
3332fcf3ce44SJohn Forte 
3333fcf3ce44SJohn Forte 	if (lock) {
333482527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3335fcf3ce44SJohn Forte 	}
3336291a2b48SSukumar Swaminathan 
3337fcf3ce44SJohn Forte 	return (iocbq);
3338fcf3ce44SJohn Forte 
333982527734SSukumar Swaminathan } /* emlxs_tx_get() */
334082527734SSukumar Swaminathan 
3341fcf3ce44SJohn Forte 
334282527734SSukumar Swaminathan /*
334382527734SSukumar Swaminathan  * Remove all cmd from from_rp's txq to to_rp's txq for ndlp.
334482527734SSukumar Swaminathan  * The old IoTag has to be released, the new one has to be
334582527734SSukumar Swaminathan  * allocated.  Others no change
334682527734SSukumar Swaminathan  * TX_CHANNEL lock is held
334782527734SSukumar Swaminathan  */
334882527734SSukumar Swaminathan extern void
334982527734SSukumar Swaminathan emlxs_tx_move(NODELIST *ndlp, CHANNEL *from_chan, CHANNEL *to_chan,
335082527734SSukumar Swaminathan     uint32_t cmd, emlxs_buf_t *fpkt, uint32_t lock)
335182527734SSukumar Swaminathan {
335282527734SSukumar Swaminathan 	emlxs_hba_t *hba;
335382527734SSukumar Swaminathan 	emlxs_port_t *port;
335482527734SSukumar Swaminathan 	uint32_t fchanno, tchanno, i;
335582527734SSukumar Swaminathan 
335682527734SSukumar Swaminathan 	IOCBQ *iocbq;
335782527734SSukumar Swaminathan 	IOCBQ *prev;
335882527734SSukumar Swaminathan 	IOCBQ *next;
335982527734SSukumar Swaminathan 	IOCB *iocb, *icmd;
336082527734SSukumar Swaminathan 	Q tbm;		/* To Be Moved Q */
336182527734SSukumar Swaminathan 	MATCHMAP *mp;
336282527734SSukumar Swaminathan 
336382527734SSukumar Swaminathan 	NODELIST *nlp = ndlp;
336482527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
336582527734SSukumar Swaminathan 
336682527734SSukumar Swaminathan 	NODELIST *n_prev = NULL;
336782527734SSukumar Swaminathan 	NODELIST *n_next = NULL;
336882527734SSukumar Swaminathan 	uint16_t count = 0;
336982527734SSukumar Swaminathan 
337082527734SSukumar Swaminathan 	hba = from_chan->hba;
337182527734SSukumar Swaminathan 	port = &PPORT;
337282527734SSukumar Swaminathan 	cmd = cmd; /* To pass lint */
337382527734SSukumar Swaminathan 
337482527734SSukumar Swaminathan 	fchanno = from_chan->channelno;
337582527734SSukumar Swaminathan 	tchanno = to_chan->channelno;
337682527734SSukumar Swaminathan 
337782527734SSukumar Swaminathan 	if (lock) {
337882527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
337982527734SSukumar Swaminathan 	}
338082527734SSukumar Swaminathan 
338182527734SSukumar Swaminathan 	bzero((void *)&tbm, sizeof (Q));
338282527734SSukumar Swaminathan 
338382527734SSukumar Swaminathan 	/* Scan the ndlp's fchanno txq to get the iocb of fcp cmd */
338482527734SSukumar Swaminathan 	prev = NULL;
338582527734SSukumar Swaminathan 	iocbq = (IOCBQ *)nlp->nlp_tx[fchanno].q_first;
338682527734SSukumar Swaminathan 
338782527734SSukumar Swaminathan 	while (iocbq) {
338882527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
338982527734SSukumar Swaminathan 		/* Check if this iocb is fcp cmd */
339082527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
339182527734SSukumar Swaminathan 
339282527734SSukumar Swaminathan 		switch (iocb->ULPCOMMAND) {
339382527734SSukumar Swaminathan 		/* FCP commands */
339482527734SSukumar Swaminathan 		case CMD_FCP_ICMND_CR:
339582527734SSukumar Swaminathan 		case CMD_FCP_ICMND_CX:
339682527734SSukumar Swaminathan 		case CMD_FCP_IREAD_CR:
339782527734SSukumar Swaminathan 		case CMD_FCP_IREAD_CX:
339882527734SSukumar Swaminathan 		case CMD_FCP_IWRITE_CR:
339982527734SSukumar Swaminathan 		case CMD_FCP_IWRITE_CX:
340082527734SSukumar Swaminathan 		case CMD_FCP_ICMND64_CR:
340182527734SSukumar Swaminathan 		case CMD_FCP_ICMND64_CX:
340282527734SSukumar Swaminathan 		case CMD_FCP_IREAD64_CR:
340382527734SSukumar Swaminathan 		case CMD_FCP_IREAD64_CX:
340482527734SSukumar Swaminathan 		case CMD_FCP_IWRITE64_CR:
340582527734SSukumar Swaminathan 		case CMD_FCP_IWRITE64_CX:
340682527734SSukumar Swaminathan 			/* We found a fcp cmd */
340782527734SSukumar Swaminathan 			break;
340882527734SSukumar Swaminathan 		default:
340982527734SSukumar Swaminathan 			/* this is not fcp cmd continue */
341082527734SSukumar Swaminathan 			prev = iocbq;
341182527734SSukumar Swaminathan 			iocbq = next;
341282527734SSukumar Swaminathan 			continue;
341382527734SSukumar Swaminathan 		}
341482527734SSukumar Swaminathan 
341582527734SSukumar Swaminathan 		/* found a fcp cmd iocb in fchanno txq, now deque it */
341682527734SSukumar Swaminathan 		if (next == NULL) {
341782527734SSukumar Swaminathan 			/* This is the last iocbq */
341882527734SSukumar Swaminathan 			nlp->nlp_tx[fchanno].q_last =
341982527734SSukumar Swaminathan 			    (uint8_t *)prev;
342082527734SSukumar Swaminathan 		}
342182527734SSukumar Swaminathan 
342282527734SSukumar Swaminathan 		if (prev == NULL) {
342382527734SSukumar Swaminathan 			/* This is the first one then remove it from head */
342482527734SSukumar Swaminathan 			nlp->nlp_tx[fchanno].q_first =
342582527734SSukumar Swaminathan 			    (uint8_t *)next;
342682527734SSukumar Swaminathan 		} else {
342782527734SSukumar Swaminathan 			prev->next = next;
342882527734SSukumar Swaminathan 		}
342982527734SSukumar Swaminathan 
343082527734SSukumar Swaminathan 		iocbq->next = NULL;
343182527734SSukumar Swaminathan 		nlp->nlp_tx[fchanno].q_cnt--;
343282527734SSukumar Swaminathan 
343382527734SSukumar Swaminathan 		/* Add this iocb to our local toberemovedq */
343482527734SSukumar Swaminathan 		/* This way we donot hold the TX_CHANNEL lock too long */
343582527734SSukumar Swaminathan 
343682527734SSukumar Swaminathan 		if (tbm.q_first) {
343782527734SSukumar Swaminathan 			((IOCBQ *)tbm.q_last)->next = iocbq;
343882527734SSukumar Swaminathan 			tbm.q_last = (uint8_t *)iocbq;
343982527734SSukumar Swaminathan 			tbm.q_cnt++;
344082527734SSukumar Swaminathan 		} else {
344182527734SSukumar Swaminathan 			tbm.q_first = (uint8_t *)iocbq;
344282527734SSukumar Swaminathan 			tbm.q_last = (uint8_t *)iocbq;
344382527734SSukumar Swaminathan 			tbm.q_cnt = 1;
344482527734SSukumar Swaminathan 		}
344582527734SSukumar Swaminathan 
344682527734SSukumar Swaminathan 		iocbq = next;
344782527734SSukumar Swaminathan 
344882527734SSukumar Swaminathan 	}	/* While (iocbq) */
344982527734SSukumar Swaminathan 
345082527734SSukumar Swaminathan 	if ((tchanno == hba->channel_fcp) && (tbm.q_cnt != 0)) {
345182527734SSukumar Swaminathan 
345282527734SSukumar Swaminathan 		/* from_chan->nodeq.q_first must be non NULL */
345382527734SSukumar Swaminathan 		if (from_chan->nodeq.q_first) {
345482527734SSukumar Swaminathan 
345582527734SSukumar Swaminathan 			/* nodeq is not empty, now deal with the node itself */
345682527734SSukumar Swaminathan 			if ((nlp->nlp_tx[fchanno].q_first)) {
345782527734SSukumar Swaminathan 
345882527734SSukumar Swaminathan 				if (!nlp->nlp_base) {
345982527734SSukumar Swaminathan 					from_chan->nodeq.q_last =
346082527734SSukumar Swaminathan 					    (void *)nlp;
346182527734SSukumar Swaminathan 					from_chan->nodeq.q_first =
346282527734SSukumar Swaminathan 					    nlp->nlp_next[fchanno];
346382527734SSukumar Swaminathan 				}
346482527734SSukumar Swaminathan 
346582527734SSukumar Swaminathan 			} else {
346682527734SSukumar Swaminathan 				n_prev = (NODELIST *)from_chan->nodeq.q_first;
346782527734SSukumar Swaminathan 				count = from_chan->nodeq.q_cnt;
346882527734SSukumar Swaminathan 
346982527734SSukumar Swaminathan 				if (n_prev == nlp) {
347082527734SSukumar Swaminathan 
347182527734SSukumar Swaminathan 					/* If this is the only node on list */
347282527734SSukumar Swaminathan 					if (from_chan->nodeq.q_last ==
347382527734SSukumar Swaminathan 					    (void *)nlp) {
347482527734SSukumar Swaminathan 						from_chan->nodeq.q_last =
347582527734SSukumar Swaminathan 						    NULL;
347682527734SSukumar Swaminathan 						from_chan->nodeq.q_first =
347782527734SSukumar Swaminathan 						    NULL;
347882527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt = 0;
347982527734SSukumar Swaminathan 					} else {
348082527734SSukumar Swaminathan 						from_chan->nodeq.q_first =
348182527734SSukumar Swaminathan 						    nlp->nlp_next[fchanno];
348282527734SSukumar Swaminathan 						((NODELIST *)from_chan->
348382527734SSukumar Swaminathan 						    nodeq.q_last)->
348482527734SSukumar Swaminathan 						    nlp_next[fchanno] =
348582527734SSukumar Swaminathan 						    from_chan->nodeq.q_first;
348682527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt--;
348782527734SSukumar Swaminathan 					}
348882527734SSukumar Swaminathan 					/* Clear node */
348982527734SSukumar Swaminathan 					nlp->nlp_next[fchanno] = NULL;
349082527734SSukumar Swaminathan 				} else {
349182527734SSukumar Swaminathan 					count--;
349282527734SSukumar Swaminathan 					do {
349382527734SSukumar Swaminathan 						n_next =
349482527734SSukumar Swaminathan 						    n_prev->nlp_next[fchanno];
349582527734SSukumar Swaminathan 						if (n_next == nlp) {
349682527734SSukumar Swaminathan 							break;
349782527734SSukumar Swaminathan 						}
349882527734SSukumar Swaminathan 						n_prev = n_next;
349982527734SSukumar Swaminathan 					} while (count--);
350082527734SSukumar Swaminathan 
350182527734SSukumar Swaminathan 					if (count != 0) {
350282527734SSukumar Swaminathan 
350382527734SSukumar Swaminathan 						if (n_next ==
350482527734SSukumar Swaminathan 						    (NODELIST *)from_chan->
350582527734SSukumar Swaminathan 						    nodeq.q_last) {
350682527734SSukumar Swaminathan 							n_prev->
350782527734SSukumar Swaminathan 							    nlp_next[fchanno]
350882527734SSukumar Swaminathan 							    =
350982527734SSukumar Swaminathan 							    ((NODELIST *)
351082527734SSukumar Swaminathan 							    from_chan->
351182527734SSukumar Swaminathan 							    nodeq.q_last)->
351282527734SSukumar Swaminathan 							    nlp_next
351382527734SSukumar Swaminathan 							    [fchanno];
351482527734SSukumar Swaminathan 							from_chan->nodeq.q_last
351582527734SSukumar Swaminathan 							    = (uint8_t *)n_prev;
351682527734SSukumar Swaminathan 						} else {
351782527734SSukumar Swaminathan 
351882527734SSukumar Swaminathan 							n_prev->
351982527734SSukumar Swaminathan 							    nlp_next[fchanno]
352082527734SSukumar Swaminathan 							    =
352182527734SSukumar Swaminathan 							    n_next-> nlp_next
352282527734SSukumar Swaminathan 							    [fchanno];
352382527734SSukumar Swaminathan 						}
352482527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt--;
352582527734SSukumar Swaminathan 						/* Clear node */
352682527734SSukumar Swaminathan 						nlp->nlp_next[fchanno] =
352782527734SSukumar Swaminathan 						    NULL;
352882527734SSukumar Swaminathan 					}
352982527734SSukumar Swaminathan 				}
353082527734SSukumar Swaminathan 			}
353182527734SSukumar Swaminathan 		}
353282527734SSukumar Swaminathan 	}
353382527734SSukumar Swaminathan 
353482527734SSukumar Swaminathan 	/* Now cleanup the iocb's */
353582527734SSukumar Swaminathan 	prev = NULL;
353682527734SSukumar Swaminathan 	iocbq = (IOCBQ *)tbm.q_first;
353782527734SSukumar Swaminathan 
353882527734SSukumar Swaminathan 	while (iocbq) {
353982527734SSukumar Swaminathan 
354082527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
354182527734SSukumar Swaminathan 
354282527734SSukumar Swaminathan 		/* Free the IoTag and the bmp */
354382527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
354482527734SSukumar Swaminathan 
354582527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
354682527734SSukumar Swaminathan 			sbp = iocbq->sbp;
354782527734SSukumar Swaminathan 			if (sbp) {
3548*8f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
354982527734SSukumar Swaminathan 			}
355082527734SSukumar Swaminathan 		} else {
355182527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
355282527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
355382527734SSukumar Swaminathan 		}
355482527734SSukumar Swaminathan 
355582527734SSukumar Swaminathan 		if (sbp && (sbp != STALE_PACKET)) {
355682527734SSukumar Swaminathan 			mutex_enter(&sbp->mtx);
355782527734SSukumar Swaminathan 			sbp->pkt_flags |= PACKET_IN_FLUSH;
355882527734SSukumar Swaminathan 
355982527734SSukumar Swaminathan 			/*
356082527734SSukumar Swaminathan 			 * If the fpkt is already set, then we will leave it
356182527734SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
356282527734SSukumar Swaminathan 			 * for on one fpkt->flush_count
356382527734SSukumar Swaminathan 			 */
356482527734SSukumar Swaminathan 			if (!sbp->fpkt && fpkt) {
356582527734SSukumar Swaminathan 				mutex_enter(&fpkt->mtx);
356682527734SSukumar Swaminathan 				sbp->fpkt = fpkt;
356782527734SSukumar Swaminathan 				fpkt->flush_count++;
356882527734SSukumar Swaminathan 				mutex_exit(&fpkt->mtx);
356982527734SSukumar Swaminathan 			}
357082527734SSukumar Swaminathan 			mutex_exit(&sbp->mtx);
357182527734SSukumar Swaminathan 		}
357282527734SSukumar Swaminathan 		iocbq = next;
357382527734SSukumar Swaminathan 
357482527734SSukumar Swaminathan 	}	/* end of while */
357582527734SSukumar Swaminathan 
357682527734SSukumar Swaminathan 	iocbq = (IOCBQ *)tbm.q_first;
357782527734SSukumar Swaminathan 	while (iocbq) {
357882527734SSukumar Swaminathan 		/* Save the next iocbq for now */
357982527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
358082527734SSukumar Swaminathan 
358182527734SSukumar Swaminathan 		/* Unlink this iocbq */
358282527734SSukumar Swaminathan 		iocbq->next = NULL;
358382527734SSukumar Swaminathan 
358482527734SSukumar Swaminathan 		/* Get the pkt */
358582527734SSukumar Swaminathan 		sbp = (emlxs_buf_t *)iocbq->sbp;
358682527734SSukumar Swaminathan 
358782527734SSukumar Swaminathan 		if (sbp) {
358882527734SSukumar Swaminathan 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
358982527734SSukumar Swaminathan 			"tx: sbp=%p node=%p", sbp, sbp->node);
359082527734SSukumar Swaminathan 
359182527734SSukumar Swaminathan 			if (hba->state >= FC_LINK_UP) {
359282527734SSukumar Swaminathan 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
359382527734SSukumar Swaminathan 				    IOERR_ABORT_REQUESTED, 1);
359482527734SSukumar Swaminathan 			} else {
359582527734SSukumar Swaminathan 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
359682527734SSukumar Swaminathan 				    IOERR_LINK_DOWN, 1);
359782527734SSukumar Swaminathan 			}
359882527734SSukumar Swaminathan 
359982527734SSukumar Swaminathan 		}
360082527734SSukumar Swaminathan 		/* Free the iocb and its associated buffers */
360182527734SSukumar Swaminathan 		else {
360282527734SSukumar Swaminathan 			icmd = &iocbq->iocb;
360382527734SSukumar Swaminathan 
360482527734SSukumar Swaminathan 			/* SLI3 */
360582527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
360682527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
360782527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
360882527734SSukumar Swaminathan 				if ((hba->flag &
360982527734SSukumar Swaminathan 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
361082527734SSukumar Swaminathan 					/* HBA is detaching or offlining */
361182527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
361282527734SSukumar Swaminathan 					    CMD_QUE_RING_LIST64_CN) {
3613a9800bebSGarrett D'Amore 						void *tmp;
361482527734SSukumar Swaminathan 						RING *rp;
361582527734SSukumar Swaminathan 						int ch;
361682527734SSukumar Swaminathan 
361782527734SSukumar Swaminathan 						ch = from_chan->channelno;
361882527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
361982527734SSukumar Swaminathan 
362082527734SSukumar Swaminathan 						for (i = 0;
362182527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
362282527734SSukumar Swaminathan 						    i++) {
362382527734SSukumar Swaminathan 							mp = EMLXS_GET_VADDR(
362482527734SSukumar Swaminathan 							    hba, rp, icmd);
362582527734SSukumar Swaminathan 
3626a9800bebSGarrett D'Amore 							tmp = (void *)mp;
362782527734SSukumar Swaminathan 							if (mp) {
3628a9800bebSGarrett D'Amore 							emlxs_mem_put(
362982527734SSukumar Swaminathan 							    hba,
363082527734SSukumar Swaminathan 							    MEM_BUF,
363182527734SSukumar Swaminathan 							    tmp);
363282527734SSukumar Swaminathan 							}
363382527734SSukumar Swaminathan 						}
363482527734SSukumar Swaminathan 
363582527734SSukumar Swaminathan 					}
363682527734SSukumar Swaminathan 
3637a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
3638a9800bebSGarrett D'Amore 					    (void *)iocbq);
363982527734SSukumar Swaminathan 				} else {
364082527734SSukumar Swaminathan 					/* repost the unsolicited buffer */
364182527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
364282527734SSukumar Swaminathan 					    from_chan, iocbq);
364382527734SSukumar Swaminathan 				}
364482527734SSukumar Swaminathan 			}
364582527734SSukumar Swaminathan 		}
364682527734SSukumar Swaminathan 
364782527734SSukumar Swaminathan 		iocbq = next;
364882527734SSukumar Swaminathan 
364982527734SSukumar Swaminathan 	}	/* end of while */
365082527734SSukumar Swaminathan 
365182527734SSukumar Swaminathan 	/* Now flush the chipq if any */
365282527734SSukumar Swaminathan 	if (!(nlp->nlp_flag[fchanno] & NLP_CLOSED)) {
365382527734SSukumar Swaminathan 
365482527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
365582527734SSukumar Swaminathan 
365682527734SSukumar Swaminathan 		(void) emlxs_chipq_node_flush(port, from_chan, nlp, 0);
365782527734SSukumar Swaminathan 
365882527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
365982527734SSukumar Swaminathan 	}
366082527734SSukumar Swaminathan 
366182527734SSukumar Swaminathan 	if (lock) {
366282527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
366382527734SSukumar Swaminathan 	}
366482527734SSukumar Swaminathan 
366582527734SSukumar Swaminathan 	return;
366682527734SSukumar Swaminathan 
366782527734SSukumar Swaminathan } /* emlxs_tx_move */
3668fcf3ce44SJohn Forte 
3669fcf3ce44SJohn Forte 
3670fcf3ce44SJohn Forte extern uint32_t
367182527734SSukumar Swaminathan emlxs_chipq_node_flush(emlxs_port_t *port, CHANNEL *chan, NODELIST *ndlp,
3672291a2b48SSukumar Swaminathan     emlxs_buf_t *fpkt)
3673fcf3ce44SJohn Forte {
3674fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3675fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3676fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3677fcf3ce44SJohn Forte 	IOCBQ *next;
3678fcf3ce44SJohn Forte 	Q abort;
367982527734SSukumar Swaminathan 	CHANNEL *cp;
368082527734SSukumar Swaminathan 	uint32_t channelno;
368182527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
3682fcf3ce44SJohn Forte 	uint32_t iotag;
3683fcf3ce44SJohn Forte 
3684fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
3685fcf3ce44SJohn Forte 	bzero((void *)flag, sizeof (flag));
3686fcf3ce44SJohn Forte 
368782527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
368882527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3689fcf3ce44SJohn Forte 
369082527734SSukumar Swaminathan 		if (chan && cp != chan) {
3691fcf3ce44SJohn Forte 			continue;
3692fcf3ce44SJohn Forte 		}
3693291a2b48SSukumar Swaminathan 
369482527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3695fcf3ce44SJohn Forte 
369682527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
369782527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3698fcf3ce44SJohn Forte 
3699fcf3ce44SJohn Forte 			if (sbp && (sbp != STALE_PACKET) &&
3700fcf3ce44SJohn Forte 			    (sbp->pkt_flags & PACKET_IN_CHIPQ) &&
3701fcf3ce44SJohn Forte 			    (sbp->node == ndlp) &&
370282527734SSukumar Swaminathan 			    (sbp->channel == cp) &&
3703fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
3704291a2b48SSukumar Swaminathan 				emlxs_sbp_abort_add(port, sbp, &abort, flag,
3705291a2b48SSukumar Swaminathan 				    fpkt);
3706fcf3ce44SJohn Forte 			}
3707291a2b48SSukumar Swaminathan 
3708fcf3ce44SJohn Forte 		}
370982527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3710fcf3ce44SJohn Forte 
3711fcf3ce44SJohn Forte 	}	/* for */
3712fcf3ce44SJohn Forte 
3713fcf3ce44SJohn Forte 	/* Now put the iocb's on the tx queue */
3714fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
3715fcf3ce44SJohn Forte 	while (iocbq) {
3716fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
3717fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
3718fcf3ce44SJohn Forte 
3719fcf3ce44SJohn Forte 		/* Unlink this iocbq */
3720fcf3ce44SJohn Forte 		iocbq->next = NULL;
3721fcf3ce44SJohn Forte 
3722fcf3ce44SJohn Forte 		/* Send this iocbq */
3723fcf3ce44SJohn Forte 		emlxs_tx_put(iocbq, 1);
3724fcf3ce44SJohn Forte 
3725fcf3ce44SJohn Forte 		iocbq = next;
3726fcf3ce44SJohn Forte 	}
3727fcf3ce44SJohn Forte 
372882527734SSukumar Swaminathan 	/* Now trigger channel service */
372982527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
373082527734SSukumar Swaminathan 		if (!flag[channelno]) {
3731fcf3ce44SJohn Forte 			continue;
3732fcf3ce44SJohn Forte 		}
3733291a2b48SSukumar Swaminathan 
373482527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
3735fcf3ce44SJohn Forte 	}
3736fcf3ce44SJohn Forte 
3737fcf3ce44SJohn Forte 	return (abort.q_cnt);
3738fcf3ce44SJohn Forte 
373982527734SSukumar Swaminathan } /* emlxs_chipq_node_flush() */
3740fcf3ce44SJohn Forte 
3741fcf3ce44SJohn Forte 
3742fcf3ce44SJohn Forte /* Flush all IO's left on all iotag lists */
374382527734SSukumar Swaminathan extern uint32_t
3744fcf3ce44SJohn Forte emlxs_iotag_flush(emlxs_hba_t *hba)
3745fcf3ce44SJohn Forte {
3746fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
3747fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3748fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3749fcf3ce44SJohn Forte 	IOCB *iocb;
3750fcf3ce44SJohn Forte 	Q abort;
375182527734SSukumar Swaminathan 	CHANNEL *cp;
375282527734SSukumar Swaminathan 	uint32_t channelno;
3753fcf3ce44SJohn Forte 	uint32_t iotag;
3754fcf3ce44SJohn Forte 	uint32_t count;
3755fcf3ce44SJohn Forte 
3756fcf3ce44SJohn Forte 	count = 0;
375782527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
375882527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3759fcf3ce44SJohn Forte 
3760fcf3ce44SJohn Forte 		bzero((void *)&abort, sizeof (Q));
3761fcf3ce44SJohn Forte 
376282527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3763fcf3ce44SJohn Forte 
376482527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
376582527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3766fcf3ce44SJohn Forte 
376782527734SSukumar Swaminathan 			/* Check if the slot is empty */
3768fcf3ce44SJohn Forte 			if (!sbp || (sbp == STALE_PACKET)) {
3769fcf3ce44SJohn Forte 				continue;
3770fcf3ce44SJohn Forte 			}
3771291a2b48SSukumar Swaminathan 
377282527734SSukumar Swaminathan 			/* We are building an abort list per channel */
377382527734SSukumar Swaminathan 			if (sbp->channel != cp) {
377482527734SSukumar Swaminathan 				continue;
377582527734SSukumar Swaminathan 			}
3776fcf3ce44SJohn Forte 
3777a9800bebSGarrett D'Amore 			hba->fc_table[iotag] = STALE_PACKET;
3778a9800bebSGarrett D'Amore 			hba->io_count--;
3779a9800bebSGarrett D'Amore 
3780a9800bebSGarrett D'Amore 			/* Check if IO is valid */
3781a9800bebSGarrett D'Amore 			if (!(sbp->pkt_flags & PACKET_VALID) ||
3782a9800bebSGarrett D'Amore 			    (sbp->pkt_flags & (PACKET_ULP_OWNED|
3783a9800bebSGarrett D'Amore 			    PACKET_COMPLETED|PACKET_IN_COMPLETION))) {
3784a9800bebSGarrett D'Amore 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
3785*8f23e9faSHans Rosenfeld 				    "iotag_flush: Invalid IO found. iotag=%d",
3786a9800bebSGarrett D'Amore 				    iotag);
3787a9800bebSGarrett D'Amore 
3788a9800bebSGarrett D'Amore 				continue;
3789a9800bebSGarrett D'Amore 			}
3790a9800bebSGarrett D'Amore 
3791a9800bebSGarrett D'Amore 			sbp->iotag = 0;
3792a9800bebSGarrett D'Amore 
3793fcf3ce44SJohn Forte 			/* Set IOCB status */
3794fcf3ce44SJohn Forte 			iocbq = &sbp->iocbq;
3795fcf3ce44SJohn Forte 			iocb = &iocbq->iocb;
3796fcf3ce44SJohn Forte 
379782527734SSukumar Swaminathan 			iocb->ULPSTATUS = IOSTAT_LOCAL_REJECT;
3798fcf3ce44SJohn Forte 			iocb->un.grsp.perr.statLocalError = IOERR_LINK_DOWN;
379982527734SSukumar Swaminathan 			iocb->ULPLE = 1;
3800fcf3ce44SJohn Forte 			iocbq->next = NULL;
3801fcf3ce44SJohn Forte 
380282527734SSukumar Swaminathan 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3803a9800bebSGarrett D'Amore 				if (sbp->xrip) {
3804a9800bebSGarrett D'Amore 					EMLXS_MSGF(EMLXS_CONTEXT,
3805a9800bebSGarrett D'Amore 					    &emlxs_sli_debug_msg,
3806*8f23e9faSHans Rosenfeld 					    "iotag_flush: iotag=%d sbp=%p "
3807a9800bebSGarrett D'Amore 					    "xrip=%p state=%x flag=%x",
3808a9800bebSGarrett D'Amore 					    iotag, sbp, sbp->xrip,
3809a9800bebSGarrett D'Amore 					    sbp->xrip->state, sbp->xrip->flag);
3810a9800bebSGarrett D'Amore 				} else {
3811a9800bebSGarrett D'Amore 					EMLXS_MSGF(EMLXS_CONTEXT,
3812a9800bebSGarrett D'Amore 					    &emlxs_sli_debug_msg,
3813*8f23e9faSHans Rosenfeld 					    "iotag_flush: iotag=%d sbp=%p "
3814*8f23e9faSHans Rosenfeld 					    "xrip=NULL", iotag, sbp);
3815a9800bebSGarrett D'Amore 				}
3816291a2b48SSukumar Swaminathan 
3817*8f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 0);
3818a9800bebSGarrett D'Amore 			} else {
381982527734SSukumar Swaminathan 				/* Clean up the sbp */
382082527734SSukumar Swaminathan 				mutex_enter(&sbp->mtx);
382182527734SSukumar Swaminathan 
382282527734SSukumar Swaminathan 				if (sbp->pkt_flags & PACKET_IN_TXQ) {
382382527734SSukumar Swaminathan 					sbp->pkt_flags &= ~PACKET_IN_TXQ;
382482527734SSukumar Swaminathan 					hba->channel_tx_count --;
382582527734SSukumar Swaminathan 				}
382682527734SSukumar Swaminathan 
382782527734SSukumar Swaminathan 				if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
382882527734SSukumar Swaminathan 					sbp->pkt_flags &= ~PACKET_IN_CHIPQ;
382982527734SSukumar Swaminathan 				}
3830291a2b48SSukumar Swaminathan 
383182527734SSukumar Swaminathan 				if (sbp->bmp) {
3832a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_BPL,
3833a9800bebSGarrett D'Amore 					    (void *)sbp->bmp);
383482527734SSukumar Swaminathan 					sbp->bmp = 0;
383582527734SSukumar Swaminathan 				}
383682527734SSukumar Swaminathan 
383782527734SSukumar Swaminathan 				mutex_exit(&sbp->mtx);
3838fcf3ce44SJohn Forte 			}
3839291a2b48SSukumar Swaminathan 
3840fcf3ce44SJohn Forte 			/* At this point all nodes are assumed destroyed */
384182527734SSukumar Swaminathan 			mutex_enter(&sbp->mtx);
3842fcf3ce44SJohn Forte 			sbp->node = 0;
3843fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3844fcf3ce44SJohn Forte 
3845fcf3ce44SJohn Forte 			/* Add this iocb to our local abort Q */
3846fcf3ce44SJohn Forte 			if (abort.q_first) {
3847291a2b48SSukumar Swaminathan 				((IOCBQ *)abort.q_last)->next = iocbq;
3848fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
3849fcf3ce44SJohn Forte 				abort.q_cnt++;
3850fcf3ce44SJohn Forte 			} else {
3851fcf3ce44SJohn Forte 				abort.q_first = (uint8_t *)iocbq;
3852fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
3853fcf3ce44SJohn Forte 				abort.q_cnt = 1;
3854fcf3ce44SJohn Forte 			}
3855fcf3ce44SJohn Forte 		}
3856fcf3ce44SJohn Forte 
385782527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3858fcf3ce44SJohn Forte 
3859fcf3ce44SJohn Forte 		/* Trigger deferred completion */
3860fcf3ce44SJohn Forte 		if (abort.q_first) {
386182527734SSukumar Swaminathan 			mutex_enter(&cp->rsp_lock);
386282527734SSukumar Swaminathan 			if (cp->rsp_head == NULL) {
386382527734SSukumar Swaminathan 				cp->rsp_head = (IOCBQ *)abort.q_first;
386482527734SSukumar Swaminathan 				cp->rsp_tail = (IOCBQ *)abort.q_last;
3865fcf3ce44SJohn Forte 			} else {
386682527734SSukumar Swaminathan 				cp->rsp_tail->next = (IOCBQ *)abort.q_first;
386782527734SSukumar Swaminathan 				cp->rsp_tail = (IOCBQ *)abort.q_last;
3868fcf3ce44SJohn Forte 			}
386982527734SSukumar Swaminathan 			mutex_exit(&cp->rsp_lock);
3870fcf3ce44SJohn Forte 
387182527734SSukumar Swaminathan 			emlxs_thread_trigger2(&cp->intr_thread,
387282527734SSukumar Swaminathan 			    emlxs_proc_channel, cp);
3873fcf3ce44SJohn Forte 
3874a9800bebSGarrett D'Amore 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
3875a9800bebSGarrett D'Amore 			    "iotag_flush: channel=%d count=%d",
387682527734SSukumar Swaminathan 			    channelno, abort.q_cnt);
3877fcf3ce44SJohn Forte 
3878fcf3ce44SJohn Forte 			count += abort.q_cnt;
3879fcf3ce44SJohn Forte 		}
3880fcf3ce44SJohn Forte 	}
3881fcf3ce44SJohn Forte 
3882fcf3ce44SJohn Forte 	return (count);
3883fcf3ce44SJohn Forte 
388482527734SSukumar Swaminathan } /* emlxs_iotag_flush() */
3885fcf3ce44SJohn Forte 
3886fcf3ce44SJohn Forte 
3887fcf3ce44SJohn Forte 
388882527734SSukumar Swaminathan /* Checks for IO's on all or a given channel for a given node */
3889fcf3ce44SJohn Forte extern uint32_t
389082527734SSukumar Swaminathan emlxs_chipq_node_check(emlxs_port_t *port, CHANNEL *chan, NODELIST *ndlp)
3891fcf3ce44SJohn Forte {
3892fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3893fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
389482527734SSukumar Swaminathan 	CHANNEL *cp;
389582527734SSukumar Swaminathan 	uint32_t channelno;
3896fcf3ce44SJohn Forte 	uint32_t count;
3897fcf3ce44SJohn Forte 	uint32_t iotag;
3898fcf3ce44SJohn Forte 
3899fcf3ce44SJohn Forte 	count = 0;
3900fcf3ce44SJohn Forte 
390182527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
390282527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3903fcf3ce44SJohn Forte 
390482527734SSukumar Swaminathan 		if (chan && cp != chan) {
3905fcf3ce44SJohn Forte 			continue;
3906fcf3ce44SJohn Forte 		}
3907291a2b48SSukumar Swaminathan 
390882527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3909fcf3ce44SJohn Forte 
391082527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
391182527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3912fcf3ce44SJohn Forte 
3913fcf3ce44SJohn Forte 			if (sbp && (sbp != STALE_PACKET) &&
3914fcf3ce44SJohn Forte 			    (sbp->pkt_flags & PACKET_IN_CHIPQ) &&
3915fcf3ce44SJohn Forte 			    (sbp->node == ndlp) &&
391682527734SSukumar Swaminathan 			    (sbp->channel == cp) &&
3917fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
3918fcf3ce44SJohn Forte 				count++;
3919fcf3ce44SJohn Forte 			}
3920291a2b48SSukumar Swaminathan 
3921fcf3ce44SJohn Forte 		}
392282527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3923fcf3ce44SJohn Forte 
3924fcf3ce44SJohn Forte 	}	/* for */
3925fcf3ce44SJohn Forte 
3926fcf3ce44SJohn Forte 	return (count);
3927fcf3ce44SJohn Forte 
392882527734SSukumar Swaminathan } /* emlxs_chipq_node_check() */
3929fcf3ce44SJohn Forte 
3930fcf3ce44SJohn Forte 
3931fcf3ce44SJohn Forte 
393282527734SSukumar Swaminathan /* Flush all IO's for a given node's lun (on any channel) */
3933fcf3ce44SJohn Forte extern uint32_t
393482527734SSukumar Swaminathan emlxs_chipq_lun_flush(emlxs_port_t *port, NODELIST *ndlp,
393582527734SSukumar Swaminathan     uint32_t lun, emlxs_buf_t *fpkt)
3936fcf3ce44SJohn Forte {
3937fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3938fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3939fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3940fcf3ce44SJohn Forte 	IOCBQ *next;
3941fcf3ce44SJohn Forte 	Q abort;
3942fcf3ce44SJohn Forte 	uint32_t iotag;
394382527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
394482527734SSukumar Swaminathan 	uint32_t channelno;
3945fcf3ce44SJohn Forte 
3946a9800bebSGarrett D'Amore 	if (lun == EMLXS_LUN_NONE) {
3947a9800bebSGarrett D'Amore 		return (0);
3948a9800bebSGarrett D'Amore 	}
3949a9800bebSGarrett D'Amore 
3950fcf3ce44SJohn Forte 	bzero((void *)flag, sizeof (flag));
3951fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
3952fcf3ce44SJohn Forte 
395382527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
395482527734SSukumar Swaminathan 	for (iotag = 1; iotag < hba->max_iotag; iotag++) {
395582527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
3956fcf3ce44SJohn Forte 
3957fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET) &&
3958fcf3ce44SJohn Forte 		    sbp->pkt_flags & PACKET_IN_CHIPQ &&
3959fcf3ce44SJohn Forte 		    sbp->node == ndlp &&
3960fcf3ce44SJohn Forte 		    sbp->lun == lun &&
3961fcf3ce44SJohn Forte 		    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
396282527734SSukumar Swaminathan 			emlxs_sbp_abort_add(port, sbp,
396382527734SSukumar Swaminathan 			    &abort, flag, fpkt);
3964fcf3ce44SJohn Forte 		}
3965fcf3ce44SJohn Forte 	}
396682527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
3967fcf3ce44SJohn Forte 
3968fcf3ce44SJohn Forte 	/* Now put the iocb's on the tx queue */
3969fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
3970fcf3ce44SJohn Forte 	while (iocbq) {
3971fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
3972fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
3973fcf3ce44SJohn Forte 
3974fcf3ce44SJohn Forte 		/* Unlink this iocbq */
3975fcf3ce44SJohn Forte 		iocbq->next = NULL;
3976fcf3ce44SJohn Forte 
3977fcf3ce44SJohn Forte 		/* Send this iocbq */
3978fcf3ce44SJohn Forte 		emlxs_tx_put(iocbq, 1);
3979fcf3ce44SJohn Forte 
3980fcf3ce44SJohn Forte 		iocbq = next;
3981fcf3ce44SJohn Forte 	}
3982fcf3ce44SJohn Forte 
398382527734SSukumar Swaminathan 	/* Now trigger channel service */
398482527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
398582527734SSukumar Swaminathan 		if (!flag[channelno]) {
398682527734SSukumar Swaminathan 			continue;
398782527734SSukumar Swaminathan 		}
398882527734SSukumar Swaminathan 
398982527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
3990fcf3ce44SJohn Forte 	}
3991291a2b48SSukumar Swaminathan 
3992fcf3ce44SJohn Forte 	return (abort.q_cnt);
3993fcf3ce44SJohn Forte 
399482527734SSukumar Swaminathan } /* emlxs_chipq_lun_flush() */
3995fcf3ce44SJohn Forte 
3996fcf3ce44SJohn Forte 
3997fcf3ce44SJohn Forte 
3998fcf3ce44SJohn Forte /*
3999fcf3ce44SJohn Forte  * Issue an ABORT_XRI_CN iocb command to abort an FCP command already issued.
4000fe199829SSukumar Swaminathan  * This must be called while holding the EMLXS_FCTAB_LOCK
4001fcf3ce44SJohn Forte  */
4002fcf3ce44SJohn Forte extern IOCBQ *
4003291a2b48SSukumar Swaminathan emlxs_create_abort_xri_cn(emlxs_port_t *port, NODELIST *ndlp,
400482527734SSukumar Swaminathan     uint16_t iotag, CHANNEL *cp, uint8_t class, int32_t flag)
4005fcf3ce44SJohn Forte {
4006fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4007fcf3ce44SJohn Forte 	IOCBQ *iocbq;
4008fcf3ce44SJohn Forte 	IOCB *iocb;
400982527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
401082527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
4011fcf3ce44SJohn Forte 	uint16_t abort_iotag;
4012fcf3ce44SJohn Forte 
4013*8f23e9faSHans Rosenfeld 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
4014fcf3ce44SJohn Forte 		return (NULL);
4015fcf3ce44SJohn Forte 	}
4016291a2b48SSukumar Swaminathan 
401782527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
4018fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
4019fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
4020fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
4021fcf3ce44SJohn Forte 
4022fcf3ce44SJohn Forte 	/*
4023fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
4024fcf3ce44SJohn Forte 	 */
402582527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
402682527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
4027fcf3ce44SJohn Forte 	}
402882527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
4029291a2b48SSukumar Swaminathan 
4030fcf3ce44SJohn Forte 
403182527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
403282527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
403382527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
4034fcf3ce44SJohn Forte 
403582527734SSukumar Swaminathan 		/* Try to issue abort by XRI if possible */
4036a9800bebSGarrett D'Amore 		if (sbp == NULL || sbp == STALE_PACKET || sbp->xrip == NULL) {
403782527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_REQ_TAG;
403882527734SSukumar Swaminathan 			wqe->AbortTag = iotag;
403982527734SSukumar Swaminathan 		} else {
404082527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_XRI_TAG;
4041a9800bebSGarrett D'Amore 			wqe->AbortTag = sbp->xrip->XRI;
404282527734SSukumar Swaminathan 		}
404382527734SSukumar Swaminathan 		wqe->un.Abort.IA = 0;
404482527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
404582527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
404682527734SSukumar Swaminathan 		wqe->Class = CLASS3;
4047*8f23e9faSHans Rosenfeld 		wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
404882527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
404982527734SSukumar Swaminathan 	} else {
405082527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
405182527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
405282527734SSukumar Swaminathan 		iocb->un.acxri.abortType = flag;
405382527734SSukumar Swaminathan 		iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi;
405482527734SSukumar Swaminathan 		iocb->un.acxri.abortIoTag = iotag;
405582527734SSukumar Swaminathan 		iocb->ULPLE = 1;
405682527734SSukumar Swaminathan 		iocb->ULPCLASS = class;
405782527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_ABORT_XRI_CN;
405882527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
405982527734SSukumar Swaminathan 	}
4060fcf3ce44SJohn Forte 
4061fcf3ce44SJohn Forte 	return (iocbq);
4062fcf3ce44SJohn Forte 
406382527734SSukumar Swaminathan } /* emlxs_create_abort_xri_cn() */
4064fcf3ce44SJohn Forte 
4065fcf3ce44SJohn Forte 
4066fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4067fcf3ce44SJohn Forte extern IOCBQ *
4068fcf3ce44SJohn Forte emlxs_create_abort_xri_cx(emlxs_port_t *port, NODELIST *ndlp, uint16_t xid,
406982527734SSukumar Swaminathan     CHANNEL *cp, uint8_t class, int32_t flag)
4070fcf3ce44SJohn Forte {
4071fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4072fcf3ce44SJohn Forte 	IOCBQ *iocbq;
4073fcf3ce44SJohn Forte 	IOCB *iocb;
407482527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
4075fcf3ce44SJohn Forte 	uint16_t abort_iotag;
4076fcf3ce44SJohn Forte 
4077*8f23e9faSHans Rosenfeld 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
4078fcf3ce44SJohn Forte 		return (NULL);
4079fcf3ce44SJohn Forte 	}
4080291a2b48SSukumar Swaminathan 
408182527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
4082fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
4083fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
4084fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
4085fcf3ce44SJohn Forte 
4086fcf3ce44SJohn Forte 	/*
4087fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
4088fcf3ce44SJohn Forte 	 */
408982527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
409082527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
409182527734SSukumar Swaminathan 	}
409282527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
409382527734SSukumar Swaminathan 
409482527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
409582527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
409682527734SSukumar Swaminathan 		wqe->un.Abort.Criteria = ABORT_XRI_TAG;
409782527734SSukumar Swaminathan 		wqe->un.Abort.IA = 0;
409882527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
409982527734SSukumar Swaminathan 		wqe->AbortTag = xid;
410082527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
410182527734SSukumar Swaminathan 		wqe->Class = CLASS3;
4102*8f23e9faSHans Rosenfeld 		wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
410382527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
410482527734SSukumar Swaminathan 	} else {
410582527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
410682527734SSukumar Swaminathan 		iocb->ULPCONTEXT = xid;
410782527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
410882527734SSukumar Swaminathan 		iocb->un.acxri.abortType = flag;
410982527734SSukumar Swaminathan 		iocb->ULPLE = 1;
411082527734SSukumar Swaminathan 		iocb->ULPCLASS = class;
411182527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_ABORT_XRI_CX;
411282527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
4113fcf3ce44SJohn Forte 	}
4114291a2b48SSukumar Swaminathan 
4115fcf3ce44SJohn Forte 	return (iocbq);
4116fcf3ce44SJohn Forte 
411782527734SSukumar Swaminathan } /* emlxs_create_abort_xri_cx() */
4118fcf3ce44SJohn Forte 
4119fcf3ce44SJohn Forte 
4120fcf3ce44SJohn Forte 
4121fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4122fcf3ce44SJohn Forte extern IOCBQ *
4123fcf3ce44SJohn Forte emlxs_create_close_xri_cn(emlxs_port_t *port, NODELIST *ndlp,
412482527734SSukumar Swaminathan     uint16_t iotag, CHANNEL *cp)
4125fcf3ce44SJohn Forte {
4126fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4127fcf3ce44SJohn Forte 	IOCBQ *iocbq;
4128fcf3ce44SJohn Forte 	IOCB *iocb;
412982527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
413082527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
4131fcf3ce44SJohn Forte 	uint16_t abort_iotag;
4132fcf3ce44SJohn Forte 
4133*8f23e9faSHans Rosenfeld 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
4134fcf3ce44SJohn Forte 		return (NULL);
4135fcf3ce44SJohn Forte 	}
4136291a2b48SSukumar Swaminathan 
413782527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
4138fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
4139fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
4140fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
4141fcf3ce44SJohn Forte 
4142fcf3ce44SJohn Forte 	/*
4143fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
4144fcf3ce44SJohn Forte 	 */
414582527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
414682527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
4147fcf3ce44SJohn Forte 	}
414882527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
4149291a2b48SSukumar Swaminathan 
415082527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
415182527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
415282527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
4153fcf3ce44SJohn Forte 
415482527734SSukumar Swaminathan 		/* Try to issue close by XRI if possible */
4155a9800bebSGarrett D'Amore 		if (sbp == NULL || sbp == STALE_PACKET || sbp->xrip == NULL) {
415682527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_REQ_TAG;
415782527734SSukumar Swaminathan 			wqe->AbortTag = iotag;
415882527734SSukumar Swaminathan 		} else {
415982527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_XRI_TAG;
4160a9800bebSGarrett D'Amore 			wqe->AbortTag = sbp->xrip->XRI;
416182527734SSukumar Swaminathan 		}
416282527734SSukumar Swaminathan 		wqe->un.Abort.IA = 1;
416382527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
416482527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
416582527734SSukumar Swaminathan 		wqe->Class = CLASS3;
4166*8f23e9faSHans Rosenfeld 		wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
416782527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
416882527734SSukumar Swaminathan 	} else {
416982527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
417082527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
417182527734SSukumar Swaminathan 		iocb->un.acxri.abortType = 0;
417282527734SSukumar Swaminathan 		iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi;
417382527734SSukumar Swaminathan 		iocb->un.acxri.abortIoTag = iotag;
417482527734SSukumar Swaminathan 		iocb->ULPLE = 1;
417582527734SSukumar Swaminathan 		iocb->ULPCLASS = 0;
417682527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_CLOSE_XRI_CN;
417782527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
417882527734SSukumar Swaminathan 	}
4179fcf3ce44SJohn Forte 
4180fcf3ce44SJohn Forte 	return (iocbq);
4181fcf3ce44SJohn Forte 
418282527734SSukumar Swaminathan } /* emlxs_create_close_xri_cn() */
4183fcf3ce44SJohn Forte 
4184fcf3ce44SJohn Forte 
4185fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4186fcf3ce44SJohn Forte extern IOCBQ *
4187291a2b48SSukumar Swaminathan emlxs_create_close_xri_cx(emlxs_port_t *port, NODELIST *ndlp, uint16_t xid,
418882527734SSukumar Swaminathan     CHANNEL *cp)
4189fcf3ce44SJohn Forte {
4190fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4191fcf3ce44SJohn Forte 	IOCBQ *iocbq;
4192fcf3ce44SJohn Forte 	IOCB *iocb;
419382527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
4194fcf3ce44SJohn Forte 	uint16_t abort_iotag;
4195fcf3ce44SJohn Forte 
4196*8f23e9faSHans Rosenfeld 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
4197fcf3ce44SJohn Forte 		return (NULL);
4198fcf3ce44SJohn Forte 	}
4199291a2b48SSukumar Swaminathan 
420082527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
4201fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
4202fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
4203fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
4204fcf3ce44SJohn Forte 
4205fcf3ce44SJohn Forte 	/*
4206fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
4207fcf3ce44SJohn Forte 	 */
420882527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
420982527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
421082527734SSukumar Swaminathan 	}
421182527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
421282527734SSukumar Swaminathan 
421382527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
421482527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
421582527734SSukumar Swaminathan 		wqe->un.Abort.Criteria = ABORT_XRI_TAG;
421682527734SSukumar Swaminathan 		wqe->un.Abort.IA = 1;
421782527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
421882527734SSukumar Swaminathan 		wqe->AbortTag = xid;
421982527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
422082527734SSukumar Swaminathan 		wqe->Class = CLASS3;
4221*8f23e9faSHans Rosenfeld 		wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
422282527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
422382527734SSukumar Swaminathan 	} else {
422482527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
422582527734SSukumar Swaminathan 		iocb->ULPCONTEXT = xid;
422682527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
422782527734SSukumar Swaminathan 		iocb->ULPLE = 1;
422882527734SSukumar Swaminathan 		iocb->ULPCLASS = 0;
422982527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_CLOSE_XRI_CX;
423082527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
4231fcf3ce44SJohn Forte 	}
4232291a2b48SSukumar Swaminathan 
4233fcf3ce44SJohn Forte 	return (iocbq);
4234fcf3ce44SJohn Forte 
423582527734SSukumar Swaminathan } /* emlxs_create_close_xri_cx() */
4236fcf3ce44SJohn Forte 
4237fcf3ce44SJohn Forte 
4238a9800bebSGarrett D'Amore void
4239a9800bebSGarrett D'Amore emlxs_close_els_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4240a9800bebSGarrett D'Amore {
4241a9800bebSGarrett D'Amore 	CHANNEL *cp;
4242a9800bebSGarrett D'Amore 	IOCBQ *iocbq;
4243a9800bebSGarrett D'Amore 	IOCB *iocb;
4244a9800bebSGarrett D'Amore 
4245a9800bebSGarrett D'Amore 	if (rxid == 0 || rxid == 0xFFFF) {
4246a9800bebSGarrett D'Amore 		return;
4247a9800bebSGarrett D'Amore 	}
4248a9800bebSGarrett D'Amore 
4249a9800bebSGarrett D'Amore 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4250a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4251a9800bebSGarrett D'Amore 		    "Closing ELS exchange: xid=%x", rxid);
4252a9800bebSGarrett D'Amore 
4253*8f23e9faSHans Rosenfeld 		if (emlxs_sli4_unreserve_xri(port, rxid, 1) == 0) {
4254a9800bebSGarrett D'Amore 			return;
4255a9800bebSGarrett D'Amore 		}
4256a9800bebSGarrett D'Amore 	}
4257a9800bebSGarrett D'Amore 
4258a9800bebSGarrett D'Amore 	cp = &hba->chan[hba->channel_els];
4259a9800bebSGarrett D'Amore 
4260a9800bebSGarrett D'Amore 	mutex_enter(&EMLXS_FCTAB_LOCK);
4261a9800bebSGarrett D'Amore 
4262a9800bebSGarrett D'Amore 	/* Create the abort IOCB */
4263a9800bebSGarrett D'Amore 	iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4264a9800bebSGarrett D'Amore 
4265a9800bebSGarrett D'Amore 	mutex_exit(&EMLXS_FCTAB_LOCK);
4266a9800bebSGarrett D'Amore 
4267a9800bebSGarrett D'Amore 	if (iocbq) {
4268a9800bebSGarrett D'Amore 		iocb = &iocbq->iocb;
4269a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4270*8f23e9faSHans Rosenfeld 		    "Closing ELS exchange: xid=%x iotag=%d", rxid,
4271a9800bebSGarrett D'Amore 		    iocb->ULPIOTAG);
4272a9800bebSGarrett D'Amore 
4273a9800bebSGarrett D'Amore 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4274a9800bebSGarrett D'Amore 	}
4275a9800bebSGarrett D'Amore 
4276a9800bebSGarrett D'Amore } /* emlxs_close_els_exchange() */
4277a9800bebSGarrett D'Amore 
4278a9800bebSGarrett D'Amore 
4279fe199829SSukumar Swaminathan void
4280fe199829SSukumar Swaminathan emlxs_abort_els_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4281fe199829SSukumar Swaminathan {
4282fe199829SSukumar Swaminathan 	CHANNEL *cp;
4283fe199829SSukumar Swaminathan 	IOCBQ *iocbq;
4284fe199829SSukumar Swaminathan 	IOCB *iocb;
4285fe199829SSukumar Swaminathan 
4286fe199829SSukumar Swaminathan 	if (rxid == 0 || rxid == 0xFFFF) {
4287fe199829SSukumar Swaminathan 		return;
4288fe199829SSukumar Swaminathan 	}
4289fe199829SSukumar Swaminathan 
4290fe199829SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4291fe199829SSukumar Swaminathan 
4292fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4293fe199829SSukumar Swaminathan 		    "Aborting ELS exchange: xid=%x", rxid);
4294fe199829SSukumar Swaminathan 
4295*8f23e9faSHans Rosenfeld 		if (emlxs_sli4_unreserve_xri(port, rxid, 1) == 0) {
4296fe199829SSukumar Swaminathan 			/* We have no way to abort unsolicited exchanges */
4297fe199829SSukumar Swaminathan 			/* that we have not responded to at this time */
4298fe199829SSukumar Swaminathan 			/* So we will return for now */
4299fe199829SSukumar Swaminathan 			return;
4300fe199829SSukumar Swaminathan 		}
4301fe199829SSukumar Swaminathan 	}
4302fe199829SSukumar Swaminathan 
4303fe199829SSukumar Swaminathan 	cp = &hba->chan[hba->channel_els];
4304fe199829SSukumar Swaminathan 
4305fe199829SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
4306fe199829SSukumar Swaminathan 
4307fe199829SSukumar Swaminathan 	/* Create the abort IOCB */
4308fe199829SSukumar Swaminathan 	if (hba->state >= FC_LINK_UP) {
4309fe199829SSukumar Swaminathan 		iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4310fe199829SSukumar Swaminathan 		    CLASS3, ABORT_TYPE_ABTS);
4311fe199829SSukumar Swaminathan 	} else {
4312fe199829SSukumar Swaminathan 		iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4313fe199829SSukumar Swaminathan 	}
4314fe199829SSukumar Swaminathan 
4315fe199829SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
4316fe199829SSukumar Swaminathan 
4317fe199829SSukumar Swaminathan 	if (iocbq) {
4318fe199829SSukumar Swaminathan 		iocb = &iocbq->iocb;
4319fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4320*8f23e9faSHans Rosenfeld 		    "Aborting ELS exchange: xid=%x iotag=%d", rxid,
4321fe199829SSukumar Swaminathan 		    iocb->ULPIOTAG);
4322fe199829SSukumar Swaminathan 
4323fe199829SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4324fe199829SSukumar Swaminathan 	}
4325fe199829SSukumar Swaminathan 
4326fe199829SSukumar Swaminathan } /* emlxs_abort_els_exchange() */
4327fe199829SSukumar Swaminathan 
4328fe199829SSukumar Swaminathan 
4329728bdc9bSSukumar Swaminathan void
4330bb63f56eSSukumar Swaminathan emlxs_abort_ct_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4331728bdc9bSSukumar Swaminathan {
433282527734SSukumar Swaminathan 	CHANNEL *cp;
4333728bdc9bSSukumar Swaminathan 	IOCBQ *iocbq;
4334fe199829SSukumar Swaminathan 	IOCB *iocb;
4335728bdc9bSSukumar Swaminathan 
4336fe199829SSukumar Swaminathan 	if (rxid == 0 || rxid == 0xFFFF) {
4337fe199829SSukumar Swaminathan 		return;
4338fe199829SSukumar Swaminathan 	}
433982527734SSukumar Swaminathan 
434082527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4341fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ct_msg,
4342fe199829SSukumar Swaminathan 		    "Aborting CT exchange: xid=%x", rxid);
4343fe199829SSukumar Swaminathan 
4344*8f23e9faSHans Rosenfeld 		if (emlxs_sli4_unreserve_xri(port, rxid, 1) == 0) {
434582527734SSukumar Swaminathan 			/* We have no way to abort unsolicited exchanges */
434682527734SSukumar Swaminathan 			/* that we have not responded to at this time */
434782527734SSukumar Swaminathan 			/* So we will return for now */
434882527734SSukumar Swaminathan 			return;
434982527734SSukumar Swaminathan 		}
435082527734SSukumar Swaminathan 	}
435182527734SSukumar Swaminathan 
435282527734SSukumar Swaminathan 	cp = &hba->chan[hba->channel_ct];
4353728bdc9bSSukumar Swaminathan 
4354fe199829SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
4355fe199829SSukumar Swaminathan 
4356728bdc9bSSukumar Swaminathan 	/* Create the abort IOCB */
4357728bdc9bSSukumar Swaminathan 	if (hba->state >= FC_LINK_UP) {
4358fe199829SSukumar Swaminathan 		iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4359fe199829SSukumar Swaminathan 		    CLASS3, ABORT_TYPE_ABTS);
4360291a2b48SSukumar Swaminathan 	} else {
436182527734SSukumar Swaminathan 		iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4362728bdc9bSSukumar Swaminathan 	}
436382527734SSukumar Swaminathan 
4364fe199829SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
4365fe199829SSukumar Swaminathan 
4366bb63f56eSSukumar Swaminathan 	if (iocbq) {
4367fe199829SSukumar Swaminathan 		iocb = &iocbq->iocb;
4368fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4369*8f23e9faSHans Rosenfeld 		    "Aborting CT exchange: xid=%x iotag=%d", rxid,
4370fe199829SSukumar Swaminathan 		    iocb->ULPIOTAG);
4371fe199829SSukumar Swaminathan 
437282527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4373bb63f56eSSukumar Swaminathan 	}
437482527734SSukumar Swaminathan 
437582527734SSukumar Swaminathan } /* emlxs_abort_ct_exchange() */
4376728bdc9bSSukumar Swaminathan 
4377fcf3ce44SJohn Forte 
4378fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4379fcf3ce44SJohn Forte static void
4380fcf3ce44SJohn Forte emlxs_sbp_abort_add(emlxs_port_t *port, emlxs_buf_t *sbp, Q *abort,
4381fcf3ce44SJohn Forte     uint8_t *flag, emlxs_buf_t *fpkt)
4382fcf3ce44SJohn Forte {
4383fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4384fcf3ce44SJohn Forte 	IOCBQ *iocbq;
438582527734SSukumar Swaminathan 	CHANNEL *cp;
4386fcf3ce44SJohn Forte 	NODELIST *ndlp;
4387fcf3ce44SJohn Forte 
438882527734SSukumar Swaminathan 	cp = (CHANNEL *)sbp->channel;
4389fcf3ce44SJohn Forte 	ndlp = sbp->node;
4390fcf3ce44SJohn Forte 
4391fcf3ce44SJohn Forte 	/* Create the close XRI IOCB */
4392a9800bebSGarrett D'Amore 	if (hba->state >= FC_LINK_UP) {
4393a9800bebSGarrett D'Amore 		iocbq = emlxs_create_abort_xri_cn(port, ndlp, sbp->iotag, cp,
4394a9800bebSGarrett D'Amore 		    CLASS3, ABORT_TYPE_ABTS);
4395a9800bebSGarrett D'Amore 	} else {
4396a9800bebSGarrett D'Amore 		iocbq = emlxs_create_close_xri_cn(port, ndlp, sbp->iotag, cp);
4397a9800bebSGarrett D'Amore 	}
4398291a2b48SSukumar Swaminathan 	/*
4399291a2b48SSukumar Swaminathan 	 * Add this iocb to our local abort Q
4400291a2b48SSukumar Swaminathan 	 * This way we don't hold the CHIPQ lock too long
4401291a2b48SSukumar Swaminathan 	 */
4402fcf3ce44SJohn Forte 	if (iocbq) {
4403fcf3ce44SJohn Forte 		if (abort->q_first) {
4404291a2b48SSukumar Swaminathan 			((IOCBQ *)abort->q_last)->next = iocbq;
4405fcf3ce44SJohn Forte 			abort->q_last = (uint8_t *)iocbq;
4406fcf3ce44SJohn Forte 			abort->q_cnt++;
4407fcf3ce44SJohn Forte 		} else {
4408fcf3ce44SJohn Forte 			abort->q_first = (uint8_t *)iocbq;
4409fcf3ce44SJohn Forte 			abort->q_last = (uint8_t *)iocbq;
4410fcf3ce44SJohn Forte 			abort->q_cnt = 1;
4411fcf3ce44SJohn Forte 		}
4412fcf3ce44SJohn Forte 		iocbq->next = NULL;
4413fcf3ce44SJohn Forte 	}
4414291a2b48SSukumar Swaminathan 
4415fcf3ce44SJohn Forte 	/* set the flags */
4416fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
4417fcf3ce44SJohn Forte 
4418fcf3ce44SJohn Forte 	sbp->pkt_flags |= (PACKET_IN_FLUSH | PACKET_XRI_CLOSED);
441982527734SSukumar Swaminathan 
4420fcf3ce44SJohn Forte 	sbp->ticks = hba->timer_tics + 10;
4421fcf3ce44SJohn Forte 	sbp->abort_attempts++;
4422fcf3ce44SJohn Forte 
442382527734SSukumar Swaminathan 	flag[cp->channelno] = 1;
4424fcf3ce44SJohn Forte 
4425fcf3ce44SJohn Forte 	/*
4426291a2b48SSukumar Swaminathan 	 * If the fpkt is already set, then we will leave it alone
4427fcf3ce44SJohn Forte 	 * This ensures that this pkt is only accounted for on one
4428fcf3ce44SJohn Forte 	 * fpkt->flush_count
4429fcf3ce44SJohn Forte 	 */
4430fcf3ce44SJohn Forte 	if (!sbp->fpkt && fpkt) {
4431fcf3ce44SJohn Forte 		mutex_enter(&fpkt->mtx);
4432fcf3ce44SJohn Forte 		sbp->fpkt = fpkt;
4433fcf3ce44SJohn Forte 		fpkt->flush_count++;
4434fcf3ce44SJohn Forte 		mutex_exit(&fpkt->mtx);
4435fcf3ce44SJohn Forte 	}
4436291a2b48SSukumar Swaminathan 
4437fcf3ce44SJohn Forte 	mutex_exit(&sbp->mtx);
4438fcf3ce44SJohn Forte 
4439fcf3ce44SJohn Forte 	return;
4440fcf3ce44SJohn Forte 
444182527734SSukumar Swaminathan }	/* emlxs_sbp_abort_add() */
4442