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.
25a3170057SPaul 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
emlxs_handle_fcp_event(emlxs_hba_t * hba,CHANNEL * cp,IOCBQ * iocbq)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
emlxs_post_buffer(emlxs_hba_t * hba,RING * rp,int16_t cnt)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
emlxs_fcp_tag_nodes(emlxs_port_t * port)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 *
emlxs_find_tagged_node(emlxs_port_t * port)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
emlxs_port_offline(emlxs_port_t * port,uint32_t scope)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) {
982*088c6f3fSHans Rosenfeld 		hba->flag &= ~FC_GPIO_LINK_UP;
983*088c6f3fSHans Rosenfeld 
984fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
985fcf3ce44SJohn Forte 
986fcf3ce44SJohn Forte 		port->flag &= EMLXS_PORT_LINKDOWN_MASK;
987fcf3ce44SJohn Forte 
988fcf3ce44SJohn Forte 		if (port->ulp_statec != FC_STATE_OFFLINE) {
989fcf3ce44SJohn Forte 			port->ulp_statec = FC_STATE_OFFLINE;
9908f23e9faSHans Rosenfeld 
991a9800bebSGarrett D'Amore 			port->prev_did = port->did;
9928f23e9faSHans Rosenfeld 			port->did = 0;
9938f23e9faSHans Rosenfeld 			port->rdid = 0;
9948f23e9faSHans Rosenfeld 
995a9800bebSGarrett D'Amore 			bcopy(&port->fabric_sparam, &port->prev_fabric_sparam,
996a9800bebSGarrett D'Amore 			    sizeof (SERV_PARM));
9978f23e9faSHans Rosenfeld 			bzero(&port->fabric_sparam, sizeof (SERV_PARM));
9988f23e9faSHans Rosenfeld 
999fcf3ce44SJohn Forte 			update = 1;
1000fcf3ce44SJohn Forte 		}
1001291a2b48SSukumar Swaminathan 
1002fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1003fcf3ce44SJohn Forte 
10048f23e9faSHans Rosenfeld 		emlxs_timer_cancel_clean_address(port);
10058f23e9faSHans Rosenfeld 
1006fcf3ce44SJohn Forte 		/* Tell ULP about it */
1007fcf3ce44SJohn Forte 		if (update) {
1008fcf3ce44SJohn Forte 			if (port->flag & EMLXS_PORT_BOUND) {
1009fcf3ce44SJohn Forte 				if (port->vpi == 0) {
1010fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1011291a2b48SSukumar Swaminathan 					    &emlxs_link_down_msg, NULL);
1012fcf3ce44SJohn Forte 				}
1013291a2b48SSukumar Swaminathan 
10148f23e9faSHans Rosenfeld 				if (port->mode == MODE_INITIATOR) {
10158f23e9faSHans Rosenfeld 					emlxs_fca_link_down(port);
10163be114edSSukumar Swaminathan 				}
1017291a2b48SSukumar Swaminathan #ifdef SFCT_SUPPORT
10188f23e9faSHans Rosenfeld 				else if (port->mode == MODE_TARGET) {
1019fcf3ce44SJohn Forte 					emlxs_fct_link_down(port);
10203be114edSSukumar Swaminathan 				}
1021291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
1022fcf3ce44SJohn Forte 
1023fcf3ce44SJohn Forte 			} else {
1024fcf3ce44SJohn Forte 				if (port->vpi == 0) {
1025fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1026291a2b48SSukumar Swaminathan 					    &emlxs_link_down_msg, "*");
1027fcf3ce44SJohn Forte 				}
1028fcf3ce44SJohn Forte 			}
1029fcf3ce44SJohn Forte 
1030fcf3ce44SJohn Forte 
1031fcf3ce44SJohn Forte 		}
1032291a2b48SSukumar Swaminathan 
1033fcf3ce44SJohn Forte 		unreg_vpi = 1;
1034fcf3ce44SJohn Forte 
1035fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1036fcf3ce44SJohn Forte 		/* Stop authentication with all nodes */
1037fcf3ce44SJohn Forte 		emlxs_dhc_auth_stop(port, NULL);
1038291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1039fcf3ce44SJohn Forte 
1040fcf3ce44SJohn Forte 		/* Flush the base node */
1041fcf3ce44SJohn Forte 		(void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0);
1042fcf3ce44SJohn Forte 		(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);
1043fcf3ce44SJohn Forte 
1044fcf3ce44SJohn Forte 		/* Flush any pending ub buffers */
1045fcf3ce44SJohn Forte 		emlxs_ub_flush(port);
1046fcf3ce44SJohn Forte 	}
1047fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1048fcf3ce44SJohn Forte 	/* virtual link down */
1049fcf3ce44SJohn Forte 	else if (vlinkdown) {
1050fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1051fcf3ce44SJohn Forte 
1052fcf3ce44SJohn Forte 		if (port->ulp_statec != FC_STATE_OFFLINE) {
1053fcf3ce44SJohn Forte 			port->ulp_statec = FC_STATE_OFFLINE;
1054fcf3ce44SJohn Forte 			update = 1;
1055fcf3ce44SJohn Forte 		}
1056291a2b48SSukumar Swaminathan 
1057fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1058fcf3ce44SJohn Forte 
10598f23e9faSHans Rosenfeld 		emlxs_timer_cancel_clean_address(port);
10608f23e9faSHans Rosenfeld 
1061fcf3ce44SJohn Forte 		/* Tell ULP about it */
1062fcf3ce44SJohn Forte 		if (update) {
1063fcf3ce44SJohn Forte 			if (port->flag & EMLXS_PORT_BOUND) {
1064fcf3ce44SJohn Forte 				if (port->vpi == 0) {
1065fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1066fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
1067fcf3ce44SJohn Forte 					    "Switch authentication failed.");
1068fcf3ce44SJohn Forte 				}
1069291a2b48SSukumar Swaminathan 
10708f23e9faSHans Rosenfeld 				if (port->mode == MODE_INITIATOR) {
10718f23e9faSHans Rosenfeld 					emlxs_fca_link_down(port);
10728f23e9faSHans Rosenfeld 				}
1073fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
10748f23e9faSHans Rosenfeld 				else if (port->mode == MODE_TARGET) {
1075fcf3ce44SJohn Forte 					emlxs_fct_link_down(port);
1076fcf3ce44SJohn Forte 				}
10778f23e9faSHans Rosenfeld #endif /* SFCT_SUPPORT */
1078fcf3ce44SJohn Forte 			} else {
1079fcf3ce44SJohn Forte 				if (port->vpi == 0) {
1080fcf3ce44SJohn Forte 					EMLXS_MSGF(EMLXS_CONTEXT,
1081fcf3ce44SJohn Forte 					    &emlxs_link_down_msg,
1082fcf3ce44SJohn Forte 					    "Switch authentication failed. *");
1083fcf3ce44SJohn Forte 				}
1084fcf3ce44SJohn Forte 			}
1085fcf3ce44SJohn Forte 
1086fcf3ce44SJohn Forte 
1087fcf3ce44SJohn Forte 		}
1088291a2b48SSukumar Swaminathan 
1089fcf3ce44SJohn Forte 		/* Flush the base node */
1090fcf3ce44SJohn Forte 		(void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0);
1091fcf3ce44SJohn Forte 		(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);
1092fcf3ce44SJohn Forte 	}
1093291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
10948f23e9faSHans Rosenfeld 	else {
10958f23e9faSHans Rosenfeld 		emlxs_timer_cancel_clean_address(port);
10968f23e9faSHans Rosenfeld 	}
1097fcf3ce44SJohn Forte 
10988f23e9faSHans Rosenfeld 	if (port->mode == MODE_TARGET) {
10998f23e9faSHans Rosenfeld 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
11008f23e9faSHans Rosenfeld 			/* Set the node tags */
11018f23e9faSHans Rosenfeld 			emlxs_fcp_tag_nodes(port);
11028f23e9faSHans Rosenfeld 			unreg_vpi = 0;
11038f23e9faSHans Rosenfeld 			while ((nlp = emlxs_find_tagged_node(port))) {
11048f23e9faSHans Rosenfeld 				(void) emlxs_rpi_pause_notify(port,
11058f23e9faSHans Rosenfeld 				    nlp->rpip);
11068f23e9faSHans Rosenfeld 				/*
11078f23e9faSHans Rosenfeld 				 * In port_online we need to resume
11088f23e9faSHans Rosenfeld 				 * these RPIs before we can use them.
11098f23e9faSHans Rosenfeld 				 */
11108f23e9faSHans Rosenfeld 			}
11118f23e9faSHans Rosenfeld 		}
1112fcf3ce44SJohn Forte 		goto done;
1113fcf3ce44SJohn Forte 	}
1114291a2b48SSukumar Swaminathan 
1115fcf3ce44SJohn Forte 	/* Set the node tags */
11168f23e9faSHans Rosenfeld 	emlxs_fcp_tag_nodes(port);
1117fcf3ce44SJohn Forte 
1118a9800bebSGarrett D'Amore 	if (!clear_all && (hba->flag & FC_ONLINE_MODE)) {
1119fcf3ce44SJohn Forte 		adisc_support = cfg[CFG_ADISC_SUPPORT].current;
1120fcf3ce44SJohn Forte 	} else {
1121fcf3ce44SJohn Forte 		adisc_support = 0;
1122fcf3ce44SJohn Forte 	}
1123fcf3ce44SJohn Forte 
1124fcf3ce44SJohn Forte 	/* Check ADISC support level */
1125fcf3ce44SJohn Forte 	switch (adisc_support) {
1126fcf3ce44SJohn Forte 	case 0:	/* No support - Flush all IO to all matching nodes */
1127fcf3ce44SJohn Forte 
1128291a2b48SSukumar Swaminathan 		for (;;) {
1129fcf3ce44SJohn Forte 			/*
1130fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
11318f23e9faSHans Rosenfeld 			 * EMLXS_SLI_UNREG_NODE and the flush routines enter the
1132291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
1133291a2b48SSukumar Swaminathan 			 * can change out from under us.
1134fcf3ce44SJohn Forte 			 */
1135fcf3ce44SJohn Forte 
1136fcf3ce44SJohn Forte 			/* Find first node */
1137fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1138fcf3ce44SJohn Forte 			action = 0;
1139fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1140fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1141fcf3ce44SJohn Forte 				while (nlp != NULL) {
1142fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1143fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1144fcf3ce44SJohn Forte 						continue;
1145fcf3ce44SJohn Forte 					}
1146fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1147fcf3ce44SJohn Forte 
1148fcf3ce44SJohn Forte 					/*
1149fcf3ce44SJohn Forte 					 * Check for any device that matches
1150fcf3ce44SJohn Forte 					 * our mask
1151fcf3ce44SJohn Forte 					 */
1152fcf3ce44SJohn Forte 					if ((nlp->nlp_DID & mask) == aff_d_id) {
1153fcf3ce44SJohn Forte 						if (linkdown) {
1154fcf3ce44SJohn Forte 							action = 1;
1155fcf3ce44SJohn Forte 							break;
1156291a2b48SSukumar Swaminathan 						} else { /* Must be an RCSN */
1157291a2b48SSukumar Swaminathan 
1158fcf3ce44SJohn Forte 							action = 2;
1159fcf3ce44SJohn Forte 							break;
1160fcf3ce44SJohn Forte 						}
1161fcf3ce44SJohn Forte 					}
1162fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1163fcf3ce44SJohn Forte 				}
1164fcf3ce44SJohn Forte 
1165fcf3ce44SJohn Forte 				if (action) {
1166fcf3ce44SJohn Forte 					break;
1167fcf3ce44SJohn Forte 				}
1168fcf3ce44SJohn Forte 			}
1169fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1170fcf3ce44SJohn Forte 
1171fcf3ce44SJohn Forte 
1172fcf3ce44SJohn Forte 			/* Check if nothing was found */
1173fcf3ce44SJohn Forte 			if (action == 0) {
1174fcf3ce44SJohn Forte 				break;
1175fcf3ce44SJohn Forte 			} else if (action == 1) {
11768f23e9faSHans Rosenfeld 				(void) EMLXS_SLI_UNREG_NODE(port, nlp,
1177fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1178fcf3ce44SJohn Forte 			} else if (action == 2) {
11798f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
11808f23e9faSHans Rosenfeld 
1181fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1182fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1183291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1184fcf3ce44SJohn Forte 
1185291a2b48SSukumar Swaminathan 				/*
1186291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1187291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
1188291a2b48SSukumar Swaminathan 				 */
118982527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
119082527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
119182527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
119282527734SSukumar Swaminathan 				    hba->channel_ip, 60);
1193fcf3ce44SJohn Forte 
1194fcf3ce44SJohn Forte 				/* Flush tx queue */
1195fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1196fcf3ce44SJohn Forte 
1197fcf3ce44SJohn Forte 				/* Flush chip queue */
1198fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1199fcf3ce44SJohn Forte 			}
1200291a2b48SSukumar Swaminathan 
1201fcf3ce44SJohn Forte 		}
1202fcf3ce44SJohn Forte 
1203fcf3ce44SJohn Forte 		break;
1204fcf3ce44SJohn Forte 
1205291a2b48SSukumar Swaminathan 	case 1:	/* Partial support - Flush IO for non-FCP2 matching nodes */
1206fcf3ce44SJohn Forte 
1207fcf3ce44SJohn Forte 		for (;;) {
1208fcf3ce44SJohn Forte 
1209fcf3ce44SJohn Forte 			/*
1210fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
12118f23e9faSHans Rosenfeld 			 * EMLXS_SLI_UNREG_NODE and the flush routines enter the
1212291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
1213291a2b48SSukumar Swaminathan 			 * can change out from under us.
1214fcf3ce44SJohn Forte 			 */
1215fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1216fcf3ce44SJohn Forte 			action = 0;
1217fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1218fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1219fcf3ce44SJohn Forte 				while (nlp != NULL) {
1220fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1221fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1222fcf3ce44SJohn Forte 						continue;
1223fcf3ce44SJohn Forte 					}
1224fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1225fcf3ce44SJohn Forte 
1226fcf3ce44SJohn Forte 					/*
1227291a2b48SSukumar Swaminathan 					 * Check for special FCP2 target device
1228291a2b48SSukumar Swaminathan 					 * that matches our mask
1229fcf3ce44SJohn Forte 					 */
1230fcf3ce44SJohn Forte 					if ((nlp->nlp_fcp_info &
1231fcf3ce44SJohn Forte 					    NLP_FCP_TGT_DEVICE) &&
1232291a2b48SSukumar Swaminathan 					    (nlp-> nlp_fcp_info &
1233fcf3ce44SJohn Forte 					    NLP_FCP_2_DEVICE) &&
1234291a2b48SSukumar Swaminathan 					    (nlp->nlp_DID & mask) ==
1235291a2b48SSukumar Swaminathan 					    aff_d_id) {
1236fcf3ce44SJohn Forte 						action = 3;
1237fcf3ce44SJohn Forte 						break;
1238fcf3ce44SJohn Forte 					}
1239291a2b48SSukumar Swaminathan 
1240fcf3ce44SJohn Forte 					/*
1241fcf3ce44SJohn Forte 					 * Check for any other device that
1242fcf3ce44SJohn Forte 					 * matches our mask
1243fcf3ce44SJohn Forte 					 */
1244fcf3ce44SJohn Forte 					else if ((nlp->nlp_DID & mask) ==
1245fcf3ce44SJohn Forte 					    aff_d_id) {
1246fcf3ce44SJohn Forte 						if (linkdown) {
1247fcf3ce44SJohn Forte 							action = 1;
1248fcf3ce44SJohn Forte 							break;
1249291a2b48SSukumar Swaminathan 						} else { /* Must be an RSCN */
1250291a2b48SSukumar Swaminathan 
1251fcf3ce44SJohn Forte 							action = 2;
1252fcf3ce44SJohn Forte 							break;
1253fcf3ce44SJohn Forte 						}
1254fcf3ce44SJohn Forte 					}
1255291a2b48SSukumar Swaminathan 
1256fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1257fcf3ce44SJohn Forte 				}
1258fcf3ce44SJohn Forte 
1259fcf3ce44SJohn Forte 				if (action) {
1260fcf3ce44SJohn Forte 					break;
1261fcf3ce44SJohn Forte 				}
1262fcf3ce44SJohn Forte 			}
1263fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1264fcf3ce44SJohn Forte 
1265fcf3ce44SJohn Forte 			/* Check if nothing was found */
1266fcf3ce44SJohn Forte 			if (action == 0) {
1267fcf3ce44SJohn Forte 				break;
1268fcf3ce44SJohn Forte 			} else if (action == 1) {
12698f23e9faSHans Rosenfeld 				(void) EMLXS_SLI_UNREG_NODE(port, nlp,
1270fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1271fcf3ce44SJohn Forte 			} else if (action == 2) {
12728f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
12738f23e9faSHans Rosenfeld 
1274fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1275fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1276291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1277fcf3ce44SJohn Forte 
1278291a2b48SSukumar Swaminathan 				/*
1279291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1280291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
1281291a2b48SSukumar Swaminathan 				 */
128282527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
128382527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
128482527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
128582527734SSukumar Swaminathan 				    hba->channel_ip, 60);
1286fcf3ce44SJohn Forte 
1287fcf3ce44SJohn Forte 				/* Flush tx queue */
1288fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1289fcf3ce44SJohn Forte 
1290fcf3ce44SJohn Forte 				/* Flush chip queue */
1291fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1292291a2b48SSukumar Swaminathan 
1293fcf3ce44SJohn Forte 			} else if (action == 3) {	/* FCP2 devices */
12948f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
12958f23e9faSHans Rosenfeld 
1296fcf3ce44SJohn Forte 				unreg_vpi = 0;
1297fcf3ce44SJohn Forte 
1298a9800bebSGarrett D'Amore 				if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1299a9800bebSGarrett D'Amore 					(void) emlxs_rpi_pause_notify(port,
1300a9800bebSGarrett D'Amore 					    nlp->rpip);
1301a9800bebSGarrett D'Amore 				}
1302a9800bebSGarrett D'Amore 
1303fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT
1304fcf3ce44SJohn Forte 				emlxs_dhc_auth_stop(port, nlp);
1305291a2b48SSukumar Swaminathan #endif /* DHCHAP_SUPPORT */
1306fcf3ce44SJohn Forte 
1307291a2b48SSukumar Swaminathan 				/*
1308291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1309291a2b48SSukumar Swaminathan 				 * An ADISC or a PLOGI with reopen the node
1310291a2b48SSukumar Swaminathan 				 */
131182527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
131282527734SSukumar Swaminathan 				    hba->channel_fcp, -1);
131382527734SSukumar Swaminathan 				emlxs_node_close(port, nlp, hba->channel_ip,
1314fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1315fcf3ce44SJohn Forte 
1316fcf3ce44SJohn Forte 				/* Flush tx queues except for FCP ring */
1317fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
131882527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], 0, 0);
1319fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
132082527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], 0, 0);
1321fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
132282527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], 0, 0);
1323fcf3ce44SJohn Forte 
1324fcf3ce44SJohn Forte 				/* Flush chip queues except for FCP ring */
1325fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
132682527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], nlp, 0);
1327fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
132882527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], nlp, 0);
1329fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
133082527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], nlp, 0);
1331fcf3ce44SJohn Forte 			}
1332fcf3ce44SJohn Forte 		}
1333fcf3ce44SJohn Forte 		break;
1334fcf3ce44SJohn Forte 
1335fcf3ce44SJohn Forte 	case 2:	/* Full support - Hold FCP IO to FCP target matching nodes */
1336fcf3ce44SJohn Forte 
1337fcf3ce44SJohn Forte 		if (!linkdown && !vlinkdown) {
1338fcf3ce44SJohn Forte 			break;
1339fcf3ce44SJohn Forte 		}
1340291a2b48SSukumar Swaminathan 
1341fcf3ce44SJohn Forte 		for (;;) {
1342fcf3ce44SJohn Forte 			/*
1343fcf3ce44SJohn Forte 			 * We need to hold the locks this way because
13448f23e9faSHans Rosenfeld 			 * EMLXS_SLI_UNREG_NODE and the flush routines enter the
1345291a2b48SSukumar Swaminathan 			 * same locks. Also, when we release the lock the list
1346291a2b48SSukumar Swaminathan 			 * can change out from under us.
1347fcf3ce44SJohn Forte 			 */
1348fcf3ce44SJohn Forte 			rw_enter(&port->node_rwlock, RW_READER);
1349fcf3ce44SJohn Forte 			action = 0;
1350fcf3ce44SJohn Forte 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1351fcf3ce44SJohn Forte 				nlp = port->node_table[i];
1352fcf3ce44SJohn Forte 				while (nlp != NULL) {
1353fcf3ce44SJohn Forte 					if (!nlp->nlp_tag) {
1354fcf3ce44SJohn Forte 						nlp = nlp->nlp_list_next;
1355fcf3ce44SJohn Forte 						continue;
1356fcf3ce44SJohn Forte 					}
1357fcf3ce44SJohn Forte 					nlp->nlp_tag = 0;
1358fcf3ce44SJohn Forte 
1359fcf3ce44SJohn Forte 					/*
1360fcf3ce44SJohn Forte 					 * Check for FCP target device that
1361fcf3ce44SJohn Forte 					 * matches our mask
1362fcf3ce44SJohn Forte 					 */
1363291a2b48SSukumar Swaminathan 					if ((nlp-> nlp_fcp_info &
1364fcf3ce44SJohn Forte 					    NLP_FCP_TGT_DEVICE) &&
1365291a2b48SSukumar Swaminathan 					    (nlp->nlp_DID & mask) ==
1366291a2b48SSukumar Swaminathan 					    aff_d_id) {
1367fcf3ce44SJohn Forte 						action = 3;
1368fcf3ce44SJohn Forte 						break;
1369fcf3ce44SJohn Forte 					}
1370291a2b48SSukumar Swaminathan 
1371fcf3ce44SJohn Forte 					/*
1372fcf3ce44SJohn Forte 					 * Check for any other device that
1373fcf3ce44SJohn Forte 					 * matches our mask
1374fcf3ce44SJohn Forte 					 */
1375fcf3ce44SJohn Forte 					else if ((nlp->nlp_DID & mask) ==
1376fcf3ce44SJohn Forte 					    aff_d_id) {
1377fcf3ce44SJohn Forte 						if (linkdown) {
1378fcf3ce44SJohn Forte 							action = 1;
1379fcf3ce44SJohn Forte 							break;
1380fcf3ce44SJohn Forte 						} else { /* Must be an RSCN */
1381291a2b48SSukumar Swaminathan 
1382fcf3ce44SJohn Forte 							action = 2;
1383fcf3ce44SJohn Forte 							break;
1384fcf3ce44SJohn Forte 						}
1385fcf3ce44SJohn Forte 					}
1386291a2b48SSukumar Swaminathan 
1387fcf3ce44SJohn Forte 					nlp = nlp->nlp_list_next;
1388fcf3ce44SJohn Forte 				}
1389fcf3ce44SJohn Forte 				if (action) {
1390fcf3ce44SJohn Forte 					break;
1391fcf3ce44SJohn Forte 				}
1392fcf3ce44SJohn Forte 			}
1393fcf3ce44SJohn Forte 			rw_exit(&port->node_rwlock);
1394fcf3ce44SJohn Forte 
1395fcf3ce44SJohn Forte 			/* Check if nothing was found */
1396fcf3ce44SJohn Forte 			if (action == 0) {
1397fcf3ce44SJohn Forte 				break;
1398fcf3ce44SJohn Forte 			} else if (action == 1) {
13998f23e9faSHans Rosenfeld 				(void) EMLXS_SLI_UNREG_NODE(port, nlp,
1400fcf3ce44SJohn Forte 				    NULL, NULL, NULL);
1401fcf3ce44SJohn Forte 			} else if (action == 2) {
14028f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
14038f23e9faSHans Rosenfeld 
1404291a2b48SSukumar Swaminathan 				/*
1405291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1406291a2b48SSukumar Swaminathan 				 * A PLOGI with reopen the node
1407291a2b48SSukumar Swaminathan 				 */
140882527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
140982527734SSukumar Swaminathan 				    hba->channel_fcp, 60);
141082527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
141182527734SSukumar Swaminathan 				    hba->channel_ip, 60);
1412fcf3ce44SJohn Forte 
1413fcf3ce44SJohn Forte 				/* Flush tx queue */
1414fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp, 0, 0, 0);
1415fcf3ce44SJohn Forte 
1416fcf3ce44SJohn Forte 				/* Flush chip queue */
1417fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port, 0, nlp, 0);
1418fcf3ce44SJohn Forte 
1419fcf3ce44SJohn Forte 			} else if (action == 3) {	/* FCP2 devices */
14208f23e9faSHans Rosenfeld 				EMLXS_SET_DFC_STATE(nlp, NODE_LIMBO);
14218f23e9faSHans Rosenfeld 
1422fcf3ce44SJohn Forte 				unreg_vpi = 0;
1423fcf3ce44SJohn Forte 
1424a9800bebSGarrett D'Amore 				if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
1425a9800bebSGarrett D'Amore 					(void) emlxs_rpi_pause_notify(port,
1426a9800bebSGarrett D'Amore 					    nlp->rpip);
1427a9800bebSGarrett D'Amore 				}
1428a9800bebSGarrett D'Amore 
1429291a2b48SSukumar Swaminathan 				/*
1430291a2b48SSukumar Swaminathan 				 * Close the node for any further normal IO
1431291a2b48SSukumar Swaminathan 				 * An ADISC or a PLOGI with reopen the node
1432291a2b48SSukumar Swaminathan 				 */
143382527734SSukumar Swaminathan 				emlxs_node_close(port, nlp,
143482527734SSukumar Swaminathan 				    hba->channel_fcp, -1);
143582527734SSukumar Swaminathan 				emlxs_node_close(port, nlp, hba->channel_ip,
1436fcf3ce44SJohn Forte 				    ((linkdown) ? 0 : 60));
1437fcf3ce44SJohn Forte 
1438fcf3ce44SJohn Forte 				/* Flush tx queues except for FCP ring */
1439fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
144082527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], 0, 0);
1441fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
144282527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], 0, 0);
1443fcf3ce44SJohn Forte 				(void) emlxs_tx_node_flush(port, nlp,
144482527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], 0, 0);
1445fcf3ce44SJohn Forte 
1446fcf3ce44SJohn Forte 				/* Flush chip queues except for FCP ring */
1447fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
144882527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ct], nlp, 0);
1449fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
145082527734SSukumar Swaminathan 				    &hba->chan[hba->channel_els], nlp, 0);
1451fcf3ce44SJohn Forte 				(void) emlxs_chipq_node_flush(port,
145282527734SSukumar Swaminathan 				    &hba->chan[hba->channel_ip], nlp, 0);
1453fcf3ce44SJohn Forte 			}
1454fcf3ce44SJohn Forte 		}
1455fcf3ce44SJohn Forte 
1456fcf3ce44SJohn Forte 		break;
1457fcf3ce44SJohn Forte 
1458fcf3ce44SJohn Forte 	}	/* switch() */
1459fcf3ce44SJohn Forte 
1460fcf3ce44SJohn Forte done:
1461fcf3ce44SJohn Forte 
1462a9800bebSGarrett D'Amore 	if (unreg_vpi) {
1463a9800bebSGarrett D'Amore 		(void) emlxs_mb_unreg_vpi(port);
1464fcf3ce44SJohn Forte 	}
1465fcf3ce44SJohn Forte 
1466291a2b48SSukumar Swaminathan 	return (0);
1467fcf3ce44SJohn Forte 
146882527734SSukumar Swaminathan } /* emlxs_port_offline() */
1469fcf3ce44SJohn Forte 
1470fcf3ce44SJohn Forte 
1471fcf3ce44SJohn Forte extern void
emlxs_port_online(emlxs_port_t * vport)1472fcf3ce44SJohn Forte emlxs_port_online(emlxs_port_t *vport)
1473fcf3ce44SJohn Forte {
1474fcf3ce44SJohn Forte 	emlxs_hba_t *hba = vport->hba;
1475fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
14768f23e9faSHans Rosenfeld 	NODELIST *nlp;
1477fcf3ce44SJohn Forte 	uint32_t state;
1478fcf3ce44SJohn Forte 	uint32_t update;
1479fcf3ce44SJohn Forte 	uint32_t npiv_linkup;
1480fcf3ce44SJohn Forte 	char topology[32];
1481fcf3ce44SJohn Forte 	char linkspeed[32];
1482fcf3ce44SJohn Forte 	char mode[32];
1483fcf3ce44SJohn Forte 
1484fcf3ce44SJohn Forte 	/*
1485291a2b48SSukumar Swaminathan 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1486291a2b48SSukumar Swaminathan 	 *    "linkup_callback. vpi=%d fc_flag=%x", vport->vpi, hba->flag);
1487fcf3ce44SJohn Forte 	 */
1488fcf3ce44SJohn Forte 
1489fcf3ce44SJohn Forte 	if ((vport->vpi > 0) &&
1490fcf3ce44SJohn Forte 	    (!(hba->flag & FC_NPIV_ENABLED) ||
1491fcf3ce44SJohn Forte 	    !(hba->flag & FC_NPIV_SUPPORTED))) {
1492fcf3ce44SJohn Forte 		return;
1493fcf3ce44SJohn Forte 	}
1494291a2b48SSukumar Swaminathan 
1495fcf3ce44SJohn Forte 	if (!(vport->flag & EMLXS_PORT_BOUND) ||
14968f23e9faSHans Rosenfeld 	    !(vport->flag & EMLXS_PORT_ENABLED)) {
1497fcf3ce44SJohn Forte 		return;
1498fcf3ce44SJohn Forte 	}
1499291a2b48SSukumar Swaminathan 
1500fcf3ce44SJohn Forte 	/* Check for mode */
15018f23e9faSHans Rosenfeld 	if (port->mode == MODE_TARGET) {
15028f23e9faSHans Rosenfeld 		(void) strlcpy(mode, ", target", sizeof (mode));
15038f23e9faSHans Rosenfeld 
15048f23e9faSHans Rosenfeld 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
15058f23e9faSHans Rosenfeld 			/* Set the node tags */
15068f23e9faSHans Rosenfeld 			emlxs_fcp_tag_nodes(vport);
15078f23e9faSHans Rosenfeld 			while ((nlp = emlxs_find_tagged_node(vport))) {
15088f23e9faSHans Rosenfeld 				/* The RPI was paused in port_offline */
15098f23e9faSHans Rosenfeld 				(void) emlxs_rpi_resume_notify(vport,
15108f23e9faSHans Rosenfeld 				    nlp->rpip, 0);
15118f23e9faSHans Rosenfeld 			}
15128f23e9faSHans Rosenfeld 		}
15138f23e9faSHans Rosenfeld 	} else if (port->mode == MODE_INITIATOR) {
15148f23e9faSHans Rosenfeld 		(void) strlcpy(mode, ", initiator", sizeof (mode));
1515fcf3ce44SJohn Forte 	} else {
15168f23e9faSHans Rosenfeld 		(void) strlcpy(mode, "unknown", sizeof (mode));
1517fcf3ce44SJohn Forte 	}
15188f23e9faSHans Rosenfeld 	mutex_enter(&EMLXS_PORT_LOCK);
1519fcf3ce44SJohn Forte 
1520fcf3ce44SJohn Forte 	/* Check for loop topology */
1521fcf3ce44SJohn Forte 	if (hba->topology == TOPOLOGY_LOOP) {
1522fcf3ce44SJohn Forte 		state = FC_STATE_LOOP;
15238f23e9faSHans Rosenfeld 		(void) strlcpy(topology, ", loop", sizeof (topology));
1524fcf3ce44SJohn Forte 	} else {
1525fcf3ce44SJohn Forte 		state = FC_STATE_ONLINE;
15268f23e9faSHans Rosenfeld 		(void) strlcpy(topology, ", fabric", sizeof (topology));
1527fcf3ce44SJohn Forte 	}
1528fcf3ce44SJohn Forte 
1529fcf3ce44SJohn Forte 	/* Set the link speed */
1530fcf3ce44SJohn Forte 	switch (hba->linkspeed) {
1531fcf3ce44SJohn Forte 	case 0:
15328f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "Gb", sizeof (linkspeed));
1533fcf3ce44SJohn Forte 		state |= FC_STATE_1GBIT_SPEED;
1534fcf3ce44SJohn Forte 		break;
1535fcf3ce44SJohn Forte 
1536fcf3ce44SJohn Forte 	case LA_1GHZ_LINK:
15378f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "1Gb", sizeof (linkspeed));
1538fcf3ce44SJohn Forte 		state |= FC_STATE_1GBIT_SPEED;
1539fcf3ce44SJohn Forte 		break;
1540fcf3ce44SJohn Forte 	case LA_2GHZ_LINK:
15418f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "2Gb", sizeof (linkspeed));
1542fcf3ce44SJohn Forte 		state |= FC_STATE_2GBIT_SPEED;
1543fcf3ce44SJohn Forte 		break;
1544fcf3ce44SJohn Forte 	case LA_4GHZ_LINK:
15458f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "4Gb", sizeof (linkspeed));
1546fcf3ce44SJohn Forte 		state |= FC_STATE_4GBIT_SPEED;
1547fcf3ce44SJohn Forte 		break;
1548fcf3ce44SJohn Forte 	case LA_8GHZ_LINK:
15498f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "8Gb", sizeof (linkspeed));
1550fcf3ce44SJohn Forte 		state |= FC_STATE_8GBIT_SPEED;
1551fcf3ce44SJohn Forte 		break;
1552fcf3ce44SJohn Forte 	case LA_10GHZ_LINK:
15538f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "10Gb", sizeof (linkspeed));
1554fcf3ce44SJohn Forte 		state |= FC_STATE_10GBIT_SPEED;
1555fcf3ce44SJohn Forte 		break;
15568f23e9faSHans Rosenfeld 	case LA_16GHZ_LINK:
15578f23e9faSHans Rosenfeld 		(void) strlcpy(linkspeed, "16Gb", sizeof (linkspeed));
15588f23e9faSHans Rosenfeld 		state |= FC_STATE_16GBIT_SPEED;
15598f23e9faSHans Rosenfeld 		break;
1560a3170057SPaul Winder 	case LA_32GHZ_LINK:
1561a3170057SPaul Winder 		(void) strlcpy(linkspeed, "32Gb", sizeof (linkspeed));
1562a3170057SPaul Winder 		state |= FC_STATE_32GBIT_SPEED;
1563a3170057SPaul Winder 		break;
1564fcf3ce44SJohn Forte 	default:
15658f23e9faSHans Rosenfeld 		(void) snprintf(linkspeed, sizeof (linkspeed), "unknown(0x%x)",
15668f23e9faSHans Rosenfeld 		    hba->linkspeed);
1567fcf3ce44SJohn Forte 		break;
1568fcf3ce44SJohn Forte 	}
1569fcf3ce44SJohn Forte 
1570fcf3ce44SJohn Forte 	npiv_linkup = 0;
1571fcf3ce44SJohn Forte 	update = 0;
1572fcf3ce44SJohn Forte 
1573fcf3ce44SJohn Forte 	if ((hba->state >= FC_LINK_UP) &&
1574291a2b48SSukumar Swaminathan 	    !(hba->flag & FC_LOOPBACK_MODE) && (vport->ulp_statec != state)) {
1575fcf3ce44SJohn Forte 		update = 1;
1576fcf3ce44SJohn Forte 		vport->ulp_statec = state;
1577fcf3ce44SJohn Forte 
1578fcf3ce44SJohn Forte 		if ((vport->vpi > 0) && !(hba->flag & FC_NPIV_LINKUP)) {
1579fcf3ce44SJohn Forte 			hba->flag |= FC_NPIV_LINKUP;
1580fcf3ce44SJohn Forte 			npiv_linkup = 1;
1581fcf3ce44SJohn Forte 		}
1582fcf3ce44SJohn Forte 	}
1583291a2b48SSukumar Swaminathan 
1584fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1585fcf3ce44SJohn Forte 
1586fcf3ce44SJohn Forte 	if (update) {
1587fcf3ce44SJohn Forte 		if (vport->flag & EMLXS_PORT_BOUND) {
1588fcf3ce44SJohn Forte 			if (vport->vpi == 0) {
1589fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1590291a2b48SSukumar Swaminathan 				    "%s%s%s", linkspeed, topology, mode);
15916a573d82SSukumar Swaminathan 
1592fcf3ce44SJohn Forte 			} else if (npiv_linkup) {
1593fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT,
1594291a2b48SSukumar Swaminathan 				    &emlxs_npiv_link_up_msg, "%s%s%s",
1595fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1596fcf3ce44SJohn Forte 			}
1597291a2b48SSukumar Swaminathan 
15988f23e9faSHans Rosenfeld 			if (vport->mode == MODE_INITIATOR) {
15998f23e9faSHans Rosenfeld 				emlxs_fca_link_up(vport);
1600fcf3ce44SJohn Forte 			}
16013be114edSSukumar Swaminathan #ifdef SFCT_SUPPORT
16028f23e9faSHans Rosenfeld 			else if (vport->mode == MODE_TARGET) {
16033be114edSSukumar Swaminathan 				emlxs_fct_link_up(vport);
16043be114edSSukumar Swaminathan 			}
16053be114edSSukumar Swaminathan #endif /* SFCT_SUPPORT */
1606fcf3ce44SJohn Forte 		} else {
1607fcf3ce44SJohn Forte 			if (vport->vpi == 0) {
1608fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg,
1609291a2b48SSukumar Swaminathan 				    "%s%s%s *", linkspeed, topology, mode);
16106a573d82SSukumar Swaminathan 
1611fcf3ce44SJohn Forte 			} else if (npiv_linkup) {
1612fcf3ce44SJohn Forte 				EMLXS_MSGF(EMLXS_CONTEXT,
1613291a2b48SSukumar Swaminathan 				    &emlxs_npiv_link_up_msg, "%s%s%s *",
1614fcf3ce44SJohn Forte 				    linkspeed, topology, mode);
1615fcf3ce44SJohn Forte 			}
1616fcf3ce44SJohn Forte 		}
1617fcf3ce44SJohn Forte 
1618fcf3ce44SJohn Forte 		/* Check for waiting threads */
1619fcf3ce44SJohn Forte 		if (vport->vpi == 0) {
1620fcf3ce44SJohn Forte 			mutex_enter(&EMLXS_LINKUP_LOCK);
1621fcf3ce44SJohn Forte 			if (hba->linkup_wait_flag == TRUE) {
1622fcf3ce44SJohn Forte 				hba->linkup_wait_flag = FALSE;
1623fcf3ce44SJohn Forte 				cv_broadcast(&EMLXS_LINKUP_CV);
1624fcf3ce44SJohn Forte 			}
1625fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_LINKUP_LOCK);
1626fcf3ce44SJohn Forte 		}
1627291a2b48SSukumar Swaminathan 
1628fcf3ce44SJohn Forte 		/* Flush any pending ub buffers */
1629fcf3ce44SJohn Forte 		emlxs_ub_flush(vport);
1630fcf3ce44SJohn Forte 	}
1631291a2b48SSukumar Swaminathan 
1632*088c6f3fSHans Rosenfeld 	hba->flag |= FC_GPIO_LINK_UP;
1633*088c6f3fSHans Rosenfeld 
1634fcf3ce44SJohn Forte 	return;
1635fcf3ce44SJohn Forte 
163682527734SSukumar Swaminathan } /* emlxs_port_online() */
1637fcf3ce44SJohn Forte 
1638fcf3ce44SJohn Forte 
1639a9800bebSGarrett D'Amore /* SLI3 */
1640fcf3ce44SJohn Forte extern void
emlxs_linkdown(emlxs_hba_t * hba)1641fcf3ce44SJohn Forte emlxs_linkdown(emlxs_hba_t *hba)
1642fcf3ce44SJohn Forte {
1643fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1644fcf3ce44SJohn Forte 	int i;
1645a9800bebSGarrett D'Amore 	uint32_t scope;
1646fcf3ce44SJohn Forte 
1647fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1648fcf3ce44SJohn Forte 
164982527734SSukumar Swaminathan 	if (hba->state > FC_LINK_DOWN) {
165082527734SSukumar Swaminathan 		HBASTATS.LinkDown++;
165182527734SSukumar Swaminathan 		EMLXS_STATE_CHANGE_LOCKED(hba, FC_LINK_DOWN);
165282527734SSukumar Swaminathan 	}
1653fcf3ce44SJohn Forte 
1654a9800bebSGarrett D'Amore 	/* Set scope */
1655a9800bebSGarrett D'Amore 	scope = (hba->flag & FC_NEW_FABRIC)? 0xFDFFFFFF:0xFFFFFFFF;
1656a9800bebSGarrett D'Amore 
1657fcf3ce44SJohn Forte 	/* Filter hba flags */
1658fcf3ce44SJohn Forte 	hba->flag &= FC_LINKDOWN_MASK;
1659fcf3ce44SJohn Forte 	hba->discovery_timer = 0;
1660fcf3ce44SJohn Forte 	hba->linkup_timer = 0;
1661fcf3ce44SJohn Forte 
1662fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1663fcf3ce44SJohn Forte 
1664fcf3ce44SJohn Forte 	for (i = 0; i < MAX_VPORTS; i++) {
1665fcf3ce44SJohn Forte 		port = &VPORT(i);
1666fcf3ce44SJohn Forte 
1667fcf3ce44SJohn Forte 		if (!(port->flag & EMLXS_PORT_BOUND)) {
1668fcf3ce44SJohn Forte 			continue;
1669fcf3ce44SJohn Forte 		}
1670291a2b48SSukumar Swaminathan 
1671a9800bebSGarrett D'Amore 		(void) emlxs_port_offline(port, scope);
1672fcf3ce44SJohn Forte 
1673fcf3ce44SJohn Forte 	}
1674fcf3ce44SJohn Forte 
1675a9800bebSGarrett D'Amore 	emlxs_log_link_event(port);
1676a9800bebSGarrett D'Amore 
1677fcf3ce44SJohn Forte 	return;
1678fcf3ce44SJohn Forte 
167982527734SSukumar Swaminathan } /* emlxs_linkdown() */
1680fcf3ce44SJohn Forte 
1681fcf3ce44SJohn Forte 
1682a9800bebSGarrett D'Amore /* SLI3 */
1683fcf3ce44SJohn Forte extern void
emlxs_linkup(emlxs_hba_t * hba)1684fcf3ce44SJohn Forte emlxs_linkup(emlxs_hba_t *hba)
1685fcf3ce44SJohn Forte {
1686fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1687fcf3ce44SJohn Forte 	emlxs_config_t *cfg = &CFG;
1688fcf3ce44SJohn Forte 
1689fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1690fcf3ce44SJohn Forte 
16918f23e9faSHans Rosenfeld 	/* Check for any mode changes */
16928f23e9faSHans Rosenfeld 	emlxs_mode_set(hba);
16938f23e9faSHans Rosenfeld 
1694fcf3ce44SJohn Forte 	HBASTATS.LinkUp++;
169582527734SSukumar Swaminathan 	EMLXS_STATE_CHANGE_LOCKED(hba, FC_LINK_UP);
1696fcf3ce44SJohn Forte 
1697fcf3ce44SJohn Forte #ifdef MENLO_SUPPORT
1698fcf3ce44SJohn Forte 	if (hba->flag & FC_MENLO_MODE) {
1699fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1700fcf3ce44SJohn Forte 
1701fcf3ce44SJohn Forte 		/*
1702fcf3ce44SJohn Forte 		 * Trigger linkup CV and don't start linkup & discovery
1703fcf3ce44SJohn Forte 		 * timers
1704fcf3ce44SJohn Forte 		 */
1705fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_LINKUP_LOCK);
1706fcf3ce44SJohn Forte 		cv_broadcast(&EMLXS_LINKUP_CV);
1707fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_LINKUP_LOCK);
1708fcf3ce44SJohn Forte 
1709a9800bebSGarrett D'Amore 		emlxs_log_link_event(port);
1710a9800bebSGarrett D'Amore 
1711fcf3ce44SJohn Forte 		return;
1712fcf3ce44SJohn Forte 	}
1713291a2b48SSukumar Swaminathan #endif /* MENLO_SUPPORT */
1714fcf3ce44SJohn Forte 
1715fcf3ce44SJohn Forte 	/* Set the linkup & discovery timers */
1716fcf3ce44SJohn Forte 	hba->linkup_timer = hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current;
1717291a2b48SSukumar Swaminathan 	hba->discovery_timer =
1718291a2b48SSukumar Swaminathan 	    hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current +
1719291a2b48SSukumar Swaminathan 	    cfg[CFG_DISC_TIMEOUT].current;
1720fcf3ce44SJohn Forte 
1721fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1722fcf3ce44SJohn Forte 
1723a9800bebSGarrett D'Amore 	emlxs_log_link_event(port);
1724a9800bebSGarrett D'Amore 
1725fcf3ce44SJohn Forte 	return;
1726fcf3ce44SJohn Forte 
172782527734SSukumar Swaminathan } /* emlxs_linkup() */
1728fcf3ce44SJohn Forte 
1729fcf3ce44SJohn Forte 
1730fcf3ce44SJohn Forte /*
1731fcf3ce44SJohn Forte  *  emlxs_reset_link
1732fcf3ce44SJohn Forte  *
1733fcf3ce44SJohn Forte  *  Description:
1734fcf3ce44SJohn Forte  *  Called to reset the link with an init_link
1735fcf3ce44SJohn Forte  *
1736fcf3ce44SJohn Forte  *    Returns:
1737fcf3ce44SJohn Forte  *
1738fcf3ce44SJohn Forte  */
1739fcf3ce44SJohn Forte extern int
emlxs_reset_link(emlxs_hba_t * hba,uint32_t linkup,uint32_t wait)174082527734SSukumar Swaminathan emlxs_reset_link(emlxs_hba_t *hba, uint32_t linkup, uint32_t wait)
1741fcf3ce44SJohn Forte {
1742fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1743fcf3ce44SJohn Forte 	emlxs_config_t *cfg;
174482527734SSukumar Swaminathan 	MAILBOXQ *mbq = NULL;
174582527734SSukumar Swaminathan 	MAILBOX *mb = NULL;
174682527734SSukumar Swaminathan 	int rval = 0;
17478f23e9faSHans Rosenfeld 	int tmo;
174882527734SSukumar Swaminathan 	int rc;
1749fcf3ce44SJohn Forte 
1750fcf3ce44SJohn Forte 	/*
1751fcf3ce44SJohn Forte 	 * Get a buffer to use for the mailbox command
1752fcf3ce44SJohn Forte 	 */
17538f23e9faSHans Rosenfeld 	if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))
175482527734SSukumar Swaminathan 	    == NULL) {
1755fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_failed_msg,
1756fcf3ce44SJohn Forte 		    "Unable to allocate mailbox buffer.");
175782527734SSukumar Swaminathan 		rval = 1;
175882527734SSukumar Swaminathan 		goto reset_link_fail;
175982527734SSukumar Swaminathan 	}
1760fcf3ce44SJohn Forte 
1761a9800bebSGarrett D'Amore 	if (linkup) {
1762a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg,
1763a9800bebSGarrett D'Amore 		    "Resetting link...");
1764a9800bebSGarrett D'Amore 	} else {
1765a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg,
1766a9800bebSGarrett D'Amore 		    "Disabling link...");
1767a9800bebSGarrett D'Amore 	}
1768a9800bebSGarrett D'Amore 
176982527734SSukumar Swaminathan 	mb = (MAILBOX *)mbq;
177082527734SSukumar Swaminathan 
177182527734SSukumar Swaminathan 	/* Bring link down first */
177282527734SSukumar Swaminathan 	emlxs_mb_down_link(hba, mbq);
177382527734SSukumar Swaminathan 
177482527734SSukumar Swaminathan #define	MBXERR_LINK_DOWN	0x33
177582527734SSukumar Swaminathan 
177682527734SSukumar Swaminathan 	if (wait) {
177782527734SSukumar Swaminathan 		wait = MBX_WAIT;
177882527734SSukumar Swaminathan 	} else {
177982527734SSukumar Swaminathan 		wait = MBX_NOWAIT;
178082527734SSukumar Swaminathan 	}
178182527734SSukumar Swaminathan 	rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, wait, 0);
178282527734SSukumar Swaminathan 	if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS) &&
178382527734SSukumar Swaminathan 	    (rc != MBXERR_LINK_DOWN)) {
178482527734SSukumar Swaminathan 		rval = 1;
178582527734SSukumar Swaminathan 		goto reset_link_fail;
1786fcf3ce44SJohn Forte 	}
1787291a2b48SSukumar Swaminathan 
17888f23e9faSHans Rosenfeld 	tmo = 120;
17898f23e9faSHans Rosenfeld 	do {
17908f23e9faSHans Rosenfeld 		delay(drv_usectohz(500000));
17918f23e9faSHans Rosenfeld 		tmo--;
17928f23e9faSHans Rosenfeld 
17938f23e9faSHans Rosenfeld 		if (!tmo)   {
17948f23e9faSHans Rosenfeld 			rval = 1;
17958f23e9faSHans Rosenfeld 
17968f23e9faSHans Rosenfeld 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg,
17978f23e9faSHans Rosenfeld 			    "Linkdown timeout.");
17988f23e9faSHans Rosenfeld 
17998f23e9faSHans Rosenfeld 			goto reset_link_fail;
18008f23e9faSHans Rosenfeld 		}
18018f23e9faSHans Rosenfeld 	} while ((hba->state >= FC_LINK_UP) && (hba->state != FC_ERROR));
18028f23e9faSHans Rosenfeld 
1803fcf3ce44SJohn Forte 	if (linkup) {
1804fcf3ce44SJohn Forte 		/*
1805fcf3ce44SJohn Forte 		 * Setup and issue mailbox INITIALIZE LINK command
1806fcf3ce44SJohn Forte 		 */
1807fcf3ce44SJohn Forte 
180882527734SSukumar Swaminathan 		if (wait == MBX_NOWAIT) {
18098f23e9faSHans Rosenfeld 			if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX))
181082527734SSukumar Swaminathan 			    == NULL) {
181182527734SSukumar Swaminathan 				EMLXS_MSGF(EMLXS_CONTEXT,
181282527734SSukumar Swaminathan 				    &emlxs_link_reset_failed_msg,
181382527734SSukumar Swaminathan 				    "Unable to allocate mailbox buffer.");
181482527734SSukumar Swaminathan 				rval = 1;
181582527734SSukumar Swaminathan 				goto reset_link_fail;
181682527734SSukumar Swaminathan 			}
181782527734SSukumar Swaminathan 			mb = (MAILBOX *)mbq;
181882527734SSukumar Swaminathan 		} else {
181982527734SSukumar Swaminathan 			/* Reuse mbq from previous mbox */
182082527734SSukumar Swaminathan 			mb = (MAILBOX *)mbq;
182182527734SSukumar Swaminathan 		}
182282527734SSukumar Swaminathan 		cfg = &CFG;
182382527734SSukumar Swaminathan 
182482527734SSukumar Swaminathan 		emlxs_mb_init_link(hba, mbq,
1825fcf3ce44SJohn Forte 		    cfg[CFG_TOPOLOGY].current, cfg[CFG_LINK_SPEED].current);
1826fcf3ce44SJohn Forte 
1827fcf3ce44SJohn Forte 		mb->un.varInitLnk.lipsr_AL_PA = 0;
1828fcf3ce44SJohn Forte 
1829fcf3ce44SJohn Forte 		/* Clear the loopback mode */
1830fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1831fcf3ce44SJohn Forte 		hba->flag &= ~FC_LOOPBACK_MODE;
1832291a2b48SSukumar Swaminathan 		hba->loopback_tics = 0;
1833fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1834fcf3ce44SJohn Forte 
183582527734SSukumar Swaminathan 		rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, wait, 0);
183682527734SSukumar Swaminathan 		if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
183782527734SSukumar Swaminathan 			rval = 1;
183882527734SSukumar Swaminathan 			goto reset_link_fail;
1839fcf3ce44SJohn Forte 		}
1840291a2b48SSukumar Swaminathan 
1841fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg, NULL);
184282527734SSukumar Swaminathan 	}
1843fcf3ce44SJohn Forte 
184482527734SSukumar Swaminathan reset_link_fail:
1845291a2b48SSukumar Swaminathan 
184682527734SSukumar Swaminathan 	if ((wait == MBX_WAIT) && mbq) {
1847a9800bebSGarrett D'Amore 		emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
1848fcf3ce44SJohn Forte 	}
1849fcf3ce44SJohn Forte 
185082527734SSukumar Swaminathan 	return (rval);
185182527734SSukumar Swaminathan } /* emlxs_reset_link() */
1852fcf3ce44SJohn Forte 
1853fcf3ce44SJohn Forte 
1854fcf3ce44SJohn Forte extern int
emlxs_online(emlxs_hba_t * hba)1855fcf3ce44SJohn Forte emlxs_online(emlxs_hba_t *hba)
1856fcf3ce44SJohn Forte {
1857fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1858fcf3ce44SJohn Forte 	int32_t rval = 0;
1859fcf3ce44SJohn Forte 	uint32_t i = 0;
1860fcf3ce44SJohn Forte 
1861fcf3ce44SJohn Forte 	/* Make sure adapter is offline or exit trying (30 seconds) */
1862291a2b48SSukumar Swaminathan 	while (i++ < 30) {
1863fcf3ce44SJohn Forte 		/* Check if adapter is already going online */
1864fcf3ce44SJohn Forte 		if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) {
1865fcf3ce44SJohn Forte 			return (0);
1866fcf3ce44SJohn Forte 		}
1867291a2b48SSukumar Swaminathan 
1868fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1869fcf3ce44SJohn Forte 
1870fcf3ce44SJohn Forte 		/* Check again */
1871fcf3ce44SJohn Forte 		if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) {
1872fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1873fcf3ce44SJohn Forte 			return (0);
1874fcf3ce44SJohn Forte 		}
1875291a2b48SSukumar Swaminathan 
1876fcf3ce44SJohn Forte 		/* Check if adapter is offline */
1877fcf3ce44SJohn Forte 		if (hba->flag & FC_OFFLINE_MODE) {
1878fcf3ce44SJohn Forte 			/* Mark it going online */
1879fcf3ce44SJohn Forte 			hba->flag &= ~FC_OFFLINE_MODE;
1880fcf3ce44SJohn Forte 			hba->flag |= FC_ONLINING_MODE;
1881fcf3ce44SJohn Forte 
1882fcf3ce44SJohn Forte 			/* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */
1883fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1884fcf3ce44SJohn Forte 			break;
1885fcf3ce44SJohn Forte 		}
1886291a2b48SSukumar Swaminathan 
1887fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1888fcf3ce44SJohn Forte 
18898f23e9faSHans Rosenfeld 		BUSYWAIT_MS(1000);
1890fcf3ce44SJohn Forte 	}
1891fcf3ce44SJohn Forte 
1892fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
1893fcf3ce44SJohn Forte 	    "Going online...");
1894fcf3ce44SJohn Forte 
189582527734SSukumar Swaminathan 	if (rval = EMLXS_SLI_ONLINE(hba)) {
1896291a2b48SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg, "status=%x",
1897fcf3ce44SJohn Forte 		    rval);
1898fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL);
1899fcf3ce44SJohn Forte 
1900fcf3ce44SJohn Forte 		/* Set FC_OFFLINE_MODE */
1901fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1902fcf3ce44SJohn Forte 		hba->flag |= FC_OFFLINE_MODE;
1903fcf3ce44SJohn Forte 		hba->flag &= ~FC_ONLINING_MODE;
1904fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1905fcf3ce44SJohn Forte 
1906fcf3ce44SJohn Forte 		return (rval);
1907fcf3ce44SJohn Forte 	}
1908291a2b48SSukumar Swaminathan 
1909fcf3ce44SJohn Forte 	/* Start the timer */
1910fcf3ce44SJohn Forte 	emlxs_timer_start(hba);
1911fcf3ce44SJohn Forte 
1912fcf3ce44SJohn Forte 	/* Set FC_ONLINE_MODE */
1913fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
1914fcf3ce44SJohn Forte 	hba->flag |= FC_ONLINE_MODE;
1915fcf3ce44SJohn Forte 	hba->flag &= ~FC_ONLINING_MODE;
1916fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
1917fcf3ce44SJohn Forte 
1918fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_online_msg, NULL);
1919fcf3ce44SJohn Forte 
1920fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
19218f23e9faSHans Rosenfeld 	if (port->flag & EMLXS_TGT_ENABLED) {
19228f23e9faSHans Rosenfeld 		(void) emlxs_fct_port_initialize(port);
19238f23e9faSHans Rosenfeld 	}
1924291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
1925fcf3ce44SJohn Forte 
1926fcf3ce44SJohn Forte 	return (rval);
1927fcf3ce44SJohn Forte 
192882527734SSukumar Swaminathan } /* emlxs_online() */
1929fcf3ce44SJohn Forte 
1930fcf3ce44SJohn Forte 
1931fcf3ce44SJohn Forte extern int
emlxs_offline(emlxs_hba_t * hba,uint32_t reset_requested)19328f23e9faSHans Rosenfeld emlxs_offline(emlxs_hba_t *hba, uint32_t reset_requested)
1933fcf3ce44SJohn Forte {
1934fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
1935fcf3ce44SJohn Forte 	uint32_t i = 0;
1936fcf3ce44SJohn Forte 	int rval = 1;
1937fcf3ce44SJohn Forte 
1938fcf3ce44SJohn Forte 	/* Make sure adapter is online or exit trying (30 seconds) */
1939291a2b48SSukumar Swaminathan 	while (i++ < 30) {
1940fcf3ce44SJohn Forte 		/* Check if adapter is already going offline */
1941fcf3ce44SJohn Forte 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1942fcf3ce44SJohn Forte 			return (0);
1943fcf3ce44SJohn Forte 		}
1944291a2b48SSukumar Swaminathan 
1945fcf3ce44SJohn Forte 		mutex_enter(&EMLXS_PORT_LOCK);
1946fcf3ce44SJohn Forte 
1947fcf3ce44SJohn Forte 		/* Check again */
1948fcf3ce44SJohn Forte 		if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1949fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1950fcf3ce44SJohn Forte 			return (0);
1951fcf3ce44SJohn Forte 		}
1952291a2b48SSukumar Swaminathan 
1953fcf3ce44SJohn Forte 		/* Check if adapter is online */
1954fcf3ce44SJohn Forte 		if (hba->flag & FC_ONLINE_MODE) {
1955fcf3ce44SJohn Forte 			/* Mark it going offline */
1956fcf3ce44SJohn Forte 			hba->flag &= ~FC_ONLINE_MODE;
1957fcf3ce44SJohn Forte 			hba->flag |= FC_OFFLINING_MODE;
1958fcf3ce44SJohn Forte 
1959fcf3ce44SJohn Forte 			/* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */
1960fcf3ce44SJohn Forte 			mutex_exit(&EMLXS_PORT_LOCK);
1961fcf3ce44SJohn Forte 			break;
1962fcf3ce44SJohn Forte 		}
1963291a2b48SSukumar Swaminathan 
1964fcf3ce44SJohn Forte 		mutex_exit(&EMLXS_PORT_LOCK);
1965fcf3ce44SJohn Forte 
19668f23e9faSHans Rosenfeld 		BUSYWAIT_MS(1000);
1967fcf3ce44SJohn Forte 	}
1968fcf3ce44SJohn Forte 
1969291a2b48SSukumar Swaminathan 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg,
1970291a2b48SSukumar Swaminathan 	    "Going offline...");
1971fcf3ce44SJohn Forte 
19728f23e9faSHans Rosenfeld 	/* Declare link down */
19738f23e9faSHans Rosenfeld 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
19748f23e9faSHans Rosenfeld 		(void) emlxs_fcf_shutdown_notify(port, 1);
19758f23e9faSHans Rosenfeld 	} else {
19768f23e9faSHans Rosenfeld 		emlxs_linkdown(hba);
1977fcf3ce44SJohn Forte 	}
19788f23e9faSHans Rosenfeld 
1979fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT
19808f23e9faSHans Rosenfeld 	if (port->flag & EMLXS_TGT_ENABLED) {
1981fcf3ce44SJohn Forte 		(void) emlxs_fct_port_shutdown(port);
1982fcf3ce44SJohn Forte 	}
1983291a2b48SSukumar Swaminathan #endif /* SFCT_SUPPORT */
1984fcf3ce44SJohn Forte 
1985fcf3ce44SJohn Forte 	/* Check if adapter was shutdown */
1986fcf3ce44SJohn Forte 	if (hba->flag & FC_HARDWARE_ERROR) {
1987291a2b48SSukumar Swaminathan 		/*
1988291a2b48SSukumar Swaminathan 		 * Force mailbox cleanup
1989291a2b48SSukumar Swaminathan 		 * This will wake any sleeping or polling threads
1990291a2b48SSukumar Swaminathan 		 */
1991fcf3ce44SJohn Forte 		emlxs_mb_fini(hba, NULL, MBX_HARDWARE_ERROR);
1992fcf3ce44SJohn Forte 	}
1993291a2b48SSukumar Swaminathan 
1994fcf3ce44SJohn Forte 	/* Pause here for the IO to settle */
1995fcf3ce44SJohn Forte 	delay(drv_usectohz(1000000));	/* 1 sec */
1996fcf3ce44SJohn Forte 
1997fcf3ce44SJohn Forte 	/* Unregister all nodes */
1998fcf3ce44SJohn Forte 	emlxs_ffcleanup(hba);
1999fcf3ce44SJohn Forte 
2000fcf3ce44SJohn Forte 	if (hba->bus_type == SBUS_FC) {
200182527734SSukumar Swaminathan 		WRITE_SBUS_CSR_REG(hba, FC_SHS_REG(hba), 0x9A);
20024baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
200382527734SSukumar Swaminathan 		/* Access handle validation */
200482527734SSukumar Swaminathan 		EMLXS_CHK_ACC_HANDLE(hba, hba->sli.sli3.sbus_csr_handle);
20054baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
2006fcf3ce44SJohn Forte 	}
2007291a2b48SSukumar Swaminathan 
2008fcf3ce44SJohn Forte 	/* Stop the timer */
2009fcf3ce44SJohn Forte 	emlxs_timer_stop(hba);
2010fcf3ce44SJohn Forte 
2011fcf3ce44SJohn Forte 	/* For safety flush every iotag list */
2012fcf3ce44SJohn Forte 	if (emlxs_iotag_flush(hba)) {
2013fcf3ce44SJohn Forte 		/* Pause here for the IO to flush */
2014728bdc9bSSukumar Swaminathan 		delay(drv_usectohz(1000));
2015728bdc9bSSukumar Swaminathan 	}
2016728bdc9bSSukumar Swaminathan 
2017728bdc9bSSukumar Swaminathan 	/* Wait for poll command request to settle */
2018728bdc9bSSukumar Swaminathan 	while (hba->io_poll_count > 0) {
2019728bdc9bSSukumar Swaminathan 		delay(drv_usectohz(2000000));   /* 2 sec */
2020fcf3ce44SJohn Forte 	}
2021728bdc9bSSukumar Swaminathan 
202282527734SSukumar Swaminathan 	/* Shutdown the adapter interface */
20238f23e9faSHans Rosenfeld 	EMLXS_SLI_OFFLINE(hba, reset_requested);
2024fcf3ce44SJohn Forte 
2025fcf3ce44SJohn Forte 	mutex_enter(&EMLXS_PORT_LOCK);
2026fcf3ce44SJohn Forte 	hba->flag |= FC_OFFLINE_MODE;
2027fcf3ce44SJohn Forte 	hba->flag &= ~FC_OFFLINING_MODE;
2028fcf3ce44SJohn Forte 	mutex_exit(&EMLXS_PORT_LOCK);
2029fcf3ce44SJohn Forte 
2030fcf3ce44SJohn Forte 	rval = 0;
2031fcf3ce44SJohn Forte 
2032fcf3ce44SJohn Forte 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL);
2033fcf3ce44SJohn Forte 
2034fcf3ce44SJohn Forte done:
2035fcf3ce44SJohn Forte 
2036fcf3ce44SJohn Forte 	return (rval);
2037fcf3ce44SJohn Forte 
203882527734SSukumar Swaminathan } /* emlxs_offline() */
2039fcf3ce44SJohn Forte 
2040fcf3ce44SJohn Forte 
2041fcf3ce44SJohn Forte 
2042fcf3ce44SJohn Forte extern int
emlxs_power_down(emlxs_hba_t * hba)2043fcf3ce44SJohn Forte emlxs_power_down(emlxs_hba_t *hba)
2044fcf3ce44SJohn Forte {
20454baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
20464baa2c25SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
20474baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
2048fcf3ce44SJohn Forte 	int32_t rval = 0;
2049fcf3ce44SJohn Forte 
20508f23e9faSHans Rosenfeld 	if ((rval = emlxs_offline(hba, 0))) {
2051fcf3ce44SJohn Forte 		return (rval);
2052fcf3ce44SJohn Forte 	}
205382527734SSukumar Swaminathan 	EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
2054291a2b48SSukumar Swaminathan 
2055fcf3ce44SJohn Forte 
20564baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
20574baa2c25SSukumar Swaminathan 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
20584baa2c25SSukumar Swaminathan 	    != DDI_FM_OK) {
20594baa2c25SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT,
20604baa2c25SSukumar Swaminathan 		    &emlxs_invalid_access_handle_msg, NULL);
20614baa2c25SSukumar Swaminathan 		return (1);
20624baa2c25SSukumar Swaminathan 	}
20634baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
20644baa2c25SSukumar Swaminathan 
2065fcf3ce44SJohn Forte 	return (0);
2066fcf3ce44SJohn Forte 
206782527734SSukumar Swaminathan } /* End emlxs_power_down */
2068fcf3ce44SJohn Forte 
2069fcf3ce44SJohn Forte 
2070fcf3ce44SJohn Forte extern int
emlxs_power_up(emlxs_hba_t * hba)2071fcf3ce44SJohn Forte emlxs_power_up(emlxs_hba_t *hba)
2072fcf3ce44SJohn Forte {
20734baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
20744baa2c25SSukumar Swaminathan 	emlxs_port_t *port = &PPORT;
20754baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
2076fcf3ce44SJohn Forte 	int32_t rval = 0;
2077fcf3ce44SJohn Forte 
2078fcf3ce44SJohn Forte 
20794baa2c25SSukumar Swaminathan #ifdef FMA_SUPPORT
20804baa2c25SSukumar Swaminathan 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
20814baa2c25SSukumar Swaminathan 	    != DDI_FM_OK) {
20824baa2c25SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT,
20834baa2c25SSukumar Swaminathan 		    &emlxs_invalid_access_handle_msg, NULL);
20844baa2c25SSukumar Swaminathan 		return (1);
20854baa2c25SSukumar Swaminathan 	}
20864baa2c25SSukumar Swaminathan #endif  /* FMA_SUPPORT */
20874baa2c25SSukumar Swaminathan 
2088fcf3ce44SJohn Forte 	/* Bring adapter online */
2089fcf3ce44SJohn Forte 	if ((rval = emlxs_online(hba))) {
2090a9800bebSGarrett D'Amore 		if (hba->pci_cap_offset[PCI_CAP_ID_PM]) {
2091a9800bebSGarrett D'Amore 			/* Put chip in D3 state */
2092a9800bebSGarrett D'Amore 			(void) ddi_put8(hba->pci_acc_handle,
2093a9800bebSGarrett D'Amore 			    (uint8_t *)(hba->pci_addr +
2094a9800bebSGarrett D'Amore 			    hba->pci_cap_offset[PCI_CAP_ID_PM] +
2095a9800bebSGarrett D'Amore 			    PCI_PMCSR),
2096a9800bebSGarrett D'Amore 			    (uint8_t)PCI_PMCSR_D3HOT);
2097a9800bebSGarrett D'Amore 		}
2098fcf3ce44SJohn Forte 		return (rval);
2099fcf3ce44SJohn Forte 	}
2100291a2b48SSukumar Swaminathan 
2101fcf3ce44SJohn Forte 	return (rval);
2102fcf3ce44SJohn Forte 
21038f23e9faSHans Rosenfeld } /* emlxs_power_up() */
2104fcf3ce44SJohn Forte 
2105fcf3ce44SJohn Forte 
2106fcf3ce44SJohn Forte /*
2107291a2b48SSukumar Swaminathan  *
2108fcf3ce44SJohn Forte  * NAME:     emlxs_ffcleanup
2109fcf3ce44SJohn Forte  *
2110fcf3ce44SJohn Forte  * FUNCTION: Cleanup all the Firefly resources used by configuring the adapter
2111fcf3ce44SJohn Forte  *
2112fcf3ce44SJohn Forte  * EXECUTION ENVIRONMENT: process only
2113fcf3ce44SJohn Forte  *
2114fcf3ce44SJohn Forte  * CALLED FROM: CFG_TERM
2115fcf3ce44SJohn Forte  *
2116fcf3ce44SJohn Forte  * INPUT: hba       - pointer to the dev_ctl area.
2117fcf3ce44SJohn Forte  *
2118fcf3ce44SJohn Forte  * RETURNS: none
2119fcf3ce44SJohn Forte  */
2120fcf3ce44SJohn Forte extern void
emlxs_ffcleanup(emlxs_hba_t * hba)2121fcf3ce44SJohn Forte emlxs_ffcleanup(emlxs_hba_t *hba)
2122fcf3ce44SJohn Forte {
2123fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2124291a2b48SSukumar Swaminathan 	uint32_t i;
2125fcf3ce44SJohn Forte 
2126fcf3ce44SJohn Forte 	/* Disable all but the mailbox interrupt */
212782527734SSukumar Swaminathan 	EMLXS_SLI_DISABLE_INTR(hba, HC_MBINT_ENA);
2128fcf3ce44SJohn Forte 
2129fcf3ce44SJohn Forte 	/* Make sure all port nodes are destroyed */
2130291a2b48SSukumar Swaminathan 	for (i = 0; i < MAX_VPORTS; i++) {
2131291a2b48SSukumar Swaminathan 		port = &VPORT(i);
2132fcf3ce44SJohn Forte 
2133fcf3ce44SJohn Forte 		if (port->node_count) {
21348f23e9faSHans Rosenfeld 			(void) EMLXS_SLI_UNREG_NODE(port, 0, 0, 0, 0);
2135fcf3ce44SJohn Forte 		}
2136fcf3ce44SJohn Forte 	}
2137fcf3ce44SJohn Forte 
2138fcf3ce44SJohn Forte 	/* Clear all interrupt enable conditions */
213982527734SSukumar Swaminathan 	EMLXS_SLI_DISABLE_INTR(hba, 0);
2140fcf3ce44SJohn Forte 
2141fcf3ce44SJohn Forte 	return;
2142fcf3ce44SJohn Forte 
214382527734SSukumar Swaminathan } /* emlxs_ffcleanup() */
2144fcf3ce44SJohn Forte 
2145fcf3ce44SJohn Forte 
2146fcf3ce44SJohn Forte extern uint16_t
emlxs_register_pkt(CHANNEL * cp,emlxs_buf_t * sbp)214782527734SSukumar Swaminathan emlxs_register_pkt(CHANNEL *cp, emlxs_buf_t *sbp)
2148fcf3ce44SJohn Forte {
2149fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
2150fcf3ce44SJohn Forte 	emlxs_port_t *port;
2151fcf3ce44SJohn Forte 	uint16_t iotag;
2152fcf3ce44SJohn Forte 	uint32_t i;
2153fcf3ce44SJohn Forte 
215482527734SSukumar Swaminathan 	hba = cp->hba;
2155fcf3ce44SJohn Forte 
215682527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
2157fcf3ce44SJohn Forte 
2158fcf3ce44SJohn Forte 	if (sbp->iotag != 0) {
2159fcf3ce44SJohn Forte 		port = &PPORT;
2160fcf3ce44SJohn Forte 
2161fcf3ce44SJohn Forte 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
216282527734SSukumar Swaminathan 		    "Pkt already registered! channel=%d iotag=%d sbp=%p",
216382527734SSukumar Swaminathan 		    sbp->channel, sbp->iotag, sbp);
2164fcf3ce44SJohn Forte 	}
2165291a2b48SSukumar Swaminathan 
2166fcf3ce44SJohn Forte 	iotag = 0;
216782527734SSukumar Swaminathan 	for (i = 0; i < hba->max_iotag; i++) {
216882527734SSukumar Swaminathan 		if (!hba->fc_iotag || hba->fc_iotag >= hba->max_iotag) {
216982527734SSukumar Swaminathan 			hba->fc_iotag = 1;
2170fcf3ce44SJohn Forte 		}
217182527734SSukumar Swaminathan 		iotag = hba->fc_iotag++;
2172fcf3ce44SJohn Forte 
217382527734SSukumar Swaminathan 		if (hba->fc_table[iotag] == 0 ||
217482527734SSukumar Swaminathan 		    hba->fc_table[iotag] == STALE_PACKET) {
217582527734SSukumar Swaminathan 			hba->io_count++;
217682527734SSukumar Swaminathan 			hba->fc_table[iotag] = sbp;
2177fcf3ce44SJohn Forte 
2178fcf3ce44SJohn Forte 			sbp->iotag = iotag;
217982527734SSukumar Swaminathan 			sbp->channel = cp;
2180fcf3ce44SJohn Forte 
2181fcf3ce44SJohn Forte 			break;
2182fcf3ce44SJohn Forte 		}
2183fcf3ce44SJohn Forte 		iotag = 0;
2184fcf3ce44SJohn Forte 	}
2185fcf3ce44SJohn Forte 
218682527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
2187fcf3ce44SJohn Forte 
2188fcf3ce44SJohn Forte 	/*
2189fcf3ce44SJohn Forte 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
21908f23e9faSHans Rosenfeld 	 *    "register_pkt: channel=%d iotag=%d sbp=%p",
219182527734SSukumar Swaminathan 	 *    cp->channelno, iotag, sbp);
2192fcf3ce44SJohn Forte 	 */
2193fcf3ce44SJohn Forte 
2194fcf3ce44SJohn Forte 	return (iotag);
2195fcf3ce44SJohn Forte 
219682527734SSukumar Swaminathan } /* emlxs_register_pkt() */
2197fcf3ce44SJohn Forte 
2198fcf3ce44SJohn Forte 
2199fcf3ce44SJohn Forte 
2200fcf3ce44SJohn Forte extern emlxs_buf_t *
emlxs_unregister_pkt(CHANNEL * cp,uint16_t iotag,uint32_t forced)220182527734SSukumar Swaminathan emlxs_unregister_pkt(CHANNEL *cp, uint16_t iotag, uint32_t forced)
2202fcf3ce44SJohn Forte {
2203fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
2204fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
220582527734SSukumar Swaminathan 
220682527734SSukumar Swaminathan 	sbp = NULL;
220782527734SSukumar Swaminathan 	hba = cp->hba;
2208fcf3ce44SJohn Forte 
2209fcf3ce44SJohn Forte 	/* Check the iotag range */
221082527734SSukumar Swaminathan 	if ((iotag == 0) || (iotag >= hba->max_iotag)) {
2211fcf3ce44SJohn Forte 		return (NULL);
2212fcf3ce44SJohn Forte 	}
2213291a2b48SSukumar Swaminathan 
2214fcf3ce44SJohn Forte 	/* Remove the sbp from the table */
221582527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
221682527734SSukumar Swaminathan 	sbp = hba->fc_table[iotag];
2217fcf3ce44SJohn Forte 
2218fcf3ce44SJohn Forte 	if (!sbp || (sbp == STALE_PACKET)) {
221982527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
2220fcf3ce44SJohn Forte 		return (sbp);
2221fcf3ce44SJohn Forte 	}
2222291a2b48SSukumar Swaminathan 
222382527734SSukumar Swaminathan 	hba->fc_table[iotag] = ((forced) ? STALE_PACKET : NULL);
222482527734SSukumar Swaminathan 	hba->io_count--;
2225fcf3ce44SJohn Forte 	sbp->iotag = 0;
2226fcf3ce44SJohn Forte 
222782527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
2228fcf3ce44SJohn Forte 
2229fcf3ce44SJohn Forte 
2230fcf3ce44SJohn Forte 	/* Clean up the sbp */
2231fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
2232fcf3ce44SJohn Forte 
2233fcf3ce44SJohn Forte 	if (sbp->pkt_flags & PACKET_IN_TXQ) {
2234fcf3ce44SJohn Forte 		sbp->pkt_flags &= ~PACKET_IN_TXQ;
223582527734SSukumar Swaminathan 		hba->channel_tx_count--;
2236fcf3ce44SJohn Forte 	}
2237291a2b48SSukumar Swaminathan 
2238fcf3ce44SJohn Forte 	if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
2239fcf3ce44SJohn Forte 		sbp->pkt_flags &= ~PACKET_IN_CHIPQ;
2240fcf3ce44SJohn Forte 	}
2241291a2b48SSukumar Swaminathan 
2242fcf3ce44SJohn Forte 	if (sbp->bmp) {
2243a9800bebSGarrett D'Amore 		emlxs_mem_put(hba, MEM_BPL, (void *)sbp->bmp);
2244fcf3ce44SJohn Forte 		sbp->bmp = 0;
2245fcf3ce44SJohn Forte 	}
2246fcf3ce44SJohn Forte 
2247291a2b48SSukumar Swaminathan 	mutex_exit(&sbp->mtx);
2248fcf3ce44SJohn Forte 
2249fcf3ce44SJohn Forte 	return (sbp);
2250fcf3ce44SJohn Forte 
225182527734SSukumar Swaminathan } /* emlxs_unregister_pkt() */
2252fcf3ce44SJohn Forte 
2253fcf3ce44SJohn Forte 
2254fcf3ce44SJohn Forte 
225582527734SSukumar Swaminathan /* Flush all IO's to all nodes for a given IO Channel */
2256fcf3ce44SJohn Forte extern uint32_t
emlxs_tx_channel_flush(emlxs_hba_t * hba,CHANNEL * cp,emlxs_buf_t * fpkt)225782527734SSukumar Swaminathan emlxs_tx_channel_flush(emlxs_hba_t *hba, CHANNEL *cp, emlxs_buf_t *fpkt)
2258fcf3ce44SJohn Forte {
2259fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
2260fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
2261fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2262fcf3ce44SJohn Forte 	IOCBQ *next;
2263fcf3ce44SJohn Forte 	IOCB *iocb;
226482527734SSukumar Swaminathan 	uint32_t channelno;
2265fcf3ce44SJohn Forte 	Q abort;
2266fcf3ce44SJohn Forte 	NODELIST *ndlp;
2267fcf3ce44SJohn Forte 	IOCB *icmd;
2268fcf3ce44SJohn Forte 	MATCHMAP *mp;
2269fcf3ce44SJohn Forte 	uint32_t i;
227082527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2271fcf3ce44SJohn Forte 
227282527734SSukumar Swaminathan 	channelno = cp->channelno;
2273fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
227482527734SSukumar Swaminathan 	bzero((void *)flag, MAX_CHANNEL * sizeof (uint8_t));
2275fcf3ce44SJohn Forte 
227682527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2277fcf3ce44SJohn Forte 
2278fcf3ce44SJohn Forte 	/* While a node needs servicing */
227982527734SSukumar Swaminathan 	while (cp->nodeq.q_first) {
228082527734SSukumar Swaminathan 		ndlp = (NODELIST *) cp->nodeq.q_first;
2281fcf3ce44SJohn Forte 
2282fcf3ce44SJohn Forte 		/* Check if priority queue is not empty */
228382527734SSukumar Swaminathan 		if (ndlp->nlp_ptx[channelno].q_first) {
2284fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2285fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
228682527734SSukumar Swaminathan 				abort.q_first =
228782527734SSukumar Swaminathan 				    ndlp->nlp_ptx[channelno].q_first;
2288fcf3ce44SJohn Forte 			} else {
2289fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
229082527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_ptx[channelno].q_first;
2291fcf3ce44SJohn Forte 			}
229282527734SSukumar Swaminathan 			flag[channelno] = 1;
2293fcf3ce44SJohn Forte 
229482527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_ptx[channelno].q_last;
229582527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_ptx[channelno].q_cnt;
2296fcf3ce44SJohn Forte 		}
2297291a2b48SSukumar Swaminathan 
2298fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
229982527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
2300fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2301fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
230282527734SSukumar Swaminathan 				abort.q_first = ndlp->nlp_tx[channelno].q_first;
2303fcf3ce44SJohn Forte 			} else {
2304fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
230582527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2306fcf3ce44SJohn Forte 			}
2307fcf3ce44SJohn Forte 
230882527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_tx[channelno].q_last;
230982527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_tx[channelno].q_cnt;
2310fcf3ce44SJohn Forte 		}
2311291a2b48SSukumar Swaminathan 
2312fcf3ce44SJohn Forte 		/* Clear the queue pointers */
231382527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_first = NULL;
231482527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_last = NULL;
231582527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_cnt = 0;
2316fcf3ce44SJohn Forte 
231782527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_first = NULL;
231882527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_last = NULL;
231982527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_cnt = 0;
2320fcf3ce44SJohn Forte 
2321fcf3ce44SJohn Forte 		/* Remove node from service queue */
2322fcf3ce44SJohn Forte 
2323fcf3ce44SJohn Forte 		/* If this is the last node on list */
232482527734SSukumar Swaminathan 		if (cp->nodeq.q_last == (void *)ndlp) {
232582527734SSukumar Swaminathan 			cp->nodeq.q_last = NULL;
232682527734SSukumar Swaminathan 			cp->nodeq.q_first = NULL;
232782527734SSukumar Swaminathan 			cp->nodeq.q_cnt = 0;
2328fcf3ce44SJohn Forte 		} else {
2329fcf3ce44SJohn Forte 			/* Remove node from head */
233082527734SSukumar Swaminathan 			cp->nodeq.q_first = ndlp->nlp_next[channelno];
233182527734SSukumar Swaminathan 			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
233282527734SSukumar Swaminathan 			    cp->nodeq.q_first;
233382527734SSukumar Swaminathan 			cp->nodeq.q_cnt--;
2334fcf3ce44SJohn Forte 		}
2335fcf3ce44SJohn Forte 
2336fcf3ce44SJohn Forte 		/* Clear node */
233782527734SSukumar Swaminathan 		ndlp->nlp_next[channelno] = NULL;
2338fcf3ce44SJohn Forte 	}
2339fcf3ce44SJohn Forte 
2340fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2341291a2b48SSukumar Swaminathan 	iocbq = (IOCBQ *) abort.q_first;
2342fcf3ce44SJohn Forte 	while (iocbq) {
2343fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2344fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
234582527734SSukumar Swaminathan 
234682527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
234782527734SSukumar Swaminathan 			sbp = iocbq->sbp;
234882527734SSukumar Swaminathan 			if (sbp) {
23498f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
235082527734SSukumar Swaminathan 			}
235182527734SSukumar Swaminathan 		} else {
235282527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
235382527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
235482527734SSukumar Swaminathan 		}
2355fcf3ce44SJohn Forte 
2356fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2357fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2358fcf3ce44SJohn Forte 
2359fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2360fcf3ce44SJohn Forte 			/*
2361fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2362291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2363291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2364fcf3ce44SJohn Forte 			 */
2365fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2366fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2367fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2368fcf3ce44SJohn Forte 				fpkt->flush_count++;
2369fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2370fcf3ce44SJohn Forte 			}
2371291a2b48SSukumar Swaminathan 
2372fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2373fcf3ce44SJohn Forte 		}
2374291a2b48SSukumar Swaminathan 
2375fcf3ce44SJohn Forte 		iocbq = (IOCBQ *)iocbq->next;
2376fcf3ce44SJohn Forte 	}	/* end of while */
2377fcf3ce44SJohn Forte 
237882527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2379fcf3ce44SJohn Forte 
2380fcf3ce44SJohn Forte 	/* Now abort the iocb's */
2381fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2382fcf3ce44SJohn Forte 	while (iocbq) {
2383fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2384fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2385fcf3ce44SJohn Forte 
2386fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2387fcf3ce44SJohn Forte 		iocbq->next = NULL;
2388fcf3ce44SJohn Forte 
2389fcf3ce44SJohn Forte 		/* Get the pkt */
2390fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2391fcf3ce44SJohn Forte 
2392fcf3ce44SJohn Forte 		if (sbp) {
2393fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2394291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2395fcf3ce44SJohn Forte 
2396fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2397fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2398fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2399fcf3ce44SJohn Forte 			} else {
2400fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2401fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2402fcf3ce44SJohn Forte 			}
2403fcf3ce44SJohn Forte 
2404fcf3ce44SJohn Forte 		}
2405fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2406fcf3ce44SJohn Forte 		else {
2407fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
240882527734SSukumar Swaminathan 
240982527734SSukumar Swaminathan 			/* SLI3 */
241082527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
241182527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
241282527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2413fcf3ce44SJohn Forte 				if ((hba->flag &
2414fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2415fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
241682527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2417fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2418a9800bebSGarrett D'Amore 						void	*tmp;
241982527734SSukumar Swaminathan 						RING *rp;
2420fcf3ce44SJohn Forte 
242182527734SSukumar Swaminathan 						rp = &hba->sli.sli3.
242282527734SSukumar Swaminathan 						    ring[channelno];
2423fcf3ce44SJohn Forte 						for (i = 0;
242482527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2425fcf3ce44SJohn Forte 						    i++) {
2426fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2427fcf3ce44SJohn Forte 							    hba, rp, icmd);
2428fcf3ce44SJohn Forte 
2429a9800bebSGarrett D'Amore 							tmp = (void *)mp;
2430fcf3ce44SJohn Forte 							if (mp) {
2431a9800bebSGarrett D'Amore 							emlxs_mem_put(
2432291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2433fcf3ce44SJohn Forte 							}
2434fcf3ce44SJohn Forte 						}
2435fcf3ce44SJohn Forte 					}
2436291a2b48SSukumar Swaminathan 
2437a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
2438a9800bebSGarrett D'Amore 					    (void *)iocbq);
2439fcf3ce44SJohn Forte 				} else {
2440fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
244182527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp,
2442291a2b48SSukumar Swaminathan 					    iocbq);
2443fcf3ce44SJohn Forte 				}
244482527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
244582527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
244682527734SSukumar Swaminathan 
244782527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
2448fcf3ce44SJohn Forte 			}
2449fcf3ce44SJohn Forte 		}
2450fcf3ce44SJohn Forte 
2451fcf3ce44SJohn Forte 		iocbq = next;
2452fcf3ce44SJohn Forte 
2453fcf3ce44SJohn Forte 	}	/* end of while */
2454fcf3ce44SJohn Forte 
245582527734SSukumar Swaminathan 	/* Now trigger channel service */
245682527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
245782527734SSukumar Swaminathan 		if (!flag[channelno]) {
245882527734SSukumar Swaminathan 			continue;
245982527734SSukumar Swaminathan 		}
246082527734SSukumar Swaminathan 
246182527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
246282527734SSukumar Swaminathan 	}
246382527734SSukumar Swaminathan 
2464fcf3ce44SJohn Forte 	return (abort.q_cnt);
2465fcf3ce44SJohn Forte 
246682527734SSukumar Swaminathan } /* emlxs_tx_channel_flush() */
2467fcf3ce44SJohn Forte 
2468fcf3ce44SJohn Forte 
2469fcf3ce44SJohn Forte /* Flush all IO's on all or a given ring for a given node */
2470fcf3ce44SJohn Forte extern uint32_t
emlxs_tx_node_flush(emlxs_port_t * port,NODELIST * ndlp,CHANNEL * chan,uint32_t shutdown,emlxs_buf_t * fpkt)247182527734SSukumar Swaminathan emlxs_tx_node_flush(emlxs_port_t *port, NODELIST *ndlp, CHANNEL *chan,
2472fcf3ce44SJohn Forte     uint32_t shutdown, emlxs_buf_t *fpkt)
2473fcf3ce44SJohn Forte {
2474fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2475fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
247682527734SSukumar Swaminathan 	uint32_t channelno;
247782527734SSukumar Swaminathan 	CHANNEL *cp;
2478fcf3ce44SJohn Forte 	IOCB *icmd;
2479fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2480fcf3ce44SJohn Forte 	NODELIST *prev;
2481fcf3ce44SJohn Forte 	IOCBQ *next;
2482fcf3ce44SJohn Forte 	IOCB *iocb;
2483fcf3ce44SJohn Forte 	Q abort;
2484fcf3ce44SJohn Forte 	uint32_t i;
2485fcf3ce44SJohn Forte 	MATCHMAP *mp;
248682527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2487fcf3ce44SJohn Forte 
2488fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
2489fcf3ce44SJohn Forte 
2490fcf3ce44SJohn Forte 	/* Flush all I/O's on tx queue to this target */
249182527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2492fcf3ce44SJohn Forte 
2493fcf3ce44SJohn Forte 	if (!ndlp->nlp_base && shutdown) {
2494fcf3ce44SJohn Forte 		ndlp->nlp_active = 0;
2495fcf3ce44SJohn Forte 	}
2496291a2b48SSukumar Swaminathan 
249782527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
249882527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
2499fcf3ce44SJohn Forte 
250082527734SSukumar Swaminathan 		if (chan && cp != chan) {
2501fcf3ce44SJohn Forte 			continue;
2502fcf3ce44SJohn Forte 		}
2503291a2b48SSukumar Swaminathan 
2504fcf3ce44SJohn Forte 		if (!ndlp->nlp_base || shutdown) {
2505fcf3ce44SJohn Forte 			/* Check if priority queue is not empty */
250682527734SSukumar Swaminathan 			if (ndlp->nlp_ptx[channelno].q_first) {
2507fcf3ce44SJohn Forte 				/* Transfer all iocb's to local queue */
2508fcf3ce44SJohn Forte 				if (abort.q_first == 0) {
2509fcf3ce44SJohn Forte 					abort.q_first =
251082527734SSukumar Swaminathan 					    ndlp->nlp_ptx[channelno].q_first;
2511fcf3ce44SJohn Forte 				} else {
251282527734SSukumar Swaminathan 					((IOCBQ *)(abort.q_last))->next =
251382527734SSukumar Swaminathan 					    (IOCBQ *)ndlp->nlp_ptx[channelno].
2514291a2b48SSukumar Swaminathan 					    q_first;
2515fcf3ce44SJohn Forte 				}
2516fcf3ce44SJohn Forte 
251782527734SSukumar Swaminathan 				flag[channelno] = 1;
251882527734SSukumar Swaminathan 
251982527734SSukumar Swaminathan 				abort.q_last = ndlp->nlp_ptx[channelno].q_last;
252082527734SSukumar Swaminathan 				abort.q_cnt += ndlp->nlp_ptx[channelno].q_cnt;
2521fcf3ce44SJohn Forte 			}
2522fcf3ce44SJohn Forte 		}
2523291a2b48SSukumar Swaminathan 
2524fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
252582527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
252682527734SSukumar Swaminathan 
2527fcf3ce44SJohn Forte 			/* Transfer all iocb's to local queue */
2528fcf3ce44SJohn Forte 			if (abort.q_first == 0) {
252982527734SSukumar Swaminathan 				abort.q_first = ndlp->nlp_tx[channelno].q_first;
2530fcf3ce44SJohn Forte 			} else {
2531fcf3ce44SJohn Forte 				((IOCBQ *)abort.q_last)->next =
253282527734SSukumar Swaminathan 				    (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2533fcf3ce44SJohn Forte 			}
2534fcf3ce44SJohn Forte 
253582527734SSukumar Swaminathan 			abort.q_last = ndlp->nlp_tx[channelno].q_last;
253682527734SSukumar Swaminathan 			abort.q_cnt += ndlp->nlp_tx[channelno].q_cnt;
2537fcf3ce44SJohn Forte 		}
2538291a2b48SSukumar Swaminathan 
2539fcf3ce44SJohn Forte 		/* Clear the queue pointers */
254082527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_first = NULL;
254182527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_last = NULL;
254282527734SSukumar Swaminathan 		ndlp->nlp_ptx[channelno].q_cnt = 0;
2543fcf3ce44SJohn Forte 
254482527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_first = NULL;
254582527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_last = NULL;
254682527734SSukumar Swaminathan 		ndlp->nlp_tx[channelno].q_cnt = 0;
2547fcf3ce44SJohn Forte 
254882527734SSukumar Swaminathan 		/* If this node was on the channel queue, remove it */
254982527734SSukumar Swaminathan 		if (ndlp->nlp_next[channelno]) {
2550fcf3ce44SJohn Forte 			/* If this is the only node on list */
255182527734SSukumar Swaminathan 			if (cp->nodeq.q_first == (void *)ndlp &&
255282527734SSukumar Swaminathan 			    cp->nodeq.q_last == (void *)ndlp) {
255382527734SSukumar Swaminathan 				cp->nodeq.q_last = NULL;
255482527734SSukumar Swaminathan 				cp->nodeq.q_first = NULL;
255582527734SSukumar Swaminathan 				cp->nodeq.q_cnt = 0;
255682527734SSukumar Swaminathan 			} else if (cp->nodeq.q_first == (void *)ndlp) {
255782527734SSukumar Swaminathan 				cp->nodeq.q_first = ndlp->nlp_next[channelno];
255882527734SSukumar Swaminathan 				((NODELIST *) cp->nodeq.q_last)->
255982527734SSukumar Swaminathan 				    nlp_next[channelno] = cp->nodeq.q_first;
256082527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
2561291a2b48SSukumar Swaminathan 			} else {
2562fcf3ce44SJohn Forte 				/*
2563291a2b48SSukumar Swaminathan 				 * This is a little more difficult find the
256482527734SSukumar Swaminathan 				 * previous node in the circular channel queue
2565fcf3ce44SJohn Forte 				 */
2566fcf3ce44SJohn Forte 				prev = ndlp;
256782527734SSukumar Swaminathan 				while (prev->nlp_next[channelno] != ndlp) {
256882527734SSukumar Swaminathan 					prev = prev->nlp_next[channelno];
2569fcf3ce44SJohn Forte 				}
2570fcf3ce44SJohn Forte 
257182527734SSukumar Swaminathan 				prev->nlp_next[channelno] =
257282527734SSukumar Swaminathan 				    ndlp->nlp_next[channelno];
2573fcf3ce44SJohn Forte 
257482527734SSukumar Swaminathan 				if (cp->nodeq.q_last == (void *)ndlp) {
257582527734SSukumar Swaminathan 					cp->nodeq.q_last = (void *)prev;
2576fcf3ce44SJohn Forte 				}
257782527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
2578fcf3ce44SJohn Forte 
2579fcf3ce44SJohn Forte 			}
2580fcf3ce44SJohn Forte 
2581fcf3ce44SJohn Forte 			/* Clear node */
258282527734SSukumar Swaminathan 			ndlp->nlp_next[channelno] = NULL;
2583fcf3ce44SJohn Forte 		}
2584291a2b48SSukumar Swaminathan 
2585fcf3ce44SJohn Forte 	}
2586fcf3ce44SJohn Forte 
2587fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2588291a2b48SSukumar Swaminathan 	iocbq = (IOCBQ *) abort.q_first;
2589fcf3ce44SJohn Forte 	while (iocbq) {
2590fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2591fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
259282527734SSukumar Swaminathan 
259382527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
259482527734SSukumar Swaminathan 			sbp = iocbq->sbp;
259582527734SSukumar Swaminathan 			if (sbp) {
25968f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
259782527734SSukumar Swaminathan 			}
259882527734SSukumar Swaminathan 		} else {
259982527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
260082527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
260182527734SSukumar Swaminathan 		}
2602fcf3ce44SJohn Forte 
2603fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2604fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2605fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2606fcf3ce44SJohn Forte 			/*
2607fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2608291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2609291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2610fcf3ce44SJohn Forte 			 */
2611fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2612fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2613fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2614fcf3ce44SJohn Forte 				fpkt->flush_count++;
2615fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2616fcf3ce44SJohn Forte 			}
2617291a2b48SSukumar Swaminathan 
2618fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2619fcf3ce44SJohn Forte 		}
2620291a2b48SSukumar Swaminathan 
2621291a2b48SSukumar Swaminathan 		iocbq = (IOCBQ *) iocbq->next;
2622fcf3ce44SJohn Forte 
2623fcf3ce44SJohn Forte 	}	/* end of while */
2624fcf3ce44SJohn Forte 
262582527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2626fcf3ce44SJohn Forte 
2627fcf3ce44SJohn Forte 	/* Now abort the iocb's outside the locks */
2628fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2629fcf3ce44SJohn Forte 	while (iocbq) {
2630fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2631fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2632fcf3ce44SJohn Forte 
2633fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2634fcf3ce44SJohn Forte 		iocbq->next = NULL;
2635fcf3ce44SJohn Forte 
2636fcf3ce44SJohn Forte 		/* Get the pkt */
2637fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2638fcf3ce44SJohn Forte 
2639fcf3ce44SJohn Forte 		if (sbp) {
2640fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2641291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2642fcf3ce44SJohn Forte 
2643fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2644fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2645fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2646fcf3ce44SJohn Forte 			} else {
2647fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2648fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2649fcf3ce44SJohn Forte 			}
2650fcf3ce44SJohn Forte 
2651fcf3ce44SJohn Forte 		}
2652fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2653fcf3ce44SJohn Forte 		else {
265482527734SSukumar Swaminathan 			/* CMD_CLOSE_XRI_CN should also free the memory */
2655fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
265682527734SSukumar Swaminathan 
265782527734SSukumar Swaminathan 			/* SLI3 */
265882527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
265982527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
266082527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2661fcf3ce44SJohn Forte 				if ((hba->flag &
2662fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2663fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
266482527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2665fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2666a9800bebSGarrett D'Amore 						void	*tmp;
266782527734SSukumar Swaminathan 						RING *rp;
266882527734SSukumar Swaminathan 						int ch;
2669fcf3ce44SJohn Forte 
267082527734SSukumar Swaminathan 						ch = ((CHANNEL *)
267182527734SSukumar Swaminathan 						    iocbq->channel)->channelno;
267282527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
2673fcf3ce44SJohn Forte 						for (i = 0;
267482527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2675fcf3ce44SJohn Forte 						    i++) {
2676fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2677fcf3ce44SJohn Forte 							    hba, rp, icmd);
2678fcf3ce44SJohn Forte 
2679a9800bebSGarrett D'Amore 							tmp = (void *)mp;
2680fcf3ce44SJohn Forte 							if (mp) {
2681a9800bebSGarrett D'Amore 							emlxs_mem_put(
2682291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2683fcf3ce44SJohn Forte 							}
2684fcf3ce44SJohn Forte 						}
2685fcf3ce44SJohn Forte 					}
2686291a2b48SSukumar Swaminathan 
2687a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
2688a9800bebSGarrett D'Amore 					    (void *)iocbq);
2689fcf3ce44SJohn Forte 				} else {
2690fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
269182527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
269282527734SSukumar Swaminathan 					    (CHANNEL *)iocbq->channel, iocbq);
2693fcf3ce44SJohn Forte 				}
269482527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
269582527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
269682527734SSukumar Swaminathan 				/*
269782527734SSukumar Swaminathan 				 * Resend the abort iocbq if any
269882527734SSukumar Swaminathan 				 */
269982527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
2700fcf3ce44SJohn Forte 			}
2701fcf3ce44SJohn Forte 		}
2702fcf3ce44SJohn Forte 
2703fcf3ce44SJohn Forte 		iocbq = next;
2704fcf3ce44SJohn Forte 
2705fcf3ce44SJohn Forte 	}	/* end of while */
2706fcf3ce44SJohn Forte 
270782527734SSukumar Swaminathan 	/* Now trigger channel service */
270882527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
270982527734SSukumar Swaminathan 		if (!flag[channelno]) {
271082527734SSukumar Swaminathan 			continue;
271182527734SSukumar Swaminathan 		}
271282527734SSukumar Swaminathan 
271382527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
271482527734SSukumar Swaminathan 	}
271582527734SSukumar Swaminathan 
2716fcf3ce44SJohn Forte 	return (abort.q_cnt);
2717fcf3ce44SJohn Forte 
271882527734SSukumar Swaminathan } /* emlxs_tx_node_flush() */
2719fcf3ce44SJohn Forte 
2720fcf3ce44SJohn Forte 
2721fcf3ce44SJohn Forte /* Check for IO's on all or a given ring for a given node */
2722fcf3ce44SJohn Forte extern uint32_t
emlxs_tx_node_check(emlxs_port_t * port,NODELIST * ndlp,CHANNEL * chan)272382527734SSukumar Swaminathan emlxs_tx_node_check(emlxs_port_t *port, NODELIST *ndlp, CHANNEL *chan)
2724fcf3ce44SJohn Forte {
2725fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
272682527734SSukumar Swaminathan 	uint32_t channelno;
272782527734SSukumar Swaminathan 	CHANNEL *cp;
2728fcf3ce44SJohn Forte 	uint32_t count;
2729fcf3ce44SJohn Forte 
2730fcf3ce44SJohn Forte 	count = 0;
2731fcf3ce44SJohn Forte 
2732fcf3ce44SJohn Forte 	/* Flush all I/O's on tx queue to this target */
273382527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2734fcf3ce44SJohn Forte 
273582527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
273682527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
2737fcf3ce44SJohn Forte 
273882527734SSukumar Swaminathan 		if (chan && cp != chan) {
2739fcf3ce44SJohn Forte 			continue;
2740fcf3ce44SJohn Forte 		}
2741291a2b48SSukumar Swaminathan 
2742fcf3ce44SJohn Forte 		/* Check if priority queue is not empty */
274382527734SSukumar Swaminathan 		if (ndlp->nlp_ptx[channelno].q_first) {
274482527734SSukumar Swaminathan 			count += ndlp->nlp_ptx[channelno].q_cnt;
2745fcf3ce44SJohn Forte 		}
2746291a2b48SSukumar Swaminathan 
2747fcf3ce44SJohn Forte 		/* Check if tx queue is not empty */
274882527734SSukumar Swaminathan 		if (ndlp->nlp_tx[channelno].q_first) {
274982527734SSukumar Swaminathan 			count += ndlp->nlp_tx[channelno].q_cnt;
2750fcf3ce44SJohn Forte 		}
2751291a2b48SSukumar Swaminathan 
2752fcf3ce44SJohn Forte 	}
2753fcf3ce44SJohn Forte 
275482527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2755fcf3ce44SJohn Forte 
2756fcf3ce44SJohn Forte 	return (count);
2757fcf3ce44SJohn Forte 
275882527734SSukumar Swaminathan } /* emlxs_tx_node_check() */
2759fcf3ce44SJohn Forte 
2760fcf3ce44SJohn Forte 
2761fcf3ce44SJohn Forte 
276282527734SSukumar Swaminathan /* Flush all IO's on the any ring for a given node's lun */
2763fcf3ce44SJohn Forte extern uint32_t
emlxs_tx_lun_flush(emlxs_port_t * port,NODELIST * ndlp,uint32_t lun,emlxs_buf_t * fpkt)2764291a2b48SSukumar Swaminathan emlxs_tx_lun_flush(emlxs_port_t *port, NODELIST *ndlp, uint32_t lun,
2765291a2b48SSukumar Swaminathan     emlxs_buf_t *fpkt)
2766fcf3ce44SJohn Forte {
2767fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
2768fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
276982527734SSukumar Swaminathan 	uint32_t channelno;
2770fcf3ce44SJohn Forte 	IOCBQ *iocbq;
2771fcf3ce44SJohn Forte 	IOCBQ *prev;
2772fcf3ce44SJohn Forte 	IOCBQ *next;
2773fcf3ce44SJohn Forte 	IOCB *iocb;
2774fcf3ce44SJohn Forte 	IOCB *icmd;
2775fcf3ce44SJohn Forte 	Q abort;
2776fcf3ce44SJohn Forte 	uint32_t i;
2777fcf3ce44SJohn Forte 	MATCHMAP *mp;
277882527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
2779fcf3ce44SJohn Forte 
2780a9800bebSGarrett D'Amore 	if (lun == EMLXS_LUN_NONE) {
2781a9800bebSGarrett D'Amore 		return (0);
2782a9800bebSGarrett D'Amore 	}
2783a9800bebSGarrett D'Amore 
2784fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
2785fcf3ce44SJohn Forte 
2786fcf3ce44SJohn Forte 	/* Flush I/O's on txQ to this target's lun */
278782527734SSukumar Swaminathan 	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
2788fcf3ce44SJohn Forte 
278982527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
2790291a2b48SSukumar Swaminathan 
279182527734SSukumar Swaminathan 		/* Scan the priority queue first */
279282527734SSukumar Swaminathan 		prev = NULL;
279382527734SSukumar Swaminathan 		iocbq = (IOCBQ *) ndlp->nlp_ptx[channelno].q_first;
2794fcf3ce44SJohn Forte 
279582527734SSukumar Swaminathan 		while (iocbq) {
279682527734SSukumar Swaminathan 			next = (IOCBQ *)iocbq->next;
279782527734SSukumar Swaminathan 			iocb = &iocbq->iocb;
279882527734SSukumar Swaminathan 			sbp = (emlxs_buf_t *)iocbq->sbp;
279982527734SSukumar Swaminathan 
280082527734SSukumar Swaminathan 			/* Check if this IO is for our lun */
280182527734SSukumar Swaminathan 			if (sbp && (sbp->lun == lun)) {
280282527734SSukumar Swaminathan 				/* Remove iocb from the node's ptx queue */
280382527734SSukumar Swaminathan 				if (next == 0) {
280482527734SSukumar Swaminathan 					ndlp->nlp_ptx[channelno].q_last =
280582527734SSukumar Swaminathan 					    (uint8_t *)prev;
280682527734SSukumar Swaminathan 				}
280782527734SSukumar Swaminathan 
280882527734SSukumar Swaminathan 				if (prev == 0) {
280982527734SSukumar Swaminathan 					ndlp->nlp_ptx[channelno].q_first =
281082527734SSukumar Swaminathan 					    (uint8_t *)next;
281182527734SSukumar Swaminathan 				} else {
281282527734SSukumar Swaminathan 					prev->next = next;
281382527734SSukumar Swaminathan 				}
281482527734SSukumar Swaminathan 
281582527734SSukumar Swaminathan 				iocbq->next = NULL;
281682527734SSukumar Swaminathan 				ndlp->nlp_ptx[channelno].q_cnt--;
281782527734SSukumar Swaminathan 
281882527734SSukumar Swaminathan 				/*
281982527734SSukumar Swaminathan 				 * Add this iocb to our local abort Q
282082527734SSukumar Swaminathan 				 */
282182527734SSukumar Swaminathan 				if (abort.q_first) {
282282527734SSukumar Swaminathan 					((IOCBQ *)abort.q_last)->next = iocbq;
282382527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
282482527734SSukumar Swaminathan 					abort.q_cnt++;
282582527734SSukumar Swaminathan 				} else {
282682527734SSukumar Swaminathan 					abort.q_first = (uint8_t *)iocbq;
282782527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
282882527734SSukumar Swaminathan 					abort.q_cnt = 1;
282982527734SSukumar Swaminathan 				}
283082527734SSukumar Swaminathan 				iocbq->next = NULL;
283182527734SSukumar Swaminathan 				flag[channelno] = 1;
2832fcf3ce44SJohn Forte 
2833fcf3ce44SJohn Forte 			} else {
283482527734SSukumar Swaminathan 				prev = iocbq;
2835fcf3ce44SJohn Forte 			}
2836fcf3ce44SJohn Forte 
283782527734SSukumar Swaminathan 			iocbq = next;
2838fcf3ce44SJohn Forte 
283982527734SSukumar Swaminathan 		}	/* while (iocbq) */
2840fcf3ce44SJohn Forte 
2841fcf3ce44SJohn Forte 
284282527734SSukumar Swaminathan 		/* Scan the regular queue */
284382527734SSukumar Swaminathan 		prev = NULL;
284482527734SSukumar Swaminathan 		iocbq = (IOCBQ *)ndlp->nlp_tx[channelno].q_first;
2845fcf3ce44SJohn Forte 
284682527734SSukumar Swaminathan 		while (iocbq) {
284782527734SSukumar Swaminathan 			next = (IOCBQ *)iocbq->next;
284882527734SSukumar Swaminathan 			iocb = &iocbq->iocb;
284982527734SSukumar Swaminathan 			sbp = (emlxs_buf_t *)iocbq->sbp;
285082527734SSukumar Swaminathan 
285182527734SSukumar Swaminathan 			/* Check if this IO is for our lun */
285282527734SSukumar Swaminathan 			if (sbp && (sbp->lun == lun)) {
285382527734SSukumar Swaminathan 				/* Remove iocb from the node's tx queue */
285482527734SSukumar Swaminathan 				if (next == 0) {
285582527734SSukumar Swaminathan 					ndlp->nlp_tx[channelno].q_last =
285682527734SSukumar Swaminathan 					    (uint8_t *)prev;
285782527734SSukumar Swaminathan 				}
2858291a2b48SSukumar Swaminathan 
285982527734SSukumar Swaminathan 				if (prev == 0) {
286082527734SSukumar Swaminathan 					ndlp->nlp_tx[channelno].q_first =
286182527734SSukumar Swaminathan 					    (uint8_t *)next;
286282527734SSukumar Swaminathan 				} else {
286382527734SSukumar Swaminathan 					prev->next = next;
286482527734SSukumar Swaminathan 				}
2865fcf3ce44SJohn Forte 
286682527734SSukumar Swaminathan 				iocbq->next = NULL;
286782527734SSukumar Swaminathan 				ndlp->nlp_tx[channelno].q_cnt--;
2868fcf3ce44SJohn Forte 
286982527734SSukumar Swaminathan 				/*
287082527734SSukumar Swaminathan 				 * Add this iocb to our local abort Q
287182527734SSukumar Swaminathan 				 */
287282527734SSukumar Swaminathan 				if (abort.q_first) {
287382527734SSukumar Swaminathan 					((IOCBQ *) abort.q_last)->next = iocbq;
287482527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
287582527734SSukumar Swaminathan 					abort.q_cnt++;
287682527734SSukumar Swaminathan 				} else {
287782527734SSukumar Swaminathan 					abort.q_first = (uint8_t *)iocbq;
287882527734SSukumar Swaminathan 					abort.q_last = (uint8_t *)iocbq;
287982527734SSukumar Swaminathan 					abort.q_cnt = 1;
288082527734SSukumar Swaminathan 				}
288182527734SSukumar Swaminathan 				iocbq->next = NULL;
2882fcf3ce44SJohn Forte 			} else {
288382527734SSukumar Swaminathan 				prev = iocbq;
2884fcf3ce44SJohn Forte 			}
2885fcf3ce44SJohn Forte 
288682527734SSukumar Swaminathan 			iocbq = next;
2887fcf3ce44SJohn Forte 
288882527734SSukumar Swaminathan 		}	/* while (iocbq) */
288982527734SSukumar Swaminathan 	}	/* for loop */
2890fcf3ce44SJohn Forte 
2891fcf3ce44SJohn Forte 	/* First cleanup the iocb's while still holding the lock */
2892fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2893fcf3ce44SJohn Forte 	while (iocbq) {
2894fcf3ce44SJohn Forte 		/* Free the IoTag and the bmp */
2895fcf3ce44SJohn Forte 		iocb = &iocbq->iocb;
289682527734SSukumar Swaminathan 
289782527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
289882527734SSukumar Swaminathan 			sbp = iocbq->sbp;
289982527734SSukumar Swaminathan 			if (sbp) {
29008f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
290182527734SSukumar Swaminathan 			}
290282527734SSukumar Swaminathan 		} else {
290382527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
290482527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
290582527734SSukumar Swaminathan 		}
2906fcf3ce44SJohn Forte 
2907fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET)) {
2908fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
2909fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
2910fcf3ce44SJohn Forte 			/*
2911fcf3ce44SJohn Forte 			 * If the fpkt is already set, then we will leave it
2912291a2b48SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
2913291a2b48SSukumar Swaminathan 			 * for on one fpkt->flush_count
2914fcf3ce44SJohn Forte 			 */
2915fcf3ce44SJohn Forte 			if (!sbp->fpkt && fpkt) {
2916fcf3ce44SJohn Forte 				mutex_enter(&fpkt->mtx);
2917fcf3ce44SJohn Forte 				sbp->fpkt = fpkt;
2918fcf3ce44SJohn Forte 				fpkt->flush_count++;
2919fcf3ce44SJohn Forte 				mutex_exit(&fpkt->mtx);
2920fcf3ce44SJohn Forte 			}
2921291a2b48SSukumar Swaminathan 
2922fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
2923fcf3ce44SJohn Forte 		}
2924291a2b48SSukumar Swaminathan 
2925291a2b48SSukumar Swaminathan 		iocbq = (IOCBQ *) iocbq->next;
2926fcf3ce44SJohn Forte 
2927fcf3ce44SJohn Forte 	}	/* end of while */
2928fcf3ce44SJohn Forte 
292982527734SSukumar Swaminathan 	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
2930fcf3ce44SJohn Forte 
2931fcf3ce44SJohn Forte 	/* Now abort the iocb's outside the locks */
2932fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
2933fcf3ce44SJohn Forte 	while (iocbq) {
2934fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
2935fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
2936fcf3ce44SJohn Forte 
2937fcf3ce44SJohn Forte 		/* Unlink this iocbq */
2938fcf3ce44SJohn Forte 		iocbq->next = NULL;
2939fcf3ce44SJohn Forte 
2940fcf3ce44SJohn Forte 		/* Get the pkt */
2941fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
2942fcf3ce44SJohn Forte 
2943fcf3ce44SJohn Forte 		if (sbp) {
2944fcf3ce44SJohn Forte 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
2945291a2b48SSukumar Swaminathan 			    "tx: sbp=%p node=%p", sbp, sbp->node);
2946fcf3ce44SJohn Forte 
2947fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
2948fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2949fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
2950fcf3ce44SJohn Forte 			} else {
2951fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
2952fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
2953fcf3ce44SJohn Forte 			}
2954fcf3ce44SJohn Forte 		}
2955291a2b48SSukumar Swaminathan 
2956fcf3ce44SJohn Forte 		/* Free the iocb and its associated buffers */
2957fcf3ce44SJohn Forte 		else {
295882527734SSukumar Swaminathan 			/* Should never happen! */
2959fcf3ce44SJohn Forte 			icmd = &iocbq->iocb;
2960fcf3ce44SJohn Forte 
296182527734SSukumar Swaminathan 			/* SLI3 */
296282527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
296382527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
296482527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
2965fcf3ce44SJohn Forte 				if ((hba->flag &
2966fcf3ce44SJohn Forte 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
2967fcf3ce44SJohn Forte 					/* HBA is detaching or offlining */
296882527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
2969fcf3ce44SJohn Forte 					    CMD_QUE_RING_LIST64_CN) {
2970a9800bebSGarrett D'Amore 						void	*tmp;
297182527734SSukumar Swaminathan 						RING *rp;
297282527734SSukumar Swaminathan 						int ch;
2973fcf3ce44SJohn Forte 
297482527734SSukumar Swaminathan 						ch = ((CHANNEL *)
297582527734SSukumar Swaminathan 						    iocbq->channel)->channelno;
297682527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
2977fcf3ce44SJohn Forte 						for (i = 0;
297882527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
2979fcf3ce44SJohn Forte 						    i++) {
2980fcf3ce44SJohn Forte 							mp = EMLXS_GET_VADDR(
2981fcf3ce44SJohn Forte 							    hba, rp, icmd);
2982fcf3ce44SJohn Forte 
2983a9800bebSGarrett D'Amore 							tmp = (void *)mp;
2984fcf3ce44SJohn Forte 							if (mp) {
2985a9800bebSGarrett D'Amore 							emlxs_mem_put(
2986291a2b48SSukumar Swaminathan 							    hba, MEM_BUF, tmp);
2987fcf3ce44SJohn Forte 							}
2988fcf3ce44SJohn Forte 						}
2989fcf3ce44SJohn Forte 					}
2990291a2b48SSukumar Swaminathan 
2991a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
2992a9800bebSGarrett D'Amore 					    (void *)iocbq);
2993fcf3ce44SJohn Forte 				} else {
2994fcf3ce44SJohn Forte 					/* repost the unsolicited buffer */
299582527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
299682527734SSukumar Swaminathan 					    (CHANNEL *)iocbq->channel, iocbq);
2997fcf3ce44SJohn Forte 				}
299882527734SSukumar Swaminathan 			} else if (icmd->ULPCOMMAND == CMD_CLOSE_XRI_CN ||
299982527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_CLOSE_XRI_CX) {
300082527734SSukumar Swaminathan 				/*
300182527734SSukumar Swaminathan 				 * Resend the abort iocbq if any
300282527734SSukumar Swaminathan 				 */
300382527734SSukumar Swaminathan 				emlxs_tx_put(iocbq, 1);
3004fcf3ce44SJohn Forte 			}
3005fcf3ce44SJohn Forte 		}
3006fcf3ce44SJohn Forte 
3007fcf3ce44SJohn Forte 		iocbq = next;
3008fcf3ce44SJohn Forte 
3009fcf3ce44SJohn Forte 	}	/* end of while */
3010fcf3ce44SJohn Forte 
301182527734SSukumar Swaminathan 	/* Now trigger channel service */
301282527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
301382527734SSukumar Swaminathan 		if (!flag[channelno]) {
301482527734SSukumar Swaminathan 			continue;
301582527734SSukumar Swaminathan 		}
301682527734SSukumar Swaminathan 
301782527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
301882527734SSukumar Swaminathan 	}
3019fcf3ce44SJohn Forte 
3020fcf3ce44SJohn Forte 	return (abort.q_cnt);
3021fcf3ce44SJohn Forte 
302282527734SSukumar Swaminathan } /* emlxs_tx_lun_flush() */
3023fcf3ce44SJohn Forte 
3024fcf3ce44SJohn Forte 
3025fcf3ce44SJohn Forte extern void
emlxs_tx_put(IOCBQ * iocbq,uint32_t lock)3026fcf3ce44SJohn Forte emlxs_tx_put(IOCBQ *iocbq, uint32_t lock)
3027fcf3ce44SJohn Forte {
3028fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
3029fcf3ce44SJohn Forte 	emlxs_port_t *port;
303082527734SSukumar Swaminathan 	uint32_t channelno;
3031fcf3ce44SJohn Forte 	NODELIST *nlp;
303282527734SSukumar Swaminathan 	CHANNEL *cp;
3033fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3034fcf3ce44SJohn Forte 
3035fcf3ce44SJohn Forte 	port = (emlxs_port_t *)iocbq->port;
3036fcf3ce44SJohn Forte 	hba = HBA;
303782527734SSukumar Swaminathan 	cp = (CHANNEL *)iocbq->channel;
3038fcf3ce44SJohn Forte 	nlp = (NODELIST *)iocbq->node;
303982527734SSukumar Swaminathan 	channelno = cp->channelno;
3040fcf3ce44SJohn Forte 	sbp = (emlxs_buf_t *)iocbq->sbp;
3041fcf3ce44SJohn Forte 
3042fcf3ce44SJohn Forte 	if (nlp == NULL) {
3043fcf3ce44SJohn Forte 		/* Set node to base node by default */
3044fcf3ce44SJohn Forte 		nlp = &port->node_base;
3045fcf3ce44SJohn Forte 
3046fcf3ce44SJohn Forte 		iocbq->node = (void *)nlp;
3047fcf3ce44SJohn Forte 
3048fcf3ce44SJohn Forte 		if (sbp) {
3049fcf3ce44SJohn Forte 			sbp->node = (void *)nlp;
3050fcf3ce44SJohn Forte 		}
3051fcf3ce44SJohn Forte 	}
3052291a2b48SSukumar Swaminathan 
3053fcf3ce44SJohn Forte 	if (lock) {
305482527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
3055fcf3ce44SJohn Forte 	}
3056291a2b48SSukumar Swaminathan 
3057fcf3ce44SJohn Forte 	if (!nlp->nlp_active || (sbp && (sbp->pkt_flags & PACKET_IN_ABORT))) {
3058fcf3ce44SJohn Forte 		if (sbp) {
3059fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
3060fcf3ce44SJohn Forte 			sbp->pkt_flags |= PACKET_IN_FLUSH;
3061fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3062fcf3ce44SJohn Forte 
306382527734SSukumar Swaminathan 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
30648f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
306582527734SSukumar Swaminathan 			} else {
306682527734SSukumar Swaminathan 				(void) emlxs_unregister_pkt(cp, sbp->iotag, 0);
306782527734SSukumar Swaminathan 			}
3068fcf3ce44SJohn Forte 
3069fcf3ce44SJohn Forte 			if (lock) {
307082527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3071fcf3ce44SJohn Forte 			}
3072291a2b48SSukumar Swaminathan 
3073fcf3ce44SJohn Forte 			if (hba->state >= FC_LINK_UP) {
3074fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
3075fcf3ce44SJohn Forte 				    IOERR_ABORT_REQUESTED, 1);
3076fcf3ce44SJohn Forte 			} else {
3077fcf3ce44SJohn Forte 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
3078fcf3ce44SJohn Forte 				    IOERR_LINK_DOWN, 1);
3079fcf3ce44SJohn Forte 			}
3080fcf3ce44SJohn Forte 			return;
3081fcf3ce44SJohn Forte 		} else {
3082fcf3ce44SJohn Forte 			if (lock) {
308382527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3084fcf3ce44SJohn Forte 			}
3085291a2b48SSukumar Swaminathan 
3086a9800bebSGarrett D'Amore 			emlxs_mem_put(hba, MEM_IOCB, (void *)iocbq);
3087fcf3ce44SJohn Forte 		}
3088fcf3ce44SJohn Forte 
3089fcf3ce44SJohn Forte 		return;
3090fcf3ce44SJohn Forte 	}
3091291a2b48SSukumar Swaminathan 
3092fcf3ce44SJohn Forte 	if (sbp) {
3093fcf3ce44SJohn Forte 
3094fcf3ce44SJohn Forte 		mutex_enter(&sbp->mtx);
3095fcf3ce44SJohn Forte 
3096291a2b48SSukumar Swaminathan 		if (sbp->pkt_flags &
3097291a2b48SSukumar Swaminathan 		    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ | PACKET_IN_TXQ)) {
3098fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3099fcf3ce44SJohn Forte 			if (lock) {
310082527734SSukumar Swaminathan 				mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3101fcf3ce44SJohn Forte 			}
3102fcf3ce44SJohn Forte 			return;
3103fcf3ce44SJohn Forte 		}
3104291a2b48SSukumar Swaminathan 
3105fcf3ce44SJohn Forte 		sbp->pkt_flags |= PACKET_IN_TXQ;
310682527734SSukumar Swaminathan 		hba->channel_tx_count++;
3107fcf3ce44SJohn Forte 
3108fcf3ce44SJohn Forte 		mutex_exit(&sbp->mtx);
3109fcf3ce44SJohn Forte 	}
3110291a2b48SSukumar Swaminathan 
3111291a2b48SSukumar Swaminathan 
3112fcf3ce44SJohn Forte 	/* Check iocbq priority */
311382527734SSukumar Swaminathan 	/* Some IOCB has the high priority like reset/close xri etc */
3114fcf3ce44SJohn Forte 	if (iocbq->flag & IOCB_PRIORITY) {
3115fcf3ce44SJohn Forte 		/* Add the iocb to the bottom of the node's ptx queue */
311682527734SSukumar Swaminathan 		if (nlp->nlp_ptx[channelno].q_first) {
311782527734SSukumar Swaminathan 			((IOCBQ *)nlp->nlp_ptx[channelno].q_last)->next = iocbq;
311882527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_last = (uint8_t *)iocbq;
311982527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_cnt++;
3120fcf3ce44SJohn Forte 		} else {
312182527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_first = (uint8_t *)iocbq;
312282527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_last = (uint8_t *)iocbq;
312382527734SSukumar Swaminathan 			nlp->nlp_ptx[channelno].q_cnt = 1;
3124fcf3ce44SJohn Forte 		}
3125fcf3ce44SJohn Forte 
3126fcf3ce44SJohn Forte 		iocbq->next = NULL;
3127fcf3ce44SJohn Forte 	} else {	/* Normal priority */
3128fcf3ce44SJohn Forte 
3129291a2b48SSukumar Swaminathan 
3130fcf3ce44SJohn Forte 		/* Add the iocb to the bottom of the node's tx queue */
313182527734SSukumar Swaminathan 		if (nlp->nlp_tx[channelno].q_first) {
313282527734SSukumar Swaminathan 			((IOCBQ *)nlp->nlp_tx[channelno].q_last)->next = iocbq;
313382527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_last = (uint8_t *)iocbq;
313482527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_cnt++;
3135fcf3ce44SJohn Forte 		} else {
313682527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_first = (uint8_t *)iocbq;
313782527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_last = (uint8_t *)iocbq;
313882527734SSukumar Swaminathan 			nlp->nlp_tx[channelno].q_cnt = 1;
3139fcf3ce44SJohn Forte 		}
3140fcf3ce44SJohn Forte 
3141fcf3ce44SJohn Forte 		iocbq->next = NULL;
3142fcf3ce44SJohn Forte 	}
3143fcf3ce44SJohn Forte 
3144fcf3ce44SJohn Forte 
3145fcf3ce44SJohn Forte 	/*
314682527734SSukumar Swaminathan 	 * Check if the node is not already on channel queue and
3147291a2b48SSukumar Swaminathan 	 * (is not closed or  is a priority request)
3148fcf3ce44SJohn Forte 	 */
314982527734SSukumar Swaminathan 	if (!nlp->nlp_next[channelno] &&
315082527734SSukumar Swaminathan 	    (!(nlp->nlp_flag[channelno] & NLP_CLOSED) ||
3151fcf3ce44SJohn Forte 	    (iocbq->flag & IOCB_PRIORITY))) {
315282527734SSukumar Swaminathan 		/* If so, then add it to the channel queue */
315382527734SSukumar Swaminathan 		if (cp->nodeq.q_first) {
315482527734SSukumar Swaminathan 			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
3155fcf3ce44SJohn Forte 			    (uint8_t *)nlp;
315682527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = cp->nodeq.q_first;
3157fcf3ce44SJohn Forte 
3158fcf3ce44SJohn Forte 			/*
3159291a2b48SSukumar Swaminathan 			 * If this is not the base node then add it
3160291a2b48SSukumar Swaminathan 			 * to the tail
3161fcf3ce44SJohn Forte 			 */
3162fcf3ce44SJohn Forte 			if (!nlp->nlp_base) {
316382527734SSukumar Swaminathan 				cp->nodeq.q_last = (uint8_t *)nlp;
3164fcf3ce44SJohn Forte 			} else {	/* Otherwise, add it to the head */
3165291a2b48SSukumar Swaminathan 
3166fcf3ce44SJohn Forte 				/* The command node always gets priority */
316782527734SSukumar Swaminathan 				cp->nodeq.q_first = (uint8_t *)nlp;
3168fcf3ce44SJohn Forte 			}
3169fcf3ce44SJohn Forte 
317082527734SSukumar Swaminathan 			cp->nodeq.q_cnt++;
3171fcf3ce44SJohn Forte 		} else {
317282527734SSukumar Swaminathan 			cp->nodeq.q_first = (uint8_t *)nlp;
317382527734SSukumar Swaminathan 			cp->nodeq.q_last = (uint8_t *)nlp;
317482527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = nlp;
317582527734SSukumar Swaminathan 			cp->nodeq.q_cnt = 1;
3176fcf3ce44SJohn Forte 		}
3177fcf3ce44SJohn Forte 	}
3178291a2b48SSukumar Swaminathan 
317982527734SSukumar Swaminathan 	HBASTATS.IocbTxPut[channelno]++;
3180fcf3ce44SJohn Forte 
318182527734SSukumar Swaminathan 	/* Adjust the channel timeout timer */
318282527734SSukumar Swaminathan 	cp->timeout = hba->timer_tics + 5;
3183fcf3ce44SJohn Forte 
3184fcf3ce44SJohn Forte 	if (lock) {
318582527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3186fcf3ce44SJohn Forte 	}
3187291a2b48SSukumar Swaminathan 
3188fcf3ce44SJohn Forte 	return;
3189fcf3ce44SJohn Forte 
319082527734SSukumar Swaminathan } /* emlxs_tx_put() */
3191fcf3ce44SJohn Forte 
3192fcf3ce44SJohn Forte 
3193fcf3ce44SJohn Forte extern IOCBQ *
emlxs_tx_get(CHANNEL * cp,uint32_t lock)319482527734SSukumar Swaminathan emlxs_tx_get(CHANNEL *cp, uint32_t lock)
3195fcf3ce44SJohn Forte {
3196fcf3ce44SJohn Forte 	emlxs_hba_t *hba;
319782527734SSukumar Swaminathan 	uint32_t channelno;
3198fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3199fcf3ce44SJohn Forte 	NODELIST *nlp;
3200fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3201fcf3ce44SJohn Forte 
320282527734SSukumar Swaminathan 	hba = cp->hba;
320382527734SSukumar Swaminathan 	channelno = cp->channelno;
3204fcf3ce44SJohn Forte 
3205fcf3ce44SJohn Forte 	if (lock) {
320682527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
3207fcf3ce44SJohn Forte 	}
3208291a2b48SSukumar Swaminathan 
3209fcf3ce44SJohn Forte begin:
3210fcf3ce44SJohn Forte 
3211fcf3ce44SJohn Forte 	iocbq = NULL;
3212fcf3ce44SJohn Forte 
3213fcf3ce44SJohn Forte 	/* Check if a node needs servicing */
321482527734SSukumar Swaminathan 	if (cp->nodeq.q_first) {
321582527734SSukumar Swaminathan 		nlp = (NODELIST *)cp->nodeq.q_first;
3216fcf3ce44SJohn Forte 
3217fcf3ce44SJohn Forte 		/* Get next iocb from node's priority queue */
3218fcf3ce44SJohn Forte 
321982527734SSukumar Swaminathan 		if (nlp->nlp_ptx[channelno].q_first) {
322082527734SSukumar Swaminathan 			iocbq = (IOCBQ *)nlp->nlp_ptx[channelno].q_first;
3221fcf3ce44SJohn Forte 
3222fcf3ce44SJohn Forte 			/* Check if this is last entry */
322382527734SSukumar Swaminathan 			if (nlp->nlp_ptx[channelno].q_last == (void *)iocbq) {
322482527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_first = NULL;
322582527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_last = NULL;
322682527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_cnt = 0;
3227fcf3ce44SJohn Forte 			} else {
3228fcf3ce44SJohn Forte 				/* Remove iocb from head */
322982527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_first =
3230fcf3ce44SJohn Forte 				    (void *)iocbq->next;
323182527734SSukumar Swaminathan 				nlp->nlp_ptx[channelno].q_cnt--;
3232fcf3ce44SJohn Forte 			}
3233fcf3ce44SJohn Forte 
3234fcf3ce44SJohn Forte 			iocbq->next = NULL;
3235fcf3ce44SJohn Forte 		}
3236291a2b48SSukumar Swaminathan 
3237fcf3ce44SJohn Forte 		/* Get next iocb from node tx queue if node not closed */
323882527734SSukumar Swaminathan 		else if (nlp->nlp_tx[channelno].q_first &&
323982527734SSukumar Swaminathan 		    !(nlp->nlp_flag[channelno] & NLP_CLOSED)) {
324082527734SSukumar Swaminathan 			iocbq = (IOCBQ *)nlp->nlp_tx[channelno].q_first;
3241fcf3ce44SJohn Forte 
3242fcf3ce44SJohn Forte 			/* Check if this is last entry */
324382527734SSukumar Swaminathan 			if (nlp->nlp_tx[channelno].q_last == (void *)iocbq) {
324482527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_first = NULL;
324582527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_last = NULL;
324682527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_cnt = 0;
3247fcf3ce44SJohn Forte 			} else {
3248fcf3ce44SJohn Forte 				/* Remove iocb from head */
324982527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_first =
3250fcf3ce44SJohn Forte 				    (void *)iocbq->next;
325182527734SSukumar Swaminathan 				nlp->nlp_tx[channelno].q_cnt--;
3252fcf3ce44SJohn Forte 			}
3253fcf3ce44SJohn Forte 
3254fcf3ce44SJohn Forte 			iocbq->next = NULL;
3255fcf3ce44SJohn Forte 		}
3256291a2b48SSukumar Swaminathan 
3257fcf3ce44SJohn Forte 		/* Now deal with node itself */
3258fcf3ce44SJohn Forte 
3259fcf3ce44SJohn Forte 		/* Check if node still needs servicing */
326082527734SSukumar Swaminathan 		if ((nlp->nlp_ptx[channelno].q_first) ||
326182527734SSukumar Swaminathan 		    (nlp->nlp_tx[channelno].q_first &&
326282527734SSukumar Swaminathan 		    !(nlp->nlp_flag[channelno] & NLP_CLOSED))) {
3263fcf3ce44SJohn Forte 
3264fcf3ce44SJohn Forte 			/*
3265fcf3ce44SJohn Forte 			 * If this is the base node, then don't shift the
3266291a2b48SSukumar Swaminathan 			 * pointers. We want to drain the base node before
3267291a2b48SSukumar Swaminathan 			 * moving on
3268fcf3ce44SJohn Forte 			 */
3269fcf3ce44SJohn Forte 			if (!nlp->nlp_base) {
3270fcf3ce44SJohn Forte 				/*
327182527734SSukumar Swaminathan 				 * Just shift channel queue pointers to next
3272fcf3ce44SJohn Forte 				 * node
3273fcf3ce44SJohn Forte 				 */
327482527734SSukumar Swaminathan 				cp->nodeq.q_last = (void *)nlp;
327582527734SSukumar Swaminathan 				cp->nodeq.q_first = nlp->nlp_next[channelno];
3276fcf3ce44SJohn Forte 			}
3277fcf3ce44SJohn Forte 		} else {
327882527734SSukumar Swaminathan 			/* Remove node from channel queue */
3279fcf3ce44SJohn Forte 
3280fcf3ce44SJohn Forte 			/* If this is the last node on list */
328182527734SSukumar Swaminathan 			if (cp->nodeq.q_last == (void *)nlp) {
328282527734SSukumar Swaminathan 				cp->nodeq.q_last = NULL;
328382527734SSukumar Swaminathan 				cp->nodeq.q_first = NULL;
328482527734SSukumar Swaminathan 				cp->nodeq.q_cnt = 0;
3285fcf3ce44SJohn Forte 			} else {
3286fcf3ce44SJohn Forte 				/* Remove node from head */
328782527734SSukumar Swaminathan 				cp->nodeq.q_first = nlp->nlp_next[channelno];
328882527734SSukumar Swaminathan 				((NODELIST *)cp->nodeq.q_last)->
328982527734SSukumar Swaminathan 				    nlp_next[channelno] = cp->nodeq.q_first;
329082527734SSukumar Swaminathan 				cp->nodeq.q_cnt--;
3291fcf3ce44SJohn Forte 
3292fcf3ce44SJohn Forte 			}
3293fcf3ce44SJohn Forte 
3294fcf3ce44SJohn Forte 			/* Clear node */
329582527734SSukumar Swaminathan 			nlp->nlp_next[channelno] = NULL;
3296fcf3ce44SJohn Forte 		}
3297fcf3ce44SJohn Forte 
3298fcf3ce44SJohn Forte 		/*
3299291a2b48SSukumar Swaminathan 		 * If no iocbq was found on this node, then it will have
3300291a2b48SSukumar Swaminathan 		 * been removed. So try again.
3301fcf3ce44SJohn Forte 		 */
3302fcf3ce44SJohn Forte 		if (!iocbq) {
3303fcf3ce44SJohn Forte 			goto begin;
3304fcf3ce44SJohn Forte 		}
3305291a2b48SSukumar Swaminathan 
3306fcf3ce44SJohn Forte 		sbp = (emlxs_buf_t *)iocbq->sbp;
3307fcf3ce44SJohn Forte 
3308fcf3ce44SJohn Forte 		if (sbp) {
3309fcf3ce44SJohn Forte 			/*
3310291a2b48SSukumar Swaminathan 			 * Check flags before we enter mutex in case this
3311291a2b48SSukumar Swaminathan 			 * has been flushed and destroyed
3312fcf3ce44SJohn Forte 			 */
3313fcf3ce44SJohn Forte 			if ((sbp->pkt_flags &
3314fcf3ce44SJohn Forte 			    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) ||
3315fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_IN_TXQ)) {
3316fcf3ce44SJohn Forte 				goto begin;
3317fcf3ce44SJohn Forte 			}
3318291a2b48SSukumar Swaminathan 
3319fcf3ce44SJohn Forte 			mutex_enter(&sbp->mtx);
3320fcf3ce44SJohn Forte 
3321fcf3ce44SJohn Forte 			if ((sbp->pkt_flags &
3322fcf3ce44SJohn Forte 			    (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) ||
3323fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_IN_TXQ)) {
3324fcf3ce44SJohn Forte 				mutex_exit(&sbp->mtx);
3325fcf3ce44SJohn Forte 				goto begin;
3326fcf3ce44SJohn Forte 			}
3327291a2b48SSukumar Swaminathan 
3328fcf3ce44SJohn Forte 			sbp->pkt_flags &= ~PACKET_IN_TXQ;
332982527734SSukumar Swaminathan 			hba->channel_tx_count--;
3330fcf3ce44SJohn Forte 
3331fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3332fcf3ce44SJohn Forte 		}
3333fcf3ce44SJohn Forte 	}
3334291a2b48SSukumar Swaminathan 
3335fcf3ce44SJohn Forte 	if (iocbq) {
333682527734SSukumar Swaminathan 		HBASTATS.IocbTxGet[channelno]++;
3337fcf3ce44SJohn Forte 	}
3338291a2b48SSukumar Swaminathan 
3339fcf3ce44SJohn Forte 	/* Adjust the ring timeout timer */
334082527734SSukumar Swaminathan 	cp->timeout = (cp->nodeq.q_first) ? (hba->timer_tics + 5) : 0;
3341fcf3ce44SJohn Forte 
3342fcf3ce44SJohn Forte 	if (lock) {
334382527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
3344fcf3ce44SJohn Forte 	}
3345291a2b48SSukumar Swaminathan 
3346fcf3ce44SJohn Forte 	return (iocbq);
3347fcf3ce44SJohn Forte 
334882527734SSukumar Swaminathan } /* emlxs_tx_get() */
334982527734SSukumar Swaminathan 
3350fcf3ce44SJohn Forte 
335182527734SSukumar Swaminathan /*
335282527734SSukumar Swaminathan  * Remove all cmd from from_rp's txq to to_rp's txq for ndlp.
335382527734SSukumar Swaminathan  * The old IoTag has to be released, the new one has to be
335482527734SSukumar Swaminathan  * allocated.  Others no change
335582527734SSukumar Swaminathan  * TX_CHANNEL lock is held
335682527734SSukumar Swaminathan  */
335782527734SSukumar Swaminathan extern void
emlxs_tx_move(NODELIST * ndlp,CHANNEL * from_chan,CHANNEL * to_chan,uint32_t cmd,emlxs_buf_t * fpkt,uint32_t lock)335882527734SSukumar Swaminathan emlxs_tx_move(NODELIST *ndlp, CHANNEL *from_chan, CHANNEL *to_chan,
335982527734SSukumar Swaminathan     uint32_t cmd, emlxs_buf_t *fpkt, uint32_t lock)
336082527734SSukumar Swaminathan {
336182527734SSukumar Swaminathan 	emlxs_hba_t *hba;
336282527734SSukumar Swaminathan 	emlxs_port_t *port;
336382527734SSukumar Swaminathan 	uint32_t fchanno, tchanno, i;
336482527734SSukumar Swaminathan 
336582527734SSukumar Swaminathan 	IOCBQ *iocbq;
336682527734SSukumar Swaminathan 	IOCBQ *prev;
336782527734SSukumar Swaminathan 	IOCBQ *next;
336882527734SSukumar Swaminathan 	IOCB *iocb, *icmd;
336982527734SSukumar Swaminathan 	Q tbm;		/* To Be Moved Q */
337082527734SSukumar Swaminathan 	MATCHMAP *mp;
337182527734SSukumar Swaminathan 
337282527734SSukumar Swaminathan 	NODELIST *nlp = ndlp;
337382527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
337482527734SSukumar Swaminathan 
337582527734SSukumar Swaminathan 	NODELIST *n_prev = NULL;
337682527734SSukumar Swaminathan 	NODELIST *n_next = NULL;
337782527734SSukumar Swaminathan 	uint16_t count = 0;
337882527734SSukumar Swaminathan 
337982527734SSukumar Swaminathan 	hba = from_chan->hba;
338082527734SSukumar Swaminathan 	port = &PPORT;
338182527734SSukumar Swaminathan 	cmd = cmd; /* To pass lint */
338282527734SSukumar Swaminathan 
338382527734SSukumar Swaminathan 	fchanno = from_chan->channelno;
338482527734SSukumar Swaminathan 	tchanno = to_chan->channelno;
338582527734SSukumar Swaminathan 
338682527734SSukumar Swaminathan 	if (lock) {
338782527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
338882527734SSukumar Swaminathan 	}
338982527734SSukumar Swaminathan 
339082527734SSukumar Swaminathan 	bzero((void *)&tbm, sizeof (Q));
339182527734SSukumar Swaminathan 
339282527734SSukumar Swaminathan 	/* Scan the ndlp's fchanno txq to get the iocb of fcp cmd */
339382527734SSukumar Swaminathan 	prev = NULL;
339482527734SSukumar Swaminathan 	iocbq = (IOCBQ *)nlp->nlp_tx[fchanno].q_first;
339582527734SSukumar Swaminathan 
339682527734SSukumar Swaminathan 	while (iocbq) {
339782527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
339882527734SSukumar Swaminathan 		/* Check if this iocb is fcp cmd */
339982527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
340082527734SSukumar Swaminathan 
340182527734SSukumar Swaminathan 		switch (iocb->ULPCOMMAND) {
340282527734SSukumar Swaminathan 		/* FCP commands */
340382527734SSukumar Swaminathan 		case CMD_FCP_ICMND_CR:
340482527734SSukumar Swaminathan 		case CMD_FCP_ICMND_CX:
340582527734SSukumar Swaminathan 		case CMD_FCP_IREAD_CR:
340682527734SSukumar Swaminathan 		case CMD_FCP_IREAD_CX:
340782527734SSukumar Swaminathan 		case CMD_FCP_IWRITE_CR:
340882527734SSukumar Swaminathan 		case CMD_FCP_IWRITE_CX:
340982527734SSukumar Swaminathan 		case CMD_FCP_ICMND64_CR:
341082527734SSukumar Swaminathan 		case CMD_FCP_ICMND64_CX:
341182527734SSukumar Swaminathan 		case CMD_FCP_IREAD64_CR:
341282527734SSukumar Swaminathan 		case CMD_FCP_IREAD64_CX:
341382527734SSukumar Swaminathan 		case CMD_FCP_IWRITE64_CR:
341482527734SSukumar Swaminathan 		case CMD_FCP_IWRITE64_CX:
341582527734SSukumar Swaminathan 			/* We found a fcp cmd */
341682527734SSukumar Swaminathan 			break;
341782527734SSukumar Swaminathan 		default:
341882527734SSukumar Swaminathan 			/* this is not fcp cmd continue */
341982527734SSukumar Swaminathan 			prev = iocbq;
342082527734SSukumar Swaminathan 			iocbq = next;
342182527734SSukumar Swaminathan 			continue;
342282527734SSukumar Swaminathan 		}
342382527734SSukumar Swaminathan 
342482527734SSukumar Swaminathan 		/* found a fcp cmd iocb in fchanno txq, now deque it */
342582527734SSukumar Swaminathan 		if (next == NULL) {
342682527734SSukumar Swaminathan 			/* This is the last iocbq */
342782527734SSukumar Swaminathan 			nlp->nlp_tx[fchanno].q_last =
342882527734SSukumar Swaminathan 			    (uint8_t *)prev;
342982527734SSukumar Swaminathan 		}
343082527734SSukumar Swaminathan 
343182527734SSukumar Swaminathan 		if (prev == NULL) {
343282527734SSukumar Swaminathan 			/* This is the first one then remove it from head */
343382527734SSukumar Swaminathan 			nlp->nlp_tx[fchanno].q_first =
343482527734SSukumar Swaminathan 			    (uint8_t *)next;
343582527734SSukumar Swaminathan 		} else {
343682527734SSukumar Swaminathan 			prev->next = next;
343782527734SSukumar Swaminathan 		}
343882527734SSukumar Swaminathan 
343982527734SSukumar Swaminathan 		iocbq->next = NULL;
344082527734SSukumar Swaminathan 		nlp->nlp_tx[fchanno].q_cnt--;
344182527734SSukumar Swaminathan 
344282527734SSukumar Swaminathan 		/* Add this iocb to our local toberemovedq */
344382527734SSukumar Swaminathan 		/* This way we donot hold the TX_CHANNEL lock too long */
344482527734SSukumar Swaminathan 
344582527734SSukumar Swaminathan 		if (tbm.q_first) {
344682527734SSukumar Swaminathan 			((IOCBQ *)tbm.q_last)->next = iocbq;
344782527734SSukumar Swaminathan 			tbm.q_last = (uint8_t *)iocbq;
344882527734SSukumar Swaminathan 			tbm.q_cnt++;
344982527734SSukumar Swaminathan 		} else {
345082527734SSukumar Swaminathan 			tbm.q_first = (uint8_t *)iocbq;
345182527734SSukumar Swaminathan 			tbm.q_last = (uint8_t *)iocbq;
345282527734SSukumar Swaminathan 			tbm.q_cnt = 1;
345382527734SSukumar Swaminathan 		}
345482527734SSukumar Swaminathan 
345582527734SSukumar Swaminathan 		iocbq = next;
345682527734SSukumar Swaminathan 
345782527734SSukumar Swaminathan 	}	/* While (iocbq) */
345882527734SSukumar Swaminathan 
345982527734SSukumar Swaminathan 	if ((tchanno == hba->channel_fcp) && (tbm.q_cnt != 0)) {
346082527734SSukumar Swaminathan 
346182527734SSukumar Swaminathan 		/* from_chan->nodeq.q_first must be non NULL */
346282527734SSukumar Swaminathan 		if (from_chan->nodeq.q_first) {
346382527734SSukumar Swaminathan 
346482527734SSukumar Swaminathan 			/* nodeq is not empty, now deal with the node itself */
346582527734SSukumar Swaminathan 			if ((nlp->nlp_tx[fchanno].q_first)) {
346682527734SSukumar Swaminathan 
346782527734SSukumar Swaminathan 				if (!nlp->nlp_base) {
346882527734SSukumar Swaminathan 					from_chan->nodeq.q_last =
346982527734SSukumar Swaminathan 					    (void *)nlp;
347082527734SSukumar Swaminathan 					from_chan->nodeq.q_first =
347182527734SSukumar Swaminathan 					    nlp->nlp_next[fchanno];
347282527734SSukumar Swaminathan 				}
347382527734SSukumar Swaminathan 
347482527734SSukumar Swaminathan 			} else {
347582527734SSukumar Swaminathan 				n_prev = (NODELIST *)from_chan->nodeq.q_first;
347682527734SSukumar Swaminathan 				count = from_chan->nodeq.q_cnt;
347782527734SSukumar Swaminathan 
347882527734SSukumar Swaminathan 				if (n_prev == nlp) {
347982527734SSukumar Swaminathan 
348082527734SSukumar Swaminathan 					/* If this is the only node on list */
348182527734SSukumar Swaminathan 					if (from_chan->nodeq.q_last ==
348282527734SSukumar Swaminathan 					    (void *)nlp) {
348382527734SSukumar Swaminathan 						from_chan->nodeq.q_last =
348482527734SSukumar Swaminathan 						    NULL;
348582527734SSukumar Swaminathan 						from_chan->nodeq.q_first =
348682527734SSukumar Swaminathan 						    NULL;
348782527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt = 0;
348882527734SSukumar Swaminathan 					} else {
348982527734SSukumar Swaminathan 						from_chan->nodeq.q_first =
349082527734SSukumar Swaminathan 						    nlp->nlp_next[fchanno];
349182527734SSukumar Swaminathan 						((NODELIST *)from_chan->
349282527734SSukumar Swaminathan 						    nodeq.q_last)->
349382527734SSukumar Swaminathan 						    nlp_next[fchanno] =
349482527734SSukumar Swaminathan 						    from_chan->nodeq.q_first;
349582527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt--;
349682527734SSukumar Swaminathan 					}
349782527734SSukumar Swaminathan 					/* Clear node */
349882527734SSukumar Swaminathan 					nlp->nlp_next[fchanno] = NULL;
349982527734SSukumar Swaminathan 				} else {
350082527734SSukumar Swaminathan 					count--;
350182527734SSukumar Swaminathan 					do {
350282527734SSukumar Swaminathan 						n_next =
350382527734SSukumar Swaminathan 						    n_prev->nlp_next[fchanno];
350482527734SSukumar Swaminathan 						if (n_next == nlp) {
350582527734SSukumar Swaminathan 							break;
350682527734SSukumar Swaminathan 						}
350782527734SSukumar Swaminathan 						n_prev = n_next;
350882527734SSukumar Swaminathan 					} while (count--);
350982527734SSukumar Swaminathan 
351082527734SSukumar Swaminathan 					if (count != 0) {
351182527734SSukumar Swaminathan 
351282527734SSukumar Swaminathan 						if (n_next ==
351382527734SSukumar Swaminathan 						    (NODELIST *)from_chan->
351482527734SSukumar Swaminathan 						    nodeq.q_last) {
351582527734SSukumar Swaminathan 							n_prev->
351682527734SSukumar Swaminathan 							    nlp_next[fchanno]
351782527734SSukumar Swaminathan 							    =
351882527734SSukumar Swaminathan 							    ((NODELIST *)
351982527734SSukumar Swaminathan 							    from_chan->
352082527734SSukumar Swaminathan 							    nodeq.q_last)->
352182527734SSukumar Swaminathan 							    nlp_next
352282527734SSukumar Swaminathan 							    [fchanno];
352382527734SSukumar Swaminathan 							from_chan->nodeq.q_last
352482527734SSukumar Swaminathan 							    = (uint8_t *)n_prev;
352582527734SSukumar Swaminathan 						} else {
352682527734SSukumar Swaminathan 
352782527734SSukumar Swaminathan 							n_prev->
352882527734SSukumar Swaminathan 							    nlp_next[fchanno]
352982527734SSukumar Swaminathan 							    =
353082527734SSukumar Swaminathan 							    n_next-> nlp_next
353182527734SSukumar Swaminathan 							    [fchanno];
353282527734SSukumar Swaminathan 						}
353382527734SSukumar Swaminathan 						from_chan->nodeq.q_cnt--;
353482527734SSukumar Swaminathan 						/* Clear node */
353582527734SSukumar Swaminathan 						nlp->nlp_next[fchanno] =
353682527734SSukumar Swaminathan 						    NULL;
353782527734SSukumar Swaminathan 					}
353882527734SSukumar Swaminathan 				}
353982527734SSukumar Swaminathan 			}
354082527734SSukumar Swaminathan 		}
354182527734SSukumar Swaminathan 	}
354282527734SSukumar Swaminathan 
354382527734SSukumar Swaminathan 	/* Now cleanup the iocb's */
354482527734SSukumar Swaminathan 	prev = NULL;
354582527734SSukumar Swaminathan 	iocbq = (IOCBQ *)tbm.q_first;
354682527734SSukumar Swaminathan 
354782527734SSukumar Swaminathan 	while (iocbq) {
354882527734SSukumar Swaminathan 
354982527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
355082527734SSukumar Swaminathan 
355182527734SSukumar Swaminathan 		/* Free the IoTag and the bmp */
355282527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
355382527734SSukumar Swaminathan 
355482527734SSukumar Swaminathan 		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
355582527734SSukumar Swaminathan 			sbp = iocbq->sbp;
355682527734SSukumar Swaminathan 			if (sbp) {
35578f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 1);
355882527734SSukumar Swaminathan 			}
355982527734SSukumar Swaminathan 		} else {
356082527734SSukumar Swaminathan 			sbp = emlxs_unregister_pkt((CHANNEL *)iocbq->channel,
356182527734SSukumar Swaminathan 			    iocb->ULPIOTAG, 0);
356282527734SSukumar Swaminathan 		}
356382527734SSukumar Swaminathan 
356482527734SSukumar Swaminathan 		if (sbp && (sbp != STALE_PACKET)) {
356582527734SSukumar Swaminathan 			mutex_enter(&sbp->mtx);
356682527734SSukumar Swaminathan 			sbp->pkt_flags |= PACKET_IN_FLUSH;
356782527734SSukumar Swaminathan 
356882527734SSukumar Swaminathan 			/*
356982527734SSukumar Swaminathan 			 * If the fpkt is already set, then we will leave it
357082527734SSukumar Swaminathan 			 * alone. This ensures that this pkt is only accounted
357182527734SSukumar Swaminathan 			 * for on one fpkt->flush_count
357282527734SSukumar Swaminathan 			 */
357382527734SSukumar Swaminathan 			if (!sbp->fpkt && fpkt) {
357482527734SSukumar Swaminathan 				mutex_enter(&fpkt->mtx);
357582527734SSukumar Swaminathan 				sbp->fpkt = fpkt;
357682527734SSukumar Swaminathan 				fpkt->flush_count++;
357782527734SSukumar Swaminathan 				mutex_exit(&fpkt->mtx);
357882527734SSukumar Swaminathan 			}
357982527734SSukumar Swaminathan 			mutex_exit(&sbp->mtx);
358082527734SSukumar Swaminathan 		}
358182527734SSukumar Swaminathan 		iocbq = next;
358282527734SSukumar Swaminathan 
358382527734SSukumar Swaminathan 	}	/* end of while */
358482527734SSukumar Swaminathan 
358582527734SSukumar Swaminathan 	iocbq = (IOCBQ *)tbm.q_first;
358682527734SSukumar Swaminathan 	while (iocbq) {
358782527734SSukumar Swaminathan 		/* Save the next iocbq for now */
358882527734SSukumar Swaminathan 		next = (IOCBQ *)iocbq->next;
358982527734SSukumar Swaminathan 
359082527734SSukumar Swaminathan 		/* Unlink this iocbq */
359182527734SSukumar Swaminathan 		iocbq->next = NULL;
359282527734SSukumar Swaminathan 
359382527734SSukumar Swaminathan 		/* Get the pkt */
359482527734SSukumar Swaminathan 		sbp = (emlxs_buf_t *)iocbq->sbp;
359582527734SSukumar Swaminathan 
359682527734SSukumar Swaminathan 		if (sbp) {
359782527734SSukumar Swaminathan 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg,
359882527734SSukumar Swaminathan 			"tx: sbp=%p node=%p", sbp, sbp->node);
359982527734SSukumar Swaminathan 
360082527734SSukumar Swaminathan 			if (hba->state >= FC_LINK_UP) {
360182527734SSukumar Swaminathan 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
360282527734SSukumar Swaminathan 				    IOERR_ABORT_REQUESTED, 1);
360382527734SSukumar Swaminathan 			} else {
360482527734SSukumar Swaminathan 				emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT,
360582527734SSukumar Swaminathan 				    IOERR_LINK_DOWN, 1);
360682527734SSukumar Swaminathan 			}
360782527734SSukumar Swaminathan 
360882527734SSukumar Swaminathan 		}
360982527734SSukumar Swaminathan 		/* Free the iocb and its associated buffers */
361082527734SSukumar Swaminathan 		else {
361182527734SSukumar Swaminathan 			icmd = &iocbq->iocb;
361282527734SSukumar Swaminathan 
361382527734SSukumar Swaminathan 			/* SLI3 */
361482527734SSukumar Swaminathan 			if (icmd->ULPCOMMAND == CMD_QUE_RING_BUF64_CN ||
361582527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_BUF_CN ||
361682527734SSukumar Swaminathan 			    icmd->ULPCOMMAND == CMD_QUE_RING_LIST64_CN) {
361782527734SSukumar Swaminathan 				if ((hba->flag &
361882527734SSukumar Swaminathan 				    (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) {
361982527734SSukumar Swaminathan 					/* HBA is detaching or offlining */
362082527734SSukumar Swaminathan 					if (icmd->ULPCOMMAND !=
362182527734SSukumar Swaminathan 					    CMD_QUE_RING_LIST64_CN) {
3622a9800bebSGarrett D'Amore 						void *tmp;
362382527734SSukumar Swaminathan 						RING *rp;
362482527734SSukumar Swaminathan 						int ch;
362582527734SSukumar Swaminathan 
362682527734SSukumar Swaminathan 						ch = from_chan->channelno;
362782527734SSukumar Swaminathan 						rp = &hba->sli.sli3.ring[ch];
362882527734SSukumar Swaminathan 
362982527734SSukumar Swaminathan 						for (i = 0;
363082527734SSukumar Swaminathan 						    i < icmd->ULPBDECOUNT;
363182527734SSukumar Swaminathan 						    i++) {
363282527734SSukumar Swaminathan 							mp = EMLXS_GET_VADDR(
363382527734SSukumar Swaminathan 							    hba, rp, icmd);
363482527734SSukumar Swaminathan 
3635a9800bebSGarrett D'Amore 							tmp = (void *)mp;
363682527734SSukumar Swaminathan 							if (mp) {
3637a9800bebSGarrett D'Amore 							emlxs_mem_put(
363882527734SSukumar Swaminathan 							    hba,
363982527734SSukumar Swaminathan 							    MEM_BUF,
364082527734SSukumar Swaminathan 							    tmp);
364182527734SSukumar Swaminathan 							}
364282527734SSukumar Swaminathan 						}
364382527734SSukumar Swaminathan 
364482527734SSukumar Swaminathan 					}
364582527734SSukumar Swaminathan 
3646a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_IOCB,
3647a9800bebSGarrett D'Amore 					    (void *)iocbq);
364882527734SSukumar Swaminathan 				} else {
364982527734SSukumar Swaminathan 					/* repost the unsolicited buffer */
365082527734SSukumar Swaminathan 					EMLXS_SLI_ISSUE_IOCB_CMD(hba,
365182527734SSukumar Swaminathan 					    from_chan, iocbq);
365282527734SSukumar Swaminathan 				}
365382527734SSukumar Swaminathan 			}
365482527734SSukumar Swaminathan 		}
365582527734SSukumar Swaminathan 
365682527734SSukumar Swaminathan 		iocbq = next;
365782527734SSukumar Swaminathan 
365882527734SSukumar Swaminathan 	}	/* end of while */
365982527734SSukumar Swaminathan 
366082527734SSukumar Swaminathan 	/* Now flush the chipq if any */
366182527734SSukumar Swaminathan 	if (!(nlp->nlp_flag[fchanno] & NLP_CLOSED)) {
366282527734SSukumar Swaminathan 
366382527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
366482527734SSukumar Swaminathan 
366582527734SSukumar Swaminathan 		(void) emlxs_chipq_node_flush(port, from_chan, nlp, 0);
366682527734SSukumar Swaminathan 
366782527734SSukumar Swaminathan 		mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
366882527734SSukumar Swaminathan 	}
366982527734SSukumar Swaminathan 
367082527734SSukumar Swaminathan 	if (lock) {
367182527734SSukumar Swaminathan 		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
367282527734SSukumar Swaminathan 	}
367382527734SSukumar Swaminathan 
367482527734SSukumar Swaminathan 	return;
367582527734SSukumar Swaminathan 
367682527734SSukumar Swaminathan } /* emlxs_tx_move */
3677fcf3ce44SJohn Forte 
3678fcf3ce44SJohn Forte 
3679fcf3ce44SJohn Forte extern uint32_t
emlxs_chipq_node_flush(emlxs_port_t * port,CHANNEL * chan,NODELIST * ndlp,emlxs_buf_t * fpkt)368082527734SSukumar Swaminathan emlxs_chipq_node_flush(emlxs_port_t *port, CHANNEL *chan, NODELIST *ndlp,
3681291a2b48SSukumar Swaminathan     emlxs_buf_t *fpkt)
3682fcf3ce44SJohn Forte {
3683fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3684fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3685fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3686fcf3ce44SJohn Forte 	IOCBQ *next;
3687fcf3ce44SJohn Forte 	Q abort;
368882527734SSukumar Swaminathan 	CHANNEL *cp;
368982527734SSukumar Swaminathan 	uint32_t channelno;
369082527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
3691fcf3ce44SJohn Forte 	uint32_t iotag;
3692fcf3ce44SJohn Forte 
3693fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
3694fcf3ce44SJohn Forte 	bzero((void *)flag, sizeof (flag));
3695fcf3ce44SJohn Forte 
369682527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
369782527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3698fcf3ce44SJohn Forte 
369982527734SSukumar Swaminathan 		if (chan && cp != chan) {
3700fcf3ce44SJohn Forte 			continue;
3701fcf3ce44SJohn Forte 		}
3702291a2b48SSukumar Swaminathan 
370382527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3704fcf3ce44SJohn Forte 
370582527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
370682527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3707fcf3ce44SJohn Forte 
3708fcf3ce44SJohn Forte 			if (sbp && (sbp != STALE_PACKET) &&
3709fcf3ce44SJohn Forte 			    (sbp->pkt_flags & PACKET_IN_CHIPQ) &&
3710fcf3ce44SJohn Forte 			    (sbp->node == ndlp) &&
371182527734SSukumar Swaminathan 			    (sbp->channel == cp) &&
3712fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
3713291a2b48SSukumar Swaminathan 				emlxs_sbp_abort_add(port, sbp, &abort, flag,
3714291a2b48SSukumar Swaminathan 				    fpkt);
3715fcf3ce44SJohn Forte 			}
3716291a2b48SSukumar Swaminathan 
3717fcf3ce44SJohn Forte 		}
371882527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3719fcf3ce44SJohn Forte 
3720fcf3ce44SJohn Forte 	}	/* for */
3721fcf3ce44SJohn Forte 
3722fcf3ce44SJohn Forte 	/* Now put the iocb's on the tx queue */
3723fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
3724fcf3ce44SJohn Forte 	while (iocbq) {
3725fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
3726fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
3727fcf3ce44SJohn Forte 
3728fcf3ce44SJohn Forte 		/* Unlink this iocbq */
3729fcf3ce44SJohn Forte 		iocbq->next = NULL;
3730fcf3ce44SJohn Forte 
3731fcf3ce44SJohn Forte 		/* Send this iocbq */
3732fcf3ce44SJohn Forte 		emlxs_tx_put(iocbq, 1);
3733fcf3ce44SJohn Forte 
3734fcf3ce44SJohn Forte 		iocbq = next;
3735fcf3ce44SJohn Forte 	}
3736fcf3ce44SJohn Forte 
373782527734SSukumar Swaminathan 	/* Now trigger channel service */
373882527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
373982527734SSukumar Swaminathan 		if (!flag[channelno]) {
3740fcf3ce44SJohn Forte 			continue;
3741fcf3ce44SJohn Forte 		}
3742291a2b48SSukumar Swaminathan 
374382527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
3744fcf3ce44SJohn Forte 	}
3745fcf3ce44SJohn Forte 
3746fcf3ce44SJohn Forte 	return (abort.q_cnt);
3747fcf3ce44SJohn Forte 
374882527734SSukumar Swaminathan } /* emlxs_chipq_node_flush() */
3749fcf3ce44SJohn Forte 
3750fcf3ce44SJohn Forte 
3751fcf3ce44SJohn Forte /* Flush all IO's left on all iotag lists */
375282527734SSukumar Swaminathan extern uint32_t
emlxs_iotag_flush(emlxs_hba_t * hba)3753fcf3ce44SJohn Forte emlxs_iotag_flush(emlxs_hba_t *hba)
3754fcf3ce44SJohn Forte {
3755fcf3ce44SJohn Forte 	emlxs_port_t *port = &PPORT;
3756fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3757fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3758fcf3ce44SJohn Forte 	IOCB *iocb;
3759fcf3ce44SJohn Forte 	Q abort;
376082527734SSukumar Swaminathan 	CHANNEL *cp;
376182527734SSukumar Swaminathan 	uint32_t channelno;
3762fcf3ce44SJohn Forte 	uint32_t iotag;
3763fcf3ce44SJohn Forte 	uint32_t count;
3764fcf3ce44SJohn Forte 
3765fcf3ce44SJohn Forte 	count = 0;
376682527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
376782527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3768fcf3ce44SJohn Forte 
3769fcf3ce44SJohn Forte 		bzero((void *)&abort, sizeof (Q));
3770fcf3ce44SJohn Forte 
377182527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3772fcf3ce44SJohn Forte 
377382527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
377482527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3775fcf3ce44SJohn Forte 
377682527734SSukumar Swaminathan 			/* Check if the slot is empty */
3777fcf3ce44SJohn Forte 			if (!sbp || (sbp == STALE_PACKET)) {
3778fcf3ce44SJohn Forte 				continue;
3779fcf3ce44SJohn Forte 			}
3780291a2b48SSukumar Swaminathan 
378182527734SSukumar Swaminathan 			/* We are building an abort list per channel */
378282527734SSukumar Swaminathan 			if (sbp->channel != cp) {
378382527734SSukumar Swaminathan 				continue;
378482527734SSukumar Swaminathan 			}
3785fcf3ce44SJohn Forte 
3786a9800bebSGarrett D'Amore 			hba->fc_table[iotag] = STALE_PACKET;
3787a9800bebSGarrett D'Amore 			hba->io_count--;
3788a9800bebSGarrett D'Amore 
3789a9800bebSGarrett D'Amore 			/* Check if IO is valid */
3790a9800bebSGarrett D'Amore 			if (!(sbp->pkt_flags & PACKET_VALID) ||
3791a9800bebSGarrett D'Amore 			    (sbp->pkt_flags & (PACKET_ULP_OWNED|
3792a9800bebSGarrett D'Amore 			    PACKET_COMPLETED|PACKET_IN_COMPLETION))) {
3793a9800bebSGarrett D'Amore 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
37948f23e9faSHans Rosenfeld 				    "iotag_flush: Invalid IO found. iotag=%d",
3795a9800bebSGarrett D'Amore 				    iotag);
3796a9800bebSGarrett D'Amore 
3797a9800bebSGarrett D'Amore 				continue;
3798a9800bebSGarrett D'Amore 			}
3799a9800bebSGarrett D'Amore 
3800a9800bebSGarrett D'Amore 			sbp->iotag = 0;
3801a9800bebSGarrett D'Amore 
3802fcf3ce44SJohn Forte 			/* Set IOCB status */
3803fcf3ce44SJohn Forte 			iocbq = &sbp->iocbq;
3804fcf3ce44SJohn Forte 			iocb = &iocbq->iocb;
3805fcf3ce44SJohn Forte 
380682527734SSukumar Swaminathan 			iocb->ULPSTATUS = IOSTAT_LOCAL_REJECT;
3807fcf3ce44SJohn Forte 			iocb->un.grsp.perr.statLocalError = IOERR_LINK_DOWN;
380882527734SSukumar Swaminathan 			iocb->ULPLE = 1;
3809fcf3ce44SJohn Forte 			iocbq->next = NULL;
3810fcf3ce44SJohn Forte 
381182527734SSukumar Swaminathan 			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3812a9800bebSGarrett D'Amore 				if (sbp->xrip) {
3813a9800bebSGarrett D'Amore 					EMLXS_MSGF(EMLXS_CONTEXT,
3814a9800bebSGarrett D'Amore 					    &emlxs_sli_debug_msg,
38158f23e9faSHans Rosenfeld 					    "iotag_flush: iotag=%d sbp=%p "
3816a9800bebSGarrett D'Amore 					    "xrip=%p state=%x flag=%x",
3817a9800bebSGarrett D'Amore 					    iotag, sbp, sbp->xrip,
3818a9800bebSGarrett D'Amore 					    sbp->xrip->state, sbp->xrip->flag);
3819a9800bebSGarrett D'Amore 				} else {
3820a9800bebSGarrett D'Amore 					EMLXS_MSGF(EMLXS_CONTEXT,
3821a9800bebSGarrett D'Amore 					    &emlxs_sli_debug_msg,
38228f23e9faSHans Rosenfeld 					    "iotag_flush: iotag=%d sbp=%p "
38238f23e9faSHans Rosenfeld 					    "xrip=NULL", iotag, sbp);
3824a9800bebSGarrett D'Amore 				}
3825291a2b48SSukumar Swaminathan 
38268f23e9faSHans Rosenfeld 				emlxs_sli4_free_xri(port, sbp, sbp->xrip, 0);
3827a9800bebSGarrett D'Amore 			} else {
382882527734SSukumar Swaminathan 				/* Clean up the sbp */
382982527734SSukumar Swaminathan 				mutex_enter(&sbp->mtx);
383082527734SSukumar Swaminathan 
383182527734SSukumar Swaminathan 				if (sbp->pkt_flags & PACKET_IN_TXQ) {
383282527734SSukumar Swaminathan 					sbp->pkt_flags &= ~PACKET_IN_TXQ;
383382527734SSukumar Swaminathan 					hba->channel_tx_count --;
383482527734SSukumar Swaminathan 				}
383582527734SSukumar Swaminathan 
383682527734SSukumar Swaminathan 				if (sbp->pkt_flags & PACKET_IN_CHIPQ) {
383782527734SSukumar Swaminathan 					sbp->pkt_flags &= ~PACKET_IN_CHIPQ;
383882527734SSukumar Swaminathan 				}
3839291a2b48SSukumar Swaminathan 
384082527734SSukumar Swaminathan 				if (sbp->bmp) {
3841a9800bebSGarrett D'Amore 					emlxs_mem_put(hba, MEM_BPL,
3842a9800bebSGarrett D'Amore 					    (void *)sbp->bmp);
384382527734SSukumar Swaminathan 					sbp->bmp = 0;
384482527734SSukumar Swaminathan 				}
384582527734SSukumar Swaminathan 
384682527734SSukumar Swaminathan 				mutex_exit(&sbp->mtx);
3847fcf3ce44SJohn Forte 			}
3848291a2b48SSukumar Swaminathan 
3849fcf3ce44SJohn Forte 			/* At this point all nodes are assumed destroyed */
385082527734SSukumar Swaminathan 			mutex_enter(&sbp->mtx);
3851fcf3ce44SJohn Forte 			sbp->node = 0;
3852fcf3ce44SJohn Forte 			mutex_exit(&sbp->mtx);
3853fcf3ce44SJohn Forte 
3854fcf3ce44SJohn Forte 			/* Add this iocb to our local abort Q */
3855fcf3ce44SJohn Forte 			if (abort.q_first) {
3856291a2b48SSukumar Swaminathan 				((IOCBQ *)abort.q_last)->next = iocbq;
3857fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
3858fcf3ce44SJohn Forte 				abort.q_cnt++;
3859fcf3ce44SJohn Forte 			} else {
3860fcf3ce44SJohn Forte 				abort.q_first = (uint8_t *)iocbq;
3861fcf3ce44SJohn Forte 				abort.q_last = (uint8_t *)iocbq;
3862fcf3ce44SJohn Forte 				abort.q_cnt = 1;
3863fcf3ce44SJohn Forte 			}
3864fcf3ce44SJohn Forte 		}
3865fcf3ce44SJohn Forte 
386682527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3867fcf3ce44SJohn Forte 
3868fcf3ce44SJohn Forte 		/* Trigger deferred completion */
3869fcf3ce44SJohn Forte 		if (abort.q_first) {
387082527734SSukumar Swaminathan 			mutex_enter(&cp->rsp_lock);
387182527734SSukumar Swaminathan 			if (cp->rsp_head == NULL) {
387282527734SSukumar Swaminathan 				cp->rsp_head = (IOCBQ *)abort.q_first;
387382527734SSukumar Swaminathan 				cp->rsp_tail = (IOCBQ *)abort.q_last;
3874fcf3ce44SJohn Forte 			} else {
387582527734SSukumar Swaminathan 				cp->rsp_tail->next = (IOCBQ *)abort.q_first;
387682527734SSukumar Swaminathan 				cp->rsp_tail = (IOCBQ *)abort.q_last;
3877fcf3ce44SJohn Forte 			}
387882527734SSukumar Swaminathan 			mutex_exit(&cp->rsp_lock);
3879fcf3ce44SJohn Forte 
388082527734SSukumar Swaminathan 			emlxs_thread_trigger2(&cp->intr_thread,
388182527734SSukumar Swaminathan 			    emlxs_proc_channel, cp);
3882fcf3ce44SJohn Forte 
3883a9800bebSGarrett D'Amore 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_debug_msg,
3884a9800bebSGarrett D'Amore 			    "iotag_flush: channel=%d count=%d",
388582527734SSukumar Swaminathan 			    channelno, abort.q_cnt);
3886fcf3ce44SJohn Forte 
3887fcf3ce44SJohn Forte 			count += abort.q_cnt;
3888fcf3ce44SJohn Forte 		}
3889fcf3ce44SJohn Forte 	}
3890fcf3ce44SJohn Forte 
3891fcf3ce44SJohn Forte 	return (count);
3892fcf3ce44SJohn Forte 
389382527734SSukumar Swaminathan } /* emlxs_iotag_flush() */
3894fcf3ce44SJohn Forte 
3895fcf3ce44SJohn Forte 
3896fcf3ce44SJohn Forte 
389782527734SSukumar Swaminathan /* Checks for IO's on all or a given channel for a given node */
3898fcf3ce44SJohn Forte extern uint32_t
emlxs_chipq_node_check(emlxs_port_t * port,CHANNEL * chan,NODELIST * ndlp)389982527734SSukumar Swaminathan emlxs_chipq_node_check(emlxs_port_t *port, CHANNEL *chan, NODELIST *ndlp)
3900fcf3ce44SJohn Forte {
3901fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3902fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
390382527734SSukumar Swaminathan 	CHANNEL *cp;
390482527734SSukumar Swaminathan 	uint32_t channelno;
3905fcf3ce44SJohn Forte 	uint32_t count;
3906fcf3ce44SJohn Forte 	uint32_t iotag;
3907fcf3ce44SJohn Forte 
3908fcf3ce44SJohn Forte 	count = 0;
3909fcf3ce44SJohn Forte 
391082527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
391182527734SSukumar Swaminathan 		cp = &hba->chan[channelno];
3912fcf3ce44SJohn Forte 
391382527734SSukumar Swaminathan 		if (chan && cp != chan) {
3914fcf3ce44SJohn Forte 			continue;
3915fcf3ce44SJohn Forte 		}
3916291a2b48SSukumar Swaminathan 
391782527734SSukumar Swaminathan 		mutex_enter(&EMLXS_FCTAB_LOCK);
3918fcf3ce44SJohn Forte 
391982527734SSukumar Swaminathan 		for (iotag = 1; iotag < hba->max_iotag; iotag++) {
392082527734SSukumar Swaminathan 			sbp = hba->fc_table[iotag];
3921fcf3ce44SJohn Forte 
3922fcf3ce44SJohn Forte 			if (sbp && (sbp != STALE_PACKET) &&
3923fcf3ce44SJohn Forte 			    (sbp->pkt_flags & PACKET_IN_CHIPQ) &&
3924fcf3ce44SJohn Forte 			    (sbp->node == ndlp) &&
392582527734SSukumar Swaminathan 			    (sbp->channel == cp) &&
3926fcf3ce44SJohn Forte 			    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
3927fcf3ce44SJohn Forte 				count++;
3928fcf3ce44SJohn Forte 			}
3929291a2b48SSukumar Swaminathan 
3930fcf3ce44SJohn Forte 		}
393182527734SSukumar Swaminathan 		mutex_exit(&EMLXS_FCTAB_LOCK);
3932fcf3ce44SJohn Forte 
3933fcf3ce44SJohn Forte 	}	/* for */
3934fcf3ce44SJohn Forte 
3935fcf3ce44SJohn Forte 	return (count);
3936fcf3ce44SJohn Forte 
393782527734SSukumar Swaminathan } /* emlxs_chipq_node_check() */
3938fcf3ce44SJohn Forte 
3939fcf3ce44SJohn Forte 
3940fcf3ce44SJohn Forte 
394182527734SSukumar Swaminathan /* Flush all IO's for a given node's lun (on any channel) */
3942fcf3ce44SJohn Forte extern uint32_t
emlxs_chipq_lun_flush(emlxs_port_t * port,NODELIST * ndlp,uint32_t lun,emlxs_buf_t * fpkt)394382527734SSukumar Swaminathan emlxs_chipq_lun_flush(emlxs_port_t *port, NODELIST *ndlp,
394482527734SSukumar Swaminathan     uint32_t lun, emlxs_buf_t *fpkt)
3945fcf3ce44SJohn Forte {
3946fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
3947fcf3ce44SJohn Forte 	emlxs_buf_t *sbp;
3948fcf3ce44SJohn Forte 	IOCBQ *iocbq;
3949fcf3ce44SJohn Forte 	IOCBQ *next;
3950fcf3ce44SJohn Forte 	Q abort;
3951fcf3ce44SJohn Forte 	uint32_t iotag;
395282527734SSukumar Swaminathan 	uint8_t flag[MAX_CHANNEL];
395382527734SSukumar Swaminathan 	uint32_t channelno;
3954fcf3ce44SJohn Forte 
3955a9800bebSGarrett D'Amore 	if (lun == EMLXS_LUN_NONE) {
3956a9800bebSGarrett D'Amore 		return (0);
3957a9800bebSGarrett D'Amore 	}
3958a9800bebSGarrett D'Amore 
3959fcf3ce44SJohn Forte 	bzero((void *)flag, sizeof (flag));
3960fcf3ce44SJohn Forte 	bzero((void *)&abort, sizeof (Q));
3961fcf3ce44SJohn Forte 
396282527734SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
396382527734SSukumar Swaminathan 	for (iotag = 1; iotag < hba->max_iotag; iotag++) {
396482527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
3965fcf3ce44SJohn Forte 
3966fcf3ce44SJohn Forte 		if (sbp && (sbp != STALE_PACKET) &&
3967fcf3ce44SJohn Forte 		    sbp->pkt_flags & PACKET_IN_CHIPQ &&
3968fcf3ce44SJohn Forte 		    sbp->node == ndlp &&
3969fcf3ce44SJohn Forte 		    sbp->lun == lun &&
3970fcf3ce44SJohn Forte 		    !(sbp->pkt_flags & PACKET_XRI_CLOSED)) {
397182527734SSukumar Swaminathan 			emlxs_sbp_abort_add(port, sbp,
397282527734SSukumar Swaminathan 			    &abort, flag, fpkt);
3973fcf3ce44SJohn Forte 		}
3974fcf3ce44SJohn Forte 	}
397582527734SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
3976fcf3ce44SJohn Forte 
3977fcf3ce44SJohn Forte 	/* Now put the iocb's on the tx queue */
3978fcf3ce44SJohn Forte 	iocbq = (IOCBQ *)abort.q_first;
3979fcf3ce44SJohn Forte 	while (iocbq) {
3980fcf3ce44SJohn Forte 		/* Save the next iocbq for now */
3981fcf3ce44SJohn Forte 		next = (IOCBQ *)iocbq->next;
3982fcf3ce44SJohn Forte 
3983fcf3ce44SJohn Forte 		/* Unlink this iocbq */
3984fcf3ce44SJohn Forte 		iocbq->next = NULL;
3985fcf3ce44SJohn Forte 
3986fcf3ce44SJohn Forte 		/* Send this iocbq */
3987fcf3ce44SJohn Forte 		emlxs_tx_put(iocbq, 1);
3988fcf3ce44SJohn Forte 
3989fcf3ce44SJohn Forte 		iocbq = next;
3990fcf3ce44SJohn Forte 	}
3991fcf3ce44SJohn Forte 
399282527734SSukumar Swaminathan 	/* Now trigger channel service */
399382527734SSukumar Swaminathan 	for (channelno = 0; channelno < hba->chan_count; channelno++) {
399482527734SSukumar Swaminathan 		if (!flag[channelno]) {
399582527734SSukumar Swaminathan 			continue;
399682527734SSukumar Swaminathan 		}
399782527734SSukumar Swaminathan 
399882527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, &hba->chan[channelno], 0);
3999fcf3ce44SJohn Forte 	}
4000291a2b48SSukumar Swaminathan 
4001fcf3ce44SJohn Forte 	return (abort.q_cnt);
4002fcf3ce44SJohn Forte 
400382527734SSukumar Swaminathan } /* emlxs_chipq_lun_flush() */
4004fcf3ce44SJohn Forte 
4005fcf3ce44SJohn Forte 
4006fcf3ce44SJohn Forte 
4007fcf3ce44SJohn Forte /*
4008fcf3ce44SJohn Forte  * Issue an ABORT_XRI_CN iocb command to abort an FCP command already issued.
4009fe199829SSukumar Swaminathan  * This must be called while holding the EMLXS_FCTAB_LOCK
4010fcf3ce44SJohn Forte  */
4011fcf3ce44SJohn Forte extern IOCBQ *
emlxs_create_abort_xri_cn(emlxs_port_t * port,NODELIST * ndlp,uint16_t iotag,CHANNEL * cp,uint8_t class,int32_t flag)4012291a2b48SSukumar Swaminathan emlxs_create_abort_xri_cn(emlxs_port_t *port, NODELIST *ndlp,
401382527734SSukumar Swaminathan     uint16_t iotag, CHANNEL *cp, uint8_t class, int32_t flag)
4014fcf3ce44SJohn Forte {
4015fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4016fcf3ce44SJohn Forte 	IOCBQ *iocbq;
4017fcf3ce44SJohn Forte 	IOCB *iocb;
401882527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
401982527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
4020fcf3ce44SJohn Forte 	uint16_t abort_iotag;
4021fcf3ce44SJohn Forte 
40228f23e9faSHans Rosenfeld 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
4023fcf3ce44SJohn Forte 		return (NULL);
4024fcf3ce44SJohn Forte 	}
4025291a2b48SSukumar Swaminathan 
402682527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
4027fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
4028fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
4029fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
4030fcf3ce44SJohn Forte 
4031fcf3ce44SJohn Forte 	/*
4032fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
4033fcf3ce44SJohn Forte 	 */
403482527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
403582527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
4036fcf3ce44SJohn Forte 	}
403782527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
4038291a2b48SSukumar Swaminathan 
4039fcf3ce44SJohn Forte 
404082527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
404182527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
404282527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
4043fcf3ce44SJohn Forte 
404482527734SSukumar Swaminathan 		/* Try to issue abort by XRI if possible */
4045a9800bebSGarrett D'Amore 		if (sbp == NULL || sbp == STALE_PACKET || sbp->xrip == NULL) {
404682527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_REQ_TAG;
404782527734SSukumar Swaminathan 			wqe->AbortTag = iotag;
404882527734SSukumar Swaminathan 		} else {
404982527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_XRI_TAG;
4050a9800bebSGarrett D'Amore 			wqe->AbortTag = sbp->xrip->XRI;
405182527734SSukumar Swaminathan 		}
405282527734SSukumar Swaminathan 		wqe->un.Abort.IA = 0;
405382527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
405482527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
405582527734SSukumar Swaminathan 		wqe->Class = CLASS3;
40568f23e9faSHans Rosenfeld 		wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
405782527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
405882527734SSukumar Swaminathan 	} else {
405982527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
406082527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
406182527734SSukumar Swaminathan 		iocb->un.acxri.abortType = flag;
406282527734SSukumar Swaminathan 		iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi;
406382527734SSukumar Swaminathan 		iocb->un.acxri.abortIoTag = iotag;
406482527734SSukumar Swaminathan 		iocb->ULPLE = 1;
406582527734SSukumar Swaminathan 		iocb->ULPCLASS = class;
406682527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_ABORT_XRI_CN;
406782527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
406882527734SSukumar Swaminathan 	}
4069fcf3ce44SJohn Forte 
4070fcf3ce44SJohn Forte 	return (iocbq);
4071fcf3ce44SJohn Forte 
407282527734SSukumar Swaminathan } /* emlxs_create_abort_xri_cn() */
4073fcf3ce44SJohn Forte 
4074fcf3ce44SJohn Forte 
4075fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4076fcf3ce44SJohn Forte extern IOCBQ *
emlxs_create_abort_xri_cx(emlxs_port_t * port,NODELIST * ndlp,uint16_t xid,CHANNEL * cp,uint8_t class,int32_t flag)4077fcf3ce44SJohn Forte emlxs_create_abort_xri_cx(emlxs_port_t *port, NODELIST *ndlp, uint16_t xid,
407882527734SSukumar Swaminathan     CHANNEL *cp, uint8_t class, int32_t flag)
4079fcf3ce44SJohn Forte {
4080fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4081fcf3ce44SJohn Forte 	IOCBQ *iocbq;
4082fcf3ce44SJohn Forte 	IOCB *iocb;
408382527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
4084fcf3ce44SJohn Forte 	uint16_t abort_iotag;
4085fcf3ce44SJohn Forte 
40868f23e9faSHans Rosenfeld 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
4087fcf3ce44SJohn Forte 		return (NULL);
4088fcf3ce44SJohn Forte 	}
4089291a2b48SSukumar Swaminathan 
409082527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
4091fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
4092fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
4093fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
4094fcf3ce44SJohn Forte 
4095fcf3ce44SJohn Forte 	/*
4096fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
4097fcf3ce44SJohn Forte 	 */
409882527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
409982527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
410082527734SSukumar Swaminathan 	}
410182527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
410282527734SSukumar Swaminathan 
410382527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
410482527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
410582527734SSukumar Swaminathan 		wqe->un.Abort.Criteria = ABORT_XRI_TAG;
410682527734SSukumar Swaminathan 		wqe->un.Abort.IA = 0;
410782527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
410882527734SSukumar Swaminathan 		wqe->AbortTag = xid;
410982527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
411082527734SSukumar Swaminathan 		wqe->Class = CLASS3;
41118f23e9faSHans Rosenfeld 		wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
411282527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
411382527734SSukumar Swaminathan 	} else {
411482527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
411582527734SSukumar Swaminathan 		iocb->ULPCONTEXT = xid;
411682527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
411782527734SSukumar Swaminathan 		iocb->un.acxri.abortType = flag;
411882527734SSukumar Swaminathan 		iocb->ULPLE = 1;
411982527734SSukumar Swaminathan 		iocb->ULPCLASS = class;
412082527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_ABORT_XRI_CX;
412182527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
4122fcf3ce44SJohn Forte 	}
4123291a2b48SSukumar Swaminathan 
4124fcf3ce44SJohn Forte 	return (iocbq);
4125fcf3ce44SJohn Forte 
412682527734SSukumar Swaminathan } /* emlxs_create_abort_xri_cx() */
4127fcf3ce44SJohn Forte 
4128fcf3ce44SJohn Forte 
4129fcf3ce44SJohn Forte 
4130fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4131fcf3ce44SJohn Forte extern IOCBQ *
emlxs_create_close_xri_cn(emlxs_port_t * port,NODELIST * ndlp,uint16_t iotag,CHANNEL * cp)4132fcf3ce44SJohn Forte emlxs_create_close_xri_cn(emlxs_port_t *port, NODELIST *ndlp,
413382527734SSukumar Swaminathan     uint16_t iotag, CHANNEL *cp)
4134fcf3ce44SJohn Forte {
4135fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4136fcf3ce44SJohn Forte 	IOCBQ *iocbq;
4137fcf3ce44SJohn Forte 	IOCB *iocb;
413882527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
413982527734SSukumar Swaminathan 	emlxs_buf_t *sbp;
4140fcf3ce44SJohn Forte 	uint16_t abort_iotag;
4141fcf3ce44SJohn Forte 
41428f23e9faSHans Rosenfeld 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
4143fcf3ce44SJohn Forte 		return (NULL);
4144fcf3ce44SJohn Forte 	}
4145291a2b48SSukumar Swaminathan 
414682527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
4147fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
4148fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
4149fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
4150fcf3ce44SJohn Forte 
4151fcf3ce44SJohn Forte 	/*
4152fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
4153fcf3ce44SJohn Forte 	 */
415482527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
415582527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
4156fcf3ce44SJohn Forte 	}
415782527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
4158291a2b48SSukumar Swaminathan 
415982527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
416082527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
416182527734SSukumar Swaminathan 		sbp = hba->fc_table[iotag];
4162fcf3ce44SJohn Forte 
416382527734SSukumar Swaminathan 		/* Try to issue close by XRI if possible */
4164a9800bebSGarrett D'Amore 		if (sbp == NULL || sbp == STALE_PACKET || sbp->xrip == NULL) {
416582527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_REQ_TAG;
416682527734SSukumar Swaminathan 			wqe->AbortTag = iotag;
416782527734SSukumar Swaminathan 		} else {
416882527734SSukumar Swaminathan 			wqe->un.Abort.Criteria = ABORT_XRI_TAG;
4169a9800bebSGarrett D'Amore 			wqe->AbortTag = sbp->xrip->XRI;
417082527734SSukumar Swaminathan 		}
417182527734SSukumar Swaminathan 		wqe->un.Abort.IA = 1;
417282527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
417382527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
417482527734SSukumar Swaminathan 		wqe->Class = CLASS3;
41758f23e9faSHans Rosenfeld 		wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
417682527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
417782527734SSukumar Swaminathan 	} else {
417882527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
417982527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
418082527734SSukumar Swaminathan 		iocb->un.acxri.abortType = 0;
418182527734SSukumar Swaminathan 		iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi;
418282527734SSukumar Swaminathan 		iocb->un.acxri.abortIoTag = iotag;
418382527734SSukumar Swaminathan 		iocb->ULPLE = 1;
418482527734SSukumar Swaminathan 		iocb->ULPCLASS = 0;
418582527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_CLOSE_XRI_CN;
418682527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
418782527734SSukumar Swaminathan 	}
4188fcf3ce44SJohn Forte 
4189fcf3ce44SJohn Forte 	return (iocbq);
4190fcf3ce44SJohn Forte 
419182527734SSukumar Swaminathan } /* emlxs_create_close_xri_cn() */
4192fcf3ce44SJohn Forte 
4193fcf3ce44SJohn Forte 
4194fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4195fcf3ce44SJohn Forte extern IOCBQ *
emlxs_create_close_xri_cx(emlxs_port_t * port,NODELIST * ndlp,uint16_t xid,CHANNEL * cp)4196291a2b48SSukumar Swaminathan emlxs_create_close_xri_cx(emlxs_port_t *port, NODELIST *ndlp, uint16_t xid,
419782527734SSukumar Swaminathan     CHANNEL *cp)
4198fcf3ce44SJohn Forte {
4199fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4200fcf3ce44SJohn Forte 	IOCBQ *iocbq;
4201fcf3ce44SJohn Forte 	IOCB *iocb;
420282527734SSukumar Swaminathan 	emlxs_wqe_t *wqe;
4203fcf3ce44SJohn Forte 	uint16_t abort_iotag;
4204fcf3ce44SJohn Forte 
42058f23e9faSHans Rosenfeld 	if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) {
4206fcf3ce44SJohn Forte 		return (NULL);
4207fcf3ce44SJohn Forte 	}
4208291a2b48SSukumar Swaminathan 
420982527734SSukumar Swaminathan 	iocbq->channel = (void *)cp;
4210fcf3ce44SJohn Forte 	iocbq->port = (void *)port;
4211fcf3ce44SJohn Forte 	iocbq->node = (void *)ndlp;
4212fcf3ce44SJohn Forte 	iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL);
4213fcf3ce44SJohn Forte 
4214fcf3ce44SJohn Forte 	/*
4215fcf3ce44SJohn Forte 	 * set up an iotag using special Abort iotags
4216fcf3ce44SJohn Forte 	 */
421782527734SSukumar Swaminathan 	if ((hba->fc_oor_iotag >= EMLXS_MAX_ABORT_TAG)) {
421882527734SSukumar Swaminathan 		hba->fc_oor_iotag = hba->max_iotag;
421982527734SSukumar Swaminathan 	}
422082527734SSukumar Swaminathan 	abort_iotag = hba->fc_oor_iotag++;
422182527734SSukumar Swaminathan 
422282527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
422382527734SSukumar Swaminathan 		wqe = &iocbq->wqe;
422482527734SSukumar Swaminathan 		wqe->un.Abort.Criteria = ABORT_XRI_TAG;
422582527734SSukumar Swaminathan 		wqe->un.Abort.IA = 1;
422682527734SSukumar Swaminathan 		wqe->RequestTag = abort_iotag;
422782527734SSukumar Swaminathan 		wqe->AbortTag = xid;
422882527734SSukumar Swaminathan 		wqe->Command = CMD_ABORT_XRI_CX;
422982527734SSukumar Swaminathan 		wqe->Class = CLASS3;
42308f23e9faSHans Rosenfeld 		wqe->CQId = (uint16_t)0xffff;  /* default CQ for response */
423182527734SSukumar Swaminathan 		wqe->CmdType = WQE_TYPE_ABORT;
423282527734SSukumar Swaminathan 	} else {
423382527734SSukumar Swaminathan 		iocb = &iocbq->iocb;
423482527734SSukumar Swaminathan 		iocb->ULPCONTEXT = xid;
423582527734SSukumar Swaminathan 		iocb->ULPIOTAG = abort_iotag;
423682527734SSukumar Swaminathan 		iocb->ULPLE = 1;
423782527734SSukumar Swaminathan 		iocb->ULPCLASS = 0;
423882527734SSukumar Swaminathan 		iocb->ULPCOMMAND = CMD_CLOSE_XRI_CX;
423982527734SSukumar Swaminathan 		iocb->ULPOWNER = OWN_CHIP;
4240fcf3ce44SJohn Forte 	}
4241291a2b48SSukumar Swaminathan 
4242fcf3ce44SJohn Forte 	return (iocbq);
4243fcf3ce44SJohn Forte 
424482527734SSukumar Swaminathan } /* emlxs_create_close_xri_cx() */
4245fcf3ce44SJohn Forte 
4246fcf3ce44SJohn Forte 
4247a9800bebSGarrett D'Amore void
emlxs_close_els_exchange(emlxs_hba_t * hba,emlxs_port_t * port,uint32_t rxid)4248a9800bebSGarrett D'Amore emlxs_close_els_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4249a9800bebSGarrett D'Amore {
4250a9800bebSGarrett D'Amore 	CHANNEL *cp;
4251a9800bebSGarrett D'Amore 	IOCBQ *iocbq;
4252a9800bebSGarrett D'Amore 	IOCB *iocb;
4253a9800bebSGarrett D'Amore 
4254a9800bebSGarrett D'Amore 	if (rxid == 0 || rxid == 0xFFFF) {
4255a9800bebSGarrett D'Amore 		return;
4256a9800bebSGarrett D'Amore 	}
4257a9800bebSGarrett D'Amore 
4258a9800bebSGarrett D'Amore 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4259a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4260a9800bebSGarrett D'Amore 		    "Closing ELS exchange: xid=%x", rxid);
4261a9800bebSGarrett D'Amore 
42628f23e9faSHans Rosenfeld 		if (emlxs_sli4_unreserve_xri(port, rxid, 1) == 0) {
4263a9800bebSGarrett D'Amore 			return;
4264a9800bebSGarrett D'Amore 		}
4265a9800bebSGarrett D'Amore 	}
4266a9800bebSGarrett D'Amore 
4267a9800bebSGarrett D'Amore 	cp = &hba->chan[hba->channel_els];
4268a9800bebSGarrett D'Amore 
4269a9800bebSGarrett D'Amore 	mutex_enter(&EMLXS_FCTAB_LOCK);
4270a9800bebSGarrett D'Amore 
4271a9800bebSGarrett D'Amore 	/* Create the abort IOCB */
4272a9800bebSGarrett D'Amore 	iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4273a9800bebSGarrett D'Amore 
4274a9800bebSGarrett D'Amore 	mutex_exit(&EMLXS_FCTAB_LOCK);
4275a9800bebSGarrett D'Amore 
4276a9800bebSGarrett D'Amore 	if (iocbq) {
4277a9800bebSGarrett D'Amore 		iocb = &iocbq->iocb;
4278a9800bebSGarrett D'Amore 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
42798f23e9faSHans Rosenfeld 		    "Closing ELS exchange: xid=%x iotag=%d", rxid,
4280a9800bebSGarrett D'Amore 		    iocb->ULPIOTAG);
4281a9800bebSGarrett D'Amore 
4282a9800bebSGarrett D'Amore 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4283a9800bebSGarrett D'Amore 	}
4284a9800bebSGarrett D'Amore 
4285a9800bebSGarrett D'Amore } /* emlxs_close_els_exchange() */
4286a9800bebSGarrett D'Amore 
4287a9800bebSGarrett D'Amore 
4288fe199829SSukumar Swaminathan void
emlxs_abort_els_exchange(emlxs_hba_t * hba,emlxs_port_t * port,uint32_t rxid)4289fe199829SSukumar Swaminathan emlxs_abort_els_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4290fe199829SSukumar Swaminathan {
4291fe199829SSukumar Swaminathan 	CHANNEL *cp;
4292fe199829SSukumar Swaminathan 	IOCBQ *iocbq;
4293fe199829SSukumar Swaminathan 	IOCB *iocb;
4294fe199829SSukumar Swaminathan 
4295fe199829SSukumar Swaminathan 	if (rxid == 0 || rxid == 0xFFFF) {
4296fe199829SSukumar Swaminathan 		return;
4297fe199829SSukumar Swaminathan 	}
4298fe199829SSukumar Swaminathan 
4299fe199829SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4300fe199829SSukumar Swaminathan 
4301fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
4302fe199829SSukumar Swaminathan 		    "Aborting ELS exchange: xid=%x", rxid);
4303fe199829SSukumar Swaminathan 
43048f23e9faSHans Rosenfeld 		if (emlxs_sli4_unreserve_xri(port, rxid, 1) == 0) {
4305fe199829SSukumar Swaminathan 			/* We have no way to abort unsolicited exchanges */
4306fe199829SSukumar Swaminathan 			/* that we have not responded to at this time */
4307fe199829SSukumar Swaminathan 			/* So we will return for now */
4308fe199829SSukumar Swaminathan 			return;
4309fe199829SSukumar Swaminathan 		}
4310fe199829SSukumar Swaminathan 	}
4311fe199829SSukumar Swaminathan 
4312fe199829SSukumar Swaminathan 	cp = &hba->chan[hba->channel_els];
4313fe199829SSukumar Swaminathan 
4314fe199829SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
4315fe199829SSukumar Swaminathan 
4316fe199829SSukumar Swaminathan 	/* Create the abort IOCB */
4317fe199829SSukumar Swaminathan 	if (hba->state >= FC_LINK_UP) {
4318fe199829SSukumar Swaminathan 		iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4319fe199829SSukumar Swaminathan 		    CLASS3, ABORT_TYPE_ABTS);
4320fe199829SSukumar Swaminathan 	} else {
4321fe199829SSukumar Swaminathan 		iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4322fe199829SSukumar Swaminathan 	}
4323fe199829SSukumar Swaminathan 
4324fe199829SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
4325fe199829SSukumar Swaminathan 
4326fe199829SSukumar Swaminathan 	if (iocbq) {
4327fe199829SSukumar Swaminathan 		iocb = &iocbq->iocb;
4328fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
43298f23e9faSHans Rosenfeld 		    "Aborting ELS exchange: xid=%x iotag=%d", rxid,
4330fe199829SSukumar Swaminathan 		    iocb->ULPIOTAG);
4331fe199829SSukumar Swaminathan 
4332fe199829SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4333fe199829SSukumar Swaminathan 	}
4334fe199829SSukumar Swaminathan 
4335fe199829SSukumar Swaminathan } /* emlxs_abort_els_exchange() */
4336fe199829SSukumar Swaminathan 
4337fe199829SSukumar Swaminathan 
4338728bdc9bSSukumar Swaminathan void
emlxs_abort_ct_exchange(emlxs_hba_t * hba,emlxs_port_t * port,uint32_t rxid)4339bb63f56eSSukumar Swaminathan emlxs_abort_ct_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4340728bdc9bSSukumar Swaminathan {
434182527734SSukumar Swaminathan 	CHANNEL *cp;
4342728bdc9bSSukumar Swaminathan 	IOCBQ *iocbq;
4343fe199829SSukumar Swaminathan 	IOCB *iocb;
4344728bdc9bSSukumar Swaminathan 
4345fe199829SSukumar Swaminathan 	if (rxid == 0 || rxid == 0xFFFF) {
4346fe199829SSukumar Swaminathan 		return;
4347fe199829SSukumar Swaminathan 	}
434882527734SSukumar Swaminathan 
434982527734SSukumar Swaminathan 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4350fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ct_msg,
4351fe199829SSukumar Swaminathan 		    "Aborting CT exchange: xid=%x", rxid);
4352fe199829SSukumar Swaminathan 
43538f23e9faSHans Rosenfeld 		if (emlxs_sli4_unreserve_xri(port, rxid, 1) == 0) {
435482527734SSukumar Swaminathan 			/* We have no way to abort unsolicited exchanges */
435582527734SSukumar Swaminathan 			/* that we have not responded to at this time */
435682527734SSukumar Swaminathan 			/* So we will return for now */
435782527734SSukumar Swaminathan 			return;
435882527734SSukumar Swaminathan 		}
435982527734SSukumar Swaminathan 	}
436082527734SSukumar Swaminathan 
436182527734SSukumar Swaminathan 	cp = &hba->chan[hba->channel_ct];
4362728bdc9bSSukumar Swaminathan 
4363fe199829SSukumar Swaminathan 	mutex_enter(&EMLXS_FCTAB_LOCK);
4364fe199829SSukumar Swaminathan 
4365728bdc9bSSukumar Swaminathan 	/* Create the abort IOCB */
4366728bdc9bSSukumar Swaminathan 	if (hba->state >= FC_LINK_UP) {
4367fe199829SSukumar Swaminathan 		iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4368fe199829SSukumar Swaminathan 		    CLASS3, ABORT_TYPE_ABTS);
4369291a2b48SSukumar Swaminathan 	} else {
437082527734SSukumar Swaminathan 		iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4371728bdc9bSSukumar Swaminathan 	}
437282527734SSukumar Swaminathan 
4373fe199829SSukumar Swaminathan 	mutex_exit(&EMLXS_FCTAB_LOCK);
4374fe199829SSukumar Swaminathan 
4375bb63f56eSSukumar Swaminathan 	if (iocbq) {
4376fe199829SSukumar Swaminathan 		iocb = &iocbq->iocb;
4377fe199829SSukumar Swaminathan 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
43788f23e9faSHans Rosenfeld 		    "Aborting CT exchange: xid=%x iotag=%d", rxid,
4379fe199829SSukumar Swaminathan 		    iocb->ULPIOTAG);
4380fe199829SSukumar Swaminathan 
438182527734SSukumar Swaminathan 		EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4382bb63f56eSSukumar Swaminathan 	}
438382527734SSukumar Swaminathan 
438482527734SSukumar Swaminathan } /* emlxs_abort_ct_exchange() */
4385728bdc9bSSukumar Swaminathan 
4386fcf3ce44SJohn Forte 
4387fe199829SSukumar Swaminathan /* This must be called while holding the EMLXS_FCTAB_LOCK */
4388fcf3ce44SJohn Forte static void
emlxs_sbp_abort_add(emlxs_port_t * port,emlxs_buf_t * sbp,Q * abort,uint8_t * flag,emlxs_buf_t * fpkt)4389fcf3ce44SJohn Forte emlxs_sbp_abort_add(emlxs_port_t *port, emlxs_buf_t *sbp, Q *abort,
4390fcf3ce44SJohn Forte     uint8_t *flag, emlxs_buf_t *fpkt)
4391fcf3ce44SJohn Forte {
4392fcf3ce44SJohn Forte 	emlxs_hba_t *hba = HBA;
4393fcf3ce44SJohn Forte 	IOCBQ *iocbq;
439482527734SSukumar Swaminathan 	CHANNEL *cp;
4395fcf3ce44SJohn Forte 	NODELIST *ndlp;
4396fcf3ce44SJohn Forte 
439782527734SSukumar Swaminathan 	cp = (CHANNEL *)sbp->channel;
4398fcf3ce44SJohn Forte 	ndlp = sbp->node;
4399fcf3ce44SJohn Forte 
4400fcf3ce44SJohn Forte 	/* Create the close XRI IOCB */
4401a9800bebSGarrett D'Amore 	if (hba->state >= FC_LINK_UP) {
4402a9800bebSGarrett D'Amore 		iocbq = emlxs_create_abort_xri_cn(port, ndlp, sbp->iotag, cp,
4403a9800bebSGarrett D'Amore 		    CLASS3, ABORT_TYPE_ABTS);
4404a9800bebSGarrett D'Amore 	} else {
4405a9800bebSGarrett D'Amore 		iocbq = emlxs_create_close_xri_cn(port, ndlp, sbp->iotag, cp);
4406a9800bebSGarrett D'Amore 	}
4407291a2b48SSukumar Swaminathan 	/*
4408291a2b48SSukumar Swaminathan 	 * Add this iocb to our local abort Q
4409291a2b48SSukumar Swaminathan 	 * This way we don't hold the CHIPQ lock too long
4410291a2b48SSukumar Swaminathan 	 */
4411fcf3ce44SJohn Forte 	if (iocbq) {
4412fcf3ce44SJohn Forte 		if (abort->q_first) {
4413291a2b48SSukumar Swaminathan 			((IOCBQ *)abort->q_last)->next = iocbq;
4414fcf3ce44SJohn Forte 			abort->q_last = (uint8_t *)iocbq;
4415fcf3ce44SJohn Forte 			abort->q_cnt++;
4416fcf3ce44SJohn Forte 		} else {
4417fcf3ce44SJohn Forte 			abort->q_first = (uint8_t *)iocbq;
4418fcf3ce44SJohn Forte 			abort->q_last = (uint8_t *)iocbq;
4419fcf3ce44SJohn Forte 			abort->q_cnt = 1;
4420fcf3ce44SJohn Forte 		}
4421fcf3ce44SJohn Forte 		iocbq->next = NULL;
4422fcf3ce44SJohn Forte 	}
4423291a2b48SSukumar Swaminathan 
4424fcf3ce44SJohn Forte 	/* set the flags */
4425fcf3ce44SJohn Forte 	mutex_enter(&sbp->mtx);
4426fcf3ce44SJohn Forte 
4427fcf3ce44SJohn Forte 	sbp->pkt_flags |= (PACKET_IN_FLUSH | PACKET_XRI_CLOSED);
442882527734SSukumar Swaminathan 
4429fcf3ce44SJohn Forte 	sbp->ticks = hba->timer_tics + 10;
4430fcf3ce44SJohn Forte 	sbp->abort_attempts++;
4431fcf3ce44SJohn Forte 
443282527734SSukumar Swaminathan 	flag[cp->channelno] = 1;
4433fcf3ce44SJohn Forte 
4434fcf3ce44SJohn Forte 	/*
4435291a2b48SSukumar Swaminathan 	 * If the fpkt is already set, then we will leave it alone
4436fcf3ce44SJohn Forte 	 * This ensures that this pkt is only accounted for on one
4437fcf3ce44SJohn Forte 	 * fpkt->flush_count
4438fcf3ce44SJohn Forte 	 */
4439fcf3ce44SJohn Forte 	if (!sbp->fpkt && fpkt) {
4440fcf3ce44SJohn Forte 		mutex_enter(&fpkt->mtx);
4441fcf3ce44SJohn Forte 		sbp->fpkt = fpkt;
4442fcf3ce44SJohn Forte 		fpkt->flush_count++;
4443fcf3ce44SJohn Forte 		mutex_exit(&fpkt->mtx);
4444fcf3ce44SJohn Forte 	}
4445291a2b48SSukumar Swaminathan 
4446fcf3ce44SJohn Forte 	mutex_exit(&sbp->mtx);
4447fcf3ce44SJohn Forte 
4448fcf3ce44SJohn Forte 	return;
4449fcf3ce44SJohn Forte 
445082527734SSukumar Swaminathan }	/* emlxs_sbp_abort_add() */
4451