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  *
88f23e9faSHans Rosenfeld  * You can obtain a copy of the license at
98f23e9faSHans 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 /*
238f23e9faSHans Rosenfeld  * Copyright (c) 2004-2012 Emulex. All rights reserved.
2482527734SSukumar Swaminathan  * Use is subject to license terms.
25*a3170057SPaul Winder  * Copyright 2020 RackTop Systems, Inc.
26fcf3ce44SJohn Forte  */
27fcf3ce44SJohn Forte 
28291a2b48SSukumar Swaminathan #include <emlxs.h>
29fcf3ce44SJohn Forte 
30fcf3ce44SJohn Forte /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
31fcf3ce44SJohn Forte EMLXS_MSG_DEF(EMLXS_FCP_C);
32fcf3ce44SJohn Forte 
33fcf3ce44SJohn Forte #define	EMLXS_GET_VADDR(hba, rp, icmd) emlxs_mem_get_vaddr(hba, rp, \
3482527734SSukumar Swaminathan 	PADDR(icmd->un.cont64[i].addrHigh, icmd->un.cont64[i].addrLow));
35fcf3ce44SJohn Forte 
36291a2b48SSukumar Swaminathan static void	emlxs_sbp_abort_add(emlxs_port_t *port, emlxs_buf_t *sbp,
37291a2b48SSukumar Swaminathan     Q *abort, uint8_t *flag, emlxs_buf_t *fpkt);
38fcf3ce44SJohn Forte 
39fcf3ce44SJohn Forte #define	SCSI3_PERSISTENT_RESERVE_IN	0x5e
40291a2b48SSukumar Swaminathan #define	SCSI_INQUIRY			0x12
41291a2b48SSukumar Swaminathan #define	SCSI_RX_DIAG    		0x1C
42fcf3ce44SJohn Forte 
43fcf3ce44SJohn Forte 
44fcf3ce44SJohn Forte /*
45fcf3ce44SJohn Forte  *  emlxs_handle_fcp_event
46fcf3ce44SJohn Forte  *
47fcf3ce44SJohn Forte  *  Description: Process an FCP Rsp Ring completion
48fcf3ce44SJohn Forte  *
49fcf3ce44SJohn Forte  */
50fcf3ce44SJohn Forte /* ARGSUSED */
51fcf3ce44SJohn Forte extern void
5282527734SSukumar Swaminathan emlxs_handle_fcp_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
53fcf3ce44SJohn Forte {
54fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
5582527734SSukumar Swaminathan 	emlxs_config_t	*cfg = &CFG;
56fcf3ce44SJohn Forte 	IOCB *cmd;
57fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
58fcf3ce44SJohn Forte 	fc_packet_t *pkt = NULL;
59291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
60291a2b48SSukumar Swaminathan 	NODELIST *ndlp;
61291a2b48SSukumar Swaminathan #endif
62fcf3ce44SJohn Forte 	uint32_t iostat;
63fcf3ce44SJohn Forte 	uint8_t localstat;
64fcf3ce44SJohn Forte 	fcp_rsp_t *rsp;
65fcf3ce44SJohn Forte 	uint32_t rsp_data_resid;
66fcf3ce44SJohn Forte 	uint32_t check_underrun;
67fcf3ce44SJohn Forte 	uint8_t asc;
68fcf3ce44SJohn Forte 	uint8_t ascq;
69fcf3ce44SJohn Forte 	uint8_t scsi_status;
70fcf3ce44SJohn Forte 	uint8_t sense;
71fcf3ce44SJohn Forte 	uint32_t did;
72fcf3ce44SJohn Forte 	uint32_t fix_it;
73fcf3ce44SJohn Forte 	uint8_t *scsi_cmd;
74fcf3ce44SJohn Forte 	uint8_t scsi_opcode;
75fcf3ce44SJohn Forte 	uint16_t scsi_dl;
76fcf3ce44SJohn Forte 	uint32_t data_rx;
778f23e9faSHans Rosenfeld 	uint32_t length;
78fcf3ce44SJohn Forte 
79fcf3ce44SJohn Forte 	cmd = &iocbq->iocb;
80fcf3ce44SJohn Forte 
81fcf3ce44SJohn Forte 	/* Initialize the status */
8282527734SSukumar Swaminathan 	iostat = cmd->ULPSTATUS;
83fcf3ce44SJohn Forte 	localstat = 0;
84fcf3ce44SJohn Forte 	scsi_status = 0;
85fcf3ce44SJohn Forte 	asc = 0;
86fcf3ce44SJohn Forte 	ascq = 0;
87fcf3ce44SJohn Forte 	sense = 0;
88fcf3ce44SJohn Forte 	check_underrun = 0;
89fcf3ce44SJohn Forte 	fix_it = 0;
90fcf3ce44SJohn Forte 
91fcf3ce44SJohn Forte 	HBASTATS.FcpEvent++;
92fcf3ce44SJohn Forte 
93fcf3ce44SJohn Forte 	sbp = (emlxs_buf_t *)iocbq->sbp;
94fcf3ce44SJohn Forte 
95fcf3ce44SJohn Forte 	if (!sbp) {
96fcf3ce44SJohn Forte 		/* completion with missing xmit command */
97fcf3ce44SJohn Forte 		HBASTATS.FcpStray++;
98fcf3ce44SJohn Forte 
99fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_fcp_completion_msg,
1008f23e9faSHans Rosenfeld 		    "cmd=%x iotag=%d", cmd->ULPCOMMAND, cmd->ULPIOTAG);
101fcf3ce44SJohn Forte 
102fcf3ce44SJohn Forte 		return;
103fcf3ce44SJohn Forte 	}
104291a2b48SSukumar Swaminathan 
105fcf3ce44SJohn Forte 	HBASTATS.FcpCompleted++;
106fcf3ce44SJohn Forte 
107291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
108291a2b48SSukumar Swaminathan 	emlxs_update_sd_bucket(sbp);
109291a2b48SSukumar Swaminathan #endif /* SAN_DIAG_SUPPORT */
110291a2b48SSukumar Swaminathan 
111fcf3ce44SJohn Forte 	pkt = PRIV2PKT(sbp);
112fcf3ce44SJohn Forte 
11382527734SSukumar Swaminathan 	did = LE_SWAP24_LO(pkt->pkt_cmd_fhdr.d_id);
114fcf3ce44SJohn Forte 	scsi_cmd = (uint8_t *)pkt->pkt_cmd;
115fcf3ce44SJohn Forte 	scsi_opcode = scsi_cmd[12];
116fcf3ce44SJohn Forte 	data_rx = 0;
117fcf3ce44SJohn Forte 
118fcf3ce44SJohn Forte 	/* Sync data in data buffer only on FC_PKT_FCP_READ */
119fcf3ce44SJohn Forte 	if (pkt->pkt_datalen && (pkt->pkt_tran_type == FC_PKT_FCP_READ)) {
12082527734SSukumar Swaminathan 		EMLXS_MPDATA_SYNC(pkt->pkt_data_dma, 0, pkt->pkt_datalen,
121fcf3ce44SJohn Forte 		    DDI_DMA_SYNC_FORKERNEL);
122fcf3ce44SJohn Forte 
123fcf3ce44SJohn Forte #ifdef TEST_SUPPORT
124fcf3ce44SJohn Forte 		if (hba->underrun_counter && (iostat == IOSTAT_SUCCESS) &&
125fcf3ce44SJohn Forte 		    (pkt->pkt_datalen >= 512)) {
126fcf3ce44SJohn Forte 			hba->underrun_counter--;
127fcf3ce44SJohn Forte 			iostat = IOSTAT_FCP_RSP_ERROR;
128fcf3ce44SJohn Forte 
129fcf3ce44SJohn Forte 			/* Report 512 bytes missing by adapter */
130fcf3ce44SJohn Forte 			cmd->un.fcpi.fcpi_parm = pkt->pkt_datalen - 512;
131fcf3ce44SJohn Forte 
132fcf3ce44SJohn Forte 			/* Corrupt 512 bytes of Data buffer */
133fcf3ce44SJohn Forte 			bzero((uint8_t *)pkt->pkt_data, 512);
134fcf3ce44SJohn Forte 
135fcf3ce44SJohn Forte 			/* Set FCP response to STATUS_GOOD */
136fcf3ce44SJohn Forte 			bzero((uint8_t *)pkt->pkt_resp, pkt->pkt_rsplen);
137fcf3ce44SJohn Forte 		}
138291a2b48SSukumar Swaminathan #endif /* TEST_SUPPORT */
139fcf3ce44SJohn Forte 	}
140291a2b48SSukumar Swaminathan 
141fcf3ce44SJohn Forte 	/* Process the pkt */
142fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
143fcf3ce44SJohn Forte 
144fcf3ce44SJohn Forte 	/* Check for immediate return */
145fcf3ce44SJohn Forte 	if ((iostat == IOSTAT_SUCCESS) &&
146fcf3ce44SJohn Forte 	    (pkt->pkt_comp) &&
147291a2b48SSukumar Swaminathan 	    !(sbp->pkt_flags &
14882527734SSukumar Swaminathan 	    (PACKET_ULP_OWNED | PACKET_COMPLETED |
149fcf3ce44SJohn Forte 	    PACKET_IN_COMPLETION | PACKET_IN_TXQ | PACKET_IN_CHIPQ |
150fcf3ce44SJohn Forte 	    PACKET_IN_DONEQ | PACKET_IN_TIMEOUT | PACKET_IN_FLUSH |
151fcf3ce44SJohn Forte 	    PACKET_IN_ABORT | PACKET_POLLED))) {
152fcf3ce44SJohn Forte 		HBASTATS.FcpGood++;
153fcf3ce44SJohn Forte 
154291a2b48SSukumar Swaminathan 		sbp->pkt_flags |=
155291a2b48SSukumar Swaminathan 		    (PACKET_STATE_VALID | PACKET_IN_COMPLETION |
15682527734SSukumar Swaminathan 		    PACKET_COMPLETED | PACKET_ULP_OWNED);
157fcf3ce44SJohn Forte 		mutex_exit(&sbp->mtx);
158fcf3ce44SJohn Forte 
159fcf3ce44SJohn Forte #if (EMLXS_MODREVX == EMLXS_MODREV2X)
160fcf3ce44SJohn Forte 		emlxs_unswap_pkt(sbp);
161291a2b48SSukumar Swaminathan #endif /* EMLXS_MODREV2X */
162b3660a96SSukumar Swaminathan 
163b3660a96SSukumar Swaminathan #ifdef FMA_SUPPORT
164b3660a96SSukumar Swaminathan 		emlxs_check_dma(hba, sbp);
165b3660a96SSukumar Swaminathan #endif  /* FMA_SUPPORT */
166b3660a96SSukumar Swaminathan 
16782527734SSukumar Swaminathan 		cp->ulpCmplCmd++;
168fcf3ce44SJohn Forte 		(*pkt->pkt_comp) (pkt);
169fcf3ce44SJohn Forte 
170b3660a96SSukumar Swaminathan #ifdef FMA_SUPPORT
171b3660a96SSukumar Swaminathan 		if (hba->flag & FC_DMA_CHECK_ERROR) {
172b3660a96SSukumar Swaminathan 			emlxs_thread_spawn(hba, emlxs_restart_thread,
173b3660a96SSukumar Swaminathan 			    NULL, NULL);
174b3660a96SSukumar Swaminathan 		}
175b3660a96SSukumar Swaminathan #endif  /* FMA_SUPPORT */
176b3660a96SSukumar Swaminathan 
177fcf3ce44SJohn Forte 		return;
178fcf3ce44SJohn Forte 	}
179291a2b48SSukumar Swaminathan 
180fcf3ce44SJohn Forte 	/*
181291a2b48SSukumar Swaminathan 	 * A response is only placed in the resp buffer if IOSTAT_FCP_RSP_ERROR
182291a2b48SSukumar Swaminathan 	 * is reported.
183fcf3ce44SJohn Forte 	 */
184fcf3ce44SJohn Forte 
1858f23e9faSHans Rosenfeld 	/* Check if a response buffer was not provided */
1868f23e9faSHans Rosenfeld 	if ((iostat != IOSTAT_FCP_RSP_ERROR) || (pkt->pkt_rsplen == 0)) {
1878f23e9faSHans Rosenfeld 		goto done;
1888f23e9faSHans Rosenfeld 	}
1898f23e9faSHans Rosenfeld 
1908f23e9faSHans Rosenfeld 	EMLXS_MPDATA_SYNC(pkt->pkt_resp_dma, 0, pkt->pkt_rsplen,
1918f23e9faSHans Rosenfeld 	    DDI_DMA_SYNC_FORKERNEL);
1928f23e9faSHans Rosenfeld 
1938f23e9faSHans Rosenfeld 	/* Get the response buffer pointer */
1948f23e9faSHans Rosenfeld 	rsp = (fcp_rsp_t *)pkt->pkt_resp;
1958f23e9faSHans Rosenfeld 
1968f23e9faSHans Rosenfeld 	/* Validate the response payload */
1978f23e9faSHans Rosenfeld 	if (!rsp->fcp_u.fcp_status.resid_under &&
1988f23e9faSHans Rosenfeld 	    !rsp->fcp_u.fcp_status.resid_over) {
1998f23e9faSHans Rosenfeld 		rsp->fcp_resid = 0;
2008f23e9faSHans Rosenfeld 	}
2018f23e9faSHans Rosenfeld 
2028f23e9faSHans Rosenfeld 	if (!rsp->fcp_u.fcp_status.rsp_len_set) {
2038f23e9faSHans Rosenfeld 		rsp->fcp_response_len = 0;
2048f23e9faSHans Rosenfeld 	}
205fcf3ce44SJohn Forte 
2068f23e9faSHans Rosenfeld 	if (!rsp->fcp_u.fcp_status.sense_len_set) {
2078f23e9faSHans Rosenfeld 		rsp->fcp_sense_len = 0;
2088f23e9faSHans Rosenfeld 	}
2098f23e9faSHans Rosenfeld 
2108f23e9faSHans Rosenfeld 	length = sizeof (fcp_rsp_t) + LE_SWAP32(rsp->fcp_response_len) +
2118f23e9faSHans Rosenfeld 	    LE_SWAP32(rsp->fcp_sense_len);
2128f23e9faSHans Rosenfeld 
2138f23e9faSHans Rosenfeld 	if (length > pkt->pkt_rsplen) {
2148f23e9faSHans Rosenfeld 		iostat = IOSTAT_RSP_INVALID;
2158f23e9faSHans Rosenfeld 		pkt->pkt_data_resid = pkt->pkt_datalen;
2168f23e9faSHans Rosenfeld 		goto done;
2178f23e9faSHans Rosenfeld 	}
218fcf3ce44SJohn Forte 
2198f23e9faSHans Rosenfeld 	/* Set the valid response flag */
2208f23e9faSHans Rosenfeld 	sbp->pkt_flags |= PACKET_FCP_RSP_VALID;
221fcf3ce44SJohn Forte 
2228f23e9faSHans Rosenfeld 	scsi_status = rsp->fcp_u.fcp_status.scsi_status;
223fcf3ce44SJohn Forte 
224291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
2258f23e9faSHans Rosenfeld 	ndlp = (NODELIST *)iocbq->node;
2268f23e9faSHans Rosenfeld 	if (scsi_status == SCSI_STAT_QUE_FULL) {
2278f23e9faSHans Rosenfeld 		emlxs_log_sd_scsi_event(port, SD_SCSI_SUBCATEGORY_QFULL,
2288f23e9faSHans Rosenfeld 		    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun);
2298f23e9faSHans Rosenfeld 	} else if (scsi_status == SCSI_STAT_BUSY) {
2308f23e9faSHans Rosenfeld 		emlxs_log_sd_scsi_event(port,
2318f23e9faSHans Rosenfeld 		    SD_SCSI_SUBCATEGORY_DEVBSY,
2328f23e9faSHans Rosenfeld 		    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun);
2338f23e9faSHans Rosenfeld 	}
234291a2b48SSukumar Swaminathan #endif
235291a2b48SSukumar Swaminathan 
2368f23e9faSHans Rosenfeld 	/*
2378f23e9faSHans Rosenfeld 	 * Convert a task abort to a check condition with no data
2388f23e9faSHans Rosenfeld 	 * transferred. We saw a data corruption when Solaris received
2398f23e9faSHans Rosenfeld 	 * a Task Abort from a tape.
2408f23e9faSHans Rosenfeld 	 */
241a9800bebSGarrett D'Amore 
2428f23e9faSHans Rosenfeld 	if (scsi_status == SCSI_STAT_TASK_ABORT) {
2438f23e9faSHans Rosenfeld 		EMLXS_MSGF(EMLXS_CONTEXT,
2448f23e9faSHans Rosenfeld 		    &emlxs_fcp_completion_error_msg,
2458f23e9faSHans Rosenfeld 		    "Task Abort. "
2468f23e9faSHans Rosenfeld 		    "Fixed. did=0x%06x sbp=%p cmd=%02x dl=%d",
2478f23e9faSHans Rosenfeld 		    did, sbp, scsi_opcode, pkt->pkt_datalen);
2488f23e9faSHans Rosenfeld 
2498f23e9faSHans Rosenfeld 		rsp->fcp_u.fcp_status.scsi_status =
2508f23e9faSHans Rosenfeld 		    SCSI_STAT_CHECK_COND;
2518f23e9faSHans Rosenfeld 		rsp->fcp_u.fcp_status.rsp_len_set = 0;
2528f23e9faSHans Rosenfeld 		rsp->fcp_u.fcp_status.sense_len_set = 0;
2538f23e9faSHans Rosenfeld 		rsp->fcp_u.fcp_status.resid_over = 0;
2548f23e9faSHans Rosenfeld 
2558f23e9faSHans Rosenfeld 		if (pkt->pkt_datalen) {
2568f23e9faSHans Rosenfeld 			rsp->fcp_u.fcp_status.resid_under = 1;
2578f23e9faSHans Rosenfeld 			rsp->fcp_resid =
2588f23e9faSHans Rosenfeld 			    LE_SWAP32(pkt->pkt_datalen);
2598f23e9faSHans Rosenfeld 		} else {
2608f23e9faSHans Rosenfeld 			rsp->fcp_u.fcp_status.resid_under = 0;
2618f23e9faSHans Rosenfeld 			rsp->fcp_resid = 0;
2628f23e9faSHans Rosenfeld 		}
263fcf3ce44SJohn Forte 
2648f23e9faSHans Rosenfeld 		scsi_status = SCSI_STAT_CHECK_COND;
2658f23e9faSHans Rosenfeld 	}
266fcf3ce44SJohn Forte 
2678f23e9faSHans Rosenfeld 	/*
2688f23e9faSHans Rosenfeld 	 * We only need to check underrun if data could
2698f23e9faSHans Rosenfeld 	 * have been sent
2708f23e9faSHans Rosenfeld 	 */
271fcf3ce44SJohn Forte 
2728f23e9faSHans Rosenfeld 	/* Always check underrun if status is good */
2738f23e9faSHans Rosenfeld 	if (scsi_status == SCSI_STAT_GOOD) {
2748f23e9faSHans Rosenfeld 		check_underrun = 1;
2758f23e9faSHans Rosenfeld 	}
2768f23e9faSHans Rosenfeld 	/* Check the sense codes if this is a check condition */
2778f23e9faSHans Rosenfeld 	else if (scsi_status == SCSI_STAT_CHECK_COND) {
2788f23e9faSHans Rosenfeld 		check_underrun = 1;
2798f23e9faSHans Rosenfeld 
2808f23e9faSHans Rosenfeld 		/* Check if sense data was provided */
2818f23e9faSHans Rosenfeld 		if (LE_SWAP32(rsp->fcp_sense_len) >= 14) {
2828f23e9faSHans Rosenfeld 			sense = *((uint8_t *)rsp + 32 + 2);
2838f23e9faSHans Rosenfeld 			asc = *((uint8_t *)rsp + 32 + 12);
2848f23e9faSHans Rosenfeld 			ascq = *((uint8_t *)rsp + 32 + 13);
285fcf3ce44SJohn Forte 		}
286291a2b48SSukumar Swaminathan 
2878f23e9faSHans Rosenfeld #ifdef SAN_DIAG_SUPPORT
2888f23e9faSHans Rosenfeld 		emlxs_log_sd_scsi_check_event(port,
2898f23e9faSHans Rosenfeld 		    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun,
2908f23e9faSHans Rosenfeld 		    scsi_opcode, sense, asc, ascq);
2918f23e9faSHans Rosenfeld #endif
2928f23e9faSHans Rosenfeld 	}
2938f23e9faSHans Rosenfeld 	/* Status is not good and this is not a check condition */
2948f23e9faSHans Rosenfeld 	/* No data should have been sent */
2958f23e9faSHans Rosenfeld 	else {
2968f23e9faSHans Rosenfeld 		check_underrun = 0;
2978f23e9faSHans Rosenfeld 	}
2988f23e9faSHans Rosenfeld 
2998f23e9faSHans Rosenfeld 	/* Initialize the resids */
3008f23e9faSHans Rosenfeld 	pkt->pkt_resp_resid = 0;
3018f23e9faSHans Rosenfeld 	pkt->pkt_data_resid = 0;
3028f23e9faSHans Rosenfeld 
3038f23e9faSHans Rosenfeld 	/* Check if no data was to be transferred */
3048f23e9faSHans Rosenfeld 	if (pkt->pkt_datalen == 0) {
3058f23e9faSHans Rosenfeld 		goto done;
3068f23e9faSHans Rosenfeld 	}
3078f23e9faSHans Rosenfeld 
3088f23e9faSHans Rosenfeld 	/* Get the residual underrun count reported by the SCSI reply */
3098f23e9faSHans Rosenfeld 	rsp_data_resid = (rsp->fcp_u.fcp_status.resid_under) ?
3108f23e9faSHans Rosenfeld 	    LE_SWAP32(rsp->fcp_resid) : 0;
3118f23e9faSHans Rosenfeld 
3128f23e9faSHans Rosenfeld 	/* Set the pkt_data_resid to what the scsi response resid */
3138f23e9faSHans Rosenfeld 	pkt->pkt_data_resid = rsp_data_resid;
3148f23e9faSHans Rosenfeld 
3158f23e9faSHans Rosenfeld 	/* Adjust the pkt_data_resid field if needed */
3168f23e9faSHans Rosenfeld 	if (pkt->pkt_tran_type == FC_PKT_FCP_READ) {
317fcf3ce44SJohn Forte 		/*
3188f23e9faSHans Rosenfeld 		 * Get the residual underrun count reported by
3198f23e9faSHans Rosenfeld 		 * our adapter
320fcf3ce44SJohn Forte 		 */
3218f23e9faSHans Rosenfeld 		pkt->pkt_data_resid = cmd->un.fcpi.fcpi_parm;
322291a2b48SSukumar Swaminathan 
323291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
3248f23e9faSHans Rosenfeld 		if ((rsp_data_resid == 0) && (pkt->pkt_data_resid)) {
3258f23e9faSHans Rosenfeld 			emlxs_log_sd_fc_rdchk_event(port,
326291a2b48SSukumar Swaminathan 			    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun,
3278f23e9faSHans Rosenfeld 			    scsi_opcode, pkt->pkt_data_resid);
328fcf3ce44SJohn Forte 		}
3298f23e9faSHans Rosenfeld #endif
3308f23e9faSHans Rosenfeld 
3318f23e9faSHans Rosenfeld 		/* Get the actual amount of data transferred */
3328f23e9faSHans Rosenfeld 		data_rx = pkt->pkt_datalen - pkt->pkt_data_resid;
333fcf3ce44SJohn Forte 
3348f23e9faSHans Rosenfeld 		/*
3358f23e9faSHans Rosenfeld 		 * If the residual being reported by the adapter is
3368f23e9faSHans Rosenfeld 		 * greater than the residual being reported in the
3378f23e9faSHans Rosenfeld 		 * reply, then we have a true underrun.
3388f23e9faSHans Rosenfeld 		 */
3398f23e9faSHans Rosenfeld 		if (check_underrun && (pkt->pkt_data_resid > rsp_data_resid)) {
3408f23e9faSHans Rosenfeld 			switch (scsi_opcode) {
3418f23e9faSHans Rosenfeld 			case SCSI_INQUIRY:
3428f23e9faSHans Rosenfeld 				scsi_dl = scsi_cmd[16];
3438f23e9faSHans Rosenfeld 				break;
3448f23e9faSHans Rosenfeld 
3458f23e9faSHans Rosenfeld 			case SCSI_RX_DIAG:
3468f23e9faSHans Rosenfeld 				scsi_dl =
3478f23e9faSHans Rosenfeld 				    (scsi_cmd[15] * 0x100) +
3488f23e9faSHans Rosenfeld 				    scsi_cmd[16];
3498f23e9faSHans Rosenfeld 				break;
350fcf3ce44SJohn Forte 
3518f23e9faSHans Rosenfeld 			default:
3528f23e9faSHans Rosenfeld 				scsi_dl = pkt->pkt_datalen;
3538f23e9faSHans Rosenfeld 			}
354fcf3ce44SJohn Forte 
3558f23e9faSHans Rosenfeld #ifdef FCP_UNDERRUN_PATCH1
3568f23e9faSHans Rosenfeld if (cfg[CFG_ENABLE_PATCH].current & FCP_UNDERRUN_PATCH1) {
357fcf3ce44SJohn Forte 			/*
3588f23e9faSHans Rosenfeld 			 * If status is not good and no data was
3598f23e9faSHans Rosenfeld 			 * actually transferred, then we must fix
3608f23e9faSHans Rosenfeld 			 * the issue
361fcf3ce44SJohn Forte 			 */
3628f23e9faSHans Rosenfeld 			if ((scsi_status != SCSI_STAT_GOOD) && (data_rx == 0)) {
3638f23e9faSHans Rosenfeld 				fix_it = 1;
3648f23e9faSHans Rosenfeld 
3658f23e9faSHans Rosenfeld 				EMLXS_MSGF(EMLXS_CONTEXT,
3668f23e9faSHans Rosenfeld 				    &emlxs_fcp_completion_error_msg,
3678f23e9faSHans Rosenfeld 				    "Underrun(1). Fixed. "
3688f23e9faSHans Rosenfeld 				    "did=0x%06x sbp=%p cmd=%02x "
3698f23e9faSHans Rosenfeld 				    "dl=%d,%d rx=%d rsp=%d",
3708f23e9faSHans Rosenfeld 				    did, sbp, scsi_opcode,
3718f23e9faSHans Rosenfeld 				    pkt->pkt_datalen, scsi_dl,
3728f23e9faSHans Rosenfeld 				    (pkt->pkt_datalen -
3738f23e9faSHans Rosenfeld 				    pkt->pkt_data_resid),
3748f23e9faSHans Rosenfeld 				    rsp_data_resid);
375fcf3ce44SJohn Forte 
376291a2b48SSukumar Swaminathan 			}
3778f23e9faSHans Rosenfeld }
3788f23e9faSHans Rosenfeld #endif /* FCP_UNDERRUN_PATCH1 */
379291a2b48SSukumar Swaminathan 
380fcf3ce44SJohn Forte 
3818f23e9faSHans Rosenfeld #ifdef FCP_UNDERRUN_PATCH2
3828f23e9faSHans Rosenfeld if (cfg[CFG_ENABLE_PATCH].current & FCP_UNDERRUN_PATCH2) {
3838f23e9faSHans Rosenfeld 			if (scsi_status == SCSI_STAT_GOOD) {
3848f23e9faSHans Rosenfeld 				emlxs_msg_t	*msg;
385fcf3ce44SJohn Forte 
3868f23e9faSHans Rosenfeld 				msg = &emlxs_fcp_completion_error_msg;
3878f23e9faSHans Rosenfeld 				/*
3888f23e9faSHans Rosenfeld 				 * If status is good and this is an
3898f23e9faSHans Rosenfeld 				 * inquiry request and the amount of
3908f23e9faSHans Rosenfeld 				 * data
3918f23e9faSHans Rosenfeld 				 */
3928f23e9faSHans Rosenfeld 				/*
3938f23e9faSHans Rosenfeld 				 * requested <= data received, then we
3948f23e9faSHans Rosenfeld 				 * must fix the issue.
3958f23e9faSHans Rosenfeld 				 */
3968f23e9faSHans Rosenfeld 
3978f23e9faSHans Rosenfeld 				if ((scsi_opcode == SCSI_INQUIRY) &&
3988f23e9faSHans Rosenfeld 				    (pkt->pkt_datalen >= data_rx) &&
3998f23e9faSHans Rosenfeld 				    (scsi_dl <= data_rx)) {
4008f23e9faSHans Rosenfeld 					fix_it = 1;
4018f23e9faSHans Rosenfeld 
4028f23e9faSHans Rosenfeld 					EMLXS_MSGF(EMLXS_CONTEXT, msg,
4038f23e9faSHans Rosenfeld 					    "Underrun(2). Fixed. "
4048f23e9faSHans Rosenfeld 					    "did=0x%06x sbp=%p "
4058f23e9faSHans Rosenfeld 					    "cmd=%02x dl=%d,%d "
4068f23e9faSHans Rosenfeld 					    "rx=%d rsp=%d",
4078f23e9faSHans Rosenfeld 					    did, sbp, scsi_opcode,
4088f23e9faSHans Rosenfeld 					    pkt->pkt_datalen, scsi_dl,
4098f23e9faSHans Rosenfeld 					    data_rx, rsp_data_resid);
410fcf3ce44SJohn Forte 
411fcf3ce44SJohn Forte 				}
412fcf3ce44SJohn Forte 
413fcf3ce44SJohn Forte 				/*
4148f23e9faSHans Rosenfeld 				 * If status is good and this is an
4158f23e9faSHans Rosenfeld 				 * inquiry request and the amount of
4168f23e9faSHans Rosenfeld 				 * data requested >= 128 bytes, but
4178f23e9faSHans Rosenfeld 				 * only 128 bytes were received,
4188f23e9faSHans Rosenfeld 				 * then we must fix the issue.
419fcf3ce44SJohn Forte 				 */
4208f23e9faSHans Rosenfeld 				else if ((scsi_opcode == SCSI_INQUIRY) &&
4218f23e9faSHans Rosenfeld 				    (pkt->pkt_datalen >= 128) &&
4228f23e9faSHans Rosenfeld 				    (scsi_dl >= 128) && (data_rx == 128)) {
423fcf3ce44SJohn Forte 					fix_it = 1;
424fcf3ce44SJohn Forte 
4258f23e9faSHans Rosenfeld 					EMLXS_MSGF(EMLXS_CONTEXT, msg,
4268f23e9faSHans Rosenfeld 					    "Underrun(3). Fixed. "
4278f23e9faSHans Rosenfeld 					    "did=0x%06x sbp=%p "
4288f23e9faSHans Rosenfeld 					    "cmd=%02x dl=%d,%d "
4298f23e9faSHans Rosenfeld 					    "rx=%d rsp=%d",
430fcf3ce44SJohn Forte 					    did, sbp, scsi_opcode,
431fcf3ce44SJohn Forte 					    pkt->pkt_datalen, scsi_dl,
4328f23e9faSHans Rosenfeld 					    data_rx, rsp_data_resid);
433fcf3ce44SJohn Forte 
434fcf3ce44SJohn Forte 				}
4358f23e9faSHans Rosenfeld 			}
43682527734SSukumar Swaminathan }
4378f23e9faSHans Rosenfeld #endif /* FCP_UNDERRUN_PATCH2 */
438fcf3ce44SJohn Forte 
4398f23e9faSHans Rosenfeld 			/*
4408f23e9faSHans Rosenfeld 			 * Check if SCSI response payload should be
4418f23e9faSHans Rosenfeld 			 * fixed or if a DATA_UNDERRUN should be
4428f23e9faSHans Rosenfeld 			 * reported
4438f23e9faSHans Rosenfeld 			 */
4448f23e9faSHans Rosenfeld 			if (fix_it) {
4458f23e9faSHans Rosenfeld 				/*
4468f23e9faSHans Rosenfeld 				 * Fix the SCSI response payload itself
4478f23e9faSHans Rosenfeld 				 */
4488f23e9faSHans Rosenfeld 				rsp->fcp_u.fcp_status.resid_under = 1;
4498f23e9faSHans Rosenfeld 				rsp->fcp_resid =
4508f23e9faSHans Rosenfeld 				    LE_SWAP32(pkt->pkt_data_resid);
4518f23e9faSHans Rosenfeld 			} else {
4528f23e9faSHans Rosenfeld 				/*
4538f23e9faSHans Rosenfeld 				 * Change the status from
4548f23e9faSHans Rosenfeld 				 * IOSTAT_FCP_RSP_ERROR to
4558f23e9faSHans Rosenfeld 				 * IOSTAT_DATA_UNDERRUN
4568f23e9faSHans Rosenfeld 				 */
4578f23e9faSHans Rosenfeld 				iostat = IOSTAT_DATA_UNDERRUN;
4588f23e9faSHans Rosenfeld 				pkt->pkt_data_resid =
4598f23e9faSHans Rosenfeld 				    pkt->pkt_datalen;
4608f23e9faSHans Rosenfeld 			}
4618f23e9faSHans Rosenfeld 		}
462fcf3ce44SJohn Forte 
4638f23e9faSHans Rosenfeld 		/*
4648f23e9faSHans Rosenfeld 		 * If the residual being reported by the adapter is
4658f23e9faSHans Rosenfeld 		 * less than the residual being reported in the reply,
4668f23e9faSHans Rosenfeld 		 * then we have a true overrun. Since we don't know
4678f23e9faSHans Rosenfeld 		 * where the extra data came from or went to then we
4688f23e9faSHans Rosenfeld 		 * cannot trust anything we received
4698f23e9faSHans Rosenfeld 		 */
4708f23e9faSHans Rosenfeld 		else if (rsp_data_resid > pkt->pkt_data_resid) {
4718f23e9faSHans Rosenfeld 			/*
4728f23e9faSHans Rosenfeld 			 * Change the status from
4738f23e9faSHans Rosenfeld 			 * IOSTAT_FCP_RSP_ERROR to
4748f23e9faSHans Rosenfeld 			 * IOSTAT_DATA_OVERRUN
4758f23e9faSHans Rosenfeld 			 */
4768f23e9faSHans Rosenfeld 			iostat = IOSTAT_DATA_OVERRUN;
4778f23e9faSHans Rosenfeld 			pkt->pkt_data_resid = pkt->pkt_datalen;
4788f23e9faSHans Rosenfeld 		}
479fcf3ce44SJohn Forte 
4808f23e9faSHans Rosenfeld 	} else if ((hba->sli_mode == EMLXS_HBA_SLI4_MODE) &&
4818f23e9faSHans Rosenfeld 	    (pkt->pkt_tran_type == FC_PKT_FCP_WRITE)) {
4828f23e9faSHans Rosenfeld 		/*
4838f23e9faSHans Rosenfeld 		 * Get the residual underrun count reported by
4848f23e9faSHans Rosenfeld 		 * our adapter
4858f23e9faSHans Rosenfeld 		 */
4868f23e9faSHans Rosenfeld 		pkt->pkt_data_resid = cmd->un.fcpi.fcpi_parm;
487fcf3ce44SJohn Forte 
4888f23e9faSHans Rosenfeld #ifdef SAN_DIAG_SUPPORT
4898f23e9faSHans Rosenfeld 		if ((rsp_data_resid == 0) && (pkt->pkt_data_resid)) {
4908f23e9faSHans Rosenfeld 			emlxs_log_sd_fc_rdchk_event(port,
4918f23e9faSHans Rosenfeld 			    (HBA_WWN *)&ndlp->nlp_portname, sbp->lun,
4928f23e9faSHans Rosenfeld 			    scsi_opcode, pkt->pkt_data_resid);
4938f23e9faSHans Rosenfeld 		}
4948f23e9faSHans Rosenfeld #endif /* SAN_DIAG_SUPPORT */
495fcf3ce44SJohn Forte 
4968f23e9faSHans Rosenfeld 		/* Get the actual amount of data transferred */
4978f23e9faSHans Rosenfeld 		data_rx = pkt->pkt_datalen - pkt->pkt_data_resid;
498fcf3ce44SJohn Forte 
4998f23e9faSHans Rosenfeld 		/*
5008f23e9faSHans Rosenfeld 		 * If the residual being reported by the adapter is
5018f23e9faSHans Rosenfeld 		 * greater than the residual being reported in the
5028f23e9faSHans Rosenfeld 		 * reply, then we have a true underrun.
5038f23e9faSHans Rosenfeld 		 */
5048f23e9faSHans Rosenfeld 		if (check_underrun && (pkt->pkt_data_resid > rsp_data_resid)) {
505291a2b48SSukumar Swaminathan 
5068f23e9faSHans Rosenfeld 			scsi_dl = pkt->pkt_datalen;
507fcf3ce44SJohn Forte 
5088f23e9faSHans Rosenfeld #ifdef FCP_UNDERRUN_PATCH1
5098f23e9faSHans Rosenfeld if (cfg[CFG_ENABLE_PATCH].current & FCP_UNDERRUN_PATCH1) {
5108f23e9faSHans Rosenfeld 			/*
5118f23e9faSHans Rosenfeld 			 * If status is not good and no data was
5128f23e9faSHans Rosenfeld 			 * actually transferred, then we must fix
5138f23e9faSHans Rosenfeld 			 * the issue
5148f23e9faSHans Rosenfeld 			 */
5158f23e9faSHans Rosenfeld 			if ((scsi_status != SCSI_STAT_GOOD) && (data_rx == 0)) {
5168f23e9faSHans Rosenfeld 				fix_it = 1;
517291a2b48SSukumar Swaminathan 
5188f23e9faSHans Rosenfeld 				EMLXS_MSGF(EMLXS_CONTEXT,
5198f23e9faSHans Rosenfeld 				    &emlxs_fcp_completion_error_msg,
5208f23e9faSHans Rosenfeld 				    "Underrun(1). Fixed. "
5218f23e9faSHans Rosenfeld 				    "did=0x%06x sbp=%p cmd=%02x "
5228f23e9faSHans Rosenfeld 				    "dl=%d,%d rx=%d rsp=%d",
5238f23e9faSHans Rosenfeld 				    did, sbp, scsi_opcode,
5248f23e9faSHans Rosenfeld 				    pkt->pkt_datalen, scsi_dl,
5258f23e9faSHans Rosenfeld 				    (pkt->pkt_datalen -
5268f23e9faSHans Rosenfeld 				    pkt->pkt_data_resid),
5278f23e9faSHans Rosenfeld 				    rsp_data_resid);
528fcf3ce44SJohn Forte 
529fcf3ce44SJohn Forte 			}
5308f23e9faSHans Rosenfeld }
5318f23e9faSHans Rosenfeld #endif /* FCP_UNDERRUN_PATCH1 */
532291a2b48SSukumar Swaminathan 
533fcf3ce44SJohn Forte 			/*
5348f23e9faSHans Rosenfeld 			 * Check if SCSI response payload should be
5358f23e9faSHans Rosenfeld 			 * fixed or if a DATA_UNDERRUN should be
5368f23e9faSHans Rosenfeld 			 * reported
537fcf3ce44SJohn Forte 			 */
5388f23e9faSHans Rosenfeld 			if (fix_it) {
5398f23e9faSHans Rosenfeld 				/*
5408f23e9faSHans Rosenfeld 				 * Fix the SCSI response payload itself
5418f23e9faSHans Rosenfeld 				 */
5428f23e9faSHans Rosenfeld 				rsp->fcp_u.fcp_status.resid_under = 1;
5438f23e9faSHans Rosenfeld 				rsp->fcp_resid =
5448f23e9faSHans Rosenfeld 				    LE_SWAP32(pkt->pkt_data_resid);
5458f23e9faSHans Rosenfeld 			} else {
546fcf3ce44SJohn Forte 				/*
547fcf3ce44SJohn Forte 				 * Change the status from
548fcf3ce44SJohn Forte 				 * IOSTAT_FCP_RSP_ERROR to
5498f23e9faSHans Rosenfeld 				 * IOSTAT_DATA_UNDERRUN
550fcf3ce44SJohn Forte 				 */
5518f23e9faSHans Rosenfeld 				iostat = IOSTAT_DATA_UNDERRUN;
5528f23e9faSHans Rosenfeld 				pkt->pkt_data_resid =
5538f23e9faSHans Rosenfeld 				    pkt->pkt_datalen;
554fcf3ce44SJohn Forte 			}
5558f23e9faSHans Rosenfeld 		}
556291a2b48SSukumar Swaminathan 
5578f23e9faSHans Rosenfeld 		/*
5588f23e9faSHans Rosenfeld 		 * If the residual being reported by the adapter is
5598f23e9faSHans Rosenfeld 		 * less than the residual being reported in the reply,
5608f23e9faSHans Rosenfeld 		 * then we have a true overrun. Since we don't know
5618f23e9faSHans Rosenfeld 		 * where the extra data came from or went to then we
5628f23e9faSHans Rosenfeld 		 * cannot trust anything we received
5638f23e9faSHans Rosenfeld 		 */
5648f23e9faSHans Rosenfeld 		else if (rsp_data_resid > pkt->pkt_data_resid) {
5658f23e9faSHans Rosenfeld 			/*
5668f23e9faSHans Rosenfeld 			 * Change the status from
5678f23e9faSHans Rosenfeld 			 * IOSTAT_FCP_RSP_ERROR to
5688f23e9faSHans Rosenfeld 			 * IOSTAT_DATA_OVERRUN
5698f23e9faSHans Rosenfeld 			 */
5708f23e9faSHans Rosenfeld 			iostat = IOSTAT_DATA_OVERRUN;
5718f23e9faSHans Rosenfeld 			pkt->pkt_data_resid = pkt->pkt_datalen;
572fcf3ce44SJohn Forte 		}
573fcf3ce44SJohn Forte 	}
574291a2b48SSukumar Swaminathan 
5758f23e9faSHans Rosenfeld done:
5768f23e9faSHans Rosenfeld 
577fcf3ce44SJohn Forte 	/* Print completion message */
578fcf3ce44SJohn Forte 	switch (iostat) {
579fcf3ce44SJohn Forte 	case IOSTAT_SUCCESS:
580fcf3ce44SJohn Forte 		/* Build SCSI GOOD status */
581fcf3ce44SJohn Forte 		if (pkt->pkt_rsplen) {
582fcf3ce44SJohn Forte 			bzero((uint8_t *)pkt->pkt_resp, pkt->pkt_rsplen);
583fcf3ce44SJohn Forte 		}
584fcf3ce44SJohn Forte 		break;
585fcf3ce44SJohn Forte 
586fcf3ce44SJohn Forte 	case IOSTAT_FCP_RSP_ERROR:
587fcf3ce44SJohn Forte 		break;
588fcf3ce44SJohn Forte 
589fcf3ce44SJohn Forte 	case IOSTAT_REMOTE_STOP:
590fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
591291a2b48SSukumar Swaminathan 		    "Remote Stop. did=0x%06x sbp=%p cmd=%02x", did, sbp,
592291a2b48SSukumar Swaminathan 		    scsi_opcode);
593fcf3ce44SJohn Forte 		break;
594fcf3ce44SJohn Forte 
595fcf3ce44SJohn Forte 	case IOSTAT_LOCAL_REJECT:
596fcf3ce44SJohn Forte 		localstat = cmd->un.grsp.perr.statLocalError;
597fcf3ce44SJohn Forte 
598fcf3ce44SJohn Forte 		switch (localstat) {
599fcf3ce44SJohn Forte 		case IOERR_SEQUENCE_TIMEOUT:
600fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT,
601fcf3ce44SJohn Forte 			    &emlxs_fcp_completion_error_msg,
602291a2b48SSukumar Swaminathan 			    "Local reject. "
603291a2b48SSukumar Swaminathan 			    "%s did=0x%06x sbp=%p cmd=%02x tmo=%d ",
604fcf3ce44SJohn Forte 			    emlxs_error_xlate(localstat), did, sbp,
605fcf3ce44SJohn Forte 			    scsi_opcode, pkt->pkt_timeout);
606fcf3ce44SJohn Forte 			break;
607fcf3ce44SJohn Forte 
608fcf3ce44SJohn Forte 		default:
609fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT,
610fcf3ce44SJohn Forte 			    &emlxs_fcp_completion_error_msg,
611a9800bebSGarrett D'Amore 			    "Local reject. %s 0x%06x %p %02x (%x)(%x)",
612291a2b48SSukumar Swaminathan 			    emlxs_error_xlate(localstat), did, sbp,
613a9800bebSGarrett D'Amore 			    scsi_opcode, (uint16_t)cmd->ULPIOTAG,
614a9800bebSGarrett D'Amore 			    (uint16_t)cmd->ULPCONTEXT);
615fcf3ce44SJohn Forte 		}
616fcf3ce44SJohn Forte 
617fcf3ce44SJohn Forte 		break;
618fcf3ce44SJohn Forte 
619fcf3ce44SJohn Forte 	case IOSTAT_NPORT_RJT:
620fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
621291a2b48SSukumar Swaminathan 		    "Nport reject. did=0x%06x sbp=%p cmd=%02x", did, sbp,
622291a2b48SSukumar Swaminathan 		    scsi_opcode);
623fcf3ce44SJohn Forte 		break;
624fcf3ce44SJohn Forte 
625fcf3ce44SJohn Forte 	case IOSTAT_FABRIC_RJT:
626fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
627291a2b48SSukumar Swaminathan 		    "Fabric reject. did=0x%06x sbp=%p cmd=%02x", did, sbp,
628291a2b48SSukumar Swaminathan 		    scsi_opcode);
629fcf3ce44SJohn Forte 		break;
630fcf3ce44SJohn Forte 
631fcf3ce44SJohn Forte 	case IOSTAT_NPORT_BSY:
632291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
633291a2b48SSukumar Swaminathan 		ndlp = (NODELIST *)iocbq->node;
634291a2b48SSukumar Swaminathan 		emlxs_log_sd_fc_bsy_event(port, (HBA_WWN *)&ndlp->nlp_portname);
635291a2b48SSukumar Swaminathan #endif
636291a2b48SSukumar Swaminathan 
637fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
638291a2b48SSukumar Swaminathan 		    "Nport busy. did=0x%06x sbp=%p cmd=%02x", did, sbp,
639291a2b48SSukumar Swaminathan 		    scsi_opcode);
640fcf3ce44SJohn Forte 		break;
641fcf3ce44SJohn Forte 
642fcf3ce44SJohn Forte 	case IOSTAT_FABRIC_BSY:
643291a2b48SSukumar Swaminathan #ifdef SAN_DIAG_SUPPORT
644291a2b48SSukumar Swaminathan 		ndlp = (NODELIST *)iocbq->node;
645291a2b48SSukumar Swaminathan 		emlxs_log_sd_fc_bsy_event(port, NULL);
646291a2b48SSukumar Swaminathan #endif
647291a2b48SSukumar Swaminathan 
648fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
649291a2b48SSukumar Swaminathan 		    "Fabric busy. did=0x%06x sbp=%p cmd=%02x", did, sbp,
650291a2b48SSukumar Swaminathan 		    scsi_opcode);
651fcf3ce44SJohn Forte 		break;
652fcf3ce44SJohn Forte 
653fcf3ce44SJohn Forte 	case IOSTAT_INTERMED_RSP:
654fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
655291a2b48SSukumar Swaminathan 		    "Intermediate response. did=0x%06x sbp=%p cmd=%02x", did,
656291a2b48SSukumar Swaminathan 		    sbp, scsi_opcode);
657fcf3ce44SJohn Forte 		break;
658fcf3ce44SJohn Forte 
659fcf3ce44SJohn Forte 	case IOSTAT_LS_RJT:
660fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
661291a2b48SSukumar Swaminathan 		    "LS Reject. did=0x%06x sbp=%p cmd=%02x", did, sbp,
662291a2b48SSukumar Swaminathan 		    scsi_opcode);
663fcf3ce44SJohn Forte 		break;
664fcf3ce44SJohn Forte 
665fcf3ce44SJohn Forte 	case IOSTAT_DATA_UNDERRUN:
666fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
667291a2b48SSukumar Swaminathan 		    "Underrun. did=0x%06x sbp=%p cmd=%02x "
668291a2b48SSukumar Swaminathan 		    "dl=%d,%d rx=%d rsp=%d (%02x,%02x,%02x,%02x)",
669291a2b48SSukumar Swaminathan 		    did, sbp, scsi_opcode, pkt->pkt_datalen, scsi_dl, data_rx,
670291a2b48SSukumar Swaminathan 		    rsp_data_resid, scsi_status, sense, asc, ascq);
671fcf3ce44SJohn Forte 		break;
672fcf3ce44SJohn Forte 
673fcf3ce44SJohn Forte 	case IOSTAT_DATA_OVERRUN:
674fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
675291a2b48SSukumar Swaminathan 		    "Overrun. did=0x%06x sbp=%p cmd=%02x "
676291a2b48SSukumar Swaminathan 		    "dl=%d,%d rx=%d rsp=%d (%02x,%02x,%02x,%02x)",
677291a2b48SSukumar Swaminathan 		    did, sbp, scsi_opcode, pkt->pkt_datalen, scsi_dl, data_rx,
678291a2b48SSukumar Swaminathan 		    rsp_data_resid, scsi_status, sense, asc, ascq);
679fcf3ce44SJohn Forte 		break;
680fcf3ce44SJohn Forte 
6818f23e9faSHans Rosenfeld 	case IOSTAT_RSP_INVALID:
6828f23e9faSHans Rosenfeld 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
6838f23e9faSHans Rosenfeld 		    "Rsp Invalid. did=0x%06x sbp=%p cmd=%02x dl=%d rl=%d"
6848f23e9faSHans Rosenfeld 		    "(%d, %d, %d)",
6858f23e9faSHans Rosenfeld 		    did, sbp, scsi_opcode, pkt->pkt_datalen, pkt->pkt_rsplen,
6868f23e9faSHans Rosenfeld 		    LE_SWAP32(rsp->fcp_resid),
6878f23e9faSHans Rosenfeld 		    LE_SWAP32(rsp->fcp_sense_len),
6888f23e9faSHans Rosenfeld 		    LE_SWAP32(rsp->fcp_response_len));
6898f23e9faSHans Rosenfeld 		break;
6908f23e9faSHans Rosenfeld 
691fcf3ce44SJohn Forte 	default:
692fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg,
693fcf3ce44SJohn Forte 		    "Unknown status=%x reason=%x did=0x%06x sbp=%p cmd=%02x",
694291a2b48SSukumar Swaminathan 		    iostat, cmd->un.grsp.perr.statLocalError, did, sbp,
695291a2b48SSukumar Swaminathan 		    scsi_opcode);
696fcf3ce44SJohn Forte 		break;
697fcf3ce44SJohn Forte 	}
698fcf3ce44SJohn Forte 
699fcf3ce44SJohn Forte 	if (iostat == IOSTAT_SUCCESS) {
700fcf3ce44SJohn Forte 		HBASTATS.FcpGood++;
701fcf3ce44SJohn Forte 	} else {
702fcf3ce44SJohn Forte 		HBASTATS.FcpError++;
703fcf3ce44SJohn Forte 	}
704fcf3ce44SJohn Forte 
705fcf3ce44SJohn Forte 	mutex_exit(&sbp->mtx);
706fcf3ce44SJohn Forte 
707fcf3ce44SJohn Forte 	emlxs_pkt_complete(sbp, iostat, localstat, 0);
708fcf3ce44SJohn Forte 
709fcf3ce44SJohn Forte 	return;
710fcf3ce44SJohn Forte 
71182527734SSukumar Swaminathan } /* emlxs_handle_fcp_event() */
712fcf3ce44SJohn Forte 
713fcf3ce44SJohn Forte 
714fcf3ce44SJohn Forte /*
715fcf3ce44SJohn Forte  *  emlxs_post_buffer
716fcf3ce44SJohn Forte  *
717fcf3ce44SJohn Forte  *  This routine will post count buffers to the
718fcf3ce44SJohn Forte  *  ring with the QUE_RING_BUF_CN command. This
719fcf3ce44SJohn Forte  *  allows 2 buffers / command to be posted.
720fcf3ce44SJohn Forte  *  Returns the number of buffers NOT posted.
721fcf3ce44SJohn Forte  */
72282527734SSukumar Swaminathan /* SLI3 */
723fcf3ce44SJohn Forte extern int
724fcf3ce44SJohn Forte emlxs_post_buffer(emlxs_hba_t *hba, RING *rp, int16_t cnt)
725fcf3ce44SJohn Forte {
726fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
727fcf3ce44SJohn Forte 	IOCB *icmd;
728fcf3ce44SJohn Forte 	IOCBQ *iocbq;
729fcf3ce44SJohn Forte 	MATCHMAP *mp;
730fcf3ce44SJohn Forte 	uint16_t tag;
731fcf3ce44SJohn Forte 	uint32_t maxqbuf;
732fcf3ce44SJohn Forte 	int32_t i;
733fcf3ce44SJohn Forte 	int32_t j;
734fcf3ce44SJohn Forte 	uint32_t seg;
735fcf3ce44SJohn Forte 	uint32_t size;
736fcf3ce44SJohn Forte 
737fcf3ce44SJohn Forte 	mp = 0;
738fcf3ce44SJohn Forte 	maxqbuf = 2;
739fcf3ce44SJohn Forte 	tag = (uint16_t)cnt;
740fcf3ce44SJohn Forte 	cnt += rp->fc_missbufcnt;
741fcf3ce44SJohn Forte 
74282527734SSukumar Swaminathan 	if (rp->ringno == hba->channel_els) {
743fcf3ce44SJohn Forte 		seg = MEM_BUF;
744fcf3ce44SJohn Forte 		size = MEM_ELSBUF_SIZE;
74582527734SSukumar Swaminathan 	} else if (rp->ringno == hba->channel_ip) {
746fcf3ce44SJohn Forte 		seg = MEM_IPBUF;
747fcf3ce44SJohn Forte 		size = MEM_IPBUF_SIZE;
74882527734SSukumar Swaminathan 	} else if (rp->ringno == hba->channel_ct) {
749fcf3ce44SJohn Forte 		seg = MEM_CTBUF;
750fcf3ce44SJohn Forte 		size = MEM_CTBUF_SIZE;
751fcf3ce44SJohn Forte 	}
752fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
75382527734SSukumar Swaminathan 	else if (rp->ringno == hba->CHANNEL_FCT) {
754fcf3ce44SJohn Forte 		seg = MEM_FCTBUF;
755fcf3ce44SJohn Forte 		size = MEM_FCTBUF_SIZE;
756fcf3ce44SJohn Forte 	}
757291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
758fcf3ce44SJohn Forte 	else {
759fcf3ce44SJohn Forte 		return (0);
760fcf3ce44SJohn Forte 	}
761fcf3ce44SJohn Forte 
762fcf3ce44SJohn Forte 	/*
763fcf3ce44SJohn Forte 	 * While there are buffers to post
764fcf3ce44SJohn Forte 	 */
765fcf3ce44SJohn Forte 	while (cnt) {
7668f23e9faSHans Rosenfeld 		if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == 0) {
767fcf3ce44SJohn Forte 			rp->fc_missbufcnt = cnt;
768fcf3ce44SJohn Forte 			return (cnt);
769fcf3ce44SJohn Forte 		}
770291a2b48SSukumar Swaminathan 
77182527734SSukumar Swaminathan 		iocbq->channel = (void *)&hba->chan[rp->ringno];
772fcf3ce44SJohn Forte 		iocbq->port = (void *)port;
773fcf3ce44SJohn Forte 		iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
774fcf3ce44SJohn Forte 
775fcf3ce44SJohn Forte 		icmd = &iocbq->iocb;
776fcf3ce44SJohn Forte 
777fcf3ce44SJohn Forte 		/*
778fcf3ce44SJohn Forte 		 * Max buffers can be posted per command
779fcf3ce44SJohn Forte 		 */
780fcf3ce44SJohn Forte 		for (i = 0; i < maxqbuf; i++) {
781fcf3ce44SJohn Forte 			if (cnt <= 0)
782fcf3ce44SJohn Forte 				break;
783fcf3ce44SJohn Forte 
784fcf3ce44SJohn Forte 			/* fill in BDEs for command */
7858f23e9faSHans Rosenfeld 			if ((mp = (MATCHMAP *)emlxs_mem_get(hba, seg))
78682527734SSukumar Swaminathan 			    == 0) {
78782527734SSukumar Swaminathan 				icmd->ULPBDECOUNT = i;
788fcf3ce44SJohn Forte 				for (j = 0; j < i; j++) {
789291a2b48SSukumar Swaminathan 					mp = EMLXS_GET_VADDR(hba, rp, icmd);
790fcf3ce44SJohn Forte 					if (mp) {
791a9800bebSGarrett D'Amore 						emlxs_mem_put(hba, seg,
792a9800bebSGarrett D'Amore 						    (void *)mp);
793fcf3ce44SJohn Forte 					}
794fcf3ce44SJohn Forte 				}
795fcf3ce44SJohn Forte 
796fcf3ce44SJohn Forte 				rp->fc_missbufcnt = cnt + i;
797fcf3ce44SJohn Forte 
798a9800bebSGarrett D'Amore 				emlxs_mem_put(hba, MEM_IOCB, (void *)iocbq);
799fcf3ce44SJohn Forte 
800fcf3ce44SJohn Forte 				return (cnt + i);
801fcf3ce44SJohn Forte 			}
802291a2b48SSukumar Swaminathan 
803fcf3ce44SJohn Forte 			/*
804fcf3ce44SJohn Forte 			 * map that page and save the address pair for lookup
805fcf3ce44SJohn Forte 			 * later
806fcf3ce44SJohn Forte 			 */
807291a2b48SSukumar Swaminathan 			emlxs_mem_map_vaddr(hba,
808291a2b48SSukumar Swaminathan 			    rp,
809291a2b48SSukumar Swaminathan 			    mp,
810fcf3ce44SJohn Forte 			    (uint32_t *)&icmd->un.cont64[i].addrHigh,
811fcf3ce44SJohn Forte 			    (uint32_t *)&icmd->un.cont64[i].addrLow);
812fcf3ce44SJohn Forte 
813fcf3ce44SJohn Forte 			icmd->un.cont64[i].tus.f.bdeSize = size;
81482527734SSukumar Swaminathan 			icmd->ULPCOMMAND = CMD_QUE_RING_BUF64_CN;
815fcf3ce44SJohn Forte 
816291a2b48SSukumar Swaminathan 			/*
817291a2b48SSukumar Swaminathan 			 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
818291a2b48SSukumar Swaminathan 			 *    "UB Post: ring=%d addr=%08x%08x size=%d",
819291a2b48SSukumar Swaminathan 			 *    rp->ringno, icmd->un.cont64[i].addrHigh,
820291a2b48SSukumar Swaminathan 			 *    icmd->un.cont64[i].addrLow, size);
821291a2b48SSukumar Swaminathan 			 */
822fcf3ce44SJohn Forte 
823fcf3ce44SJohn Forte 			cnt--;
824fcf3ce44SJohn Forte 		}
825fcf3ce44SJohn Forte 
82682527734SSukumar Swaminathan 		icmd->ULPIOTAG = tag;
82782527734SSukumar Swaminathan 		icmd->ULPBDECOUNT = i;
82882527734SSukumar Swaminathan 		icmd->ULPLE = 1;
82982527734SSukumar Swaminathan 		icmd->ULPOWNER = OWN_CHIP;
830291a2b48SSukumar Swaminathan 		/* used for delimiter between commands */
831a9800bebSGarrett D'Amore 		iocbq->bp = (void *)mp;
832fcf3ce44SJohn Forte 
83382527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[rp->ringno], iocbq);
834fcf3ce44SJohn Forte 	}
835fcf3ce44SJohn Forte 
836fcf3ce44SJohn Forte 	rp->fc_missbufcnt = 0;
837fcf3ce44SJohn Forte 
838fcf3ce44SJohn Forte 	return (0);
839fcf3ce44SJohn Forte 
84082527734SSukumar Swaminathan } /* emlxs_post_buffer() */
841fcf3ce44SJohn Forte 
842fcf3ce44SJohn Forte 
8438f23e9faSHans Rosenfeld static void
8448f23e9faSHans Rosenfeld emlxs_fcp_tag_nodes(emlxs_port_t *port)
8458f23e9faSHans Rosenfeld {
8468f23e9faSHans Rosenfeld 	NODELIST *nlp;
8478f23e9faSHans Rosenfeld 	int i;
8488f23e9faSHans Rosenfeld 
8498f23e9faSHans Rosenfeld 	/* We will process all nodes with this tag later */
8508f23e9faSHans Rosenfeld 	rw_enter(&port->node_rwlock, RW_READER);
8518f23e9faSHans Rosenfeld 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
8528f23e9faSHans Rosenfeld 		nlp = port->node_table[i];
8538f23e9faSHans Rosenfeld 		while (nlp != NULL) {
8548f23e9faSHans Rosenfeld 			nlp->nlp_tag = 1;
8558f23e9faSHans Rosenfeld 			nlp = nlp->nlp_list_next;
8568f23e9faSHans Rosenfeld 		}
8578f23e9faSHans Rosenfeld 	}
8588f23e9faSHans Rosenfeld 	rw_exit(&port->node_rwlock);
8598f23e9faSHans Rosenfeld }
8608f23e9faSHans Rosenfeld 
8618f23e9faSHans Rosenfeld 
8628f23e9faSHans Rosenfeld static NODELIST *
8638f23e9faSHans Rosenfeld emlxs_find_tagged_node(emlxs_port_t *port)
8648f23e9faSHans Rosenfeld {
8658f23e9faSHans Rosenfeld 	NODELIST *nlp;
8668f23e9faSHans Rosenfeld 	NODELIST *tagged;
8678f23e9faSHans Rosenfeld 	int i;
8688f23e9faSHans Rosenfeld 
8698f23e9faSHans Rosenfeld 	/* Find first node */
8708f23e9faSHans Rosenfeld 	rw_enter(&port->node_rwlock, RW_READER);
8718f23e9faSHans Rosenfeld 	tagged = 0;
8728f23e9faSHans Rosenfeld 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
8738f23e9faSHans Rosenfeld 		nlp = port->node_table[i];
8748f23e9faSHans Rosenfeld 		while (nlp != NULL) {
8758f23e9faSHans Rosenfeld 			if (!nlp->nlp_tag) {
8768f23e9faSHans Rosenfeld 				nlp = nlp->nlp_list_next;
8778f23e9faSHans Rosenfeld 				continue;
8788f23e9faSHans Rosenfeld 			}
8798f23e9faSHans Rosenfeld 			nlp->nlp_tag = 0;
8808f23e9faSHans Rosenfeld 
8818f23e9faSHans Rosenfeld 			if (nlp->nlp_Rpi == FABRIC_RPI) {
8828f23e9faSHans Rosenfeld 				nlp = nlp->nlp_list_next;
8838f23e9faSHans Rosenfeld 				continue;
8848f23e9faSHans Rosenfeld 			}
8858f23e9faSHans Rosenfeld 			tagged = nlp;
8868f23e9faSHans Rosenfeld 			break;
8878f23e9faSHans Rosenfeld 		}
8888f23e9faSHans Rosenfeld 		if (tagged) {
8898f23e9faSHans Rosenfeld 			break;
8908f23e9faSHans Rosenfeld 		}
8918f23e9faSHans Rosenfeld 	}
8928f23e9faSHans Rosenfeld 	rw_exit(&port->node_rwlock);
8938f23e9faSHans Rosenfeld 	return (tagged);
8948f23e9faSHans Rosenfeld }
8958f23e9faSHans Rosenfeld 
8968f23e9faSHans Rosenfeld 
897fcf3ce44SJohn Forte extern int
898fcf3ce44SJohn Forte emlxs_port_offline(emlxs_port_t *port, uint32_t scope)
899fcf3ce44SJohn Forte {
900fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
901fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
902fcf3ce44SJohn Forte 	NODELIST *nlp;
903fcf3ce44SJohn Forte 	fc_affected_id_t *aid;
904fcf3ce44SJohn Forte 	uint32_t mask;
905fcf3ce44SJohn Forte 	uint32_t aff_d_id;
906fcf3ce44SJohn Forte 	uint32_t linkdown;
907fcf3ce44SJohn Forte 	uint32_t vlinkdown;
908fcf3ce44SJohn Forte 	uint32_t action;
909fcf3ce44SJohn Forte 	int i;
910fcf3ce44SJohn Forte 	uint32_t unreg_vpi;
911fcf3ce44SJohn Forte 	uint32_t update;
912fcf3ce44SJohn Forte 	uint32_t adisc_support;
913a9800bebSGarrett D'Amore 	uint32_t clear_all;
9143be114edSSukumar Swaminathan 	uint8_t format;
915fcf3ce44SJohn Forte 
916fcf3ce44SJohn Forte 	/* Target mode only uses this routine for linkdowns */
9178f23e9faSHans Rosenfeld 	if ((port->mode == MODE_TARGET) && (scope != 0xffffffff) &&
9188f23e9faSHans Rosenfeld 	    (scope != 0xfeffffff) && (scope != 0xfdffffff)) {
919fcf3ce44SJohn Forte 		return (0);
920fcf3ce44SJohn Forte 	}
921291a2b48SSukumar Swaminathan 
922fcf3ce44SJohn Forte 	cfg = &CFG;
923fcf3ce44SJohn Forte 	aid = (fc_affected_id_t *)&scope;
924fcf3ce44SJohn Forte 	linkdown = 0;
925fcf3ce44SJohn Forte 	vlinkdown = 0;
926fcf3ce44SJohn Forte 	unreg_vpi = 0;
927fcf3ce44SJohn Forte 	update = 0;
928a9800bebSGarrett D'Amore 	clear_all = 0;
929fcf3ce44SJohn Forte 
930fcf3ce44SJohn Forte 	if (!(port->flag & EMLXS_PORT_BOUND)) {
931fcf3ce44SJohn Forte 		return (0);
932fcf3ce44SJohn Forte 	}
933291a2b48SSukumar Swaminathan 
9343be114edSSukumar Swaminathan 	format = aid->aff_format;
9353be114edSSukumar Swaminathan 
9363be114edSSukumar Swaminathan 	switch (format) {
937fcf3ce44SJohn Forte 	case 0:	/* Port */
938fcf3ce44SJohn Forte 		mask = 0x00ffffff;
939fcf3ce44SJohn Forte 		break;
940fcf3ce44SJohn Forte 
941fcf3ce44SJohn Forte 	case 1:	/* Area */
942fcf3ce44SJohn Forte 		mask = 0x00ffff00;
943fcf3ce44SJohn Forte 		break;
944fcf3ce44SJohn Forte 
945fcf3ce44SJohn Forte 	case 2:	/* Domain */
946fcf3ce44SJohn Forte 		mask = 0x00ff0000;
947fcf3ce44SJohn Forte 		break;
948fcf3ce44SJohn Forte 
949fcf3ce44SJohn Forte 	case 3:	/* Network */
950fcf3ce44SJohn Forte 		mask = 0x00000000;
951fcf3ce44SJohn Forte 		break;
952fcf3ce44SJohn Forte 
953fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
954fcf3ce44SJohn Forte 	case 0xfe:	/* Virtual link down */
955fcf3ce44SJohn Forte 		mask = 0x00000000;
956fcf3ce44SJohn Forte 		vlinkdown = 1;
957fcf3ce44SJohn Forte 		break;
958291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
959fcf3ce44SJohn Forte 
960fcf3ce44SJohn Forte 	case 0xff:	/* link is down */
961fcf3ce44SJohn Forte 		mask = 0x00000000;
962fcf3ce44SJohn Forte 		linkdown = 1;
963fcf3ce44SJohn Forte 		break;
964fcf3ce44SJohn Forte 
9658f23e9faSHans Rosenfeld 	case 0xfd:	/* New fabric */
9668f23e9faSHans Rosenfeld 	default:
9678f23e9faSHans Rosenfeld 		mask = 0x00000000;
9688f23e9faSHans Rosenfeld 		linkdown = 1;
9698f23e9faSHans Rosenfeld 		clear_all = 1;
9708f23e9faSHans Rosenfeld 		break;
971fcf3ce44SJohn Forte 	}
972fcf3ce44SJohn Forte 
973fcf3ce44SJohn Forte 	aff_d_id = aid->aff_d_id & mask;
974fcf3ce44SJohn Forte 
975fcf3ce44SJohn Forte 
976fcf3ce44SJohn Forte 	/*
977291a2b48SSukumar Swaminathan 	 * If link is down then this is a hard shutdown and flush
978291a2b48SSukumar Swaminathan 	 * If link not down then this is a soft shutdown and flush
979291a2b48SSukumar Swaminathan 	 * (e.g. RSCN)
980fcf3ce44SJohn Forte 	 */
981fcf3ce44SJohn Forte 	if (linkdown) {
982fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
983fcf3ce44SJohn Forte 
984fcf3ce44SJohn Forte 		port->flag &= EMLXS_PORT_LINKDOWN_MASK;
985fcf3ce44SJohn Forte 
986fcf3ce44SJohn Forte 		if (port->ulp_statec != FC_STATE_OFFLINE) {
987fcf3ce44SJohn Forte 			port->ulp_statec = FC_STATE_OFFLINE;
9888f23e9faSHans Rosenfeld 
989a9800bebSGarrett D'Amore 			port->prev_did = port->did;
9908f23e9faSHans Rosenfeld 			port->did = 0;
9918f23e9faSHans Rosenfeld 			port->rdid = 0;
9928f23e9faSHans Rosenfeld 
993a9800bebSGarrett D'Amore 			bcopy(&port->fabric_sparam, &port->prev_fabric_sparam,
994a9800bebSGarrett D'Amore 			    sizeof (SERV_PARM));
9958f23e9faSHans Rosenfeld 			bzero(&port->fabric_sparam, sizeof (SERV_PARM));
9968f23e9faSHans Rosenfeld 
997fcf3ce44SJohn Forte 			update = 1;
998fcf3ce44SJohn Forte 		}
999291a2b48SSukumar Swaminathan 
1000fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1001fcf3ce44SJohn Forte 
10028f23e9faSHans Rosenfeld 		emlxs_timer_cancel_clean_address(port);
10038f23e9faSHans Rosenfeld 
1004fcf3ce44SJohn Forte 		/* Tell ULP about it */
1005fcf3ce44SJohn Forte 		if (update) {
1006fcf3ce44SJohn Forte 			if (port->flag & EMLXS_PORT_BOUND) {
1007fcf3ce44SJohn Forte 				if (port->vpi == 0) {
1008fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1009291a2b48SSukumar Swaminathan 					    &emlxs_link_down_msg, NULL);
1010fcf3ce44SJohn Forte 				}
1011291a2b48SSukumar Swaminathan 
10128f23e9faSHans Rosenfeld 				if (port->mode == MODE_INITIATOR) {
10138f23e9faSHans Rosenfeld 					emlxs_fca_link_down(port);
10143be114edSSukumar Swaminathan 				}
1015291a2b48SSukumar Swaminathan #ifdef SFCT_SUPPORT
10168f23e9faSHans Rosenfeld 				else if (port->mode == MODE_TARGET) {
1017fcf3ce44SJohn Forte 					emlxs_fct_link_down(port);
10183be114edSSukumar Swaminathan 				}
1019291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
1020fcf3ce44SJohn Forte 
1021fcf3ce44SJohn Forte 			} else {
1022fcf3ce44SJohn Forte 				if (port->vpi == 0) {
1023fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1024291a2b48SSukumar Swaminathan 					    &emlxs_link_down_msg, "*");
1025fcf3ce44SJohn Forte 				}
1026fcf3ce44SJohn Forte 			}
1027fcf3ce44SJohn Forte 
1028fcf3ce44SJohn Forte 
1029fcf3ce44SJohn Forte 		}
1030291a2b48SSukumar Swaminathan 
1031fcf3ce44SJohn Forte 		unreg_vpi = 1;
1032fcf3ce44SJohn Forte 
1033fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1034fcf3ce44SJohn Forte 		/* Stop authentication with all nodes */
1035fcf3ce44SJohn Forte 		emlxs_dhc_auth_stop(port, NULL);
1036291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1037fcf3ce44SJohn Forte 
1038fcf3ce44SJohn Forte 		/* Flush the base node */
1039fcf3ce44SJohn Forte 		(void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0);
1040fcf3ce44SJohn Forte 		(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);
1041fcf3ce44SJohn Forte 
1042fcf3ce44SJohn Forte 		/* Flush any pending ub buffers */
1043fcf3ce44SJohn Forte 		emlxs_ub_flush(port);
1044fcf3ce44SJohn Forte 	}
1045fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1046fcf3ce44SJohn Forte 	/* virtual link down */
1047fcf3ce44SJohn Forte 	else if (vlinkdown) {
1048fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1049fcf3ce44SJohn Forte 
1050fcf3ce44SJohn Forte 		if (port->ulp_statec != FC_STATE_OFFLINE) {
1051fcf3ce44SJohn Forte 			port->ulp_statec = FC_STATE_OFFLINE;
1052fcf3ce44SJohn Forte 			update = 1;
1053fcf3ce44SJohn Forte 		}
1054291a2b48SSukumar Swaminathan 
1055fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1056fcf3ce44SJohn Forte 
10578f23e9faSHans Rosenfeld 		emlxs_timer_cancel_clean_address(port);
10588f23e9faSHans Rosenfeld 
1059fcf3ce44SJohn Forte 		/* Tell ULP about it */
1060fcf3ce44SJohn Forte 		if (update) {
1061fcf3ce44SJohn Forte 			if (port->flag & EMLXS_PORT_BOUND) {
1062fcf3ce44SJohn Forte 				if (port->vpi == 0) {
1063fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1064fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
1065fcf3ce44SJohn Forte 					    "Switch authentication failed.");
1066fcf3ce44SJohn Forte 				}
1067291a2b48SSukumar Swaminathan 
10688f23e9faSHans Rosenfeld 				if (port->mode == MODE_INITIATOR) {
10698f23e9faSHans Rosenfeld 					emlxs_fca_link_down(port);
10708f23e9faSHans Rosenfeld 				}
1071fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
10728f23e9faSHans Rosenfeld 				else if (port->mode == MODE_TARGET) {
1073fcf3ce44SJohn Forte 					emlxs_fct_link_down(port);
1074fcf3ce44SJohn Forte 				}
10758f23e9faSHans Rosenfeld #endif /* SFCT_SUPPORT */
1076fcf3ce44SJohn Forte 			} else {
1077fcf3ce44SJohn Forte 				if (port->vpi == 0) {
1078fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1079fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
1080fcf3ce44SJohn Forte 					    "Switch authentication failed. *");
1081fcf3ce44SJohn Forte 				}
1082fcf3ce44SJohn Forte 			}
1083fcf3ce44SJohn Forte 
1084fcf3ce44SJohn Forte 
1085fcf3ce44SJohn Forte 		}
1086291a2b48SSukumar Swaminathan 
1087fcf3ce44SJohn Forte 		/* Flush the base node */
1088fcf3ce44SJohn Forte 		(void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0);
1089fcf3ce44SJohn Forte 		(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);
1090fcf3ce44SJohn Forte 	}
1091291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
10928f23e9faSHans Rosenfeld 	else {
10938f23e9faSHans Rosenfeld 		emlxs_timer_cancel_clean_address(port);
10948f23e9faSHans Rosenfeld 	}
1095fcf3ce44SJohn Forte 
10968f23e9faSHans Rosenfeld 	if (port->mode == MODE_TARGET) {
10978f23e9faSHans Rosenfeld 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
10988f23e9faSHans Rosenfeld 			/* Set the node tags */
10998f23e9faSHans Rosenfeld 			emlxs_fcp_tag_nodes(port);
11008f23e9faSHans Rosenfeld 			unreg_vpi = 0;
11018f23e9faSHans Rosenfeld 			while ((nlp = emlxs_find_tagged_node(port))) {
11028f23e9faSHans Rosenfeld 				(void) emlxs_rpi_pause_notify(port,
11038f23e9faSHans Rosenfeld 				    nlp->rpip);
11048f23e9faSHans Rosenfeld 				/*
11058f23e9faSHans Rosenfeld 				 * In port_online we need to resume
11068f23e9faSHans Rosenfeld 				 * these RPIs before we can use them.
11078f23e9faSHans Rosenfeld 				 */
11088f23e9faSHans Rosenfeld 			}
11098f23e9faSHans Rosenfeld 		}
1110fcf3ce44SJohn Forte 		goto done;
1111fcf3ce44SJohn Forte 	}
1112291a2b48SSukumar Swaminathan 
1113fcf3ce44SJohn Forte 	/* Set the node tags */
11148f23e9faSHans Rosenfeld 	emlxs_fcp_tag_nodes(port);
1115fcf3ce44SJohn Forte 
1116a9800bebSGarrett D'Amore 	if (!clear_all && (hba->flag & FC_ONLINE_MODE)) {
1117fcf3ce44SJohn Forte 		adisc_support = cfg[CFG_ADISC_SUPPORT].current;
1118fcf3ce44SJohn Forte 	} else {
1119fcf3ce44SJohn Forte 		adisc_support = 0;
1120fcf3ce44SJohn Forte 	}
1121fcf3ce44SJohn Forte 
1122fcf3ce44SJohn Forte 	/* Check ADISC support level */
1123fcf3ce44SJohn Forte 	switch (adisc_support) {
1124fcf3ce44SJohn Forte 	case 0:	/* No support - Flush all IO to all matching nodes */
1125fcf3ce44SJohn Forte 
1126291a2b48SSukumar Swaminathan 		for (;;) {
1127fcf3ce44SJohn Forte 			/*
1128fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
11298f23e9faSHans Rosenfeld 			 * EMLXS_SLI_UNREG_NODE and the flush routines enter the
1130291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
1131291a2b48SSukumar Swaminathan 			 * can change out from under us.
1132fcf3ce44SJohn Forte 			 */
1133fcf3ce44SJohn Forte 
1134fcf3ce44SJohn Forte 			/* Find first node */
1135fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1136fcf3ce44SJohn Forte 			action = 0;
1137fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1138fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1139fcf3ce44SJohn Forte 				while (nlp != NULL) {
1140fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1141fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1142fcf3ce44SJohn Forte 						continue;
1143fcf3ce44SJohn Forte 					}
1144fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1145fcf3ce44SJohn Forte 
1146fcf3ce44SJohn Forte 					/*
1147fcf3ce44SJohn Forte 					 * Check for any device that matches
1148fcf3ce44SJohn Forte 					 * our mask
1149fcf3ce44SJohn Forte 					 */
1150fcf3ce44SJohn Forte 					if ((nlp->nlp_DID & mask) == aff_d_id) {
1151fcf3ce44SJohn Forte 						if (linkdown) {
1152fcf3ce44SJohn Forte 							action = 1;
1153fcf3ce44SJohn Forte 							break;
1154291a2b48SSukumar Swaminathan 						} else { /* Must be an RCSN */
1155291a2b48SSukumar Swaminathan 
1156fcf3ce44SJohn Forte 							action = 2;
1157fcf3ce44SJohn Forte 							break;
1158fcf3ce44SJohn Forte 						}
1159fcf3ce44SJohn Forte 					}
1160fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1161fcf3ce44SJohn Forte 				}
1162fcf3ce44SJohn Forte 
1163fcf3ce44SJohn Forte 				if (action) {
1164fcf3ce44SJohn Forte 					break;
1165fcf3ce44SJohn Forte 				}
1166fcf3ce44SJohn Forte 			}
1167fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1168fcf3ce44SJohn Forte 
1169fcf3ce44SJohn Forte 
1170fcf3ce44SJohn Forte 			/* Check if nothing was found */
1171fcf3ce44SJohn Forte 			if (action == 0) {
1172fcf3ce44SJohn Forte 				break;
1173fcf3ce44SJohn Forte 			} else if (action == 1) {
11748f23e9faSHans Rosenfeld 				(void) EMLXS_SLI_UNREG_NODE(port, nlp,
1175fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1176fcf3ce44SJohn Forte 			} else if (action == 2) {
11778f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
11788f23e9faSHans Rosenfeld 
1179fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1180fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1181291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1182fcf3ce44SJohn Forte 
1183291a2b48SSukumar Swaminathan 				/*
1184291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1185291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
1186291a2b48SSukumar Swaminathan 				 */
118782527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
118882527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
118982527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
119082527734SSukumar Swaminathan 				    hba->channel_ip, 60);
1191fcf3ce44SJohn Forte 
1192fcf3ce44SJohn Forte 				/* Flush tx queue */
1193fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1194fcf3ce44SJohn Forte 
1195fcf3ce44SJohn Forte 				/* Flush chip queue */
1196fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1197fcf3ce44SJohn Forte 			}
1198291a2b48SSukumar Swaminathan 
1199fcf3ce44SJohn Forte 		}
1200fcf3ce44SJohn Forte 
1201fcf3ce44SJohn Forte 		break;
1202fcf3ce44SJohn Forte 
1203291a2b48SSukumar Swaminathan 	case 1:	/* Partial support - Flush IO for non-FCP2 matching nodes */
1204fcf3ce44SJohn Forte 
1205fcf3ce44SJohn Forte 		for (;;) {
1206fcf3ce44SJohn Forte 
1207fcf3ce44SJohn Forte 			/*
1208fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
12098f23e9faSHans Rosenfeld 			 * EMLXS_SLI_UNREG_NODE and the flush routines enter the
1210291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
1211291a2b48SSukumar Swaminathan 			 * can change out from under us.
1212fcf3ce44SJohn Forte 			 */
1213fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1214fcf3ce44SJohn Forte 			action = 0;
1215fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1216fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1217fcf3ce44SJohn Forte 				while (nlp != NULL) {
1218fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1219fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1220fcf3ce44SJohn Forte 						continue;
1221fcf3ce44SJohn Forte 					}
1222fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1223fcf3ce44SJohn Forte 
1224fcf3ce44SJohn Forte 					/*
1225291a2b48SSukumar Swaminathan 					 * Check for special FCP2 target device
1226291a2b48SSukumar Swaminathan 					 * that matches our mask
1227fcf3ce44SJohn Forte 					 */
1228fcf3ce44SJohn Forte 					if ((nlp->nlp_fcp_info &
1229fcf3ce44SJohn Forte 					    NLP_FCP_TGT_DEVICE) &&
1230291a2b48SSukumar Swaminathan 					    (nlp-> nlp_fcp_info &
1231fcf3ce44SJohn Forte 					    NLP_FCP_2_DEVICE) &&
1232291a2b48SSukumar Swaminathan 					    (nlp->nlp_DID & mask) ==
1233291a2b48SSukumar Swaminathan 					    aff_d_id) {
1234fcf3ce44SJohn Forte 						action = 3;
1235fcf3ce44SJohn Forte 						break;
1236fcf3ce44SJohn Forte 					}
1237291a2b48SSukumar Swaminathan 
1238fcf3ce44SJohn Forte 					/*
1239fcf3ce44SJohn Forte 					 * Check for any other device that
1240fcf3ce44SJohn Forte 					 * matches our mask
1241fcf3ce44SJohn Forte 					 */
1242fcf3ce44SJohn Forte 					else if ((nlp->nlp_DID & mask) ==
1243fcf3ce44SJohn Forte 					    aff_d_id) {
1244fcf3ce44SJohn Forte 						if (linkdown) {
1245fcf3ce44SJohn Forte 							action = 1;
1246fcf3ce44SJohn Forte 							break;
1247291a2b48SSukumar Swaminathan 						} else { /* Must be an RSCN */
1248291a2b48SSukumar Swaminathan 
1249fcf3ce44SJohn Forte 							action = 2;
1250fcf3ce44SJohn Forte 							break;
1251fcf3ce44SJohn Forte 						}
1252fcf3ce44SJohn Forte 					}
1253291a2b48SSukumar Swaminathan 
1254fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1255fcf3ce44SJohn Forte 				}
1256fcf3ce44SJohn Forte 
1257fcf3ce44SJohn Forte 				if (action) {
1258fcf3ce44SJohn Forte 					break;
1259fcf3ce44SJohn Forte 				}
1260fcf3ce44SJohn Forte 			}
1261fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1262fcf3ce44SJohn Forte 
1263fcf3ce44SJohn Forte 			/* Check if nothing was found */
1264fcf3ce44SJohn Forte 			if (action == 0) {
1265fcf3ce44SJohn Forte 				break;
1266fcf3ce44SJohn Forte 			} else if (action == 1) {
12678f23e9faSHans Rosenfeld 				(void) EMLXS_SLI_UNREG_NODE(port, nlp,
1268fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1269fcf3ce44SJohn Forte 			} else if (action == 2) {
12708f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
12718f23e9faSHans Rosenfeld 
1272fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1273fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1274291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1275fcf3ce44SJohn Forte 
1276291a2b48SSukumar Swaminathan 				/*
1277291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1278291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
1279291a2b48SSukumar Swaminathan 				 */
128082527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
128182527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
128282527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
128382527734SSukumar Swaminathan 				    hba->channel_ip, 60);
1284fcf3ce44SJohn Forte 
1285fcf3ce44SJohn Forte 				/* Flush tx queue */
1286fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1287fcf3ce44SJohn Forte 
1288fcf3ce44SJohn Forte 				/* Flush chip queue */
1289fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1290291a2b48SSukumar Swaminathan 
1291fcf3ce44SJohn Forte 			} else if (action == 3) {	/* FCP2 devices */
12928f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
12938f23e9faSHans Rosenfeld 
1294fcf3ce44SJohn Forte 				unreg_vpi = 0;
1295fcf3ce44SJohn Forte 
1296a9800bebSGarrett D'Amore 				if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1297a9800bebSGarrett D'Amore 					(void) emlxs_rpi_pause_notify(port,
1298a9800bebSGarrett D'Amore 					    nlp->rpip);
1299a9800bebSGarrett D'Amore 				}
1300a9800bebSGarrett D'Amore 
1301fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1302fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1303291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1304fcf3ce44SJohn Forte 
1305291a2b48SSukumar Swaminathan 				/*
1306291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1307291a2b48SSukumar Swaminathan 				 * An ADISC or a PLOGI with reopen the node
1308291a2b48SSukumar Swaminathan 				 */
130982527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
131082527734SSukumar Swaminathan 				    hba->channel_fcp, -1);
131182527734SSukumar Swaminathan 				emlxs_node_close(port, nlp, hba->channel_ip,
1312fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1313fcf3ce44SJohn Forte 
1314fcf3ce44SJohn Forte 				/* Flush tx queues except for FCP ring */
1315fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
131682527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], 0, 0);
1317fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
131882527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], 0, 0);
1319fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
132082527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], 0, 0);
1321fcf3ce44SJohn Forte 
1322fcf3ce44SJohn Forte 				/* Flush chip queues except for FCP ring */
1323fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
132482527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], nlp, 0);
1325fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
132682527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], nlp, 0);
1327fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
132882527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], nlp, 0);
1329fcf3ce44SJohn Forte 			}
1330fcf3ce44SJohn Forte 		}
1331fcf3ce44SJohn Forte 		break;
1332fcf3ce44SJohn Forte 
1333fcf3ce44SJohn Forte 	case 2:	/* Full support - Hold FCP IO to FCP target matching nodes */
1334fcf3ce44SJohn Forte 
1335fcf3ce44SJohn Forte 		if (!linkdown && !vlinkdown) {
1336fcf3ce44SJohn Forte 			break;
1337fcf3ce44SJohn Forte 		}
1338291a2b48SSukumar Swaminathan 
1339fcf3ce44SJohn Forte 		for (;;) {
1340fcf3ce44SJohn Forte 			/*
1341fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
13428f23e9faSHans Rosenfeld 			 * EMLXS_SLI_UNREG_NODE and the flush routines enter the
1343291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
1344291a2b48SSukumar Swaminathan 			 * can change out from under us.
1345fcf3ce44SJohn Forte 			 */
1346fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1347fcf3ce44SJohn Forte 			action = 0;
1348fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1349fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1350fcf3ce44SJohn Forte 				while (nlp != NULL) {
1351fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1352fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1353fcf3ce44SJohn Forte 						continue;
1354fcf3ce44SJohn Forte 					}
1355fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1356fcf3ce44SJohn Forte 
1357fcf3ce44SJohn Forte 					/*
1358fcf3ce44SJohn Forte 					 * Check for FCP target device that
1359fcf3ce44SJohn Forte 					 * matches our mask
1360fcf3ce44SJohn Forte 					 */
1361291a2b48SSukumar Swaminathan 					if ((nlp-> nlp_fcp_info &
1362fcf3ce44SJohn Forte 					    NLP_FCP_TGT_DEVICE) &&
1363291a2b48SSukumar Swaminathan 					    (nlp->nlp_DID & mask) ==
1364291a2b48SSukumar Swaminathan 					    aff_d_id) {
1365fcf3ce44SJohn Forte 						action = 3;
1366fcf3ce44SJohn Forte 						break;
1367fcf3ce44SJohn Forte 					}
1368291a2b48SSukumar Swaminathan 
1369fcf3ce44SJohn Forte 					/*
1370fcf3ce44SJohn Forte 					 * Check for any other device that
1371fcf3ce44SJohn Forte 					 * matches our mask
1372fcf3ce44SJohn Forte 					 */
1373fcf3ce44SJohn Forte 					else if ((nlp->nlp_DID & mask) ==
1374fcf3ce44SJohn Forte 					    aff_d_id) {
1375fcf3ce44SJohn Forte 						if (linkdown) {
1376fcf3ce44SJohn Forte 							action = 1;
1377fcf3ce44SJohn Forte 							break;
1378fcf3ce44SJohn Forte 						} else { /* Must be an RSCN */
1379291a2b48SSukumar Swaminathan 
1380fcf3ce44SJohn Forte 							action = 2;
1381fcf3ce44SJohn Forte 							break;
1382fcf3ce44SJohn Forte 						}
1383fcf3ce44SJohn Forte 					}
1384291a2b48SSukumar Swaminathan 
1385fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1386fcf3ce44SJohn Forte 				}
1387fcf3ce44SJohn Forte 				if (action) {
1388fcf3ce44SJohn Forte 					break;
1389fcf3ce44SJohn Forte 				}
1390fcf3ce44SJohn Forte 			}
1391fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1392fcf3ce44SJohn Forte 
1393fcf3ce44SJohn Forte 			/* Check if nothing was found */
1394fcf3ce44SJohn Forte 			if (action == 0) {
1395fcf3ce44SJohn Forte 				break;
1396fcf3ce44SJohn Forte 			} else if (action == 1) {
13978f23e9faSHans Rosenfeld 				(void) EMLXS_SLI_UNREG_NODE(port, nlp,
1398fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1399fcf3ce44SJohn Forte 			} else if (action == 2) {
14008f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
14018f23e9faSHans Rosenfeld 
1402291a2b48SSukumar Swaminathan 				/*
1403291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1404291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
1405291a2b48SSukumar Swaminathan 				 */
140682527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
140782527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
140882527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
140982527734SSukumar Swaminathan 				    hba->channel_ip, 60);
1410fcf3ce44SJohn Forte 
1411fcf3ce44SJohn Forte 				/* Flush tx queue */
1412fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1413fcf3ce44SJohn Forte 
1414fcf3ce44SJohn Forte 				/* Flush chip queue */
1415fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1416fcf3ce44SJohn Forte 
1417fcf3ce44SJohn Forte 			} else if (action == 3) {	/* FCP2 devices */
14188f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
14198f23e9faSHans Rosenfeld 
1420fcf3ce44SJohn Forte 				unreg_vpi = 0;
1421fcf3ce44SJohn Forte 
1422a9800bebSGarrett D'Amore 				if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1423a9800bebSGarrett D'Amore 					(void) emlxs_rpi_pause_notify(port,
1424a9800bebSGarrett D'Amore 					    nlp->rpip);
1425a9800bebSGarrett D'Amore 				}
1426a9800bebSGarrett D'Amore 
1427291a2b48SSukumar Swaminathan 				/*
1428291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1429291a2b48SSukumar Swaminathan 				 * An ADISC or a PLOGI with reopen the node
1430291a2b48SSukumar Swaminathan 				 */
143182527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
143282527734SSukumar Swaminathan 				    hba->channel_fcp, -1);
143382527734SSukumar Swaminathan 				emlxs_node_close(port, nlp, hba->channel_ip,
1434fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1435fcf3ce44SJohn Forte 
1436fcf3ce44SJohn Forte 				/* Flush tx queues except for FCP ring */
1437fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
143882527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], 0, 0);
1439fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
144082527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], 0, 0);
1441fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
144282527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], 0, 0);
1443fcf3ce44SJohn Forte 
1444fcf3ce44SJohn Forte 				/* Flush chip queues except for FCP ring */
1445fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
144682527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], nlp, 0);
1447fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
144882527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], nlp, 0);
1449fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
145082527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], nlp, 0);
1451fcf3ce44SJohn Forte 			}
1452fcf3ce44SJohn Forte 		}
1453fcf3ce44SJohn Forte 
1454fcf3ce44SJohn Forte 		break;
1455fcf3ce44SJohn Forte 
1456fcf3ce44SJohn Forte 	}	/* switch() */
1457fcf3ce44SJohn Forte 
1458fcf3ce44SJohn Forte done:
1459fcf3ce44SJohn Forte 
1460a9800bebSGarrett D'Amore 	if (unreg_vpi) {
1461a9800bebSGarrett D'Amore 		(void) emlxs_mb_unreg_vpi(port);
1462fcf3ce44SJohn Forte 	}
1463fcf3ce44SJohn Forte 
1464291a2b48SSukumar Swaminathan 	return (0);
1465fcf3ce44SJohn Forte 
146682527734SSukumar Swaminathan } /* emlxs_port_offline() */
1467fcf3ce44SJohn Forte 
1468fcf3ce44SJohn Forte 
1469fcf3ce44SJohn Forte extern void
1470fcf3ce44SJohn Forte emlxs_port_online(emlxs_port_t *vport)
1471fcf3ce44SJohn Forte {
1472fcf3ce44SJohn Forte 	emlxs_hba_t *hba = vport->hba;
1473fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
14748f23e9faSHans Rosenfeld 	NODELIST *nlp;
1475fcf3ce44SJohn Forte 	uint32_t state;
1476fcf3ce44SJohn Forte 	uint32_t update;
1477fcf3ce44SJohn Forte 	uint32_t npiv_linkup;
1478fcf3ce44SJohn Forte 	char topology[32];
1479fcf3ce44SJohn Forte 	char linkspeed[32];
1480fcf3ce44SJohn Forte 	char mode[32];
1481fcf3ce44SJohn Forte 
1482fcf3ce44SJohn Forte 	/*
1483291a2b48SSukumar Swaminathan 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1484291a2b48SSukumar Swaminathan 	 *    "linkup_callback. vpi=%d fc_flag=%x", vport->vpi, hba->flag);
1485fcf3ce44SJohn Forte 	 */
1486fcf3ce44SJohn Forte 
1487fcf3ce44SJohn Forte 	if ((vport->vpi > 0) &&
1488fcf3ce44SJohn Forte 	    (!(hba->flag & FC_NPIV_ENABLED) ||
1489fcf3ce44SJohn Forte 	    !(hba->flag & FC_NPIV_SUPPORTED))) {
1490fcf3ce44SJohn Forte 		return;
1491fcf3ce44SJohn Forte 	}
1492291a2b48SSukumar Swaminathan 
1493fcf3ce44SJohn Forte 	if (!(vport->flag & EMLXS_PORT_BOUND) ||
14948f23e9faSHans Rosenfeld 	    !(vport->flag & EMLXS_PORT_ENABLED)) {
1495fcf3ce44SJohn Forte 		return;
1496fcf3ce44SJohn Forte 	}
1497291a2b48SSukumar Swaminathan 
1498fcf3ce44SJohn Forte 	/* Check for mode */
14998f23e9faSHans Rosenfeld 	if (port->mode == MODE_TARGET) {
15008f23e9faSHans Rosenfeld 		(void) strlcpy(mode, ", target", sizeof (mode));
15018f23e9faSHans Rosenfeld 
15028f23e9faSHans Rosenfeld 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
15038f23e9faSHans Rosenfeld 			/* Set the node tags */
15048f23e9faSHans Rosenfeld 			emlxs_fcp_tag_nodes(vport);
15058f23e9faSHans Rosenfeld 			while ((nlp = emlxs_find_tagged_node(vport))) {
15068f23e9faSHans Rosenfeld 				/* The RPI was paused in port_offline */
15078f23e9faSHans Rosenfeld 				(void) emlxs_rpi_resume_notify(vport,
15088f23e9faSHans Rosenfeld 				    nlp->rpip, 0);
15098f23e9faSHans Rosenfeld 			}
15108f23e9faSHans Rosenfeld 		}
15118f23e9faSHans Rosenfeld 	} else if (port->mode == MODE_INITIATOR) {
15128f23e9faSHans Rosenfeld 		(void) strlcpy(mode, ", initiator", sizeof (mode));
1513fcf3ce44SJohn Forte 	} else {
15148f23e9faSHans Rosenfeld 		(void) strlcpy(mode, "unknown", sizeof (mode));
1515fcf3ce44SJohn Forte 	}
15168f23e9faSHans Rosenfeld 	mutex_enter(&EMLXS_PORT_LOCK);
1517fcf3ce44SJohn Forte 
1518fcf3ce44SJohn Forte 	/* Check for loop topology */
1519fcf3ce44SJohn Forte 	if (hba->topology == TOPOLOGY_LOOP) {
1520fcf3ce44SJohn Forte 		state = FC_STATE_LOOP;
15218f23e9faSHans Rosenfeld 		(void) strlcpy(topology, ", loop", sizeof (topology));
1522fcf3ce44SJohn Forte 	} else {
1523fcf3ce44SJohn Forte 		state = FC_STATE_ONLINE;
15248f23e9faSHans Rosenfeld 		(void) strlcpy(topology, ", fabric", sizeof (topology));
1525fcf3ce44SJohn Forte 	}
1526fcf3ce44SJohn Forte 
1527fcf3ce44SJohn Forte 	/* Set the link speed */
1528fcf3ce44SJohn Forte 	switch (hba->linkspeed) {
1529fcf3ce44SJohn Forte 	case 0:
15308f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "Gb", sizeof (linkspeed));
1531fcf3ce44SJohn Forte 		state |= FC_STATE_1GBIT_SPEED;
1532fcf3ce44SJohn Forte 		break;
1533fcf3ce44SJohn Forte 
1534fcf3ce44SJohn Forte 	case LA_1GHZ_LINK:
15358f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "1Gb", sizeof (linkspeed));
1536fcf3ce44SJohn Forte 		state |= FC_STATE_1GBIT_SPEED;
1537fcf3ce44SJohn Forte 		break;
1538fcf3ce44SJohn Forte 	case LA_2GHZ_LINK:
15398f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "2Gb", sizeof (linkspeed));
1540fcf3ce44SJohn Forte 		state |= FC_STATE_2GBIT_SPEED;
1541fcf3ce44SJohn Forte 		break;
1542fcf3ce44SJohn Forte 	case LA_4GHZ_LINK:
15438f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "4Gb", sizeof (linkspeed));
1544fcf3ce44SJohn Forte 		state |= FC_STATE_4GBIT_SPEED;
1545fcf3ce44SJohn Forte 		break;
1546fcf3ce44SJohn Forte 	case LA_8GHZ_LINK:
15478f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "8Gb", sizeof (linkspeed));
1548fcf3ce44SJohn Forte 		state |= FC_STATE_8GBIT_SPEED;
1549fcf3ce44SJohn Forte 		break;
1550fcf3ce44SJohn Forte 	case LA_10GHZ_LINK:
15518f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "10Gb", sizeof (linkspeed));
1552fcf3ce44SJohn Forte 		state |= FC_STATE_10GBIT_SPEED;
1553fcf3ce44SJohn Forte 		break;
15548f23e9faSHans Rosenfeld 	case LA_16GHZ_LINK:
15558f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "16Gb", sizeof (linkspeed));
15568f23e9faSHans Rosenfeld 		state |= FC_STATE_16GBIT_SPEED;
15578f23e9faSHans Rosenfeld 		break;
1558*a3170057SPaul Winder 	case LA_32GHZ_LINK:
1559*a3170057SPaul Winder 		(void) strlcpy(linkspeed, "32Gb", sizeof (linkspeed));
1560*a3170057SPaul Winder 		state |= FC_STATE_32GBIT_SPEED;
1561*a3170057SPaul Winder 		break;
1562fcf3ce44SJohn Forte 	default:
15638f23e9faSHans Rosenfeld 		(void) snprintf(linkspeed, sizeof (linkspeed), "unknown(0x%x)",
15648f23e9faSHans Rosenfeld 		    hba->linkspeed);
1565fcf3ce44SJohn Forte 		break;
1566fcf3ce44SJohn Forte 	}
1567fcf3ce44SJohn Forte 
1568fcf3ce44SJohn Forte 	npiv_linkup = 0;
1569fcf3ce44SJohn Forte 	update = 0;
1570fcf3ce44SJohn Forte 
1571fcf3ce44SJohn Forte 	if ((hba->state >= FC_LINK_UP) &&
1572291a2b48SSukumar Swaminathan 	    !(hba->flag & FC_LOOPBACK_MODE) && (vport->ulp_statec != state)) {
1573fcf3ce44SJohn Forte 		update = 1;
1574fcf3ce44SJohn Forte 		vport->ulp_statec = state;
1575fcf3ce44SJohn Forte 
1576fcf3ce44SJohn Forte 		if ((vport->vpi > 0) && !(hba->flag & FC_NPIV_LINKUP)) {
1577fcf3ce44SJohn Forte 			hba->flag |= FC_NPIV_LINKUP;
1578fcf3ce44SJohn Forte 			npiv_linkup = 1;
1579fcf3ce44SJohn Forte 		}
1580fcf3ce44SJohn Forte 	}
1581291a2b48SSukumar Swaminathan 
1582fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1583fcf3ce44SJohn Forte 
1584fcf3ce44SJohn Forte 	if (update) {
1585fcf3ce44SJohn Forte 		if (vport->flag & EMLXS_PORT_BOUND) {
1586fcf3ce44SJohn Forte 			if (vport->vpi == 0) {
1587fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1588291a2b48SSukumar Swaminathan 				    "%s%s%s", linkspeed, topology, mode);
15896a573d82SSukumar Swaminathan 
1590fcf3ce44SJohn Forte 			} else if (npiv_linkup) {
1591fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT,
1592291a2b48SSukumar Swaminathan 				    &emlxs_npiv_link_up_msg, "%s%s%s",
1593fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1594fcf3ce44SJohn Forte 			}
1595291a2b48SSukumar Swaminathan 
15968f23e9faSHans Rosenfeld 			if (vport->mode == MODE_INITIATOR) {
15978f23e9faSHans Rosenfeld 				emlxs_fca_link_up(vport);
1598fcf3ce44SJohn Forte 			}
15993be114edSSukumar Swaminathan #ifdef SFCT_SUPPORT
16008f23e9faSHans Rosenfeld 			else if (vport->mode == MODE_TARGET) {
16013be114edSSukumar Swaminathan 				emlxs_fct_link_up(vport);
16023be114edSSukumar Swaminathan 			}
16033be114edSSukumar Swaminathan #endif /* SFCT_SUPPORT */
1604fcf3ce44SJohn Forte 		} else {
1605fcf3ce44SJohn Forte 			if (vport->vpi == 0) {
1606fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1607291a2b48SSukumar Swaminathan 				    "%s%s%s *", linkspeed, topology, mode);
16086a573d82SSukumar Swaminathan 
1609fcf3ce44SJohn Forte 			} else if (npiv_linkup) {
1610fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT,
1611291a2b48SSukumar Swaminathan 				    &emlxs_npiv_link_up_msg, "%s%s%s *",
1612fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1613fcf3ce44SJohn Forte 			}
1614fcf3ce44SJohn Forte 		}
1615fcf3ce44SJohn Forte 
1616fcf3ce44SJohn Forte 		/* Check for waiting threads */
1617fcf3ce44SJohn Forte 		if (vport->vpi == 0) {
1618fcf3ce44SJohn Forte 			mutex_enter(&EMLXS_LINKUP_LOCK);
1619fcf3ce44SJohn Forte 			if (hba->linkup_wait_flag == TRUE) {
1620fcf3ce44SJohn Forte 				hba->linkup_wait_flag = FALSE;
1621fcf3ce44SJohn Forte 				cv_broadcast(&EMLXS_LINKUP_CV);
1622fcf3ce44SJohn Forte 			}
1623fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_LINKUP_LOCK);
1624fcf3ce44SJohn Forte 		}
1625291a2b48SSukumar Swaminathan 
1626fcf3ce44SJohn Forte 		/* Flush any pending ub buffers */
1627fcf3ce44SJohn Forte 		emlxs_ub_flush(vport);
1628fcf3ce44SJohn Forte 	}
1629291a2b48SSukumar Swaminathan 
1630fcf3ce44SJohn Forte 	return;
1631fcf3ce44SJohn Forte 
163282527734SSukumar Swaminathan } /* emlxs_port_online() */
1633fcf3ce44SJohn Forte 
1634fcf3ce44SJohn Forte 
1635a9800bebSGarrett D'Amore /* SLI3 */
1636fcf3ce44SJohn Forte extern void
1637fcf3ce44SJohn Forte emlxs_linkdown(emlxs_hba_t *hba)
1638fcf3ce44SJohn Forte {
1639fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1640fcf3ce44SJohn Forte 	int i;
1641a9800bebSGarrett D'Amore 	uint32_t scope;
1642fcf3ce44SJohn Forte 
1643fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1644fcf3ce44SJohn Forte 
164582527734SSukumar Swaminathan 	if (hba->state > FC_LINK_DOWN) {
164682527734SSukumar Swaminathan 		HBASTATS.LinkDown++;
164782527734SSukumar Swaminathan 		EMLXS_STATE_CHANGE_LOCKED(hba, FC_LINK_DOWN);
164882527734SSukumar Swaminathan 	}
1649fcf3ce44SJohn Forte 
1650a9800bebSGarrett D'Amore 	/* Set scope */
1651a9800bebSGarrett D'Amore 	scope = (hba->flag & FC_NEW_FABRIC)? 0xFDFFFFFF:0xFFFFFFFF;
1652a9800bebSGarrett D'Amore 
1653fcf3ce44SJohn Forte 	/* Filter hba flags */
1654fcf3ce44SJohn Forte 	hba->flag &= FC_LINKDOWN_MASK;
1655fcf3ce44SJohn Forte 	hba->discovery_timer = 0;
1656fcf3ce44SJohn Forte 	hba->linkup_timer = 0;
1657fcf3ce44SJohn Forte 
1658fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1659fcf3ce44SJohn Forte 
1660fcf3ce44SJohn Forte 	for (i = 0; i < MAX_VPORTS; i++) {
1661fcf3ce44SJohn Forte 		port = &VPORT(i);
1662fcf3ce44SJohn Forte 
1663fcf3ce44SJohn Forte 		if (!(port->flag & EMLXS_PORT_BOUND)) {
1664fcf3ce44SJohn Forte 			continue;
1665fcf3ce44SJohn Forte 		}
1666291a2b48SSukumar Swaminathan 
1667a9800bebSGarrett D'Amore 		(void) emlxs_port_offline(port, scope);
1668fcf3ce44SJohn Forte 
1669fcf3ce44SJohn Forte 	}
1670fcf3ce44SJohn Forte 
1671a9800bebSGarrett D'Amore 	emlxs_log_link_event(port);
1672a9800bebSGarrett D'Amore 
1673fcf3ce44SJohn Forte 	return;
1674fcf3ce44SJohn Forte 
167582527734SSukumar Swaminathan } /* emlxs_linkdown() */
1676fcf3ce44SJohn Forte 
1677fcf3ce44SJohn Forte 
1678a9800bebSGarrett D'Amore /* SLI3 */
1679fcf3ce44SJohn Forte extern void
1680fcf3ce44SJohn Forte emlxs_linkup(emlxs_hba_t *hba)
1681fcf3ce44SJohn Forte {
1682fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1683fcf3ce44SJohn Forte 	emlxs_config_t *cfg = &CFG;
1684fcf3ce44SJohn Forte 
1685fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1686fcf3ce44SJohn Forte 
16878f23e9faSHans Rosenfeld 	/* Check for any mode changes */
16888f23e9faSHans Rosenfeld 	emlxs_mode_set(hba);
16898f23e9faSHans Rosenfeld 
1690fcf3ce44SJohn Forte 	HBASTATS.LinkUp++;
169182527734SSukumar Swaminathan 	EMLXS_STATE_CHANGE_LOCKED(hba, FC_LINK_UP);
1692fcf3ce44SJohn Forte 
1693fcf3ce44SJohn Forte #ifdef MENLO_SUPPORT
1694fcf3ce44SJohn Forte 	if (hba->flag & FC_MENLO_MODE) {
1695fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1696fcf3ce44SJohn Forte 
1697fcf3ce44SJohn Forte 		/*
1698fcf3ce44SJohn Forte 		 * Trigger linkup CV and don't start linkup & discovery
1699fcf3ce44SJohn Forte 		 * timers
1700fcf3ce44SJohn Forte 		 */
1701fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_LINKUP_LOCK);
1702fcf3ce44SJohn Forte 		cv_broadcast(&EMLXS_LINKUP_CV);
1703fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_LINKUP_LOCK);
1704fcf3ce44SJohn Forte 
1705a9800bebSGarrett D'Amore 		emlxs_log_link_event(port);
1706a9800bebSGarrett D'Amore 
1707fcf3ce44SJohn Forte 		return;
1708fcf3ce44SJohn Forte 	}
1709291a2b48SSukumar Swaminathan #endif /* MENLO_SUPPORT */
1710fcf3ce44SJohn Forte 
1711fcf3ce44SJohn Forte 	/* Set the linkup & discovery timers */
1712fcf3ce44SJohn Forte 	hba->linkup_timer = hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current;
1713291a2b48SSukumar Swaminathan 	hba->discovery_timer =
1714291a2b48SSukumar Swaminathan 	    hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current +
1715291a2b48SSukumar Swaminathan 	    cfg[CFG_DISC_TIMEOUT].current;
1716fcf3ce44SJohn Forte 
1717fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1718fcf3ce44SJohn Forte 
1719a9800bebSGarrett D'Amore 	emlxs_log_link_event(port);
1720a9800bebSGarrett D'Amore 
1721fcf3ce44SJohn Forte 	return;
1722fcf3ce44SJohn Forte 
172382527734SSukumar Swaminathan } /* emlxs_linkup() */
1724fcf3ce44SJohn Forte 
1725fcf3ce44SJohn Forte 
1726fcf3ce44SJohn Forte /*
1727fcf3ce44SJohn Forte  *  emlxs_reset_link
1728fcf3ce44SJohn Forte  *
1729fcf3ce44SJohn Forte  *  Description:
1730fcf3ce44SJohn Forte  *  Called to reset the link with an init_link
1731fcf3ce44SJohn Forte  *
1732fcf3ce44SJohn Forte  *    Returns:
1733fcf3ce44SJohn Forte  *
1734fcf3ce44SJohn Forte  */
1735fcf3ce44SJohn Forte extern int
173682527734SSukumar Swaminathan emlxs_reset_link(emlxs_hba_t *hba, uint32_t linkup, uint32_t wait)
1737fcf3ce44SJohn Forte {
1738fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1739fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
174082527734SSukumar Swaminathan 	MAILBOXQ *mbq = NULL;
174182527734SSukumar Swaminathan 	MAILBOX *mb = NULL;
174282527734SSukumar Swaminathan 	int rval = 0;
17438f23e9faSHans Rosenfeld 	int tmo;
174482527734SSukumar Swaminathan 	int rc;
1745fcf3ce44SJohn Forte 
1746fcf3ce44SJohn Forte 	/*
1747fcf3ce44SJohn Forte 	 * Get a buffer to use for the mailbox command
1748fcf3ce44SJohn Forte 	 */
17498f23e9faSHans Rosenfeld 	if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))
175082527734SSukumar Swaminathan 	    == NULL) {
1751fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_failed_msg,
1752fcf3ce44SJohn Forte 		    "Unable to allocate mailbox buffer.");
175382527734SSukumar Swaminathan 		rval = 1;
175482527734SSukumar Swaminathan 		goto reset_link_fail;
175582527734SSukumar Swaminathan 	}
1756fcf3ce44SJohn Forte 
1757a9800bebSGarrett D'Amore 	if (linkup) {
1758a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg,
1759a9800bebSGarrett D'Amore 		    "Resetting link...");
1760a9800bebSGarrett D'Amore 	} else {
1761a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg,
1762a9800bebSGarrett D'Amore 		    "Disabling link...");
1763a9800bebSGarrett D'Amore 	}
1764a9800bebSGarrett D'Amore 
176582527734SSukumar Swaminathan 	mb = (MAILBOX *)mbq;
176682527734SSukumar Swaminathan 
176782527734SSukumar Swaminathan 	/* Bring link down first */
176882527734SSukumar Swaminathan 	emlxs_mb_down_link(hba, mbq);
176982527734SSukumar Swaminathan 
177082527734SSukumar Swaminathan #define	MBXERR_LINK_DOWN	0x33
177182527734SSukumar Swaminathan 
177282527734SSukumar Swaminathan 	if (wait) {
177382527734SSukumar Swaminathan 		wait = MBX_WAIT;
177482527734SSukumar Swaminathan 	} else {
177582527734SSukumar Swaminathan 		wait = MBX_NOWAIT;
177682527734SSukumar Swaminathan 	}
177782527734SSukumar Swaminathan 	rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, wait, 0);
177882527734SSukumar Swaminathan 	if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS) &&
177982527734SSukumar Swaminathan 	    (rc != MBXERR_LINK_DOWN)) {
178082527734SSukumar Swaminathan 		rval = 1;
178182527734SSukumar Swaminathan 		goto reset_link_fail;
1782fcf3ce44SJohn Forte 	}
1783291a2b48SSukumar Swaminathan 
17848f23e9faSHans Rosenfeld 	tmo = 120;
17858f23e9faSHans Rosenfeld 	do {
17868f23e9faSHans Rosenfeld 		delay(drv_usectohz(500000));
17878f23e9faSHans Rosenfeld 		tmo--;
17888f23e9faSHans Rosenfeld 
17898f23e9faSHans Rosenfeld 		if (!tmo)   {
17908f23e9faSHans Rosenfeld 			rval = 1;
17918f23e9faSHans Rosenfeld 
17928f23e9faSHans Rosenfeld 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg,
17938f23e9faSHans Rosenfeld 			    "Linkdown timeout.");
17948f23e9faSHans Rosenfeld 
17958f23e9faSHans Rosenfeld 			goto reset_link_fail;
17968f23e9faSHans Rosenfeld 		}
17978f23e9faSHans Rosenfeld 	} while ((hba->state >= FC_LINK_UP) && (hba->state != FC_ERROR));
17988f23e9faSHans Rosenfeld 
1799fcf3ce44SJohn Forte 	if (linkup) {
1800fcf3ce44SJohn Forte 		/*
1801fcf3ce44SJohn Forte 		 * Setup and issue mailbox INITIALIZE LINK command
1802fcf3ce44SJohn Forte 		 */
1803fcf3ce44SJohn Forte 
180482527734SSukumar Swaminathan 		if (wait == MBX_NOWAIT) {
18058f23e9faSHans Rosenfeld 			if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))
180682527734SSukumar Swaminathan 			    == NULL) {
180782527734SSukumar Swaminathan 				EMLXS_MSGF(EMLXS_CONTEXT,
180882527734SSukumar Swaminathan 				    &emlxs_link_reset_failed_msg,
180982527734SSukumar Swaminathan 				    "Unable to allocate mailbox buffer.");
181082527734SSukumar Swaminathan 				rval = 1;
181182527734SSukumar Swaminathan 				goto reset_link_fail;
181282527734SSukumar Swaminathan 			}
181382527734SSukumar Swaminathan 			mb = (MAILBOX *)mbq;
181482527734SSukumar Swaminathan 		} else {
181582527734SSukumar Swaminathan 			/* Reuse mbq from previous mbox */
181682527734SSukumar Swaminathan 			mb = (MAILBOX *)mbq;
181782527734SSukumar Swaminathan 		}
181882527734SSukumar Swaminathan 		cfg = &CFG;
181982527734SSukumar Swaminathan 
182082527734SSukumar Swaminathan 		emlxs_mb_init_link(hba, mbq,
1821fcf3ce44SJohn Forte 		    cfg[CFG_TOPOLOGY].current, cfg[CFG_LINK_SPEED].current);
1822fcf3ce44SJohn Forte 
1823fcf3ce44SJohn Forte 		mb->un.varInitLnk.lipsr_AL_PA = 0;
1824fcf3ce44SJohn Forte 
1825fcf3ce44SJohn Forte 		/* Clear the loopback mode */
1826fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1827fcf3ce44SJohn Forte 		hba->flag &= ~FC_LOOPBACK_MODE;
1828291a2b48SSukumar Swaminathan 		hba->loopback_tics = 0;
1829fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1830fcf3ce44SJohn Forte 
183182527734SSukumar Swaminathan 		rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, wait, 0);
183282527734SSukumar Swaminathan 		if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
183382527734SSukumar Swaminathan 			rval = 1;
183482527734SSukumar Swaminathan 			goto reset_link_fail;
1835fcf3ce44SJohn Forte 		}
1836291a2b48SSukumar Swaminathan 
1837fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg, NULL);
183882527734SSukumar Swaminathan 	}
1839fcf3ce44SJohn Forte 
184082527734SSukumar Swaminathan reset_link_fail:
1841291a2b48SSukumar Swaminathan 
184282527734SSukumar Swaminathan 	if ((wait == MBX_WAIT) && mbq) {
1843a9800bebSGarrett D'Amore 		emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
1844fcf3ce44SJohn Forte 	}
1845fcf3ce44SJohn Forte 
184682527734SSukumar Swaminathan 	return (rval);
184782527734SSukumar Swaminathan } /* emlxs_reset_link() */
1848fcf3ce44SJohn Forte 
1849fcf3ce44SJohn Forte 
1850fcf3ce44SJohn Forte extern int
1851fcf3ce44SJohn Forte emlxs_online(emlxs_hba_t *hba)
1852fcf3ce44SJohn Forte {
1853fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1854fcf3ce44SJohn Forte 	int32_t rval = 0;
1855fcf3ce44SJohn Forte 	uint32_t i = 0;
1856fcf3ce44SJohn Forte 
1857fcf3ce44SJohn Forte 	/* Make sure adapter is offline or exit trying (30 seconds) */
1858291a2b48SSukumar Swaminathan 	while (i++ < 30) {
1859fcf3ce44SJohn Forte 		/* Check if adapter is already going online */
1860fcf3ce44SJohn Forte 		if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) {
1861fcf3ce44SJohn Forte 			return (0);
1862fcf3ce44SJohn Forte 		}
1863291a2b48SSukumar Swaminathan 
1864fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1865fcf3ce44SJohn Forte 
1866fcf3ce44SJohn Forte 		/* Check again */
1867fcf3ce44SJohn Forte 		if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) {
1868fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1869fcf3ce44SJohn Forte 			return (0);
1870fcf3ce44SJohn Forte 		}
1871291a2b48SSukumar Swaminathan 
1872fcf3ce44SJohn Forte 		/* Check if adapter is offline */
1873fcf3ce44SJohn Forte 		if (hba->flag & FC_OFFLINE_MODE) {
1874fcf3ce44SJohn Forte 			/* Mark it going online */
1875fcf3ce44SJohn Forte 			hba->flag &= ~FC_OFFLINE_MODE;
1876fcf3ce44SJohn Forte 			hba->flag |= FC_ONLINING_MODE;
1877fcf3ce44SJohn Forte 
1878fcf3ce44SJohn Forte 			/* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */
1879fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1880fcf3ce44SJohn Forte 			break;
1881fcf3ce44SJohn Forte 		}
1882291a2b48SSukumar Swaminathan 
1883fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1884fcf3ce44SJohn Forte 
18858f23e9faSHans Rosenfeld 		BUSYWAIT_MS(1000);
1886fcf3ce44SJohn Forte 	}
1887fcf3ce44SJohn Forte 
1888fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
1889fcf3ce44SJohn Forte 	    "Going online...");
1890fcf3ce44SJohn Forte 
189182527734SSukumar Swaminathan 	if (rval = EMLXS_SLI_ONLINE(hba)) {
1892291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg, "status=%x",
1893fcf3ce44SJohn Forte 		    rval);
1894fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL);
1895fcf3ce44SJohn Forte 
1896fcf3ce44SJohn Forte 		/* Set FC_OFFLINE_MODE */
1897fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1898fcf3ce44SJohn Forte 		hba->flag |= FC_OFFLINE_MODE;
1899fcf3ce44SJohn Forte 		hba->flag &= ~FC_ONLINING_MODE;
1900fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1901fcf3ce44SJohn Forte 
1902fcf3ce44SJohn Forte 		return (rval);
1903fcf3ce44SJohn Forte 	}
1904291a2b48SSukumar Swaminathan 
1905fcf3ce44SJohn Forte 	/* Start the timer */
1906fcf3ce44SJohn Forte 	emlxs_timer_start(hba);
1907fcf3ce44SJohn Forte 
1908fcf3ce44SJohn Forte 	/* Set FC_ONLINE_MODE */
1909fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1910fcf3ce44SJohn Forte 	hba->flag |= FC_ONLINE_MODE;
1911fcf3ce44SJohn Forte 	hba->flag &= ~FC_ONLINING_MODE;
1912fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1913fcf3ce44SJohn Forte 
1914fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_online_msg, NULL);
1915fcf3ce44SJohn Forte 
1916fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
19178f23e9faSHans Rosenfeld 	if (port->flag & EMLXS_TGT_ENABLED) {
19188f23e9faSHans Rosenfeld 		(void) emlxs_fct_port_initialize(port);
19198f23e9faSHans Rosenfeld 	}
1920291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
1921fcf3ce44SJohn Forte 
1922fcf3ce44SJohn Forte 	return (rval);
1923fcf3ce44SJohn Forte 
192482527734SSukumar Swaminathan } /* emlxs_online() */
1925fcf3ce44SJohn Forte 
1926fcf3ce44SJohn Forte 
1927fcf3ce44SJohn Forte extern int
19288f23e9faSHans Rosenfeld emlxs_offline(emlxs_hba_t *hba, uint32_t reset_requested)
1929fcf3ce44SJohn Forte {
1930fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1931fcf3ce44SJohn Forte 	uint32_t i = 0;
1932fcf3ce44SJohn Forte 	int rval = 1;
1933fcf3ce44SJohn Forte 
1934fcf3ce44SJohn Forte 	/* Make sure adapter is online or exit trying (30 seconds) */
1935291a2b48SSukumar Swaminathan 	while (i++ < 30) {
1936fcf3ce44SJohn Forte 		/* Check if adapter is already going offline */
1937fcf3ce44SJohn Forte 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1938fcf3ce44SJohn Forte 			return (0);
1939fcf3ce44SJohn Forte 		}
1940291a2b48SSukumar Swaminathan 
1941fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1942fcf3ce44SJohn Forte 
1943fcf3ce44SJohn Forte 		/* Check again */
1944fcf3ce44SJohn Forte 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1945fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1946fcf3ce44SJohn Forte 			return (0);
1947fcf3ce44SJohn Forte 		}
1948291a2b48SSukumar Swaminathan 
1949fcf3ce44SJohn Forte 		/* Check if adapter is online */
1950fcf3ce44SJohn Forte 		if (hba->flag & FC_ONLINE_MODE) {
1951fcf3ce44SJohn Forte 			/* Mark it going offline */
1952fcf3ce44SJohn Forte 			hba->flag &= ~FC_ONLINE_MODE;
1953fcf3ce44SJohn Forte 			hba->flag |= FC_OFFLINING_MODE;
1954fcf3ce44SJohn Forte 
1955fcf3ce44SJohn Forte 			/* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */
1956fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1957fcf3ce44SJohn Forte 			break;
1958fcf3ce44SJohn Forte 		}
1959291a2b48SSukumar Swaminathan 
1960fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1961fcf3ce44SJohn Forte 
19628f23e9faSHans Rosenfeld 		BUSYWAIT_MS(1000);
1963fcf3ce44SJohn Forte 	}
1964fcf3ce44SJohn Forte 
1965291a2b48SSukumar Swaminathan 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
1966291a2b48SSukumar Swaminathan 	    "Going offline...");
1967fcf3ce44SJohn Forte 
19688f23e9faSHans Rosenfeld 	/* Declare link down */
19698f23e9faSHans Rosenfeld 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
19708f23e9faSHans Rosenfeld 		(void) emlxs_fcf_shutdown_notify(port, 1);
19718f23e9faSHans Rosenfeld 	} else {
19728f23e9faSHans Rosenfeld 		emlxs_linkdown(hba);
1973fcf3ce44SJohn Forte 	}
19748f23e9faSHans Rosenfeld 
1975fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
19768f23e9faSHans Rosenfeld 	if (port->flag & EMLXS_TGT_ENABLED) {
1977fcf3ce44SJohn Forte 		(void) emlxs_fct_port_shutdown(port);
1978fcf3ce44SJohn Forte 	}
1979291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
1980fcf3ce44SJohn Forte 
1981fcf3ce44SJohn Forte 	/* Check if adapter was shutdown */
1982fcf3ce44SJohn Forte 	if (hba->flag & FC_HARDWARE_ERROR) {
1983291a2b48SSukumar Swaminathan 		/*
1984291a2b48SSukumar Swaminathan 		 * Force mailbox cleanup
1985291a2b48SSukumar Swaminathan 		 * This will wake any sleeping or polling threads
1986291a2b48SSukumar Swaminathan 		 */
1987fcf3ce44SJohn Forte 		emlxs_mb_fini(hba, NULL, MBX_HARDWARE_ERROR);
1988fcf3ce44SJohn Forte 	}
1989291a2b48SSukumar Swaminathan 
1990fcf3ce44SJohn Forte 	/* Pause here for the IO to settle */
1991fcf3ce44SJohn Forte 	delay(drv_usectohz(1000000));	/* 1 sec */
1992fcf3ce44SJohn Forte 
1993fcf3ce44SJohn Forte 	/* Unregister all nodes */
1994fcf3ce44SJohn Forte 	emlxs_ffcleanup(hba);
1995fcf3ce44SJohn Forte 
1996fcf3ce44SJohn Forte 	if (hba->bus_type == SBUS_FC) {
199782527734SSukumar Swaminathan 		WRITE_SBUS_CSR_REG(hba, FC_SHS_REG(hba), 0x9A);
19984baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
199982527734SSukumar Swaminathan 		/* Access handle validation */
200082527734SSukumar Swaminathan 		EMLXS_CHK_ACC_HANDLE(hba, hba->sli.sli3.sbus_csr_handle);
20014baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
2002fcf3ce44SJohn Forte 	}
2003291a2b48SSukumar Swaminathan 
2004fcf3ce44SJohn Forte 	/* Stop the timer */
2005fcf3ce44SJohn Forte 	emlxs_timer_stop(hba);
2006fcf3ce44SJohn Forte 
2007fcf3ce44SJohn Forte 	/* For safety flush every iotag list */
2008fcf3ce44SJohn Forte 	if (emlxs_iotag_flush(hba)) {
2009fcf3ce44SJohn Forte 		/* Pause here for the IO to flush */
2010728bdc9bSSukumar Swaminathan 		delay(drv_usectohz(1000));
2011728bdc9bSSukumar Swaminathan 	}
2012728bdc9bSSukumar Swaminathan 
2013728bdc9bSSukumar Swaminathan 	/* Wait for poll command request to settle */
2014728bdc9bSSukumar Swaminathan 	while (hba->io_poll_count > 0) {
2015728bdc9bSSukumar Swaminathan 		delay(drv_usectohz(2000000));   /* 2 sec */
2016fcf3ce44SJohn Forte 	}
2017728bdc9bSSukumar Swaminathan 
201882527734SSukumar Swaminathan 	/* Shutdown the adapter interface */
20198f23e9faSHans Rosenfeld 	EMLXS_SLI_OFFLINE(hba, reset_requested);
2020fcf3ce44SJohn Forte 
2021fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
2022fcf3ce44SJohn Forte 	hba->flag |= FC_OFFLINE_MODE;
2023fcf3ce44SJohn Forte 	hba->flag &= ~FC_OFFLINING_MODE;
2024fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
2025fcf3ce44SJohn Forte 
2026fcf3ce44SJohn Forte 	rval = 0;
2027fcf3ce44SJohn Forte 
2028fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL);
2029fcf3ce44SJohn Forte 
2030fcf3ce44SJohn Forte done:
2031fcf3ce44SJohn Forte 
2032fcf3ce44SJohn Forte 	return (rval);
2033fcf3ce44SJohn Forte 
203482527734SSukumar Swaminathan } /* emlxs_offline() */
2035fcf3ce44SJohn Forte 
2036fcf3ce44SJohn Forte 
2037fcf3ce44SJohn Forte 
2038fcf3ce44SJohn Forte extern int
2039fcf3ce44SJohn Forte emlxs_power_down(emlxs_hba_t *hba)
2040fcf3ce44SJohn Forte {
20414baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
20424baa2c25SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
20434baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
2044fcf3ce44SJohn Forte 	int32_t rval = 0;
2045fcf3ce44SJohn Forte 
20468f23e9faSHans Rosenfeld 	if ((rval = emlxs_offline(hba, 0))) {
2047fcf3ce44SJohn Forte 		return (rval);
2048fcf3ce44SJohn Forte 	}
204982527734SSukumar Swaminathan 	EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
2050291a2b48SSukumar Swaminathan 
2051fcf3ce44SJohn Forte 
20524baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
20534baa2c25SSukumar Swaminathan 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
20544baa2c25SSukumar Swaminathan 	    != DDI_FM_OK) {
20554baa2c25SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT,
20564baa2c25SSukumar Swaminathan 		    &emlxs_invalid_access_handle_msg, NULL);
20574baa2c25SSukumar Swaminathan 		return (1);
20584baa2c25SSukumar Swaminathan 	}
20594baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
20604baa2c25SSukumar Swaminathan 
2061fcf3ce44SJohn Forte 	return (0);
2062fcf3ce44SJohn Forte 
206382527734SSukumar Swaminathan } /* End emlxs_power_down */
2064fcf3ce44SJohn Forte 
2065fcf3ce44SJohn Forte 
2066fcf3ce44SJohn Forte extern int
2067fcf3ce44SJohn Forte emlxs_power_up(emlxs_hba_t *hba)
2068fcf3ce44SJohn Forte {
20694baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
20704baa2c25SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
20714baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
2072fcf3ce44SJohn Forte 	int32_t rval = 0;
2073fcf3ce44SJohn Forte 
2074fcf3ce44SJohn Forte 
20754baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
20764baa2c25SSukumar Swaminathan 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
20774baa2c25SSukumar Swaminathan 	    != DDI_FM_OK) {
20784baa2c25SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT,
20794baa2c25SSukumar Swaminathan 		    &emlxs_invalid_access_handle_msg, NULL);
20804baa2c25SSukumar Swaminathan 		return (1);
20814baa2c25SSukumar Swaminathan 	}
20824baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
20834baa2c25SSukumar Swaminathan 
2084fcf3ce44SJohn Forte 	/* Bring adapter online */
2085fcf3ce44SJohn Forte 	if ((rval = emlxs_online(hba))) {
2086a9800bebSGarrett D'Amore 		if (hba->pci_cap_offset[PCI_CAP_ID_PM]) {
2087a9800bebSGarrett D'Amore 			/* Put chip in D3 state */
2088a9800bebSGarrett D'Amore 			(void) ddi_put8(hba->pci_acc_handle,
2089a9800bebSGarrett D'Amore 			    (uint8_t *)(hba->pci_addr +
2090a9800bebSGarrett D'Amore 			    hba->pci_cap_offset[PCI_CAP_ID_PM] +
2091a9800bebSGarrett D'Amore 			    PCI_PMCSR),
2092a9800bebSGarrett D'Amore 			    (uint8_t)PCI_PMCSR_D3HOT);
2093a9800bebSGarrett D'Amore 		}
2094fcf3ce44SJohn Forte 		return (rval);
2095fcf3ce44SJohn Forte 	}
2096291a2b48SSukumar Swaminathan 
2097fcf3ce44SJohn Forte 	return (rval);
2098fcf3ce44SJohn Forte 
20998f23e9faSHans Rosenfeld } /* emlxs_power_up() */
2100fcf3ce44SJohn Forte 
2101fcf3ce44SJohn Forte 
2102fcf3ce44SJohn Forte /*
2103291a2b48SSukumar Swaminathan  *
2104fcf3ce44SJohn Forte  * NAME:     emlxs_ffcleanup
2105fcf3ce44SJohn Forte  *
2106fcf3ce44SJohn Forte  * FUNCTION: Cleanup all the Firefly resources used by configuring the adapter
2107fcf3ce44SJohn Forte  *
2108fcf3ce44SJohn Forte  * EXECUTION ENVIRONMENT: process only
2109fcf3ce44SJohn Forte  *
2110fcf3ce44SJohn Forte  * CALLED FROM: CFG_TERM
2111fcf3ce44SJohn Forte  *
2112fcf3ce44SJohn Forte  * INPUT: hba       - pointer to the dev_ctl area.
2113fcf3ce44SJohn Forte  *
2114fcf3ce44SJohn Forte  * RETURNS: none
2115fcf3ce44SJohn Forte  */
2116fcf3ce44SJohn Forte extern void
2117fcf3ce44SJohn Forte emlxs_ffcleanup(emlxs_hba_t *hba)
2118fcf3ce44SJohn Forte {
2119fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2120291a2b48SSukumar Swaminathan 	uint32_t i;
2121fcf3ce44SJohn Forte 
2122fcf3ce44SJohn Forte 	/* Disable all but the mailbox interrupt */
212382527734SSukumar Swaminathan 	EMLXS_SLI_DISABLE_INTR(hba, HC_MBINT_ENA);
2124fcf3ce44SJohn Forte 
2125fcf3ce44SJohn Forte 	/* Make sure all port nodes are destroyed */
2126291a2b48SSukumar Swaminathan 	for (i = 0; i < MAX_VPORTS; i++) {
2127291a2b48SSukumar Swaminathan 		port = &VPORT(i);
2128fcf3ce44SJohn Forte 
2129fcf3ce44SJohn Forte 		if (port->node_count) {
21308f23e9faSHans Rosenfeld 			(void) EMLXS_SLI_UNREG_NODE(port, 0, 0, 0, 0);
2131fcf3ce44SJohn Forte 		}
2132fcf3ce44SJohn Forte 	}
2133fcf3ce44SJohn Forte 
2134fcf3ce44SJohn Forte 	/* Clear all interrupt enable conditions */
213582527734SSukumar Swaminathan 	EMLXS_SLI_DISABLE_INTR(hba, 0);
2136fcf3ce44SJohn Forte 
2137fcf3ce44SJohn Forte 	return;
2138fcf3ce44SJohn Forte 
213982527734SSukumar Swaminathan } /* emlxs_ffcleanup() */
2140fcf3ce44SJohn Forte 
2141fcf3ce44SJohn Forte 
2142fcf3ce44SJohn Forte extern uint16_t
214382527734SSukumar Swaminathan emlxs_register_pkt(CHANNEL *cp, emlxs_buf_t *sbp)
2144fcf3ce44SJohn Forte {
2145fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
2146fcf3ce44SJohn Forte 	emlxs_port_t *port;
2147fcf3ce44SJohn Forte 	uint16_t iotag;
2148fcf3ce44SJohn Forte 	uint32_t i;
2149fcf3ce44SJohn Forte 
215082527734SSukumar Swaminathan 	hba = cp->hba;
2151fcf3ce44SJohn Forte 
215282527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
2153fcf3ce44SJohn Forte 
2154fcf3ce44SJohn Forte 	if (sbp->iotag != 0) {
2155fcf3ce44SJohn Forte 		port = &PPORT;
2156fcf3ce44SJohn Forte 
2157fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
215882527734SSukumar Swaminathan 		    "Pkt already registered! channel=%d iotag=%d sbp=%p",
215982527734SSukumar Swaminathan 		    sbp->channel, sbp->iotag, sbp);
2160fcf3ce44SJohn Forte 	}
2161291a2b48SSukumar Swaminathan 
2162fcf3ce44SJohn Forte 	iotag = 0;
216382527734SSukumar Swaminathan 	for (i = 0; i < hba->max_iotag; i++) {
216482527734SSukumar Swaminathan 		if (!hba->fc_iotag || hba->fc_iotag >= hba->max_iotag) {
216582527734SSukumar Swaminathan 			hba->fc_iotag = 1;
2166fcf3ce44SJohn Forte 		}
216782527734SSukumar Swaminathan 		iotag = hba->fc_iotag++;
2168fcf3ce44SJohn Forte 
216982527734SSukumar Swaminathan 		if (hba->fc_table[iotag] == 0 ||
217082527734SSukumar Swaminathan 		    hba->fc_table[iotag] == STALE_PACKET) {
217182527734SSukumar Swaminathan 			hba->io_count++;
217282527734SSukumar Swaminathan 			hba->fc_table[iotag] = sbp;
2173fcf3ce44SJohn Forte 
2174fcf3ce44SJohn Forte 			sbp->iotag = iotag;
217582527734SSukumar Swaminathan 			sbp->channel = cp;
2176fcf3ce44SJohn Forte 
2177fcf3ce44SJohn Forte 			break;
2178fcf3ce44SJohn Forte 		}
2179fcf3ce44SJohn Forte 		iotag = 0;
2180fcf3ce44SJohn Forte 	}
2181fcf3ce44SJohn Forte 
218282527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
2183fcf3ce44SJohn Forte 
2184fcf3ce44SJohn Forte 	/*
2185fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
21868f23e9faSHans Rosenfeld 	 *    "register_pkt: channel=%d iotag=%d sbp=%p",
218782527734SSukumar Swaminathan 	 *    cp->channelno, iotag, sbp);
2188fcf3ce44SJohn Forte 	 */
2189fcf3ce44SJohn Forte 
2190fcf3ce44SJohn Forte 	return (iotag);
2191fcf3ce44SJohn Forte 
219282527734SSukumar Swaminathan } /* emlxs_register_pkt() */
2193fcf3ce44SJohn Forte 
2194fcf3ce44SJohn Forte 
2195fcf3ce44SJohn Forte 
2196fcf3ce44SJohn Forte extern emlxs_buf_t *
219782527734SSukumar Swaminathan emlxs_unregister_pkt(CHANNEL *cp, uint16_t iotag, uint32_t forced)
2198fcf3ce44SJohn Forte {
2199fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
2200fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
220182527734SSukumar Swaminathan 
220282527734SSukumar Swaminathan 	sbp = NULL;
220382527734SSukumar Swaminathan 	hba = cp->hba;
2204fcf3ce44SJohn Forte 
2205fcf3ce44SJohn Forte 	/* Check the iotag range */
220682527734SSukumar Swaminathan 	if ((iotag == 0) || (iotag >= hba->max_iotag)) {
2207fcf3ce44SJohn Forte 		return (NULL);
2208fcf3ce44SJohn Forte 	}
2209291a2b48SSukumar Swaminathan 
2210fcf3ce44SJohn Forte 	/* Remove the sbp from the table */
221182527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
221282527734SSukumar Swaminathan 	sbp = hba->fc_table[iotag];
2213fcf3ce44SJohn Forte 
2214fcf3ce44SJohn Forte 	if (!sbp || (sbp == STALE_PACKET)) {
221582527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
2216fcf3ce44SJohn Forte 		return (sbp);
2217fcf3ce44SJohn Forte 	}
2218291a2b48SSukumar Swaminathan 
221982527734SSukumar Swaminathan 	hba->fc_table[iotag] = ((forced) ? STALE_PACKET : NULL);
222082527734SSukumar Swaminathan 	hba->io_count--;
2221fcf3ce44SJohn Forte 	sbp->iotag = 0;
2222fcf3ce44SJohn Forte 
222382527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
2224fcf3ce44SJohn Forte 
2225fcf3ce44SJohn Forte 
2226fcf3ce44SJohn Forte 	/* Clean up the sbp */
2227fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
2228fcf3ce44SJohn Forte 
2229fcf3ce44SJohn Forte 	if (sbp->pkt_flags & PACKET_IN_TXQ) {
2230fcf3ce44SJohn Forte 		sbp->pkt_flags &= ~PACKET_IN_TXQ;
223182527734SSukumar Swaminathan 		hba->channel_tx_count--;
2232fcf3ce44SJohn Forte 	}
2233291a2b48SSukumar Swaminathan 
2234fcf3ce44SJohn Forte 	if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
2235fcf3ce44SJohn Forte 		sbp->pkt_flags &= ~PACKET_IN_CHIPQ;
2236fcf3ce44SJohn Forte 	}
2237291a2b48SSukumar Swaminathan 
2238fcf3ce44SJohn Forte 	if (sbp->bmp) {
2239a9800bebSGarrett D'Amore 		emlxs_mem_put(hba, MEM_BPL, (void *)sbp->bmp);
2240fcf3ce44SJohn Forte 		sbp->bmp = 0;
2241fcf3ce44SJohn Forte 	}
2242fcf3ce44SJohn Forte 
2243291a2b48SSukumar Swaminathan 	mutex_exit(&sbp->mtx);
2244fcf3ce44SJohn Forte 
2245fcf3ce44SJohn Forte 	return (sbp);
2246fcf3ce44SJohn Forte 
224782527734SSukumar Swaminathan } /* emlxs_unregister_pkt() */
2248fcf3ce44SJohn Forte 
2249fcf3ce44SJohn Forte 
2250fcf3ce44SJohn Forte 
225182527734SSukumar Swaminathan /* Flush all IO's to all nodes for a given IO Channel */
2252fcf3ce44SJohn Forte extern uint32_t
225382527734SSukumar Swaminathan emlxs_tx_channel_flush(emlxs_hba_t *hba, CHANNEL *cp, emlxs_buf_t *fpkt)
2254fcf3ce44SJohn Forte {
2255fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2256fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2257fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2258fcf3ce44SJohn Forte 	IOCBQ *next;
2259fcf3ce44SJohn Forte 	IOCB *iocb;
226082527734SSukumar Swaminathan 	uint32_t channelno;
2261fcf3ce44SJohn Forte 	Q abort;
2262fcf3ce44SJohn Forte 	NODELIST *ndlp;
2263fcf3ce44SJohn Forte 	IOCB *icmd;
2264fcf3ce44SJohn Forte 	MATCHMAP *mp;
2265fcf3ce44SJohn Forte 	uint32_t i;
226682527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2267fcf3ce44SJohn Forte 
226882527734SSukumar Swaminathan 	channelno = cp->channelno;
2269fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
227082527734SSukumar Swaminathan 	bzero((void *)flag, MAX_CHANNEL * sizeof (uint8_t));
2271fcf3ce44SJohn Forte 
227282527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2273fcf3ce44SJohn Forte 
2274fcf3ce44SJohn Forte 	/* While a node needs servicing */
227582527734SSukumar Swaminathan 	while (cp->nodeq.q_first) {
227682527734SSukumar Swaminathan 		ndlp = (NODELIST *) cp->nodeq.q_first;
2277fcf3ce44SJohn Forte 
2278fcf3ce44SJohn Forte 		/* Check if priority queue is not empty */
227982527734SSukumar Swaminathan 		if (ndlp->nlp_ptx[channelno].q_first) {
2280fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2281fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
228282527734SSukumar Swaminathan 				abort.q_first =
228382527734SSukumar Swaminathan 				    ndlp->nlp_ptx[channelno].q_first;
2284fcf3ce44SJohn Forte 			} else {
2285fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
228682527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_ptx[channelno].q_first;
2287fcf3ce44SJohn Forte 			}
228882527734SSukumar Swaminathan 			flag[channelno] = 1;
2289fcf3ce44SJohn Forte 
229082527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_ptx[channelno].q_last;
229182527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_ptx[channelno].q_cnt;
2292fcf3ce44SJohn Forte 		}
2293291a2b48SSukumar Swaminathan 
2294fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
229582527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
2296fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2297fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
229882527734SSukumar Swaminathan 				abort.q_first = ndlp->nlp_tx[channelno].q_first;
2299fcf3ce44SJohn Forte 			} else {
2300fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
230182527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2302fcf3ce44SJohn Forte 			}
2303fcf3ce44SJohn Forte 
230482527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_tx[channelno].q_last;
230582527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_tx[channelno].q_cnt;
2306fcf3ce44SJohn Forte 		}
2307291a2b48SSukumar Swaminathan 
2308fcf3ce44SJohn Forte 		/* Clear the queue pointers */
230982527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_first = NULL;
231082527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_last = NULL;
231182527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_cnt = 0;
2312fcf3ce44SJohn Forte 
231382527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_first = NULL;
231482527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_last = NULL;
231582527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_cnt = 0;
2316fcf3ce44SJohn Forte 
2317fcf3ce44SJohn Forte 		/* Remove node from service queue */
2318fcf3ce44SJohn Forte 
2319fcf3ce44SJohn Forte 		/* If this is the last node on list */
232082527734SSukumar Swaminathan 		if (cp->nodeq.q_last == (void *)ndlp) {
232182527734SSukumar Swaminathan 			cp->nodeq.q_last = NULL;
232282527734SSukumar Swaminathan 			cp->nodeq.q_first = NULL;
232382527734SSukumar Swaminathan 			cp->nodeq.q_cnt = 0;
2324fcf3ce44SJohn Forte 		} else {
2325fcf3ce44SJohn Forte 			/* Remove node from head */
232682527734SSukumar Swaminathan 			cp->nodeq.q_first = ndlp->nlp_next[channelno];
232782527734SSukumar Swaminathan 			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
232882527734SSukumar Swaminathan 			    cp->nodeq.q_first;
232982527734SSukumar Swaminathan 			cp->nodeq.q_cnt--;
2330fcf3ce44SJohn Forte 		}
2331fcf3ce44SJohn Forte 
2332fcf3ce44SJohn Forte 		/* Clear node */
233382527734SSukumar Swaminathan 		ndlp->nlp_next[channelno] = NULL;
2334fcf3ce44SJohn Forte 	}
2335fcf3ce44SJohn Forte 
2336fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2337291a2b48SSukumar Swaminathan 	iocbq = (IOCBQ *) abort.q_first;
2338fcf3ce44SJohn Forte 	while (iocbq) {
2339fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2340fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
234182527734SSukumar Swaminathan 
234282527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
234382527734SSukumar Swaminathan 			sbp = iocbq->sbp;
234482527734SSukumar Swaminathan 			if (sbp) {
23458f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
234682527734SSukumar Swaminathan 			}
234782527734SSukumar Swaminathan 		} else {
234882527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
234982527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
235082527734SSukumar Swaminathan 		}
2351fcf3ce44SJohn Forte 
2352fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2353fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2354fcf3ce44SJohn Forte 
2355fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2356fcf3ce44SJohn Forte 			/*
2357fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2358291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2359291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2360fcf3ce44SJohn Forte 			 */
2361fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2362fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2363fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2364fcf3ce44SJohn Forte 				fpkt->flush_count++;
2365fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2366fcf3ce44SJohn Forte 			}
2367291a2b48SSukumar Swaminathan 
2368fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2369fcf3ce44SJohn Forte 		}
2370291a2b48SSukumar Swaminathan 
2371fcf3ce44SJohn Forte 		iocbq = (IOCBQ *)iocbq->next;
2372fcf3ce44SJohn Forte 	}	/* end of while */
2373fcf3ce44SJohn Forte 
237482527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2375fcf3ce44SJohn Forte 
2376fcf3ce44SJohn Forte 	/* Now abort the iocb's */
2377fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2378fcf3ce44SJohn Forte 	while (iocbq) {
2379fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2380fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2381fcf3ce44SJohn Forte 
2382fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2383fcf3ce44SJohn Forte 		iocbq->next = NULL;
2384fcf3ce44SJohn Forte 
2385fcf3ce44SJohn Forte 		/* Get the pkt */
2386fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2387fcf3ce44SJohn Forte 
2388fcf3ce44SJohn Forte 		if (sbp) {
2389fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2390291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2391fcf3ce44SJohn Forte 
2392fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2393fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2394fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2395fcf3ce44SJohn Forte 			} else {
2396fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2397fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2398fcf3ce44SJohn Forte 			}
2399fcf3ce44SJohn Forte 
2400fcf3ce44SJohn Forte 		}
2401fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2402fcf3ce44SJohn Forte 		else {
2403fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
240482527734SSukumar Swaminathan 
240582527734SSukumar Swaminathan 			/* SLI3 */
240682527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
240782527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
240882527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2409fcf3ce44SJohn Forte 				if ((hba->flag &
2410fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2411fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
241282527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2413fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2414a9800bebSGarrett D'Amore 						void	*tmp;
241582527734SSukumar Swaminathan 						RING *rp;
2416fcf3ce44SJohn Forte 
241782527734SSukumar Swaminathan 						rp = &hba->sli.sli3.
241882527734SSukumar Swaminathan 						    ring[channelno];
2419fcf3ce44SJohn Forte 						for (i = 0;
242082527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2421fcf3ce44SJohn Forte 						    i++) {
2422fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2423fcf3ce44SJohn Forte 							    hba, rp, icmd);
2424fcf3ce44SJohn Forte 
2425a9800bebSGarrett D'Amore 							tmp = (void *)mp;
2426fcf3ce44SJohn Forte 							if (mp) {
2427a9800bebSGarrett D'Amore 							emlxs_mem_put(
2428291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2429fcf3ce44SJohn Forte 							}
2430fcf3ce44SJohn Forte 						}
2431fcf3ce44SJohn Forte 					}
2432291a2b48SSukumar Swaminathan 
2433a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
2434a9800bebSGarrett D'Amore 					    (void *)iocbq);
2435fcf3ce44SJohn Forte 				} else {
2436fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
243782527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp,
2438291a2b48SSukumar Swaminathan 					    iocbq);
2439fcf3ce44SJohn Forte 				}
244082527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
244182527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
244282527734SSukumar Swaminathan 
244382527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
2444fcf3ce44SJohn Forte 			}
2445fcf3ce44SJohn Forte 		}
2446fcf3ce44SJohn Forte 
2447fcf3ce44SJohn Forte 		iocbq = next;
2448fcf3ce44SJohn Forte 
2449fcf3ce44SJohn Forte 	}	/* end of while */
2450fcf3ce44SJohn Forte 
245182527734SSukumar Swaminathan 	/* Now trigger channel service */
245282527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
245382527734SSukumar Swaminathan 		if (!flag[channelno]) {
245482527734SSukumar Swaminathan 			continue;
245582527734SSukumar Swaminathan 		}
245682527734SSukumar Swaminathan 
245782527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
245882527734SSukumar Swaminathan 	}
245982527734SSukumar Swaminathan 
2460fcf3ce44SJohn Forte 	return (abort.q_cnt);
2461fcf3ce44SJohn Forte 
246282527734SSukumar Swaminathan } /* emlxs_tx_channel_flush() */
2463fcf3ce44SJohn Forte 
2464fcf3ce44SJohn Forte 
2465fcf3ce44SJohn Forte /* Flush all IO's on all or a given ring for a given node */
2466fcf3ce44SJohn Forte extern uint32_t
246782527734SSukumar Swaminathan emlxs_tx_node_flush(emlxs_port_t *port, NODELIST *ndlp, CHANNEL *chan,
2468fcf3ce44SJohn Forte     uint32_t shutdown, emlxs_buf_t *fpkt)
2469fcf3ce44SJohn Forte {
2470fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2471fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
247282527734SSukumar Swaminathan 	uint32_t channelno;
247382527734SSukumar Swaminathan 	CHANNEL *cp;
2474fcf3ce44SJohn Forte 	IOCB *icmd;
2475fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2476fcf3ce44SJohn Forte 	NODELIST *prev;
2477fcf3ce44SJohn Forte 	IOCBQ *next;
2478fcf3ce44SJohn Forte 	IOCB *iocb;
2479fcf3ce44SJohn Forte 	Q abort;
2480fcf3ce44SJohn Forte 	uint32_t i;
2481fcf3ce44SJohn Forte 	MATCHMAP *mp;
248282527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2483fcf3ce44SJohn Forte 
2484fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
2485fcf3ce44SJohn Forte 
2486fcf3ce44SJohn Forte 	/* Flush all I/O's on tx queue to this target */
248782527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2488fcf3ce44SJohn Forte 
2489fcf3ce44SJohn Forte 	if (!ndlp->nlp_base && shutdown) {
2490fcf3ce44SJohn Forte 		ndlp->nlp_active = 0;
2491fcf3ce44SJohn Forte 	}
2492291a2b48SSukumar Swaminathan 
249382527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
249482527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
2495fcf3ce44SJohn Forte 
249682527734SSukumar Swaminathan 		if (chan && cp != chan) {
2497fcf3ce44SJohn Forte 			continue;
2498fcf3ce44SJohn Forte 		}
2499291a2b48SSukumar Swaminathan 
2500fcf3ce44SJohn Forte 		if (!ndlp->nlp_base || shutdown) {
2501fcf3ce44SJohn Forte 			/* Check if priority queue is not empty */
250282527734SSukumar Swaminathan 			if (ndlp->nlp_ptx[channelno].q_first) {
2503fcf3ce44SJohn Forte 				/* Transfer all iocb's to local queue */
2504fcf3ce44SJohn Forte 				if (abort.q_first == 0) {
2505fcf3ce44SJohn Forte 					abort.q_first =
250682527734SSukumar Swaminathan 					    ndlp->nlp_ptx[channelno].q_first;
2507fcf3ce44SJohn Forte 				} else {
250882527734SSukumar Swaminathan 					((IOCBQ *)(abort.q_last))->next =
250982527734SSukumar Swaminathan 					    (IOCBQ *)ndlp->nlp_ptx[channelno].
2510291a2b48SSukumar Swaminathan 					    q_first;
2511fcf3ce44SJohn Forte 				}
2512fcf3ce44SJohn Forte 
251382527734SSukumar Swaminathan 				flag[channelno] = 1;
251482527734SSukumar Swaminathan 
251582527734SSukumar Swaminathan 				abort.q_last = ndlp->nlp_ptx[channelno].q_last;
251682527734SSukumar Swaminathan 				abort.q_cnt += ndlp->nlp_ptx[channelno].q_cnt;
2517fcf3ce44SJohn Forte 			}
2518fcf3ce44SJohn Forte 		}
2519291a2b48SSukumar Swaminathan 
2520fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
252182527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
252282527734SSukumar Swaminathan 
2523fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2524fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
252582527734SSukumar Swaminathan 				abort.q_first = ndlp->nlp_tx[channelno].q_first;
2526fcf3ce44SJohn Forte 			} else {
2527fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
252882527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2529fcf3ce44SJohn Forte 			}
2530fcf3ce44SJohn Forte 
253182527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_tx[channelno].q_last;
253282527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_tx[channelno].q_cnt;
2533fcf3ce44SJohn Forte 		}
2534291a2b48SSukumar Swaminathan 
2535fcf3ce44SJohn Forte 		/* Clear the queue pointers */
253682527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_first = NULL;
253782527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_last = NULL;
253882527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_cnt = 0;
2539fcf3ce44SJohn Forte 
254082527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_first = NULL;
254182527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_last = NULL;
254282527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_cnt = 0;
2543fcf3ce44SJohn Forte 
254482527734SSukumar Swaminathan 		/* If this node was on the channel queue, remove it */
254582527734SSukumar Swaminathan 		if (ndlp->nlp_next[channelno]) {
2546fcf3ce44SJohn Forte 			/* If this is the only node on list */
254782527734SSukumar Swaminathan 			if (cp->nodeq.q_first == (void *)ndlp &&
254882527734SSukumar Swaminathan 			    cp->nodeq.q_last == (void *)ndlp) {
254982527734SSukumar Swaminathan 				cp->nodeq.q_last = NULL;
255082527734SSukumar Swaminathan 				cp->nodeq.q_first = NULL;
255182527734SSukumar Swaminathan 				cp->nodeq.q_cnt = 0;
255282527734SSukumar Swaminathan 			} else if (cp->nodeq.q_first == (void *)ndlp) {
255382527734SSukumar Swaminathan 				cp->nodeq.q_first = ndlp->nlp_next[channelno];
255482527734SSukumar Swaminathan 				((NODELIST *) cp->nodeq.q_last)->
255582527734SSukumar Swaminathan 				    nlp_next[channelno] = cp->nodeq.q_first;
255682527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
2557291a2b48SSukumar Swaminathan 			} else {
2558fcf3ce44SJohn Forte 				/*
2559291a2b48SSukumar Swaminathan 				 * This is a little more difficult find the
256082527734SSukumar Swaminathan 				 * previous node in the circular channel queue
2561fcf3ce44SJohn Forte 				 */
2562fcf3ce44SJohn Forte 				prev = ndlp;
256382527734SSukumar Swaminathan 				while (prev->nlp_next[channelno] != ndlp) {
256482527734SSukumar Swaminathan 					prev = prev->nlp_next[channelno];
2565fcf3ce44SJohn Forte 				}
2566fcf3ce44SJohn Forte 
256782527734SSukumar Swaminathan 				prev->nlp_next[channelno] =
256882527734SSukumar Swaminathan 				    ndlp->nlp_next[channelno];
2569fcf3ce44SJohn Forte 
257082527734SSukumar Swaminathan 				if (cp->nodeq.q_last == (void *)ndlp) {
257182527734SSukumar Swaminathan 					cp->nodeq.q_last = (void *)prev;
2572fcf3ce44SJohn Forte 				}
257382527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
2574fcf3ce44SJohn Forte 
2575fcf3ce44SJohn Forte 			}
2576fcf3ce44SJohn Forte 
2577fcf3ce44SJohn Forte 			/* Clear node */
257882527734SSukumar Swaminathan 			ndlp->nlp_next[channelno] = NULL;
2579fcf3ce44SJohn Forte 		}
2580291a2b48SSukumar Swaminathan 
2581fcf3ce44SJohn Forte 	}
2582fcf3ce44SJohn Forte 
2583fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2584291a2b48SSukumar Swaminathan 	iocbq = (IOCBQ *) abort.q_first;
2585fcf3ce44SJohn Forte 	while (iocbq) {
2586fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2587fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
258882527734SSukumar Swaminathan 
258982527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
259082527734SSukumar Swaminathan 			sbp = iocbq->sbp;
259182527734SSukumar Swaminathan 			if (sbp) {
25928f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
259382527734SSukumar Swaminathan 			}
259482527734SSukumar Swaminathan 		} else {
259582527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
259682527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
259782527734SSukumar Swaminathan 		}
2598fcf3ce44SJohn Forte 
2599fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2600fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2601fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2602fcf3ce44SJohn Forte 			/*
2603fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2604291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2605291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2606fcf3ce44SJohn Forte 			 */
2607fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2608fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2609fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2610fcf3ce44SJohn Forte 				fpkt->flush_count++;
2611fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2612fcf3ce44SJohn Forte 			}
2613291a2b48SSukumar Swaminathan 
2614fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2615fcf3ce44SJohn Forte 		}
2616291a2b48SSukumar Swaminathan 
2617291a2b48SSukumar Swaminathan 		iocbq = (IOCBQ *) iocbq->next;
2618fcf3ce44SJohn Forte 
2619fcf3ce44SJohn Forte 	}	/* end of while */
2620fcf3ce44SJohn Forte 
262182527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2622fcf3ce44SJohn Forte 
2623fcf3ce44SJohn Forte 	/* Now abort the iocb's outside the locks */
2624fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2625fcf3ce44SJohn Forte 	while (iocbq) {
2626fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2627fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2628fcf3ce44SJohn Forte 
2629fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2630fcf3ce44SJohn Forte 		iocbq->next = NULL;
2631fcf3ce44SJohn Forte 
2632fcf3ce44SJohn Forte 		/* Get the pkt */
2633fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2634fcf3ce44SJohn Forte 
2635fcf3ce44SJohn Forte 		if (sbp) {
2636fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2637291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2638fcf3ce44SJohn Forte 
2639fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2640fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2641fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2642fcf3ce44SJohn Forte 			} else {
2643fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2644fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2645fcf3ce44SJohn Forte 			}
2646fcf3ce44SJohn Forte 
2647fcf3ce44SJohn Forte 		}
2648fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2649fcf3ce44SJohn Forte 		else {
265082527734SSukumar Swaminathan 			/* CMD_CLOSE_XRI_CN should also free the memory */
2651fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
265282527734SSukumar Swaminathan 
265382527734SSukumar Swaminathan 			/* SLI3 */
265482527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
265582527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
265682527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2657fcf3ce44SJohn Forte 				if ((hba->flag &
2658fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2659fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
266082527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2661fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2662a9800bebSGarrett D'Amore 						void	*tmp;
266382527734SSukumar Swaminathan 						RING *rp;
266482527734SSukumar Swaminathan 						int ch;
2665fcf3ce44SJohn Forte 
266682527734SSukumar Swaminathan 						ch = ((CHANNEL *)
266782527734SSukumar Swaminathan 						    iocbq->channel)->channelno;
266882527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
2669fcf3ce44SJohn Forte 						for (i = 0;
267082527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2671fcf3ce44SJohn Forte 						    i++) {
2672fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2673fcf3ce44SJohn Forte 							    hba, rp, icmd);
2674fcf3ce44SJohn Forte 
2675a9800bebSGarrett D'Amore 							tmp = (void *)mp;
2676fcf3ce44SJohn Forte 							if (mp) {
2677a9800bebSGarrett D'Amore 							emlxs_mem_put(
2678291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2679fcf3ce44SJohn Forte 							}
2680fcf3ce44SJohn Forte 						}
2681fcf3ce44SJohn Forte 					}
2682291a2b48SSukumar Swaminathan 
2683a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
2684a9800bebSGarrett D'Amore 					    (void *)iocbq);
2685fcf3ce44SJohn Forte 				} else {
2686fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
268782527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
268882527734SSukumar Swaminathan 					    (CHANNEL *)iocbq->channel, iocbq);
2689fcf3ce44SJohn Forte 				}
269082527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
269182527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
269282527734SSukumar Swaminathan 				/*
269382527734SSukumar Swaminathan 				 * Resend the abort iocbq if any
269482527734SSukumar Swaminathan 				 */
269582527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
2696fcf3ce44SJohn Forte 			}
2697fcf3ce44SJohn Forte 		}
2698fcf3ce44SJohn Forte 
2699fcf3ce44SJohn Forte 		iocbq = next;
2700fcf3ce44SJohn Forte 
2701fcf3ce44SJohn Forte 	}	/* end of while */
2702fcf3ce44SJohn Forte 
270382527734SSukumar Swaminathan 	/* Now trigger channel service */
270482527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
270582527734SSukumar Swaminathan 		if (!flag[channelno]) {
270682527734SSukumar Swaminathan 			continue;
270782527734SSukumar Swaminathan 		}
270882527734SSukumar Swaminathan 
270982527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
271082527734SSukumar Swaminathan 	}
271182527734SSukumar Swaminathan 
2712fcf3ce44SJohn Forte 	return (abort.q_cnt);
2713fcf3ce44SJohn Forte 
271482527734SSukumar Swaminathan } /* emlxs_tx_node_flush() */
2715fcf3ce44SJohn Forte 
2716fcf3ce44SJohn Forte 
2717fcf3ce44SJohn Forte /* Check for IO's on all or a given ring for a given node */
2718fcf3ce44SJohn Forte extern uint32_t
271982527734SSukumar Swaminathan emlxs_tx_node_check(emlxs_port_t *port, NODELIST *ndlp, CHANNEL *chan)
2720fcf3ce44SJohn Forte {
2721fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
272282527734SSukumar Swaminathan 	uint32_t channelno;
272382527734SSukumar Swaminathan 	CHANNEL *cp;
2724fcf3ce44SJohn Forte 	uint32_t count;
2725fcf3ce44SJohn Forte 
2726fcf3ce44SJohn Forte 	count = 0;
2727fcf3ce44SJohn Forte 
2728fcf3ce44SJohn Forte 	/* Flush all I/O's on tx queue to this target */
272982527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2730fcf3ce44SJohn Forte 
273182527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
273282527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
2733fcf3ce44SJohn Forte 
273482527734SSukumar Swaminathan 		if (chan && cp != chan) {
2735fcf3ce44SJohn Forte 			continue;
2736fcf3ce44SJohn Forte 		}
2737291a2b48SSukumar Swaminathan 
2738fcf3ce44SJohn Forte 		/* Check if priority queue is not empty */
273982527734SSukumar Swaminathan 		if (ndlp->nlp_ptx[channelno].q_first) {
274082527734SSukumar Swaminathan 			count += ndlp->nlp_ptx[channelno].q_cnt;
2741fcf3ce44SJohn Forte 		}
2742291a2b48SSukumar Swaminathan 
2743fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
274482527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
274582527734SSukumar Swaminathan 			count += ndlp->nlp_tx[channelno].q_cnt;
2746fcf3ce44SJohn Forte 		}
2747291a2b48SSukumar Swaminathan 
2748fcf3ce44SJohn Forte 	}
2749fcf3ce44SJohn Forte 
275082527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2751fcf3ce44SJohn Forte 
2752fcf3ce44SJohn Forte 	return (count);
2753fcf3ce44SJohn Forte 
275482527734SSukumar Swaminathan } /* emlxs_tx_node_check() */
2755fcf3ce44SJohn Forte 
2756fcf3ce44SJohn Forte 
2757fcf3ce44SJohn Forte 
275882527734SSukumar Swaminathan /* Flush all IO's on the any ring for a given node's lun */
2759fcf3ce44SJohn Forte extern uint32_t
2760291a2b48SSukumar Swaminathan emlxs_tx_lun_flush(emlxs_port_t *port, NODELIST *ndlp, uint32_t lun,
2761291a2b48SSukumar Swaminathan     emlxs_buf_t *fpkt)
2762fcf3ce44SJohn Forte {
2763fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2764fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
276582527734SSukumar Swaminathan 	uint32_t channelno;
2766fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2767fcf3ce44SJohn Forte 	IOCBQ *prev;
2768fcf3ce44SJohn Forte 	IOCBQ *next;
2769fcf3ce44SJohn Forte 	IOCB *iocb;
2770fcf3ce44SJohn Forte 	IOCB *icmd;
2771fcf3ce44SJohn Forte 	Q abort;
2772fcf3ce44SJohn Forte 	uint32_t i;
2773fcf3ce44SJohn Forte 	MATCHMAP *mp;
277482527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2775fcf3ce44SJohn Forte 
2776a9800bebSGarrett D'Amore 	if (lun == EMLXS_LUN_NONE) {
2777a9800bebSGarrett D'Amore 		return (0);
2778a9800bebSGarrett D'Amore 	}
2779a9800bebSGarrett D'Amore 
2780fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
2781fcf3ce44SJohn Forte 
2782fcf3ce44SJohn Forte 	/* Flush I/O's on txQ to this target's lun */
278382527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2784fcf3ce44SJohn Forte 
278582527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
2786291a2b48SSukumar Swaminathan 
278782527734SSukumar Swaminathan 		/* Scan the priority queue first */
278882527734SSukumar Swaminathan 		prev = NULL;
278982527734SSukumar Swaminathan 		iocbq = (IOCBQ *) ndlp->nlp_ptx[channelno].q_first;
2790fcf3ce44SJohn Forte 
279182527734SSukumar Swaminathan 		while (iocbq) {
279282527734SSukumar Swaminathan 			next = (IOCBQ *)iocbq->next;
279382527734SSukumar Swaminathan 			iocb = &iocbq->iocb;
279482527734SSukumar Swaminathan 			sbp = (emlxs_buf_t *)iocbq->sbp;
279582527734SSukumar Swaminathan 
279682527734SSukumar Swaminathan 			/* Check if this IO is for our lun */
279782527734SSukumar Swaminathan 			if (sbp && (sbp->lun == lun)) {
279882527734SSukumar Swaminathan 				/* Remove iocb from the node's ptx queue */
279982527734SSukumar Swaminathan 				if (next == 0) {
280082527734SSukumar Swaminathan 					ndlp->nlp_ptx[channelno].q_last =
280182527734SSukumar Swaminathan 					    (uint8_t *)prev;
280282527734SSukumar Swaminathan 				}
280382527734SSukumar Swaminathan 
280482527734SSukumar Swaminathan 				if (prev == 0) {
280582527734SSukumar Swaminathan 					ndlp->nlp_ptx[channelno].q_first =
280682527734SSukumar Swaminathan 					    (uint8_t *)next;
280782527734SSukumar Swaminathan 				} else {
280882527734SSukumar Swaminathan 					prev->next = next;
280982527734SSukumar Swaminathan 				}
281082527734SSukumar Swaminathan 
281182527734SSukumar Swaminathan 				iocbq->next = NULL;
281282527734SSukumar Swaminathan 				ndlp->nlp_ptx[channelno].q_cnt--;
281382527734SSukumar Swaminathan 
281482527734SSukumar Swaminathan 				/*
281582527734SSukumar Swaminathan 				 * Add this iocb to our local abort Q
281682527734SSukumar Swaminathan 				 */
281782527734SSukumar Swaminathan 				if (abort.q_first) {
281882527734SSukumar Swaminathan 					((IOCBQ *)abort.q_last)->next = iocbq;
281982527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
282082527734SSukumar Swaminathan 					abort.q_cnt++;
282182527734SSukumar Swaminathan 				} else {
282282527734SSukumar Swaminathan 					abort.q_first = (uint8_t *)iocbq;
282382527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
282482527734SSukumar Swaminathan 					abort.q_cnt = 1;
282582527734SSukumar Swaminathan 				}
282682527734SSukumar Swaminathan 				iocbq->next = NULL;
282782527734SSukumar Swaminathan 				flag[channelno] = 1;
2828fcf3ce44SJohn Forte 
2829fcf3ce44SJohn Forte 			} else {
283082527734SSukumar Swaminathan 				prev = iocbq;
2831fcf3ce44SJohn Forte 			}
2832fcf3ce44SJohn Forte 
283382527734SSukumar Swaminathan 			iocbq = next;
2834fcf3ce44SJohn Forte 
283582527734SSukumar Swaminathan 		}	/* while (iocbq) */
2836fcf3ce44SJohn Forte 
2837fcf3ce44SJohn Forte 
283882527734SSukumar Swaminathan 		/* Scan the regular queue */
283982527734SSukumar Swaminathan 		prev = NULL;
284082527734SSukumar Swaminathan 		iocbq = (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2841fcf3ce44SJohn Forte 
284282527734SSukumar Swaminathan 		while (iocbq) {
284382527734SSukumar Swaminathan 			next = (IOCBQ *)iocbq->next;
284482527734SSukumar Swaminathan 			iocb = &iocbq->iocb;
284582527734SSukumar Swaminathan 			sbp = (emlxs_buf_t *)iocbq->sbp;
284682527734SSukumar Swaminathan 
284782527734SSukumar Swaminathan 			/* Check if this IO is for our lun */
284882527734SSukumar Swaminathan 			if (sbp && (sbp->lun == lun)) {
284982527734SSukumar Swaminathan 				/* Remove iocb from the node's tx queue */
285082527734SSukumar Swaminathan 				if (next == 0) {
285182527734SSukumar Swaminathan 					ndlp->nlp_tx[channelno].q_last =
285282527734SSukumar Swaminathan 					    (uint8_t *)prev;
285382527734SSukumar Swaminathan 				}
2854291a2b48SSukumar Swaminathan 
285582527734SSukumar Swaminathan 				if (prev == 0) {
285682527734SSukumar Swaminathan 					ndlp->nlp_tx[channelno].q_first =
285782527734SSukumar Swaminathan 					    (uint8_t *)next;
285882527734SSukumar Swaminathan 				} else {
285982527734SSukumar Swaminathan 					prev->next = next;
286082527734SSukumar Swaminathan 				}
2861fcf3ce44SJohn Forte 
286282527734SSukumar Swaminathan 				iocbq->next = NULL;
286382527734SSukumar Swaminathan 				ndlp->nlp_tx[channelno].q_cnt--;
2864fcf3ce44SJohn Forte 
286582527734SSukumar Swaminathan 				/*
286682527734SSukumar Swaminathan 				 * Add this iocb to our local abort Q
286782527734SSukumar Swaminathan 				 */
286882527734SSukumar Swaminathan 				if (abort.q_first) {
286982527734SSukumar Swaminathan 					((IOCBQ *) abort.q_last)->next = iocbq;
287082527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
287182527734SSukumar Swaminathan 					abort.q_cnt++;
287282527734SSukumar Swaminathan 				} else {
287382527734SSukumar Swaminathan 					abort.q_first = (uint8_t *)iocbq;
287482527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
287582527734SSukumar Swaminathan 					abort.q_cnt = 1;
287682527734SSukumar Swaminathan 				}
287782527734SSukumar Swaminathan 				iocbq->next = NULL;
2878fcf3ce44SJohn Forte 			} else {
287982527734SSukumar Swaminathan 				prev = iocbq;
2880fcf3ce44SJohn Forte 			}
2881fcf3ce44SJohn Forte 
288282527734SSukumar Swaminathan 			iocbq = next;
2883fcf3ce44SJohn Forte 
288482527734SSukumar Swaminathan 		}	/* while (iocbq) */
288582527734SSukumar Swaminathan 	}	/* for loop */
2886fcf3ce44SJohn Forte 
2887fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2888fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2889fcf3ce44SJohn Forte 	while (iocbq) {
2890fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2891fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
289282527734SSukumar Swaminathan 
289382527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
289482527734SSukumar Swaminathan 			sbp = iocbq->sbp;
289582527734SSukumar Swaminathan 			if (sbp) {
28968f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
289782527734SSukumar Swaminathan 			}
289882527734SSukumar Swaminathan 		} else {
289982527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
290082527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
290182527734SSukumar Swaminathan 		}
2902fcf3ce44SJohn Forte 
2903fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2904fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2905fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2906fcf3ce44SJohn Forte 			/*
2907fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2908291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2909291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2910fcf3ce44SJohn Forte 			 */
2911fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2912fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2913fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2914fcf3ce44SJohn Forte 				fpkt->flush_count++;
2915fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2916fcf3ce44SJohn Forte 			}
2917291a2b48SSukumar Swaminathan 
2918fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2919fcf3ce44SJohn Forte 		}
2920291a2b48SSukumar Swaminathan 
2921291a2b48SSukumar Swaminathan 		iocbq = (IOCBQ *) iocbq->next;
2922fcf3ce44SJohn Forte 
2923fcf3ce44SJohn Forte 	}	/* end of while */
2924fcf3ce44SJohn Forte 
292582527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2926fcf3ce44SJohn Forte 
2927fcf3ce44SJohn Forte 	/* Now abort the iocb's outside the locks */
2928fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2929fcf3ce44SJohn Forte 	while (iocbq) {
2930fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2931fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2932fcf3ce44SJohn Forte 
2933fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2934fcf3ce44SJohn Forte 		iocbq->next = NULL;
2935fcf3ce44SJohn Forte 
2936fcf3ce44SJohn Forte 		/* Get the pkt */
2937fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2938fcf3ce44SJohn Forte 
2939fcf3ce44SJohn Forte 		if (sbp) {
2940fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2941291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2942fcf3ce44SJohn Forte 
2943fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2944fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2945fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2946fcf3ce44SJohn Forte 			} else {
2947fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2948fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2949fcf3ce44SJohn Forte 			}
2950fcf3ce44SJohn Forte 		}
2951291a2b48SSukumar Swaminathan 
2952fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2953fcf3ce44SJohn Forte 		else {
295482527734SSukumar Swaminathan 			/* Should never happen! */
2955fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
2956fcf3ce44SJohn Forte 
295782527734SSukumar Swaminathan 			/* SLI3 */
295882527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
295982527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
296082527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2961fcf3ce44SJohn Forte 				if ((hba->flag &
2962fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2963fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
296482527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2965fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2966a9800bebSGarrett D'Amore 						void	*tmp;
296782527734SSukumar Swaminathan 						RING *rp;
296882527734SSukumar Swaminathan 						int ch;
2969fcf3ce44SJohn Forte 
297082527734SSukumar Swaminathan 						ch = ((CHANNEL *)
297182527734SSukumar Swaminathan 						    iocbq->channel)->channelno;
297282527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
2973fcf3ce44SJohn Forte 						for (i = 0;
297482527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2975fcf3ce44SJohn Forte 						    i++) {
2976fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2977fcf3ce44SJohn Forte 							    hba, rp, icmd);
2978fcf3ce44SJohn Forte 
2979a9800bebSGarrett D'Amore 							tmp = (void *)mp;
2980fcf3ce44SJohn Forte 							if (mp) {
2981a9800bebSGarrett D'Amore 							emlxs_mem_put(
2982291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2983fcf3ce44SJohn Forte 							}
2984fcf3ce44SJohn Forte 						}
2985fcf3ce44SJohn Forte 					}
2986291a2b48SSukumar Swaminathan 
2987a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
2988a9800bebSGarrett D'Amore 					    (void *)iocbq);
2989fcf3ce44SJohn Forte 				} else {
2990fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
299182527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
299282527734SSukumar Swaminathan 					    (CHANNEL *)iocbq->channel, iocbq);
2993fcf3ce44SJohn Forte 				}
299482527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
299582527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
299682527734SSukumar Swaminathan 				/*
299782527734SSukumar Swaminathan 				 * Resend the abort iocbq if any
299882527734SSukumar Swaminathan 				 */
299982527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
3000fcf3ce44SJohn Forte 			}
3001fcf3ce44SJohn Forte 		}
3002fcf3ce44SJohn Forte 
3003fcf3ce44SJohn Forte 		iocbq = next;
3004fcf3ce44SJohn Forte 
3005fcf3ce44SJohn Forte 	}	/* end of while */
3006fcf3ce44SJohn Forte 
300782527734SSukumar Swaminathan 	/* Now trigger channel service */
300882527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
300982527734SSukumar Swaminathan 		if (!flag[channelno]) {
301082527734SSukumar Swaminathan 			continue;
301182527734SSukumar Swaminathan 		}
301282527734SSukumar Swaminathan 
301382527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
301482527734SSukumar Swaminathan 	}
3015fcf3ce44SJohn Forte 
3016fcf3ce44SJohn Forte 	return (abort.q_cnt);
3017fcf3ce44SJohn Forte 
301882527734SSukumar Swaminathan } /* emlxs_tx_lun_flush() */
3019fcf3ce44SJohn Forte 
3020fcf3ce44SJohn Forte 
3021fcf3ce44SJohn Forte extern void
3022fcf3ce44SJohn Forte emlxs_tx_put(IOCBQ *iocbq, uint32_t lock)
3023fcf3ce44SJohn Forte {
3024fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
3025fcf3ce44SJohn Forte 	emlxs_port_t *port;
302682527734SSukumar Swaminathan 	uint32_t channelno;
3027fcf3ce44SJohn Forte 	NODELIST *nlp;
302882527734SSukumar Swaminathan 	CHANNEL *cp;
3029fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3030fcf3ce44SJohn Forte 
3031fcf3ce44SJohn Forte 	port = (emlxs_port_t *)iocbq->port;
3032fcf3ce44SJohn Forte 	hba = HBA;
303382527734SSukumar Swaminathan 	cp = (CHANNEL *)iocbq->channel;
3034fcf3ce44SJohn Forte 	nlp = (NODELIST *)iocbq->node;
303582527734SSukumar Swaminathan 	channelno = cp->channelno;
3036fcf3ce44SJohn Forte 	sbp = (emlxs_buf_t *)iocbq->sbp;
3037fcf3ce44SJohn Forte 
3038fcf3ce44SJohn Forte 	if (nlp == NULL) {
3039fcf3ce44SJohn Forte 		/* Set node to base node by default */
3040fcf3ce44SJohn Forte 		nlp = &port->node_base;
3041fcf3ce44SJohn Forte 
3042fcf3ce44SJohn Forte 		iocbq->node = (void *)nlp;
3043fcf3ce44SJohn Forte 
3044fcf3ce44SJohn Forte 		if (sbp) {
3045fcf3ce44SJohn Forte 			sbp->node = (void *)nlp;
3046fcf3ce44SJohn Forte 		}
3047fcf3ce44SJohn Forte 	}
3048291a2b48SSukumar Swaminathan 
3049fcf3ce44SJohn Forte 	if (lock) {
305082527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
3051fcf3ce44SJohn Forte 	}
3052291a2b48SSukumar Swaminathan 
3053fcf3ce44SJohn Forte 	if (!nlp->nlp_active || (sbp && (sbp->pkt_flags & PACKET_IN_ABORT))) {
3054fcf3ce44SJohn Forte 		if (sbp) {
3055fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
3056fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
3057fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3058fcf3ce44SJohn Forte 
305982527734SSukumar Swaminathan 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
30608f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
306182527734SSukumar Swaminathan 			} else {
306282527734SSukumar Swaminathan 				(void) emlxs_unregister_pkt(cp, sbp->iotag, 0);
306382527734SSukumar Swaminathan 			}
3064fcf3ce44SJohn Forte 
3065fcf3ce44SJohn Forte 			if (lock) {
306682527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3067fcf3ce44SJohn Forte 			}
3068291a2b48SSukumar Swaminathan 
3069fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
3070fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
3071fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
3072fcf3ce44SJohn Forte 			} else {
3073fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
3074fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
3075fcf3ce44SJohn Forte 			}
3076fcf3ce44SJohn Forte 			return;
3077fcf3ce44SJohn Forte 		} else {
3078fcf3ce44SJohn Forte 			if (lock) {
307982527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3080fcf3ce44SJohn Forte 			}
3081291a2b48SSukumar Swaminathan 
3082a9800bebSGarrett D'Amore 			emlxs_mem_put(hba, MEM_IOCB, (void *)iocbq);
3083fcf3ce44SJohn Forte 		}
3084fcf3ce44SJohn Forte 
3085fcf3ce44SJohn Forte 		return;
3086fcf3ce44SJohn Forte 	}
3087291a2b48SSukumar Swaminathan 
3088fcf3ce44SJohn Forte 	if (sbp) {
3089fcf3ce44SJohn Forte 
3090fcf3ce44SJohn Forte 		mutex_enter(&sbp->mtx);
3091fcf3ce44SJohn Forte 
3092291a2b48SSukumar Swaminathan 		if (sbp->pkt_flags &
3093291a2b48SSukumar Swaminathan 		    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ | PACKET_IN_TXQ)) {
3094fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3095fcf3ce44SJohn Forte 			if (lock) {
309682527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3097fcf3ce44SJohn Forte 			}
3098fcf3ce44SJohn Forte 			return;
3099fcf3ce44SJohn Forte 		}
3100291a2b48SSukumar Swaminathan 
3101fcf3ce44SJohn Forte 		sbp->pkt_flags |= PACKET_IN_TXQ;
310282527734SSukumar Swaminathan 		hba->channel_tx_count++;
3103fcf3ce44SJohn Forte 
3104fcf3ce44SJohn Forte 		mutex_exit(&sbp->mtx);
3105fcf3ce44SJohn Forte 	}
3106291a2b48SSukumar Swaminathan 
3107291a2b48SSukumar Swaminathan 
3108fcf3ce44SJohn Forte 	/* Check iocbq priority */
310982527734SSukumar Swaminathan 	/* Some IOCB has the high priority like reset/close xri etc */
3110fcf3ce44SJohn Forte 	if (iocbq->flag & IOCB_PRIORITY) {
3111fcf3ce44SJohn Forte 		/* Add the iocb to the bottom of the node's ptx queue */
311282527734SSukumar Swaminathan 		if (nlp->nlp_ptx[channelno].q_first) {
311382527734SSukumar Swaminathan 			((IOCBQ *)nlp->nlp_ptx[channelno].q_last)->next = iocbq;
311482527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_last = (uint8_t *)iocbq;
311582527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_cnt++;
3116fcf3ce44SJohn Forte 		} else {
311782527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_first = (uint8_t *)iocbq;
311882527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_last = (uint8_t *)iocbq;
311982527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_cnt = 1;
3120fcf3ce44SJohn Forte 		}
3121fcf3ce44SJohn Forte 
3122fcf3ce44SJohn Forte 		iocbq->next = NULL;
3123fcf3ce44SJohn Forte 	} else {	/* Normal priority */
3124fcf3ce44SJohn Forte 
3125291a2b48SSukumar Swaminathan 
3126fcf3ce44SJohn Forte 		/* Add the iocb to the bottom of the node's tx queue */
312782527734SSukumar Swaminathan 		if (nlp->nlp_tx[channelno].q_first) {
312882527734SSukumar Swaminathan 			((IOCBQ *)nlp->nlp_tx[channelno].q_last)->next = iocbq;
312982527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_last = (uint8_t *)iocbq;
313082527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_cnt++;
3131fcf3ce44SJohn Forte 		} else {
313282527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_first = (uint8_t *)iocbq;
313382527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_last = (uint8_t *)iocbq;
313482527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_cnt = 1;
3135fcf3ce44SJohn Forte 		}
3136fcf3ce44SJohn Forte 
3137fcf3ce44SJohn Forte 		iocbq->next = NULL;
3138fcf3ce44SJohn Forte 	}
3139fcf3ce44SJohn Forte 
3140fcf3ce44SJohn Forte 
3141fcf3ce44SJohn Forte 	/*
314282527734SSukumar Swaminathan 	 * Check if the node is not already on channel queue and
3143291a2b48SSukumar Swaminathan 	 * (is not closed or  is a priority request)
3144fcf3ce44SJohn Forte 	 */
314582527734SSukumar Swaminathan 	if (!nlp->nlp_next[channelno] &&
314682527734SSukumar Swaminathan 	    (!(nlp->nlp_flag[channelno] & NLP_CLOSED) ||
3147fcf3ce44SJohn Forte 	    (iocbq->flag & IOCB_PRIORITY))) {
314882527734SSukumar Swaminathan 		/* If so, then add it to the channel queue */
314982527734SSukumar Swaminathan 		if (cp->nodeq.q_first) {
315082527734SSukumar Swaminathan 			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
3151fcf3ce44SJohn Forte 			    (uint8_t *)nlp;
315282527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = cp->nodeq.q_first;
3153fcf3ce44SJohn Forte 
3154fcf3ce44SJohn Forte 			/*
3155291a2b48SSukumar Swaminathan 			 * If this is not the base node then add it
3156291a2b48SSukumar Swaminathan 			 * to the tail
3157fcf3ce44SJohn Forte 			 */
3158fcf3ce44SJohn Forte 			if (!nlp->nlp_base) {
315982527734SSukumar Swaminathan 				cp->nodeq.q_last = (uint8_t *)nlp;
3160fcf3ce44SJohn Forte 			} else {	/* Otherwise, add it to the head */
3161291a2b48SSukumar Swaminathan 
3162fcf3ce44SJohn Forte 				/* The command node always gets priority */
316382527734SSukumar Swaminathan 				cp->nodeq.q_first = (uint8_t *)nlp;
3164fcf3ce44SJohn Forte 			}
3165fcf3ce44SJohn Forte 
316682527734SSukumar Swaminathan 			cp->nodeq.q_cnt++;
3167fcf3ce44SJohn Forte 		} else {
316882527734SSukumar Swaminathan 			cp->nodeq.q_first = (uint8_t *)nlp;
316982527734SSukumar Swaminathan 			cp->nodeq.q_last = (uint8_t *)nlp;
317082527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = nlp;
317182527734SSukumar Swaminathan 			cp->nodeq.q_cnt = 1;
3172fcf3ce44SJohn Forte 		}
3173fcf3ce44SJohn Forte 	}
3174291a2b48SSukumar Swaminathan 
317582527734SSukumar Swaminathan 	HBASTATS.IocbTxPut[channelno]++;
3176fcf3ce44SJohn Forte 
317782527734SSukumar Swaminathan 	/* Adjust the channel timeout timer */
317882527734SSukumar Swaminathan 	cp->timeout = hba->timer_tics + 5;
3179fcf3ce44SJohn Forte 
3180fcf3ce44SJohn Forte 	if (lock) {
318182527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3182fcf3ce44SJohn Forte 	}
3183291a2b48SSukumar Swaminathan 
3184fcf3ce44SJohn Forte 	return;
3185fcf3ce44SJohn Forte 
318682527734SSukumar Swaminathan } /* emlxs_tx_put() */
3187fcf3ce44SJohn Forte 
3188fcf3ce44SJohn Forte 
3189fcf3ce44SJohn Forte extern IOCBQ *
319082527734SSukumar Swaminathan emlxs_tx_get(CHANNEL *cp, uint32_t lock)
3191fcf3ce44SJohn Forte {
3192fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
319382527734SSukumar Swaminathan 	uint32_t channelno;
3194fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3195fcf3ce44SJohn Forte 	NODELIST *nlp;
3196fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3197fcf3ce44SJohn Forte 
319882527734SSukumar Swaminathan 	hba = cp->hba;
319982527734SSukumar Swaminathan 	channelno = cp->channelno;
3200fcf3ce44SJohn Forte 
3201fcf3ce44SJohn Forte 	if (lock) {
320282527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
3203fcf3ce44SJohn Forte 	}
3204291a2b48SSukumar Swaminathan 
3205fcf3ce44SJohn Forte begin:
3206fcf3ce44SJohn Forte 
3207fcf3ce44SJohn Forte 	iocbq = NULL;
3208fcf3ce44SJohn Forte 
3209fcf3ce44SJohn Forte 	/* Check if a node needs servicing */
321082527734SSukumar Swaminathan 	if (cp->nodeq.q_first) {
321182527734SSukumar Swaminathan 		nlp = (NODELIST *)cp->nodeq.q_first;
3212fcf3ce44SJohn Forte 
3213fcf3ce44SJohn Forte 		/* Get next iocb from node's priority queue */
3214fcf3ce44SJohn Forte 
321582527734SSukumar Swaminathan 		if (nlp->nlp_ptx[channelno].q_first) {
321682527734SSukumar Swaminathan 			iocbq = (IOCBQ *)nlp->nlp_ptx[channelno].q_first;
3217fcf3ce44SJohn Forte 
3218fcf3ce44SJohn Forte 			/* Check if this is last entry */
321982527734SSukumar Swaminathan 			if (nlp->nlp_ptx[channelno].q_last == (void *)iocbq) {
322082527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_first = NULL;
322182527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_last = NULL;
322282527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_cnt = 0;
3223fcf3ce44SJohn Forte 			} else {
3224fcf3ce44SJohn Forte 				/* Remove iocb from head */
322582527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_first =
3226fcf3ce44SJohn Forte 				    (void *)iocbq->next;
322782527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_cnt--;
3228fcf3ce44SJohn Forte 			}
3229fcf3ce44SJohn Forte 
3230fcf3ce44SJohn Forte 			iocbq->next = NULL;
3231fcf3ce44SJohn Forte 		}
3232291a2b48SSukumar Swaminathan 
3233fcf3ce44SJohn Forte 		/* Get next iocb from node tx queue if node not closed */
323482527734SSukumar Swaminathan 		else if (nlp->nlp_tx[channelno].q_first &&
323582527734SSukumar Swaminathan 		    !(nlp->nlp_flag[channelno] & NLP_CLOSED)) {
323682527734SSukumar Swaminathan 			iocbq = (IOCBQ *)nlp->nlp_tx[channelno].q_first;
3237fcf3ce44SJohn Forte 
3238fcf3ce44SJohn Forte 			/* Check if this is last entry */
323982527734SSukumar Swaminathan 			if (nlp->nlp_tx[channelno].q_last == (void *)iocbq) {
324082527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_first = NULL;
324182527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_last = NULL;
324282527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_cnt = 0;
3243fcf3ce44SJohn Forte 			} else {
3244fcf3ce44SJohn Forte 				/* Remove iocb from head */
324582527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_first =
3246fcf3ce44SJohn Forte 				    (void *)iocbq->next;
324782527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_cnt--;
3248fcf3ce44SJohn Forte 			}
3249fcf3ce44SJohn Forte 
3250fcf3ce44SJohn Forte 			iocbq->next = NULL;
3251fcf3ce44SJohn Forte 		}
3252291a2b48SSukumar Swaminathan 
3253fcf3ce44SJohn Forte 		/* Now deal with node itself */
3254fcf3ce44SJohn Forte 
3255fcf3ce44SJohn Forte 		/* Check if node still needs servicing */
325682527734SSukumar Swaminathan 		if ((nlp->nlp_ptx[channelno].q_first) ||
325782527734SSukumar Swaminathan 		    (nlp->nlp_tx[channelno].q_first &&
325882527734SSukumar Swaminathan 		    !(nlp->nlp_flag[channelno] & NLP_CLOSED))) {
3259fcf3ce44SJohn Forte 
3260fcf3ce44SJohn Forte 			/*
3261fcf3ce44SJohn Forte 			 * If this is the base node, then don't shift the
3262291a2b48SSukumar Swaminathan 			 * pointers. We want to drain the base node before
3263291a2b48SSukumar Swaminathan 			 * moving on
3264fcf3ce44SJohn Forte 			 */
3265fcf3ce44SJohn Forte 			if (!nlp->nlp_base) {
3266fcf3ce44SJohn Forte 				/*
326782527734SSukumar Swaminathan 				 * Just shift channel queue pointers to next
3268fcf3ce44SJohn Forte 				 * node
3269fcf3ce44SJohn Forte 				 */
327082527734SSukumar Swaminathan 				cp->nodeq.q_last = (void *)nlp;
327182527734SSukumar Swaminathan 				cp->nodeq.q_first = nlp->nlp_next[channelno];
3272fcf3ce44SJohn Forte 			}
3273fcf3ce44SJohn Forte 		} else {
327482527734SSukumar Swaminathan 			/* Remove node from channel queue */
3275fcf3ce44SJohn Forte 
3276fcf3ce44SJohn Forte 			/* If this is the last node on list */
327782527734SSukumar Swaminathan 			if (cp->nodeq.q_last == (void *)nlp) {
327882527734SSukumar Swaminathan 				cp->nodeq.q_last = NULL;
327982527734SSukumar Swaminathan 				cp->nodeq.q_first = NULL;
328082527734SSukumar Swaminathan 				cp->nodeq.q_cnt = 0;
3281fcf3ce44SJohn Forte 			} else {
3282fcf3ce44SJohn Forte 				/* Remove node from head */
328382527734SSukumar Swaminathan 				cp->nodeq.q_first = nlp->nlp_next[channelno];
328482527734SSukumar Swaminathan 				((NODELIST *)cp->nodeq.q_last)->
328582527734SSukumar Swaminathan 				    nlp_next[channelno] = cp->nodeq.q_first;
328682527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
3287fcf3ce44SJohn Forte 
3288fcf3ce44SJohn Forte 			}
3289fcf3ce44SJohn Forte 
3290fcf3ce44SJohn Forte 			/* Clear node */
329182527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = NULL;
3292fcf3ce44SJohn Forte 		}
3293fcf3ce44SJohn Forte 
3294fcf3ce44SJohn Forte 		/*
3295291a2b48SSukumar Swaminathan 		 * If no iocbq was found on this node, then it will have
3296291a2b48SSukumar Swaminathan 		 * been removed. So try again.
3297fcf3ce44SJohn Forte 		 */
3298fcf3ce44SJohn Forte 		if (!iocbq) {
3299fcf3ce44SJohn Forte 			goto begin;
3300fcf3ce44SJohn Forte 		}
3301291a2b48SSukumar Swaminathan 
3302fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
3303fcf3ce44SJohn Forte 
3304fcf3ce44SJohn Forte 		if (sbp) {
3305fcf3ce44SJohn Forte 			/*
3306291a2b48SSukumar Swaminathan 			 * Check flags before we enter mutex in case this
3307291a2b48SSukumar Swaminathan 			 * has been flushed and destroyed
3308fcf3ce44SJohn Forte 			 */
3309fcf3ce44SJohn Forte 			if ((sbp->pkt_flags &
3310fcf3ce44SJohn Forte 			    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) ||
3311fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_IN_TXQ)) {
3312fcf3ce44SJohn Forte 				goto begin;
3313fcf3ce44SJohn Forte 			}
3314291a2b48SSukumar Swaminathan 
3315fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
3316fcf3ce44SJohn Forte 
3317fcf3ce44SJohn Forte 			if ((sbp->pkt_flags &
3318fcf3ce44SJohn Forte 			    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) ||
3319fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_IN_TXQ)) {
3320fcf3ce44SJohn Forte 				mutex_exit(&sbp->mtx);
3321fcf3ce44SJohn Forte 				goto begin;
3322fcf3ce44SJohn Forte 			}
3323291a2b48SSukumar Swaminathan 
3324fcf3ce44SJohn Forte 			sbp->pkt_flags &= ~PACKET_IN_TXQ;
332582527734SSukumar Swaminathan 			hba->channel_tx_count--;
3326fcf3ce44SJohn Forte 
3327fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3328fcf3ce44SJohn Forte 		}
3329fcf3ce44SJohn Forte 	}
3330291a2b48SSukumar Swaminathan 
3331fcf3ce44SJohn Forte 	if (iocbq) {
333282527734SSukumar Swaminathan 		HBASTATS.IocbTxGet[channelno]++;
3333fcf3ce44SJohn Forte 	}
3334291a2b48SSukumar Swaminathan 
3335fcf3ce44SJohn Forte 	/* Adjust the ring timeout timer */
333682527734SSukumar Swaminathan 	cp->timeout = (cp->nodeq.q_first) ? (hba->timer_tics + 5) : 0;
3337fcf3ce44SJohn Forte 
3338fcf3ce44SJohn Forte 	if (lock) {
333982527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3340fcf3ce44SJohn Forte 	}
3341291a2b48SSukumar Swaminathan 
3342fcf3ce44SJohn Forte 	return (iocbq);
3343fcf3ce44SJohn Forte 
334482527734SSukumar Swaminathan } /* emlxs_tx_get() */
334582527734SSukumar Swaminathan 
3346fcf3ce44SJohn Forte 
334782527734SSukumar Swaminathan /*
334882527734SSukumar Swaminathan  * Remove all cmd from from_rp's txq to to_rp's txq for ndlp.
334982527734SSukumar Swaminathan  * The old IoTag has to be released, the new one has to be
335082527734SSukumar Swaminathan  * allocated.  Others no change
335182527734SSukumar Swaminathan  * TX_CHANNEL lock is held
335282527734SSukumar Swaminathan  */
335382527734SSukumar Swaminathan extern void
335482527734SSukumar Swaminathan emlxs_tx_move(NODELIST *ndlp, CHANNEL *from_chan, CHANNEL *to_chan,
335582527734SSukumar Swaminathan     uint32_t cmd, emlxs_buf_t *fpkt, uint32_t lock)
335682527734SSukumar Swaminathan {
335782527734SSukumar Swaminathan 	emlxs_hba_t *hba;
335882527734SSukumar Swaminathan 	emlxs_port_t *port;
335982527734SSukumar Swaminathan 	uint32_t fchanno, tchanno, i;
336082527734SSukumar Swaminathan 
336182527734SSukumar Swaminathan 	IOCBQ *iocbq;
336282527734SSukumar Swaminathan 	IOCBQ *prev;
336382527734SSukumar Swaminathan 	IOCBQ *next;
336482527734SSukumar Swaminathan 	IOCB *iocb, *icmd;
336582527734SSukumar Swaminathan 	Q tbm;		/* To Be Moved Q */
336682527734SSukumar Swaminathan 	MATCHMAP *mp;
336782527734SSukumar Swaminathan 
336882527734SSukumar Swaminathan 	NODELIST *nlp = ndlp;
336982527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
337082527734SSukumar Swaminathan 
337182527734SSukumar Swaminathan 	NODELIST *n_prev = NULL;
337282527734SSukumar Swaminathan 	NODELIST *n_next = NULL;
337382527734SSukumar Swaminathan 	uint16_t count = 0;
337482527734SSukumar Swaminathan 
337582527734SSukumar Swaminathan 	hba = from_chan->hba;
337682527734SSukumar Swaminathan 	port = &PPORT;
337782527734SSukumar Swaminathan 	cmd = cmd; /* To pass lint */
337882527734SSukumar Swaminathan 
337982527734SSukumar Swaminathan 	fchanno = from_chan->channelno;
338082527734SSukumar Swaminathan 	tchanno = to_chan->channelno;
338182527734SSukumar Swaminathan 
338282527734SSukumar Swaminathan 	if (lock) {
338382527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
338482527734SSukumar Swaminathan 	}
338582527734SSukumar Swaminathan 
338682527734SSukumar Swaminathan 	bzero((void *)&tbm, sizeof (Q));
338782527734SSukumar Swaminathan 
338882527734SSukumar Swaminathan 	/* Scan the ndlp's fchanno txq to get the iocb of fcp cmd */
338982527734SSukumar Swaminathan 	prev = NULL;
339082527734SSukumar Swaminathan 	iocbq = (IOCBQ *)nlp->nlp_tx[fchanno].q_first;
339182527734SSukumar Swaminathan 
339282527734SSukumar Swaminathan 	while (iocbq) {
339382527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
339482527734SSukumar Swaminathan 		/* Check if this iocb is fcp cmd */
339582527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
339682527734SSukumar Swaminathan 
339782527734SSukumar Swaminathan 		switch (iocb->ULPCOMMAND) {
339882527734SSukumar Swaminathan 		/* FCP commands */
339982527734SSukumar Swaminathan 		case CMD_FCP_ICMND_CR:
340082527734SSukumar Swaminathan 		case CMD_FCP_ICMND_CX:
340182527734SSukumar Swaminathan 		case CMD_FCP_IREAD_CR:
340282527734SSukumar Swaminathan 		case CMD_FCP_IREAD_CX:
340382527734SSukumar Swaminathan 		case CMD_FCP_IWRITE_CR:
340482527734SSukumar Swaminathan 		case CMD_FCP_IWRITE_CX:
340582527734SSukumar Swaminathan 		case CMD_FCP_ICMND64_CR:
340682527734SSukumar Swaminathan 		case CMD_FCP_ICMND64_CX:
340782527734SSukumar Swaminathan 		case CMD_FCP_IREAD64_CR:
340882527734SSukumar Swaminathan 		case CMD_FCP_IREAD64_CX:
340982527734SSukumar Swaminathan 		case CMD_FCP_IWRITE64_CR:
341082527734SSukumar Swaminathan 		case CMD_FCP_IWRITE64_CX:
341182527734SSukumar Swaminathan 			/* We found a fcp cmd */
341282527734SSukumar Swaminathan 			break;
341382527734SSukumar Swaminathan 		default:
341482527734SSukumar Swaminathan 			/* this is not fcp cmd continue */
341582527734SSukumar Swaminathan 			prev = iocbq;
341682527734SSukumar Swaminathan 			iocbq = next;
341782527734SSukumar Swaminathan 			continue;
341882527734SSukumar Swaminathan 		}
341982527734SSukumar Swaminathan 
342082527734SSukumar Swaminathan 		/* found a fcp cmd iocb in fchanno txq, now deque it */
342182527734SSukumar Swaminathan 		if (next == NULL) {
342282527734SSukumar Swaminathan 			/* This is the last iocbq */
342382527734SSukumar Swaminathan 			nlp->nlp_tx[fchanno].q_last =
342482527734SSukumar Swaminathan 			    (uint8_t *)prev;
342582527734SSukumar Swaminathan 		}
342682527734SSukumar Swaminathan 
342782527734SSukumar Swaminathan 		if (prev == NULL) {
342882527734SSukumar Swaminathan 			/* This is the first one then remove it from head */
342982527734SSukumar Swaminathan 			nlp->nlp_tx[fchanno].q_first =
343082527734SSukumar Swaminathan 			    (uint8_t *)next;
343182527734SSukumar Swaminathan 		} else {
343282527734SSukumar Swaminathan 			prev->next = next;
343382527734SSukumar Swaminathan 		}
343482527734SSukumar Swaminathan 
343582527734SSukumar Swaminathan 		iocbq->next = NULL;
343682527734SSukumar Swaminathan 		nlp->nlp_tx[fchanno].q_cnt--;
343782527734SSukumar Swaminathan 
343882527734SSukumar Swaminathan 		/* Add this iocb to our local toberemovedq */
343982527734SSukumar Swaminathan 		/* This way we donot hold the TX_CHANNEL lock too long */
344082527734SSukumar Swaminathan 
344182527734SSukumar Swaminathan 		if (tbm.q_first) {
344282527734SSukumar Swaminathan 			((IOCBQ *)tbm.q_last)->next = iocbq;
344382527734SSukumar Swaminathan 			tbm.q_last = (uint8_t *)iocbq;
344482527734SSukumar Swaminathan 			tbm.q_cnt++;
344582527734SSukumar Swaminathan 		} else {
344682527734SSukumar Swaminathan 			tbm.q_first = (uint8_t *)iocbq;
344782527734SSukumar Swaminathan 			tbm.q_last = (uint8_t *)iocbq;
344882527734SSukumar Swaminathan 			tbm.q_cnt = 1;
344982527734SSukumar Swaminathan 		}
345082527734SSukumar Swaminathan 
345182527734SSukumar Swaminathan 		iocbq = next;
345282527734SSukumar Swaminathan 
345382527734SSukumar Swaminathan 	}	/* While (iocbq) */
345482527734SSukumar Swaminathan 
345582527734SSukumar Swaminathan 	if ((tchanno == hba->channel_fcp) && (tbm.q_cnt != 0)) {
345682527734SSukumar Swaminathan 
345782527734SSukumar Swaminathan 		/* from_chan->nodeq.q_first must be non NULL */
345882527734SSukumar Swaminathan 		if (from_chan->nodeq.q_first) {
345982527734SSukumar Swaminathan 
346082527734SSukumar Swaminathan 			/* nodeq is not empty, now deal with the node itself */
346182527734SSukumar Swaminathan 			if ((nlp->nlp_tx[fchanno].q_first)) {
346282527734SSukumar Swaminathan 
346382527734SSukumar Swaminathan 				if (!nlp->nlp_base) {
346482527734SSukumar Swaminathan 					from_chan->nodeq.q_last =
346582527734SSukumar Swaminathan 					    (void *)nlp;
346682527734SSukumar Swaminathan 					from_chan->nodeq.q_first =
346782527734SSukumar Swaminathan 					    nlp->nlp_next[fchanno];
346882527734SSukumar Swaminathan 				}
346982527734SSukumar Swaminathan 
347082527734SSukumar Swaminathan 			} else {
347182527734SSukumar Swaminathan 				n_prev = (NODELIST *)from_chan->nodeq.q_first;
347282527734SSukumar Swaminathan 				count = from_chan->nodeq.q_cnt;
347382527734SSukumar Swaminathan 
347482527734SSukumar Swaminathan 				if (n_prev == nlp) {
347582527734SSukumar Swaminathan 
347682527734SSukumar Swaminathan 					/* If this is the only node on list */
347782527734SSukumar Swaminathan 					if (from_chan->nodeq.q_last ==
347882527734SSukumar Swaminathan 					    (void *)nlp) {
347982527734SSukumar Swaminathan 						from_chan->nodeq.q_last =
348082527734SSukumar Swaminathan 						    NULL;
348182527734SSukumar Swaminathan 						from_chan->nodeq.q_first =
348282527734SSukumar Swaminathan 						    NULL;
348382527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt = 0;
348482527734SSukumar Swaminathan 					} else {
348582527734SSukumar Swaminathan 						from_chan->nodeq.q_first =
348682527734SSukumar Swaminathan 						    nlp->nlp_next[fchanno];
348782527734SSukumar Swaminathan 						((NODELIST *)from_chan->
348882527734SSukumar Swaminathan 						    nodeq.q_last)->
348982527734SSukumar Swaminathan 						    nlp_next[fchanno] =
349082527734SSukumar Swaminathan 						    from_chan->nodeq.q_first;
349182527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt--;
349282527734SSukumar Swaminathan 					}
349382527734SSukumar Swaminathan 					/* Clear node */
349482527734SSukumar Swaminathan 					nlp->nlp_next[fchanno] = NULL;
349582527734SSukumar Swaminathan 				} else {
349682527734SSukumar Swaminathan 					count--;
349782527734SSukumar Swaminathan 					do {
349882527734SSukumar Swaminathan 						n_next =
349982527734SSukumar Swaminathan 						    n_prev->nlp_next[fchanno];
350082527734SSukumar Swaminathan 						if (n_next == nlp) {
350182527734SSukumar Swaminathan 							break;
350282527734SSukumar Swaminathan 						}
350382527734SSukumar Swaminathan 						n_prev = n_next;
350482527734SSukumar Swaminathan 					} while (count--);
350582527734SSukumar Swaminathan 
350682527734SSukumar Swaminathan 					if (count != 0) {
350782527734SSukumar Swaminathan 
350882527734SSukumar Swaminathan 						if (n_next ==
350982527734SSukumar Swaminathan 						    (NODELIST *)from_chan->
351082527734SSukumar Swaminathan 						    nodeq.q_last) {
351182527734SSukumar Swaminathan 							n_prev->
351282527734SSukumar Swaminathan 							    nlp_next[fchanno]
351382527734SSukumar Swaminathan 							    =
351482527734SSukumar Swaminathan 							    ((NODELIST *)
351582527734SSukumar Swaminathan 							    from_chan->
351682527734SSukumar Swaminathan 							    nodeq.q_last)->
351782527734SSukumar Swaminathan 							    nlp_next
351882527734SSukumar Swaminathan 							    [fchanno];
351982527734SSukumar Swaminathan 							from_chan->nodeq.q_last
352082527734SSukumar Swaminathan 							    = (uint8_t *)n_prev;
352182527734SSukumar Swaminathan 						} else {
352282527734SSukumar Swaminathan 
352382527734SSukumar Swaminathan 							n_prev->
352482527734SSukumar Swaminathan 							    nlp_next[fchanno]
352582527734SSukumar Swaminathan 							    =
352682527734SSukumar Swaminathan 							    n_next-> nlp_next
352782527734SSukumar Swaminathan 							    [fchanno];
352882527734SSukumar Swaminathan 						}
352982527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt--;
353082527734SSukumar Swaminathan 						/* Clear node */
353182527734SSukumar Swaminathan 						nlp->nlp_next[fchanno] =
353282527734SSukumar Swaminathan 						    NULL;
353382527734SSukumar Swaminathan 					}
353482527734SSukumar Swaminathan 				}
353582527734SSukumar Swaminathan 			}
353682527734SSukumar Swaminathan 		}
353782527734SSukumar Swaminathan 	}
353882527734SSukumar Swaminathan 
353982527734SSukumar Swaminathan 	/* Now cleanup the iocb's */
354082527734SSukumar Swaminathan 	prev = NULL;
354182527734SSukumar Swaminathan 	iocbq = (IOCBQ *)tbm.q_first;
354282527734SSukumar Swaminathan 
354382527734SSukumar Swaminathan 	while (iocbq) {
354482527734SSukumar Swaminathan 
354582527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
354682527734SSukumar Swaminathan 
354782527734SSukumar Swaminathan 		/* Free the IoTag and the bmp */
354882527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
354982527734SSukumar Swaminathan 
355082527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
355182527734SSukumar Swaminathan 			sbp = iocbq->sbp;
355282527734SSukumar Swaminathan 			if (sbp) {
35538f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
355482527734SSukumar Swaminathan 			}
355582527734SSukumar Swaminathan 		} else {
355682527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
355782527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
355882527734SSukumar Swaminathan 		}
355982527734SSukumar Swaminathan 
356082527734SSukumar Swaminathan 		if (sbp && (sbp != STALE_PACKET)) {
356182527734SSukumar Swaminathan 			mutex_enter(&sbp->mtx);
356282527734SSukumar Swaminathan 			sbp->pkt_flags |= PACKET_IN_FLUSH;
356382527734SSukumar Swaminathan 
356482527734SSukumar Swaminathan 			/*
356582527734SSukumar Swaminathan 			 * If the fpkt is already set, then we will leave it
356682527734SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
356782527734SSukumar Swaminathan 			 * for on one fpkt->flush_count
356882527734SSukumar Swaminathan 			 */
356982527734SSukumar Swaminathan 			if (!sbp->fpkt && fpkt) {
357082527734SSukumar Swaminathan 				mutex_enter(&fpkt->mtx);
357182527734SSukumar Swaminathan 				sbp->fpkt = fpkt;
357282527734SSukumar Swaminathan 				fpkt->flush_count++;
357382527734SSukumar Swaminathan 				mutex_exit(&fpkt->mtx);
357482527734SSukumar Swaminathan 			}
357582527734SSukumar Swaminathan 			mutex_exit(&sbp->mtx);
357682527734SSukumar Swaminathan 		}
357782527734SSukumar Swaminathan 		iocbq = next;
357882527734SSukumar Swaminathan 
357982527734SSukumar Swaminathan 	}	/* end of while */
358082527734SSukumar Swaminathan 
358182527734SSukumar Swaminathan 	iocbq = (IOCBQ *)tbm.q_first;
358282527734SSukumar Swaminathan 	while (iocbq) {
358382527734SSukumar Swaminathan 		/* Save the next iocbq for now */
358482527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
358582527734SSukumar Swaminathan 
358682527734SSukumar Swaminathan 		/* Unlink this iocbq */
358782527734SSukumar Swaminathan 		iocbq->next = NULL;
358882527734SSukumar Swaminathan 
358982527734SSukumar Swaminathan 		/* Get the pkt */
359082527734SSukumar Swaminathan 		sbp = (emlxs_buf_t *)iocbq->sbp;
359182527734SSukumar Swaminathan 
359282527734SSukumar Swaminathan 		if (sbp) {
359382527734SSukumar Swaminathan 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
359482527734SSukumar Swaminathan 			"tx: sbp=%p node=%p", sbp, sbp->node);
359582527734SSukumar Swaminathan 
359682527734SSukumar Swaminathan 			if (hba->state >= FC_LINK_UP) {
359782527734SSukumar Swaminathan 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
359882527734SSukumar Swaminathan 				    IOERR_ABORT_REQUESTED, 1);
359982527734SSukumar Swaminathan 			} else {
360082527734SSukumar Swaminathan 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
360182527734SSukumar Swaminathan 				    IOERR_LINK_DOWN, 1);
360282527734SSukumar Swaminathan 			}
360382527734SSukumar Swaminathan 
360482527734SSukumar Swaminathan 		}
360582527734SSukumar Swaminathan 		/* Free the iocb and its associated buffers */
360682527734SSukumar Swaminathan 		else {
360782527734SSukumar Swaminathan 			icmd = &iocbq->iocb;
360882527734SSukumar Swaminathan 
360982527734SSukumar Swaminathan 			/* SLI3 */
361082527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
361182527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
361282527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
361382527734SSukumar Swaminathan 				if ((hba->flag &
361482527734SSukumar Swaminathan 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
361582527734SSukumar Swaminathan 					/* HBA is detaching or offlining */
361682527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
361782527734SSukumar Swaminathan 					    CMD_QUE_RING_LIST64_CN) {
3618a9800bebSGarrett D'Amore 						void *tmp;
361982527734SSukumar Swaminathan 						RING *rp;
362082527734SSukumar Swaminathan 						int ch;
362182527734SSukumar Swaminathan 
362282527734SSukumar Swaminathan 						ch = from_chan->channelno;
362382527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
362482527734SSukumar Swaminathan 
362582527734SSukumar Swaminathan 						for (i = 0;
362682527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
362782527734SSukumar Swaminathan 						    i++) {
362882527734SSukumar Swaminathan 							mp = EMLXS_GET_VADDR(
362982527734SSukumar Swaminathan 							    hba, rp, icmd);
363082527734SSukumar Swaminathan 
3631a9800bebSGarrett D'Amore 							tmp = (void *)mp;
363282527734SSukumar Swaminathan 							if (mp) {
3633a9800bebSGarrett D'Amore 							emlxs_mem_put(
363482527734SSukumar Swaminathan 							    hba,
363582527734SSukumar Swaminathan 							    MEM_BUF,
363682527734SSukumar Swaminathan 							    tmp);
363782527734SSukumar Swaminathan 							}
363882527734SSukumar Swaminathan 						}
363982527734SSukumar Swaminathan 
364082527734SSukumar Swaminathan 					}
364182527734SSukumar Swaminathan 
3642a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
3643a9800bebSGarrett D'Amore 					    (void *)iocbq);
364482527734SSukumar Swaminathan 				} else {
364582527734SSukumar Swaminathan 					/* repost the unsolicited buffer */
364682527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
364782527734SSukumar Swaminathan 					    from_chan, iocbq);
364882527734SSukumar Swaminathan 				}
364982527734SSukumar Swaminathan 			}
365082527734SSukumar Swaminathan 		}
365182527734SSukumar Swaminathan 
365282527734SSukumar Swaminathan 		iocbq = next;
365382527734SSukumar Swaminathan 
365482527734SSukumar Swaminathan 	}	/* end of while */
365582527734SSukumar Swaminathan 
365682527734SSukumar Swaminathan 	/* Now flush the chipq if any */
365782527734SSukumar Swaminathan 	if (!(nlp->nlp_flag[fchanno] & NLP_CLOSED)) {
365882527734SSukumar Swaminathan 
365982527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
366082527734SSukumar Swaminathan 
366182527734SSukumar Swaminathan 		(void) emlxs_chipq_node_flush(port, from_chan, nlp, 0);
366282527734SSukumar Swaminathan 
366382527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
366482527734SSukumar Swaminathan 	}
366582527734SSukumar Swaminathan 
366682527734SSukumar Swaminathan 	if (lock) {
366782527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
366882527734SSukumar Swaminathan 	}
366982527734SSukumar Swaminathan 
367082527734SSukumar Swaminathan 	return;
367182527734SSukumar Swaminathan 
367282527734SSukumar Swaminathan } /* emlxs_tx_move */
3673fcf3ce44SJohn Forte 
3674fcf3ce44SJohn Forte 
3675fcf3ce44SJohn Forte extern uint32_t
367682527734SSukumar Swaminathan emlxs_chipq_node_flush(emlxs_port_t *port, CHANNEL *chan, NODELIST *ndlp,
3677291a2b48SSukumar Swaminathan     emlxs_buf_t *fpkt)
3678fcf3ce44SJohn Forte {
3679fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3680fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3681fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3682fcf3ce44SJohn Forte 	IOCBQ *next;
3683fcf3ce44SJohn Forte 	Q abort;
368482527734SSukumar Swaminathan 	CHANNEL *cp;
368582527734SSukumar Swaminathan 	uint32_t channelno;
368682527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
3687fcf3ce44SJohn Forte 	uint32_t iotag;
3688fcf3ce44SJohn Forte 
3689fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
3690fcf3ce44SJohn Forte 	bzero((void *)flag, sizeof (flag));
3691fcf3ce44SJohn Forte 
369282527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
369382527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3694fcf3ce44SJohn Forte 
369582527734SSukumar Swaminathan 		if (chan && cp != chan) {
3696fcf3ce44SJohn Forte 			continue;
3697fcf3ce44SJohn Forte 		}
3698291a2b48SSukumar Swaminathan 
369982527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3700fcf3ce44SJohn Forte 
370182527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
370282527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3703fcf3ce44SJohn Forte 
3704fcf3ce44SJohn Forte 			if (sbp && (sbp != STALE_PACKET) &&
3705fcf3ce44SJohn Forte 			    (sbp->pkt_flags & PACKET_IN_CHIPQ) &&
3706fcf3ce44SJohn Forte 			    (sbp->node == ndlp) &&
370782527734SSukumar Swaminathan 			    (sbp->channel == cp) &&
3708fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
3709291a2b48SSukumar Swaminathan 				emlxs_sbp_abort_add(port, sbp, &abort, flag,
3710291a2b48SSukumar Swaminathan 				    fpkt);
3711fcf3ce44SJohn Forte 			}
3712291a2b48SSukumar Swaminathan 
3713fcf3ce44SJohn Forte 		}
371482527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3715fcf3ce44SJohn Forte 
3716fcf3ce44SJohn Forte 	}	/* for */
3717fcf3ce44SJohn Forte 
3718fcf3ce44SJohn Forte 	/* Now put the iocb's on the tx queue */
3719fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
3720fcf3ce44SJohn Forte 	while (iocbq) {
3721fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
3722fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
3723fcf3ce44SJohn Forte 
3724fcf3ce44SJohn Forte 		/* Unlink this iocbq */
3725fcf3ce44SJohn Forte 		iocbq->next = NULL;
3726fcf3ce44SJohn Forte 
3727fcf3ce44SJohn Forte 		/* Send this iocbq */
3728fcf3ce44SJohn Forte 		emlxs_tx_put(iocbq, 1);
3729fcf3ce44SJohn Forte 
3730fcf3ce44SJohn Forte 		iocbq = next;
3731fcf3ce44SJohn Forte 	}
3732fcf3ce44SJohn Forte 
373382527734SSukumar Swaminathan 	/* Now trigger channel service */
373482527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
373582527734SSukumar Swaminathan 		if (!flag[channelno]) {
3736fcf3ce44SJohn Forte 			continue;
3737fcf3ce44SJohn Forte 		}
3738291a2b48SSukumar Swaminathan 
373982527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
3740fcf3ce44SJohn Forte 	}
3741fcf3ce44SJohn Forte 
3742fcf3ce44SJohn Forte 	return (abort.q_cnt);
3743fcf3ce44SJohn Forte 
374482527734SSukumar Swaminathan } /* emlxs_chipq_node_flush() */
3745fcf3ce44SJohn Forte 
3746fcf3ce44SJohn Forte 
3747fcf3ce44SJohn Forte /* Flush all IO's left on all iotag lists */
374882527734SSukumar Swaminathan extern uint32_t
3749fcf3ce44SJohn Forte emlxs_iotag_flush(emlxs_hba_t *hba)
3750fcf3ce44SJohn Forte {
3751fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
3752fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3753fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3754fcf3ce44SJohn Forte 	IOCB *iocb;
3755fcf3ce44SJohn Forte 	Q abort;
375682527734SSukumar Swaminathan 	CHANNEL *cp;
375782527734SSukumar Swaminathan 	uint32_t channelno;
3758fcf3ce44SJohn Forte 	uint32_t iotag;
3759fcf3ce44SJohn Forte 	uint32_t count;
3760fcf3ce44SJohn Forte 
3761fcf3ce44SJohn Forte 	count = 0;
376282527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
376382527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3764fcf3ce44SJohn Forte 
3765fcf3ce44SJohn Forte 		bzero((void *)&abort, sizeof (Q));
3766fcf3ce44SJohn Forte 
376782527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3768fcf3ce44SJohn Forte 
376982527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
377082527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3771fcf3ce44SJohn Forte 
377282527734SSukumar Swaminathan 			/* Check if the slot is empty */
3773fcf3ce44SJohn Forte 			if (!sbp || (sbp == STALE_PACKET)) {
3774fcf3ce44SJohn Forte 				continue;
3775fcf3ce44SJohn Forte 			}
3776291a2b48SSukumar Swaminathan 
377782527734SSukumar Swaminathan 			/* We are building an abort list per channel */
377882527734SSukumar Swaminathan 			if (sbp->channel != cp) {
377982527734SSukumar Swaminathan 				continue;
378082527734SSukumar Swaminathan 			}
3781fcf3ce44SJohn Forte 
3782a9800bebSGarrett D'Amore 			hba->fc_table[iotag] = STALE_PACKET;
3783a9800bebSGarrett D'Amore 			hba->io_count--;
3784a9800bebSGarrett D'Amore 
3785a9800bebSGarrett D'Amore 			/* Check if IO is valid */
3786a9800bebSGarrett D'Amore 			if (!(sbp->pkt_flags & PACKET_VALID) ||
3787a9800bebSGarrett D'Amore 			    (sbp->pkt_flags & (PACKET_ULP_OWNED|
3788a9800bebSGarrett D'Amore 			    PACKET_COMPLETED|PACKET_IN_COMPLETION))) {
3789a9800bebSGarrett D'Amore 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
37908f23e9faSHans Rosenfeld 				    "iotag_flush: Invalid IO found. iotag=%d",
3791a9800bebSGarrett D'Amore 				    iotag);
3792a9800bebSGarrett D'Amore 
3793a9800bebSGarrett D'Amore 				continue;
3794a9800bebSGarrett D'Amore 			}
3795a9800bebSGarrett D'Amore 
3796a9800bebSGarrett D'Amore 			sbp->iotag = 0;
3797a9800bebSGarrett D'Amore 
3798fcf3ce44SJohn Forte 			/* Set IOCB status */
3799fcf3ce44SJohn Forte 			iocbq = &sbp->iocbq;
3800fcf3ce44SJohn Forte 			iocb = &iocbq->iocb;
3801fcf3ce44SJohn Forte 
380282527734SSukumar Swaminathan 			iocb->ULPSTATUS = IOSTAT_LOCAL_REJECT;
3803fcf3ce44SJohn Forte 			iocb->un.grsp.perr.statLocalError = IOERR_LINK_DOWN;
380482527734SSukumar Swaminathan 			iocb->ULPLE = 1;
3805fcf3ce44SJohn Forte 			iocbq->next = NULL;
3806fcf3ce44SJohn Forte 
380782527734SSukumar Swaminathan 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3808a9800bebSGarrett D'Amore 				if (sbp->xrip) {
3809a9800bebSGarrett D'Amore 					EMLXS_MSGF(EMLXS_CONTEXT,
3810a9800bebSGarrett D'Amore 					    &emlxs_sli_debug_msg,
38118f23e9faSHans Rosenfeld 					    "iotag_flush: iotag=%d sbp=%p "
3812a9800bebSGarrett D'Amore 					    "xrip=%p state=%x flag=%x",
3813a9800bebSGarrett D'Amore 					    iotag, sbp, sbp->xrip,
3814a9800bebSGarrett D'Amore 					    sbp->xrip->state, sbp->xrip->flag);
3815a9800bebSGarrett D'Amore 				} else {
3816a9800bebSGarrett D'Amore 					EMLXS_MSGF(EMLXS_CONTEXT,
3817a9800bebSGarrett D'Amore 					    &emlxs_sli_debug_msg,
38188f23e9faSHans Rosenfeld 					    "iotag_flush: iotag=%d sbp=%p "
38198f23e9faSHans Rosenfeld 					    "xrip=NULL", iotag, sbp);
3820a9800bebSGarrett D'Amore 				}
3821291a2b48SSukumar Swaminathan 
38228f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 0);
3823a9800bebSGarrett D'Amore 			} else {
382482527734SSukumar Swaminathan 				/* Clean up the sbp */
382582527734SSukumar Swaminathan 				mutex_enter(&sbp->mtx);
382682527734SSukumar Swaminathan 
382782527734SSukumar Swaminathan 				if (sbp->pkt_flags & PACKET_IN_TXQ) {
382882527734SSukumar Swaminathan 					sbp->pkt_flags &= ~PACKET_IN_TXQ;
382982527734SSukumar Swaminathan 					hba->channel_tx_count --;
383082527734SSukumar Swaminathan 				}
383182527734SSukumar Swaminathan 
383282527734SSukumar Swaminathan 				if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
383382527734SSukumar Swaminathan 					sbp->pkt_flags &= ~PACKET_IN_CHIPQ;
383482527734SSukumar Swaminathan 				}
3835291a2b48SSukumar Swaminathan 
383682527734SSukumar Swaminathan 				if (sbp->bmp) {
3837a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_BPL,
3838a9800bebSGarrett D'Amore 					    (void *)sbp->bmp);
383982527734SSukumar Swaminathan 					sbp->bmp = 0;
384082527734SSukumar Swaminathan 				}
384182527734SSukumar Swaminathan 
384282527734SSukumar Swaminathan 				mutex_exit(&sbp->mtx);
3843fcf3ce44SJohn Forte 			}
3844291a2b48SSukumar Swaminathan 
3845fcf3ce44SJohn Forte 			/* At this point all nodes are assumed destroyed */
384682527734SSukumar Swaminathan 			mutex_enter(&sbp->mtx);
3847fcf3ce44SJohn Forte 			sbp->node = 0;
3848fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3849fcf3ce44SJohn Forte 
3850fcf3ce44SJohn Forte 			/* Add this iocb to our local abort Q */
3851fcf3ce44SJohn Forte 			if (abort.q_first) {
3852291a2b48SSukumar Swaminathan 				((IOCBQ *)abort.q_last)->next = iocbq;
3853fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
3854fcf3ce44SJohn Forte 				abort.q_cnt++;
3855fcf3ce44SJohn Forte 			} else {
3856fcf3ce44SJohn Forte 				abort.q_first = (uint8_t *)iocbq;
3857fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
3858fcf3ce44SJohn Forte 				abort.q_cnt = 1;
3859fcf3ce44SJohn Forte 			}
3860fcf3ce44SJohn Forte 		}
3861fcf3ce44SJohn Forte 
386282527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3863fcf3ce44SJohn Forte 
3864fcf3ce44SJohn Forte 		/* Trigger deferred completion */
3865fcf3ce44SJohn Forte 		if (abort.q_first) {
386682527734SSukumar Swaminathan 			mutex_enter(&cp->rsp_lock);
386782527734SSukumar Swaminathan 			if (cp->rsp_head == NULL) {
386882527734SSukumar Swaminathan 				cp->rsp_head = (IOCBQ *)abort.q_first;
386982527734SSukumar Swaminathan 				cp->rsp_tail = (IOCBQ *)abort.q_last;
3870fcf3ce44SJohn Forte 			} else {
387182527734SSukumar Swaminathan 				cp->rsp_tail->next = (IOCBQ *)abort.q_first;
387282527734SSukumar Swaminathan 				cp->rsp_tail = (IOCBQ *)abort.q_last;
3873fcf3ce44SJohn Forte 			}
387482527734SSukumar Swaminathan 			mutex_exit(&cp->rsp_lock);
3875fcf3ce44SJohn Forte 
387682527734SSukumar Swaminathan 			emlxs_thread_trigger2(&cp->intr_thread,
387782527734SSukumar Swaminathan 			    emlxs_proc_channel, cp);
3878fcf3ce44SJohn Forte 
3879a9800bebSGarrett D'Amore 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
3880a9800bebSGarrett D'Amore 			    "iotag_flush: channel=%d count=%d",
388182527734SSukumar Swaminathan 			    channelno, abort.q_cnt);
3882fcf3ce44SJohn Forte 
3883fcf3ce44SJohn Forte 			count += abort.q_cnt;
3884fcf3ce44SJohn Forte 		}
3885fcf3ce44SJohn Forte 	}
3886fcf3ce44SJohn Forte 
3887fcf3ce44SJohn Forte 	return (count);
3888fcf3ce44SJohn Forte 
388982527734SSukumar Swaminathan } /* emlxs_iotag_flush() */
3890fcf3ce44SJohn Forte 
3891fcf3ce44SJohn Forte 
3892fcf3ce44SJohn Forte 
389382527734SSukumar Swaminathan /* Checks for IO's on all or a given channel for a given node */
3894fcf3ce44SJohn Forte extern uint32_t
389582527734SSukumar Swaminathan emlxs_chipq_node_check(emlxs_port_t *port, CHANNEL *chan, NODELIST *ndlp)
3896fcf3ce44SJohn Forte {
3897fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3898fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
389982527734SSukumar Swaminathan 	CHANNEL *cp;
390082527734SSukumar Swaminathan 	uint32_t channelno;
3901fcf3ce44SJohn Forte 	uint32_t count;
3902fcf3ce44SJohn Forte 	uint32_t iotag;
3903fcf3ce44SJohn Forte 
3904fcf3ce44SJohn Forte 	count = 0;
3905fcf3ce44SJohn Forte 
390682527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
390782527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3908fcf3ce44SJohn Forte 
390982527734SSukumar Swaminathan 		if (chan && cp != chan) {
3910fcf3ce44SJohn Forte 			continue;
3911fcf3ce44SJohn Forte 		}
3912291a2b48SSukumar Swaminathan 
391382527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3914fcf3ce44SJohn Forte 
391582527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
391682527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3917fcf3ce44SJohn Forte 
3918fcf3ce44SJohn Forte 			if (sbp && (sbp != STALE_PACKET) &&
3919fcf3ce44SJohn Forte 			    (sbp->pkt_flags & PACKET_IN_CHIPQ) &&
3920fcf3ce44SJohn Forte 			    (sbp->node == ndlp) &&
392182527734SSukumar Swaminathan 			    (sbp->channel == cp) &&
3922fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
3923fcf3ce44SJohn Forte 				count++;
3924fcf3ce44SJohn Forte 			}
3925291a2b48SSukumar Swaminathan 
3926fcf3ce44SJohn Forte 		}
392782527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3928fcf3ce44SJohn Forte 
3929fcf3ce44SJohn Forte 	}	/* for */
3930fcf3ce44SJohn Forte 
3931fcf3ce44SJohn Forte 	return (count);
3932fcf3ce44SJohn Forte 
393382527734SSukumar Swaminathan } /* emlxs_chipq_node_check() */
3934fcf3ce44SJohn Forte 
3935fcf3ce44SJohn Forte 
3936fcf3ce44SJohn Forte 
393782527734SSukumar Swaminathan /* Flush all IO's for a given node's lun (on any channel) */
3938fcf3ce44SJohn Forte extern uint32_t
393982527734SSukumar Swaminathan emlxs_chipq_lun_flush(emlxs_port_t *port, NODELIST *ndlp,
394082527734SSukumar Swaminathan     uint32_t lun, emlxs_buf_t *fpkt)
3941fcf3ce44SJohn Forte {
3942fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3943fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3944fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3945fcf3ce44SJohn Forte 	IOCBQ *next;
3946fcf3ce44SJohn Forte 	Q abort;
3947fcf3ce44SJohn Forte 	uint32_t iotag;
394882527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
394982527734SSukumar Swaminathan 	uint32_t channelno;
3950fcf3ce44SJohn Forte 
3951a9800bebSGarrett D'Amore 	if (lun == EMLXS_LUN_NONE) {
3952a9800bebSGarrett D'Amore 		return (0);
3953a9800bebSGarrett D'Amore 	}
3954a9800bebSGarrett D'Amore 
3955fcf3ce44SJohn Forte 	bzero((void *)flag, sizeof (flag));
3956fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
3957fcf3ce44SJohn Forte 
395882527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
395982527734SSukumar Swaminathan 	for (iotag = 1; iotag < hba->max_iotag; iotag++) {
396082527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
3961fcf3ce44SJohn Forte 
3962fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET) &&
3963fcf3ce44SJohn Forte 		    sbp->pkt_flags & PACKET_IN_CHIPQ &&
3964fcf3ce44SJohn Forte 		    sbp->node == ndlp &&
3965fcf3ce44SJohn Forte 		    sbp->lun == lun &&
3966fcf3ce44SJohn Forte 		    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
396782527734SSukumar Swaminathan 			emlxs_sbp_abort_add(port, sbp,
396882527734SSukumar Swaminathan 			    &abort, flag, fpkt);
3969fcf3ce44SJohn Forte 		}
3970fcf3ce44SJohn Forte 	}
397182527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
3972fcf3ce44SJohn Forte 
3973fcf3ce44SJohn Forte 	/* Now put the iocb's on the tx queue */
3974fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
3975fcf3ce44SJohn Forte 	while (iocbq) {
3976fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
3977fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
3978fcf3ce44SJohn Forte 
3979fcf3ce44SJohn Forte 		/* Unlink this iocbq */
3980fcf3ce44SJohn Forte 		iocbq->next = NULL;
3981fcf3ce44SJohn Forte 
3982fcf3ce44SJohn Forte 		/* Send this iocbq */
3983fcf3ce44SJohn Forte 		emlxs_tx_put(iocbq, 1);
3984fcf3ce44SJohn Forte 
3985fcf3ce44SJohn Forte 		iocbq = next;
3986fcf3ce44SJohn Forte 	}
3987fcf3ce44SJohn Forte 
398882527734SSukumar Swaminathan 	/* Now trigger channel service */
398982527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
399082527734SSukumar Swaminathan 		if (!flag[channelno]) {
399182527734SSukumar Swaminathan 			continue;
399282527734SSukumar Swaminathan 		}
399382527734SSukumar Swaminathan 
399482527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
3995fcf3ce44SJohn Forte 	}
3996291a2b48SSukumar Swaminathan 
3997fcf3ce44SJohn Forte 	return (abort.q_cnt);
3998fcf3ce44SJohn Forte 
399982527734SSukumar Swaminathan } /* emlxs_chipq_lun_flush() */
4000fcf3ce44SJohn Forte 
4001fcf3ce44SJohn Forte 
4002fcf3ce44SJohn Forte 
4003fcf3ce44SJohn Forte /*
4004fcf3ce44SJohn Forte  * Issue an ABORT_XRI_CN iocb command to abort an FCP command already issued.
4005fe199829SSukumar Swaminathan  * This must be called while holding the EMLXS_FCTAB_LOCK
4006fcf3ce44SJohn Forte  */
4007fcf3ce44SJohn Forte extern IOCBQ *
4008291a2b48SSukumar Swaminathan emlxs_create_abort_xri_cn(emlxs_port_t *port, NODELIST *ndlp,
400982527734SSukumar Swaminathan     uint16_t iotag, CHANNEL *cp, uint8_t class, int32_t flag)
4010fcf3ce44SJohn Forte {
4011fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4012fcf3ce44SJohn Forte 	IOCBQ *iocbq;
4013fcf3ce44SJohn Forte 	IOCB *iocb;
401482527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
401582527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
4016fcf3ce44SJohn Forte 	uint16_t abort_iotag;
4017fcf3ce44SJohn Forte 
40188f23e9faSHans Rosenfeld 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
4019fcf3ce44SJohn Forte 		return (NULL);
4020fcf3ce44SJohn Forte 	}
4021291a2b48SSukumar Swaminathan 
402282527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
4023fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
4024fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
4025fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
4026fcf3ce44SJohn Forte 
4027fcf3ce44SJohn Forte 	/*
4028fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
4029fcf3ce44SJohn Forte 	 */
403082527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
403182527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
4032fcf3ce44SJohn Forte 	}
403382527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
4034291a2b48SSukumar Swaminathan 
4035fcf3ce44SJohn Forte 
403682527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
403782527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
403882527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
4039fcf3ce44SJohn Forte 
404082527734SSukumar Swaminathan 		/* Try to issue abort by XRI if possible */
4041a9800bebSGarrett D'Amore 		if (sbp == NULL || sbp == STALE_PACKET || sbp->xrip == NULL) {
404282527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_REQ_TAG;
404382527734SSukumar Swaminathan 			wqe->AbortTag = iotag;
404482527734SSukumar Swaminathan 		} else {
404582527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_XRI_TAG;
4046a9800bebSGarrett D'Amore 			wqe->AbortTag = sbp->xrip->XRI;
404782527734SSukumar Swaminathan 		}
404882527734SSukumar Swaminathan 		wqe->un.Abort.IA = 0;
404982527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
405082527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
405182527734SSukumar Swaminathan 		wqe->Class = CLASS3;
40528f23e9faSHans Rosenfeld 		wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
405382527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
405482527734SSukumar Swaminathan 	} else {
405582527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
405682527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
405782527734SSukumar Swaminathan 		iocb->un.acxri.abortType = flag;
405882527734SSukumar Swaminathan 		iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi;
405982527734SSukumar Swaminathan 		iocb->un.acxri.abortIoTag = iotag;
406082527734SSukumar Swaminathan 		iocb->ULPLE = 1;
406182527734SSukumar Swaminathan 		iocb->ULPCLASS = class;
406282527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_ABORT_XRI_CN;
406382527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
406482527734SSukumar Swaminathan 	}
4065fcf3ce44SJohn Forte 
4066fcf3ce44SJohn Forte 	return (iocbq);
4067fcf3ce44SJohn Forte 
406882527734SSukumar Swaminathan } /* emlxs_create_abort_xri_cn() */
4069fcf3ce44SJohn Forte 
4070fcf3ce44SJohn Forte 
4071fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4072fcf3ce44SJohn Forte extern IOCBQ *
4073fcf3ce44SJohn Forte emlxs_create_abort_xri_cx(emlxs_port_t *port, NODELIST *ndlp, uint16_t xid,
407482527734SSukumar Swaminathan     CHANNEL *cp, uint8_t class, int32_t flag)
4075fcf3ce44SJohn Forte {
4076fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4077fcf3ce44SJohn Forte 	IOCBQ *iocbq;
4078fcf3ce44SJohn Forte 	IOCB *iocb;
407982527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
4080fcf3ce44SJohn Forte 	uint16_t abort_iotag;
4081fcf3ce44SJohn Forte 
40828f23e9faSHans Rosenfeld 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
4083fcf3ce44SJohn Forte 		return (NULL);
4084fcf3ce44SJohn Forte 	}
4085291a2b48SSukumar Swaminathan 
408682527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
4087fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
4088fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
4089fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
4090fcf3ce44SJohn Forte 
4091fcf3ce44SJohn Forte 	/*
4092fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
4093fcf3ce44SJohn Forte 	 */
409482527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
409582527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
409682527734SSukumar Swaminathan 	}
409782527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
409882527734SSukumar Swaminathan 
409982527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
410082527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
410182527734SSukumar Swaminathan 		wqe->un.Abort.Criteria = ABORT_XRI_TAG;
410282527734SSukumar Swaminathan 		wqe->un.Abort.IA = 0;
410382527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
410482527734SSukumar Swaminathan 		wqe->AbortTag = xid;
410582527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
410682527734SSukumar Swaminathan 		wqe->Class = CLASS3;
41078f23e9faSHans Rosenfeld 		wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
410882527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
410982527734SSukumar Swaminathan 	} else {
411082527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
411182527734SSukumar Swaminathan 		iocb->ULPCONTEXT = xid;
411282527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
411382527734SSukumar Swaminathan 		iocb->un.acxri.abortType = flag;
411482527734SSukumar Swaminathan 		iocb->ULPLE = 1;
411582527734SSukumar Swaminathan 		iocb->ULPCLASS = class;
411682527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_ABORT_XRI_CX;
411782527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
4118fcf3ce44SJohn Forte 	}
4119291a2b48SSukumar Swaminathan 
4120fcf3ce44SJohn Forte 	return (iocbq);
4121fcf3ce44SJohn Forte 
412282527734SSukumar Swaminathan } /* emlxs_create_abort_xri_cx() */
4123fcf3ce44SJohn Forte 
4124fcf3ce44SJohn Forte 
4125fcf3ce44SJohn Forte 
4126fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4127fcf3ce44SJohn Forte extern IOCBQ *
4128fcf3ce44SJohn Forte emlxs_create_close_xri_cn(emlxs_port_t *port, NODELIST *ndlp,
412982527734SSukumar Swaminathan     uint16_t iotag, CHANNEL *cp)
4130fcf3ce44SJohn Forte {
4131fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4132fcf3ce44SJohn Forte 	IOCBQ *iocbq;
4133fcf3ce44SJohn Forte 	IOCB *iocb;
413482527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
413582527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
4136fcf3ce44SJohn Forte 	uint16_t abort_iotag;
4137fcf3ce44SJohn Forte 
41388f23e9faSHans Rosenfeld 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
4139fcf3ce44SJohn Forte 		return (NULL);
4140fcf3ce44SJohn Forte 	}
4141291a2b48SSukumar Swaminathan 
414282527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
4143fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
4144fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
4145fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
4146fcf3ce44SJohn Forte 
4147fcf3ce44SJohn Forte 	/*
4148fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
4149fcf3ce44SJohn Forte 	 */
415082527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
415182527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
4152fcf3ce44SJohn Forte 	}
415382527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
4154291a2b48SSukumar Swaminathan 
415582527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
415682527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
415782527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
4158fcf3ce44SJohn Forte 
415982527734SSukumar Swaminathan 		/* Try to issue close by XRI if possible */
4160a9800bebSGarrett D'Amore 		if (sbp == NULL || sbp == STALE_PACKET || sbp->xrip == NULL) {
416182527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_REQ_TAG;
416282527734SSukumar Swaminathan 			wqe->AbortTag = iotag;
416382527734SSukumar Swaminathan 		} else {
416482527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_XRI_TAG;
4165a9800bebSGarrett D'Amore 			wqe->AbortTag = sbp->xrip->XRI;
416682527734SSukumar Swaminathan 		}
416782527734SSukumar Swaminathan 		wqe->un.Abort.IA = 1;
416882527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
416982527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
417082527734SSukumar Swaminathan 		wqe->Class = CLASS3;
41718f23e9faSHans Rosenfeld 		wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
417282527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
417382527734SSukumar Swaminathan 	} else {
417482527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
417582527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
417682527734SSukumar Swaminathan 		iocb->un.acxri.abortType = 0;
417782527734SSukumar Swaminathan 		iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi;
417882527734SSukumar Swaminathan 		iocb->un.acxri.abortIoTag = iotag;
417982527734SSukumar Swaminathan 		iocb->ULPLE = 1;
418082527734SSukumar Swaminathan 		iocb->ULPCLASS = 0;
418182527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_CLOSE_XRI_CN;
418282527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
418382527734SSukumar Swaminathan 	}
4184fcf3ce44SJohn Forte 
4185fcf3ce44SJohn Forte 	return (iocbq);
4186fcf3ce44SJohn Forte 
418782527734SSukumar Swaminathan } /* emlxs_create_close_xri_cn() */
4188fcf3ce44SJohn Forte 
4189fcf3ce44SJohn Forte 
4190fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4191fcf3ce44SJohn Forte extern IOCBQ *
4192291a2b48SSukumar Swaminathan emlxs_create_close_xri_cx(emlxs_port_t *port, NODELIST *ndlp, uint16_t xid,
419382527734SSukumar Swaminathan     CHANNEL *cp)
4194fcf3ce44SJohn Forte {
4195fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4196fcf3ce44SJohn Forte 	IOCBQ *iocbq;
4197fcf3ce44SJohn Forte 	IOCB *iocb;
419882527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
4199fcf3ce44SJohn Forte 	uint16_t abort_iotag;
4200fcf3ce44SJohn Forte 
42018f23e9faSHans Rosenfeld 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
4202fcf3ce44SJohn Forte 		return (NULL);
4203fcf3ce44SJohn Forte 	}
4204291a2b48SSukumar Swaminathan 
420582527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
4206fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
4207fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
4208fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
4209fcf3ce44SJohn Forte 
4210fcf3ce44SJohn Forte 	/*
4211fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
4212fcf3ce44SJohn Forte 	 */
421382527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
421482527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
421582527734SSukumar Swaminathan 	}
421682527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
421782527734SSukumar Swaminathan 
421882527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
421982527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
422082527734SSukumar Swaminathan 		wqe->un.Abort.Criteria = ABORT_XRI_TAG;
422182527734SSukumar Swaminathan 		wqe->un.Abort.IA = 1;
422282527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
422382527734SSukumar Swaminathan 		wqe->AbortTag = xid;
422482527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
422582527734SSukumar Swaminathan 		wqe->Class = CLASS3;
42268f23e9faSHans Rosenfeld 		wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
422782527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
422882527734SSukumar Swaminathan 	} else {
422982527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
423082527734SSukumar Swaminathan 		iocb->ULPCONTEXT = xid;
423182527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
423282527734SSukumar Swaminathan 		iocb->ULPLE = 1;
423382527734SSukumar Swaminathan 		iocb->ULPCLASS = 0;
423482527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_CLOSE_XRI_CX;
423582527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
4236fcf3ce44SJohn Forte 	}
4237291a2b48SSukumar Swaminathan 
4238fcf3ce44SJohn Forte 	return (iocbq);
4239fcf3ce44SJohn Forte 
424082527734SSukumar Swaminathan } /* emlxs_create_close_xri_cx() */
4241fcf3ce44SJohn Forte 
4242fcf3ce44SJohn Forte 
4243a9800bebSGarrett D'Amore void
4244a9800bebSGarrett D'Amore emlxs_close_els_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4245a9800bebSGarrett D'Amore {
4246a9800bebSGarrett D'Amore 	CHANNEL *cp;
4247a9800bebSGarrett D'Amore 	IOCBQ *iocbq;
4248a9800bebSGarrett D'Amore 	IOCB *iocb;
4249a9800bebSGarrett D'Amore 
4250a9800bebSGarrett D'Amore 	if (rxid == 0 || rxid == 0xFFFF) {
4251a9800bebSGarrett D'Amore 		return;
4252a9800bebSGarrett D'Amore 	}
4253a9800bebSGarrett D'Amore 
4254a9800bebSGarrett D'Amore 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4255a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4256a9800bebSGarrett D'Amore 		    "Closing ELS exchange: xid=%x", rxid);
4257a9800bebSGarrett D'Amore 
42588f23e9faSHans Rosenfeld 		if (emlxs_sli4_unreserve_xri(port, rxid, 1) == 0) {
4259a9800bebSGarrett D'Amore 			return;
4260a9800bebSGarrett D'Amore 		}
4261a9800bebSGarrett D'Amore 	}
4262a9800bebSGarrett D'Amore 
4263a9800bebSGarrett D'Amore 	cp = &hba->chan[hba->channel_els];
4264a9800bebSGarrett D'Amore 
4265a9800bebSGarrett D'Amore 	mutex_enter(&EMLXS_FCTAB_LOCK);
4266a9800bebSGarrett D'Amore 
4267a9800bebSGarrett D'Amore 	/* Create the abort IOCB */
4268a9800bebSGarrett D'Amore 	iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4269a9800bebSGarrett D'Amore 
4270a9800bebSGarrett D'Amore 	mutex_exit(&EMLXS_FCTAB_LOCK);
4271a9800bebSGarrett D'Amore 
4272a9800bebSGarrett D'Amore 	if (iocbq) {
4273a9800bebSGarrett D'Amore 		iocb = &iocbq->iocb;
4274a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
42758f23e9faSHans Rosenfeld 		    "Closing ELS exchange: xid=%x iotag=%d", rxid,
4276a9800bebSGarrett D'Amore 		    iocb->ULPIOTAG);
4277a9800bebSGarrett D'Amore 
4278a9800bebSGarrett D'Amore 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4279a9800bebSGarrett D'Amore 	}
4280a9800bebSGarrett D'Amore 
4281a9800bebSGarrett D'Amore } /* emlxs_close_els_exchange() */
4282a9800bebSGarrett D'Amore 
4283a9800bebSGarrett D'Amore 
4284fe199829SSukumar Swaminathan void
4285fe199829SSukumar Swaminathan emlxs_abort_els_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4286fe199829SSukumar Swaminathan {
4287fe199829SSukumar Swaminathan 	CHANNEL *cp;
4288fe199829SSukumar Swaminathan 	IOCBQ *iocbq;
4289fe199829SSukumar Swaminathan 	IOCB *iocb;
4290fe199829SSukumar Swaminathan 
4291fe199829SSukumar Swaminathan 	if (rxid == 0 || rxid == 0xFFFF) {
4292fe199829SSukumar Swaminathan 		return;
4293fe199829SSukumar Swaminathan 	}
4294fe199829SSukumar Swaminathan 
4295fe199829SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4296fe199829SSukumar Swaminathan 
4297fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4298fe199829SSukumar Swaminathan 		    "Aborting ELS exchange: xid=%x", rxid);
4299fe199829SSukumar Swaminathan 
43008f23e9faSHans Rosenfeld 		if (emlxs_sli4_unreserve_xri(port, rxid, 1) == 0) {
4301fe199829SSukumar Swaminathan 			/* We have no way to abort unsolicited exchanges */
4302fe199829SSukumar Swaminathan 			/* that we have not responded to at this time */
4303fe199829SSukumar Swaminathan 			/* So we will return for now */
4304fe199829SSukumar Swaminathan 			return;
4305fe199829SSukumar Swaminathan 		}
4306fe199829SSukumar Swaminathan 	}
4307fe199829SSukumar Swaminathan 
4308fe199829SSukumar Swaminathan 	cp = &hba->chan[hba->channel_els];
4309fe199829SSukumar Swaminathan 
4310fe199829SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
4311fe199829SSukumar Swaminathan 
4312fe199829SSukumar Swaminathan 	/* Create the abort IOCB */
4313fe199829SSukumar Swaminathan 	if (hba->state >= FC_LINK_UP) {
4314fe199829SSukumar Swaminathan 		iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4315fe199829SSukumar Swaminathan 		    CLASS3, ABORT_TYPE_ABTS);
4316fe199829SSukumar Swaminathan 	} else {
4317fe199829SSukumar Swaminathan 		iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4318fe199829SSukumar Swaminathan 	}
4319fe199829SSukumar Swaminathan 
4320fe199829SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
4321fe199829SSukumar Swaminathan 
4322fe199829SSukumar Swaminathan 	if (iocbq) {
4323fe199829SSukumar Swaminathan 		iocb = &iocbq->iocb;
4324fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
43258f23e9faSHans Rosenfeld 		    "Aborting ELS exchange: xid=%x iotag=%d", rxid,
4326fe199829SSukumar Swaminathan 		    iocb->ULPIOTAG);
4327fe199829SSukumar Swaminathan 
4328fe199829SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4329fe199829SSukumar Swaminathan 	}
4330fe199829SSukumar Swaminathan 
4331fe199829SSukumar Swaminathan } /* emlxs_abort_els_exchange() */
4332fe199829SSukumar Swaminathan 
4333fe199829SSukumar Swaminathan 
4334728bdc9bSSukumar Swaminathan void
4335bb63f56eSSukumar Swaminathan emlxs_abort_ct_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4336728bdc9bSSukumar Swaminathan {
433782527734SSukumar Swaminathan 	CHANNEL *cp;
4338728bdc9bSSukumar Swaminathan 	IOCBQ *iocbq;
4339fe199829SSukumar Swaminathan 	IOCB *iocb;
4340728bdc9bSSukumar Swaminathan 
4341fe199829SSukumar Swaminathan 	if (rxid == 0 || rxid == 0xFFFF) {
4342fe199829SSukumar Swaminathan 		return;
4343fe199829SSukumar Swaminathan 	}
434482527734SSukumar Swaminathan 
434582527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4346fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ct_msg,
4347fe199829SSukumar Swaminathan 		    "Aborting CT exchange: xid=%x", rxid);
4348fe199829SSukumar Swaminathan 
43498f23e9faSHans Rosenfeld 		if (emlxs_sli4_unreserve_xri(port, rxid, 1) == 0) {
435082527734SSukumar Swaminathan 			/* We have no way to abort unsolicited exchanges */
435182527734SSukumar Swaminathan 			/* that we have not responded to at this time */
435282527734SSukumar Swaminathan 			/* So we will return for now */
435382527734SSukumar Swaminathan 			return;
435482527734SSukumar Swaminathan 		}
435582527734SSukumar Swaminathan 	}
435682527734SSukumar Swaminathan 
435782527734SSukumar Swaminathan 	cp = &hba->chan[hba->channel_ct];
4358728bdc9bSSukumar Swaminathan 
4359fe199829SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
4360fe199829SSukumar Swaminathan 
4361728bdc9bSSukumar Swaminathan 	/* Create the abort IOCB */
4362728bdc9bSSukumar Swaminathan 	if (hba->state >= FC_LINK_UP) {
4363fe199829SSukumar Swaminathan 		iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4364fe199829SSukumar Swaminathan 		    CLASS3, ABORT_TYPE_ABTS);
4365291a2b48SSukumar Swaminathan 	} else {
436682527734SSukumar Swaminathan 		iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4367728bdc9bSSukumar Swaminathan 	}
436882527734SSukumar Swaminathan 
4369fe199829SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
4370fe199829SSukumar Swaminathan 
4371bb63f56eSSukumar Swaminathan 	if (iocbq) {
4372fe199829SSukumar Swaminathan 		iocb = &iocbq->iocb;
4373fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
43748f23e9faSHans Rosenfeld 		    "Aborting CT exchange: xid=%x iotag=%d", rxid,
4375fe199829SSukumar Swaminathan 		    iocb->ULPIOTAG);
4376fe199829SSukumar Swaminathan 
437782527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4378bb63f56eSSukumar Swaminathan 	}
437982527734SSukumar Swaminathan 
438082527734SSukumar Swaminathan } /* emlxs_abort_ct_exchange() */
4381728bdc9bSSukumar Swaminathan 
4382fcf3ce44SJohn Forte 
4383fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4384fcf3ce44SJohn Forte static void
4385fcf3ce44SJohn Forte emlxs_sbp_abort_add(emlxs_port_t *port, emlxs_buf_t *sbp, Q *abort,
4386fcf3ce44SJohn Forte     uint8_t *flag, emlxs_buf_t *fpkt)
4387fcf3ce44SJohn Forte {
4388fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4389fcf3ce44SJohn Forte 	IOCBQ *iocbq;
439082527734SSukumar Swaminathan 	CHANNEL *cp;
4391fcf3ce44SJohn Forte 	NODELIST *ndlp;
4392fcf3ce44SJohn Forte 
439382527734SSukumar Swaminathan 	cp = (CHANNEL *)sbp->channel;
4394fcf3ce44SJohn Forte 	ndlp = sbp->node;
4395fcf3ce44SJohn Forte 
4396fcf3ce44SJohn Forte 	/* Create the close XRI IOCB */
4397a9800bebSGarrett D'Amore 	if (hba->state >= FC_LINK_UP) {
4398a9800bebSGarrett D'Amore 		iocbq = emlxs_create_abort_xri_cn(port, ndlp, sbp->iotag, cp,
4399a9800bebSGarrett D'Amore 		    CLASS3, ABORT_TYPE_ABTS);
4400a9800bebSGarrett D'Amore 	} else {
4401a9800bebSGarrett D'Amore 		iocbq = emlxs_create_close_xri_cn(port, ndlp, sbp->iotag, cp);
4402a9800bebSGarrett D'Amore 	}
4403291a2b48SSukumar Swaminathan 	/*
4404291a2b48SSukumar Swaminathan 	 * Add this iocb to our local abort Q
4405291a2b48SSukumar Swaminathan 	 * This way we don't hold the CHIPQ lock too long
4406291a2b48SSukumar Swaminathan 	 */
4407fcf3ce44SJohn Forte 	if (iocbq) {
4408fcf3ce44SJohn Forte 		if (abort->q_first) {
4409291a2b48SSukumar Swaminathan 			((IOCBQ *)abort->q_last)->next = iocbq;
4410fcf3ce44SJohn Forte 			abort->q_last = (uint8_t *)iocbq;
4411fcf3ce44SJohn Forte 			abort->q_cnt++;
4412fcf3ce44SJohn Forte 		} else {
4413fcf3ce44SJohn Forte 			abort->q_first = (uint8_t *)iocbq;
4414fcf3ce44SJohn Forte 			abort->q_last = (uint8_t *)iocbq;
4415fcf3ce44SJohn Forte 			abort->q_cnt = 1;
4416fcf3ce44SJohn Forte 		}
4417fcf3ce44SJohn Forte 		iocbq->next = NULL;
4418fcf3ce44SJohn Forte 	}
4419291a2b48SSukumar Swaminathan 
4420fcf3ce44SJohn Forte 	/* set the flags */
4421fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
4422fcf3ce44SJohn Forte 
4423fcf3ce44SJohn Forte 	sbp->pkt_flags |= (PACKET_IN_FLUSH | PACKET_XRI_CLOSED);
442482527734SSukumar Swaminathan 
4425fcf3ce44SJohn Forte 	sbp->ticks = hba->timer_tics + 10;
4426fcf3ce44SJohn Forte 	sbp->abort_attempts++;
4427fcf3ce44SJohn Forte 
442882527734SSukumar Swaminathan 	flag[cp->channelno] = 1;
4429fcf3ce44SJohn Forte 
4430fcf3ce44SJohn Forte 	/*
4431291a2b48SSukumar Swaminathan 	 * If the fpkt is already set, then we will leave it alone
4432fcf3ce44SJohn Forte 	 * This ensures that this pkt is only accounted for on one
4433fcf3ce44SJohn Forte 	 * fpkt->flush_count
4434fcf3ce44SJohn Forte 	 */
4435fcf3ce44SJohn Forte 	if (!sbp->fpkt && fpkt) {
4436fcf3ce44SJohn Forte 		mutex_enter(&fpkt->mtx);
4437fcf3ce44SJohn Forte 		sbp->fpkt = fpkt;
4438fcf3ce44SJohn Forte 		fpkt->flush_count++;
4439fcf3ce44SJohn Forte 		mutex_exit(&fpkt->mtx);
4440fcf3ce44SJohn Forte 	}
4441291a2b48SSukumar Swaminathan 
4442fcf3ce44SJohn Forte 	mutex_exit(&sbp->mtx);
4443fcf3ce44SJohn Forte 
4444fcf3ce44SJohn Forte 	return;
4445fcf3ce44SJohn Forte 
444682527734SSukumar Swaminathan }	/* emlxs_sbp_abort_add() */
4447