1*fcf3ce44SJohn Forte /* 2*fcf3ce44SJohn Forte * CDDL HEADER START 3*fcf3ce44SJohn Forte * 4*fcf3ce44SJohn Forte * The contents of this file are subject to the terms of the 5*fcf3ce44SJohn Forte * Common Development and Distribution License (the "License"). 6*fcf3ce44SJohn Forte * You may not use this file except in compliance with the License. 7*fcf3ce44SJohn Forte * 8*fcf3ce44SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*fcf3ce44SJohn Forte * or http://www.opensolaris.org/os/licensing. 10*fcf3ce44SJohn Forte * See the License for the specific language governing permissions 11*fcf3ce44SJohn Forte * and limitations under the License. 12*fcf3ce44SJohn Forte * 13*fcf3ce44SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each 14*fcf3ce44SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*fcf3ce44SJohn Forte * If applicable, add the following below this CDDL HEADER, with the 16*fcf3ce44SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying 17*fcf3ce44SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner] 18*fcf3ce44SJohn Forte * 19*fcf3ce44SJohn Forte * CDDL HEADER END 20*fcf3ce44SJohn Forte */ 21*fcf3ce44SJohn Forte 22*fcf3ce44SJohn Forte /* 23*fcf3ce44SJohn Forte * Copyright 2008 Emulex. All rights reserved. 24*fcf3ce44SJohn Forte * Use is subject to License terms. 25*fcf3ce44SJohn Forte */ 26*fcf3ce44SJohn Forte 27*fcf3ce44SJohn Forte 28*fcf3ce44SJohn Forte #include "emlxs.h" 29*fcf3ce44SJohn Forte 30*fcf3ce44SJohn Forte /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */ 31*fcf3ce44SJohn Forte EMLXS_MSG_DEF(EMLXS_FCP_C); 32*fcf3ce44SJohn Forte 33*fcf3ce44SJohn Forte #define EMLXS_GET_VADDR(hba, rp, icmd) emlxs_mem_get_vaddr(hba, rp, \ 34*fcf3ce44SJohn Forte getPaddr(icmd->un.cont64[i].addrHigh, icmd->un.cont64[i].addrLow)); 35*fcf3ce44SJohn Forte 36*fcf3ce44SJohn Forte static void emlxs_sbp_abort_add(emlxs_port_t *port, emlxs_buf_t *sbp, Q *abort, 37*fcf3ce44SJohn Forte uint8_t *flag, emlxs_buf_t *fpkt); 38*fcf3ce44SJohn Forte static uint32_t emlxs_iotag_flush(emlxs_hba_t *hba); 39*fcf3ce44SJohn Forte 40*fcf3ce44SJohn Forte /* 41*fcf3ce44SJohn Forte * This routine copies data from src then potentially swaps the destination to 42*fcf3ce44SJohn Forte * big endian. Assumes cnt is a multiple of * sizeof(uint32_t). 43*fcf3ce44SJohn Forte */ 44*fcf3ce44SJohn Forte extern void 45*fcf3ce44SJohn Forte emlxs_pcimem_bcopy(uint32_t *src, uint32_t *dest, uint32_t cnt) 46*fcf3ce44SJohn Forte { 47*fcf3ce44SJohn Forte uint32_t ldata; 48*fcf3ce44SJohn Forte int32_t i; 49*fcf3ce44SJohn Forte 50*fcf3ce44SJohn Forte for (i = 0; i < (int)cnt; i += sizeof (uint32_t)) { 51*fcf3ce44SJohn Forte ldata = *src++; 52*fcf3ce44SJohn Forte ldata = PCIMEM_LONG(ldata); 53*fcf3ce44SJohn Forte *dest++ = ldata; 54*fcf3ce44SJohn Forte } 55*fcf3ce44SJohn Forte } /* emlxs_pcimem_bcopy */ 56*fcf3ce44SJohn Forte 57*fcf3ce44SJohn Forte 58*fcf3ce44SJohn Forte /* 59*fcf3ce44SJohn Forte * This routine copies data from src then swaps the destination to big endian. 60*fcf3ce44SJohn Forte * Assumes cnt is a multiple of sizeof(uint32_t). 61*fcf3ce44SJohn Forte */ 62*fcf3ce44SJohn Forte extern void 63*fcf3ce44SJohn Forte emlxs_swap_bcopy(uint32_t *src, uint32_t *dest, uint32_t cnt) 64*fcf3ce44SJohn Forte { 65*fcf3ce44SJohn Forte uint32_t ldata; 66*fcf3ce44SJohn Forte int32_t i; 67*fcf3ce44SJohn Forte 68*fcf3ce44SJohn Forte for (i = 0; i < (int)cnt; i += sizeof (uint32_t)) { 69*fcf3ce44SJohn Forte ldata = *src++; 70*fcf3ce44SJohn Forte ldata = SWAP_DATA32(ldata); 71*fcf3ce44SJohn Forte *dest++ = ldata; 72*fcf3ce44SJohn Forte } 73*fcf3ce44SJohn Forte } /* End fc_swap_bcopy */ 74*fcf3ce44SJohn Forte 75*fcf3ce44SJohn Forte 76*fcf3ce44SJohn Forte #define SCSI3_PERSISTENT_RESERVE_IN 0x5e 77*fcf3ce44SJohn Forte #define SCSI_INQUIRY 0x12 78*fcf3ce44SJohn Forte #define SCSI_RX_DIAG 0x1C 79*fcf3ce44SJohn Forte 80*fcf3ce44SJohn Forte 81*fcf3ce44SJohn Forte /* 82*fcf3ce44SJohn Forte * emlxs_handle_fcp_event 83*fcf3ce44SJohn Forte * 84*fcf3ce44SJohn Forte * Description: Process an FCP Rsp Ring completion 85*fcf3ce44SJohn Forte * 86*fcf3ce44SJohn Forte */ 87*fcf3ce44SJohn Forte /* ARGSUSED */ 88*fcf3ce44SJohn Forte extern void 89*fcf3ce44SJohn Forte emlxs_handle_fcp_event(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq) 90*fcf3ce44SJohn Forte { 91*fcf3ce44SJohn Forte emlxs_port_t *port = &PPORT; 92*fcf3ce44SJohn Forte IOCB *cmd; 93*fcf3ce44SJohn Forte emlxs_buf_t *sbp; 94*fcf3ce44SJohn Forte fc_packet_t *pkt = NULL; 95*fcf3ce44SJohn Forte uint32_t iostat; 96*fcf3ce44SJohn Forte uint8_t localstat; 97*fcf3ce44SJohn Forte fcp_rsp_t *rsp; 98*fcf3ce44SJohn Forte uint32_t rsp_data_resid; 99*fcf3ce44SJohn Forte uint32_t check_underrun; 100*fcf3ce44SJohn Forte uint8_t asc; 101*fcf3ce44SJohn Forte uint8_t ascq; 102*fcf3ce44SJohn Forte uint8_t scsi_status; 103*fcf3ce44SJohn Forte uint8_t sense; 104*fcf3ce44SJohn Forte uint32_t did; 105*fcf3ce44SJohn Forte uint32_t fix_it; 106*fcf3ce44SJohn Forte uint8_t *scsi_cmd; 107*fcf3ce44SJohn Forte uint8_t scsi_opcode; 108*fcf3ce44SJohn Forte uint16_t scsi_dl; 109*fcf3ce44SJohn Forte uint32_t data_rx; 110*fcf3ce44SJohn Forte 111*fcf3ce44SJohn Forte cmd = &iocbq->iocb; 112*fcf3ce44SJohn Forte 113*fcf3ce44SJohn Forte /* Initialize the status */ 114*fcf3ce44SJohn Forte iostat = cmd->ulpStatus; 115*fcf3ce44SJohn Forte localstat = 0; 116*fcf3ce44SJohn Forte scsi_status = 0; 117*fcf3ce44SJohn Forte asc = 0; 118*fcf3ce44SJohn Forte ascq = 0; 119*fcf3ce44SJohn Forte sense = 0; 120*fcf3ce44SJohn Forte check_underrun = 0; 121*fcf3ce44SJohn Forte fix_it = 0; 122*fcf3ce44SJohn Forte 123*fcf3ce44SJohn Forte HBASTATS.FcpEvent++; 124*fcf3ce44SJohn Forte 125*fcf3ce44SJohn Forte sbp = (emlxs_buf_t *)iocbq->sbp; 126*fcf3ce44SJohn Forte 127*fcf3ce44SJohn Forte if (!sbp) { 128*fcf3ce44SJohn Forte /* completion with missing xmit command */ 129*fcf3ce44SJohn Forte HBASTATS.FcpStray++; 130*fcf3ce44SJohn Forte 131*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_fcp_completion_msg, 132*fcf3ce44SJohn Forte "cmd=%x iotag=%x", 133*fcf3ce44SJohn Forte cmd->ulpCommand, cmd->ulpIoTag); 134*fcf3ce44SJohn Forte 135*fcf3ce44SJohn Forte return; 136*fcf3ce44SJohn Forte } 137*fcf3ce44SJohn Forte HBASTATS.FcpCompleted++; 138*fcf3ce44SJohn Forte 139*fcf3ce44SJohn Forte pkt = PRIV2PKT(sbp); 140*fcf3ce44SJohn Forte 141*fcf3ce44SJohn Forte did = SWAP_DATA24_LO(pkt->pkt_cmd_fhdr.d_id); 142*fcf3ce44SJohn Forte scsi_cmd = (uint8_t *)pkt->pkt_cmd; 143*fcf3ce44SJohn Forte scsi_opcode = scsi_cmd[12]; 144*fcf3ce44SJohn Forte data_rx = 0; 145*fcf3ce44SJohn Forte 146*fcf3ce44SJohn Forte /* Sync data in data buffer only on FC_PKT_FCP_READ */ 147*fcf3ce44SJohn Forte if (pkt->pkt_datalen && (pkt->pkt_tran_type == FC_PKT_FCP_READ)) { 148*fcf3ce44SJohn Forte emlxs_mpdata_sync(pkt->pkt_data_dma, 0, pkt->pkt_datalen, 149*fcf3ce44SJohn Forte DDI_DMA_SYNC_FORKERNEL); 150*fcf3ce44SJohn Forte 151*fcf3ce44SJohn Forte #ifdef TEST_SUPPORT 152*fcf3ce44SJohn Forte if (hba->underrun_counter && (iostat == IOSTAT_SUCCESS) && 153*fcf3ce44SJohn Forte (pkt->pkt_datalen >= 512)) { 154*fcf3ce44SJohn Forte hba->underrun_counter--; 155*fcf3ce44SJohn Forte iostat = IOSTAT_FCP_RSP_ERROR; 156*fcf3ce44SJohn Forte 157*fcf3ce44SJohn Forte /* Report 512 bytes missing by adapter */ 158*fcf3ce44SJohn Forte cmd->un.fcpi.fcpi_parm = pkt->pkt_datalen - 512; 159*fcf3ce44SJohn Forte 160*fcf3ce44SJohn Forte /* Corrupt 512 bytes of Data buffer */ 161*fcf3ce44SJohn Forte bzero((uint8_t *)pkt->pkt_data, 512); 162*fcf3ce44SJohn Forte 163*fcf3ce44SJohn Forte /* Set FCP response to STATUS_GOOD */ 164*fcf3ce44SJohn Forte bzero((uint8_t *)pkt->pkt_resp, pkt->pkt_rsplen); 165*fcf3ce44SJohn Forte } 166*fcf3ce44SJohn Forte #endif /* TEST_SUPPORT */ 167*fcf3ce44SJohn Forte } 168*fcf3ce44SJohn Forte /* Process the pkt */ 169*fcf3ce44SJohn Forte mutex_enter(&sbp->mtx); 170*fcf3ce44SJohn Forte 171*fcf3ce44SJohn Forte /* Check for immediate return */ 172*fcf3ce44SJohn Forte if ((iostat == IOSTAT_SUCCESS) && 173*fcf3ce44SJohn Forte (pkt->pkt_comp) && 174*fcf3ce44SJohn Forte !(sbp->pkt_flags & (PACKET_RETURNED | PACKET_COMPLETED | 175*fcf3ce44SJohn Forte PACKET_IN_COMPLETION | PACKET_IN_TXQ | PACKET_IN_CHIPQ | 176*fcf3ce44SJohn Forte PACKET_IN_DONEQ | PACKET_IN_TIMEOUT | PACKET_IN_FLUSH | 177*fcf3ce44SJohn Forte PACKET_IN_ABORT | PACKET_POLLED))) { 178*fcf3ce44SJohn Forte HBASTATS.FcpGood++; 179*fcf3ce44SJohn Forte 180*fcf3ce44SJohn Forte sbp->pkt_flags |= (PACKET_STATE_VALID | PACKET_IN_COMPLETION | 181*fcf3ce44SJohn Forte PACKET_COMPLETED | PACKET_RETURNED); 182*fcf3ce44SJohn Forte mutex_exit(&sbp->mtx); 183*fcf3ce44SJohn Forte 184*fcf3ce44SJohn Forte #if (EMLXS_MODREVX == EMLXS_MODREV2X) 185*fcf3ce44SJohn Forte emlxs_unswap_pkt(sbp); 186*fcf3ce44SJohn Forte #endif /* EMLXS_MODREV2X */ 187*fcf3ce44SJohn Forte 188*fcf3ce44SJohn Forte (*pkt->pkt_comp) (pkt); 189*fcf3ce44SJohn Forte 190*fcf3ce44SJohn Forte return; 191*fcf3ce44SJohn Forte } 192*fcf3ce44SJohn Forte /* 193*fcf3ce44SJohn Forte * A response is only placed in the resp buffer if 194*fcf3ce44SJohn Forte * IOSTAT_FCP_RSP_ERROR is reported 195*fcf3ce44SJohn Forte */ 196*fcf3ce44SJohn Forte 197*fcf3ce44SJohn Forte /* Check if a response buffer was provided */ 198*fcf3ce44SJohn Forte if ((iostat == IOSTAT_FCP_RSP_ERROR) && pkt->pkt_rsplen) { 199*fcf3ce44SJohn Forte emlxs_mpdata_sync(pkt->pkt_resp_dma, 0, pkt->pkt_rsplen, 200*fcf3ce44SJohn Forte DDI_DMA_SYNC_FORKERNEL); 201*fcf3ce44SJohn Forte 202*fcf3ce44SJohn Forte /* Get the response buffer pointer */ 203*fcf3ce44SJohn Forte rsp = (fcp_rsp_t *)pkt->pkt_resp; 204*fcf3ce44SJohn Forte 205*fcf3ce44SJohn Forte /* Set the valid response flag */ 206*fcf3ce44SJohn Forte sbp->pkt_flags |= PACKET_FCP_RSP_VALID; 207*fcf3ce44SJohn Forte 208*fcf3ce44SJohn Forte scsi_status = rsp->fcp_u.fcp_status.scsi_status; 209*fcf3ce44SJohn Forte 210*fcf3ce44SJohn Forte /* 211*fcf3ce44SJohn Forte * Convert a task abort to a check condition with no data 212*fcf3ce44SJohn Forte * transferred 213*fcf3ce44SJohn Forte */ 214*fcf3ce44SJohn Forte /* 215*fcf3ce44SJohn Forte * We saw a data corruption when Solaris received a Task 216*fcf3ce44SJohn Forte * Abort from a tape 217*fcf3ce44SJohn Forte */ 218*fcf3ce44SJohn Forte if (scsi_status == SCSI_STAT_TASK_ABORT) { 219*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, 220*fcf3ce44SJohn Forte &emlxs_fcp_completion_error_msg, 221*fcf3ce44SJohn Forte "Task Abort. Fixed. " 222*fcf3ce44SJohn Forte "did=0x%06x sbp=%p cmd=%02x dl=%d", 223*fcf3ce44SJohn Forte did, sbp, scsi_opcode, pkt->pkt_datalen); 224*fcf3ce44SJohn Forte 225*fcf3ce44SJohn Forte rsp->fcp_u.fcp_status.scsi_status = 226*fcf3ce44SJohn Forte SCSI_STAT_CHECK_COND; 227*fcf3ce44SJohn Forte rsp->fcp_u.fcp_status.rsp_len_set = 0; 228*fcf3ce44SJohn Forte rsp->fcp_u.fcp_status.sense_len_set = 0; 229*fcf3ce44SJohn Forte rsp->fcp_u.fcp_status.resid_over = 0; 230*fcf3ce44SJohn Forte 231*fcf3ce44SJohn Forte if (pkt->pkt_datalen) { 232*fcf3ce44SJohn Forte rsp->fcp_u.fcp_status.resid_under = 1; 233*fcf3ce44SJohn Forte rsp->fcp_resid = SWAP_DATA32(pkt->pkt_datalen); 234*fcf3ce44SJohn Forte } else { 235*fcf3ce44SJohn Forte rsp->fcp_u.fcp_status.resid_under = 0; 236*fcf3ce44SJohn Forte rsp->fcp_resid = 0; 237*fcf3ce44SJohn Forte } 238*fcf3ce44SJohn Forte 239*fcf3ce44SJohn Forte scsi_status = SCSI_STAT_CHECK_COND; 240*fcf3ce44SJohn Forte } 241*fcf3ce44SJohn Forte /* 242*fcf3ce44SJohn Forte * We only need to check underrun if data could have been 243*fcf3ce44SJohn Forte * sent 244*fcf3ce44SJohn Forte */ 245*fcf3ce44SJohn Forte 246*fcf3ce44SJohn Forte /* Always check underrun if status is good */ 247*fcf3ce44SJohn Forte if (scsi_status == SCSI_STAT_GOOD) { 248*fcf3ce44SJohn Forte check_underrun = 1; 249*fcf3ce44SJohn Forte } 250*fcf3ce44SJohn Forte /* Check the sense codes if this is a check condition */ 251*fcf3ce44SJohn Forte else if (scsi_status == SCSI_STAT_CHECK_COND) { 252*fcf3ce44SJohn Forte check_underrun = 1; 253*fcf3ce44SJohn Forte 254*fcf3ce44SJohn Forte /* Check if sense data was provided */ 255*fcf3ce44SJohn Forte if (SWAP_DATA32(rsp->fcp_sense_len) >= 14) { 256*fcf3ce44SJohn Forte sense = *((uint8_t *)rsp + 32 + 2); 257*fcf3ce44SJohn Forte asc = *((uint8_t *)rsp + 32 + 12); 258*fcf3ce44SJohn Forte ascq = *((uint8_t *)rsp + 32 + 13); 259*fcf3ce44SJohn Forte } 260*fcf3ce44SJohn Forte } 261*fcf3ce44SJohn Forte /* Status is not good and this is not a check condition */ 262*fcf3ce44SJohn Forte /* No data should have been sent */ 263*fcf3ce44SJohn Forte else { 264*fcf3ce44SJohn Forte check_underrun = 0; 265*fcf3ce44SJohn Forte } 266*fcf3ce44SJohn Forte 267*fcf3ce44SJohn Forte /* Get the residual underrun count reported by the SCSI reply */ 268*fcf3ce44SJohn Forte rsp_data_resid = (pkt->pkt_datalen && 269*fcf3ce44SJohn Forte rsp->fcp_u.fcp_status.resid_under) 270*fcf3ce44SJohn Forte ? SWAP_DATA32(rsp->fcp_resid) : 0; 271*fcf3ce44SJohn Forte 272*fcf3ce44SJohn Forte /* Set the pkt resp_resid field */ 273*fcf3ce44SJohn Forte pkt->pkt_resp_resid = 0; 274*fcf3ce44SJohn Forte 275*fcf3ce44SJohn Forte /* Set the pkt data_resid field */ 276*fcf3ce44SJohn Forte if (pkt->pkt_datalen && 277*fcf3ce44SJohn Forte (pkt->pkt_tran_type == FC_PKT_FCP_READ)) { 278*fcf3ce44SJohn Forte /* 279*fcf3ce44SJohn Forte * Get the residual underrun count reported by our 280*fcf3ce44SJohn Forte * adapter 281*fcf3ce44SJohn Forte */ 282*fcf3ce44SJohn Forte pkt->pkt_data_resid = cmd->un.fcpi.fcpi_parm; 283*fcf3ce44SJohn Forte 284*fcf3ce44SJohn Forte /* Get the actual amount of data transferred */ 285*fcf3ce44SJohn Forte data_rx = pkt->pkt_datalen - pkt->pkt_data_resid; 286*fcf3ce44SJohn Forte 287*fcf3ce44SJohn Forte /* 288*fcf3ce44SJohn Forte * If the residual being reported by the adapter is 289*fcf3ce44SJohn Forte * greater than the residual being reported in the 290*fcf3ce44SJohn Forte * reply, then we have a true underrun. 291*fcf3ce44SJohn Forte */ 292*fcf3ce44SJohn Forte if (check_underrun && 293*fcf3ce44SJohn Forte (pkt->pkt_data_resid > rsp_data_resid)) { 294*fcf3ce44SJohn Forte switch (scsi_opcode) { 295*fcf3ce44SJohn Forte case SCSI_INQUIRY: 296*fcf3ce44SJohn Forte scsi_dl = scsi_cmd[16]; 297*fcf3ce44SJohn Forte break; 298*fcf3ce44SJohn Forte 299*fcf3ce44SJohn Forte case SCSI_RX_DIAG: 300*fcf3ce44SJohn Forte scsi_dl = (scsi_cmd[15] * 0x100) + 301*fcf3ce44SJohn Forte scsi_cmd[16]; 302*fcf3ce44SJohn Forte break; 303*fcf3ce44SJohn Forte 304*fcf3ce44SJohn Forte default: 305*fcf3ce44SJohn Forte scsi_dl = pkt->pkt_datalen; 306*fcf3ce44SJohn Forte } 307*fcf3ce44SJohn Forte 308*fcf3ce44SJohn Forte #ifdef FCP_UNDERRUN_PATCH1 309*fcf3ce44SJohn Forte /* 310*fcf3ce44SJohn Forte * If status is not good and no data was 311*fcf3ce44SJohn Forte * actually transferred, then we must fix the 312*fcf3ce44SJohn Forte * issue 313*fcf3ce44SJohn Forte */ 314*fcf3ce44SJohn Forte if ((scsi_status != SCSI_STAT_GOOD) && 315*fcf3ce44SJohn Forte (data_rx == 0)) { 316*fcf3ce44SJohn Forte fix_it = 1; 317*fcf3ce44SJohn Forte 318*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, 319*fcf3ce44SJohn Forte &emlxs_fcp_completion_error_msg, 320*fcf3ce44SJohn Forte "Underrun(1). Fixed. did=0x%06x " 321*fcf3ce44SJohn Forte "sbp=%p cmd=%02x dl=%d,%d rx=%d " 322*fcf3ce44SJohn Forte "rsp=%d", 323*fcf3ce44SJohn Forte did, sbp, scsi_opcode, 324*fcf3ce44SJohn Forte pkt->pkt_datalen, scsi_dl, 325*fcf3ce44SJohn Forte (pkt->pkt_datalen - 326*fcf3ce44SJohn Forte cmd->un.fcpi.fcpi_parm), 327*fcf3ce44SJohn Forte rsp_data_resid); 328*fcf3ce44SJohn Forte 329*fcf3ce44SJohn Forte } 330*fcf3ce44SJohn Forte #endif /* FCP_UNDERRUN_PATCH1 */ 331*fcf3ce44SJohn Forte 332*fcf3ce44SJohn Forte 333*fcf3ce44SJohn Forte #ifdef FCP_UNDERRUN_PATCH2 334*fcf3ce44SJohn Forte if ((scsi_status == SCSI_STAT_GOOD)) { 335*fcf3ce44SJohn Forte emlxs_msg_t *msg; 336*fcf3ce44SJohn Forte 337*fcf3ce44SJohn Forte msg = &emlxs_fcp_completion_error_msg; 338*fcf3ce44SJohn Forte /* 339*fcf3ce44SJohn Forte * If status is good and this is an 340*fcf3ce44SJohn Forte * inquiry request and the amount of 341*fcf3ce44SJohn Forte * data 342*fcf3ce44SJohn Forte */ 343*fcf3ce44SJohn Forte /* 344*fcf3ce44SJohn Forte * requested <= data received, then 345*fcf3ce44SJohn Forte * we must fix the issue. 346*fcf3ce44SJohn Forte */ 347*fcf3ce44SJohn Forte 348*fcf3ce44SJohn Forte if ((scsi_opcode == SCSI_INQUIRY) && 349*fcf3ce44SJohn Forte (pkt->pkt_datalen >= data_rx) && 350*fcf3ce44SJohn Forte (scsi_dl <= data_rx)) { 351*fcf3ce44SJohn Forte fix_it = 1; 352*fcf3ce44SJohn Forte 353*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, 354*fcf3ce44SJohn Forte msg, 355*fcf3ce44SJohn Forte "Underrun(2). Fixed. " 356*fcf3ce44SJohn Forte "did=0x%06x sbp=%p " 357*fcf3ce44SJohn Forte "cmd=%02x dl=%d,%d " 358*fcf3ce44SJohn Forte "rx=%d rsp=%d", 359*fcf3ce44SJohn Forte did, sbp, scsi_opcode, 360*fcf3ce44SJohn Forte pkt->pkt_datalen, scsi_dl, 361*fcf3ce44SJohn Forte data_rx, rsp_data_resid); 362*fcf3ce44SJohn Forte 363*fcf3ce44SJohn Forte } 364*fcf3ce44SJohn Forte /* 365*fcf3ce44SJohn Forte * If status is good and this is an 366*fcf3ce44SJohn Forte * inquiry request and the amount of 367*fcf3ce44SJohn Forte * data 368*fcf3ce44SJohn Forte */ 369*fcf3ce44SJohn Forte /* 370*fcf3ce44SJohn Forte * requested >= 128 bytes, but only 371*fcf3ce44SJohn Forte * 128 bytes were received, 372*fcf3ce44SJohn Forte */ 373*fcf3ce44SJohn Forte /* then we must fix the issue. */ 374*fcf3ce44SJohn Forte else if ((scsi_opcode == SCSI_INQUIRY)&& 375*fcf3ce44SJohn Forte (pkt->pkt_datalen >= 128) && 376*fcf3ce44SJohn Forte (scsi_dl >= 128) && 377*fcf3ce44SJohn Forte (data_rx == 128)) { 378*fcf3ce44SJohn Forte fix_it = 1; 379*fcf3ce44SJohn Forte 380*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, 381*fcf3ce44SJohn Forte msg, 382*fcf3ce44SJohn Forte "Underrun(3). Fixed. " 383*fcf3ce44SJohn Forte "did=0x%06x sbp=%p " 384*fcf3ce44SJohn Forte "cmd=%02x dl=%d,%d rx=%d " 385*fcf3ce44SJohn Forte "rsp=%d", 386*fcf3ce44SJohn Forte did, sbp, scsi_opcode, 387*fcf3ce44SJohn Forte pkt->pkt_datalen, scsi_dl, 388*fcf3ce44SJohn Forte data_rx, rsp_data_resid); 389*fcf3ce44SJohn Forte 390*fcf3ce44SJohn Forte } 391*fcf3ce44SJohn Forte } 392*fcf3ce44SJohn Forte #endif /* FCP_UNDERRUN_PATCH2 */ 393*fcf3ce44SJohn Forte 394*fcf3ce44SJohn Forte /* 395*fcf3ce44SJohn Forte * Check if SCSI response payload should be 396*fcf3ce44SJohn Forte * fixed or 397*fcf3ce44SJohn Forte */ 398*fcf3ce44SJohn Forte /* if a DATA_UNDERRUN should be reported */ 399*fcf3ce44SJohn Forte if (fix_it) { 400*fcf3ce44SJohn Forte /* 401*fcf3ce44SJohn Forte * Fix the SCSI response payload 402*fcf3ce44SJohn Forte * itself 403*fcf3ce44SJohn Forte */ 404*fcf3ce44SJohn Forte rsp->fcp_u.fcp_status.resid_under = 1; 405*fcf3ce44SJohn Forte rsp->fcp_resid = 406*fcf3ce44SJohn Forte SWAP_DATA32(pkt->pkt_data_resid); 407*fcf3ce44SJohn Forte } else { 408*fcf3ce44SJohn Forte /* 409*fcf3ce44SJohn Forte * Change the status from 410*fcf3ce44SJohn Forte * IOSTAT_FCP_RSP_ERROR to 411*fcf3ce44SJohn Forte * IOSTAT_DATA_UNDERRUN 412*fcf3ce44SJohn Forte */ 413*fcf3ce44SJohn Forte iostat = IOSTAT_DATA_UNDERRUN; 414*fcf3ce44SJohn Forte pkt->pkt_data_resid = pkt->pkt_datalen; 415*fcf3ce44SJohn Forte } 416*fcf3ce44SJohn Forte } 417*fcf3ce44SJohn Forte /* 418*fcf3ce44SJohn Forte * If the residual being reported by the adapter is 419*fcf3ce44SJohn Forte * less than the residual being reported in the 420*fcf3ce44SJohn Forte * reply, then we have a true overrun. Since we don't 421*fcf3ce44SJohn Forte * know where the extra data came from or went to 422*fcf3ce44SJohn Forte * then we cannot trust anything we received 423*fcf3ce44SJohn Forte */ 424*fcf3ce44SJohn Forte else if (rsp_data_resid > pkt->pkt_data_resid) { 425*fcf3ce44SJohn Forte /* 426*fcf3ce44SJohn Forte * Change the status from 427*fcf3ce44SJohn Forte * IOSTAT_FCP_RSP_ERROR to 428*fcf3ce44SJohn Forte * IOSTAT_DATA_OVERRUN 429*fcf3ce44SJohn Forte */ 430*fcf3ce44SJohn Forte iostat = IOSTAT_DATA_OVERRUN; 431*fcf3ce44SJohn Forte pkt->pkt_data_resid = pkt->pkt_datalen; 432*fcf3ce44SJohn Forte } 433*fcf3ce44SJohn Forte } else { /* pkt->pkt_datalen==0 or FC_PKT_FCP_WRITE */ 434*fcf3ce44SJohn Forte /* Report whatever the target reported */ 435*fcf3ce44SJohn Forte pkt->pkt_data_resid = rsp_data_resid; 436*fcf3ce44SJohn Forte } 437*fcf3ce44SJohn Forte } 438*fcf3ce44SJohn Forte /* 439*fcf3ce44SJohn Forte * If pkt is tagged for timeout then set the return codes 440*fcf3ce44SJohn Forte * appropriately 441*fcf3ce44SJohn Forte */ 442*fcf3ce44SJohn Forte if (sbp->pkt_flags & PACKET_IN_TIMEOUT) { 443*fcf3ce44SJohn Forte iostat = IOSTAT_LOCAL_REJECT; 444*fcf3ce44SJohn Forte localstat = IOERR_ABORT_TIMEOUT; 445*fcf3ce44SJohn Forte goto done; 446*fcf3ce44SJohn Forte } 447*fcf3ce44SJohn Forte /* If pkt is tagged for abort then set the return codes appropriately */ 448*fcf3ce44SJohn Forte if (sbp->pkt_flags & (PACKET_IN_FLUSH | PACKET_IN_ABORT)) { 449*fcf3ce44SJohn Forte iostat = IOSTAT_LOCAL_REJECT; 450*fcf3ce44SJohn Forte localstat = IOERR_ABORT_REQUESTED; 451*fcf3ce44SJohn Forte goto done; 452*fcf3ce44SJohn Forte } 453*fcf3ce44SJohn Forte /* Print completion message */ 454*fcf3ce44SJohn Forte switch (iostat) { 455*fcf3ce44SJohn Forte case IOSTAT_SUCCESS: 456*fcf3ce44SJohn Forte /* Build SCSI GOOD status */ 457*fcf3ce44SJohn Forte if (pkt->pkt_rsplen) { 458*fcf3ce44SJohn Forte bzero((uint8_t *)pkt->pkt_resp, pkt->pkt_rsplen); 459*fcf3ce44SJohn Forte } 460*fcf3ce44SJohn Forte break; 461*fcf3ce44SJohn Forte 462*fcf3ce44SJohn Forte case IOSTAT_FCP_RSP_ERROR: 463*fcf3ce44SJohn Forte break; 464*fcf3ce44SJohn Forte 465*fcf3ce44SJohn Forte case IOSTAT_REMOTE_STOP: 466*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg, 467*fcf3ce44SJohn Forte "Remote Stop. did=0x%06x sbp=%p cmd=%02x", 468*fcf3ce44SJohn Forte did, sbp, scsi_opcode); 469*fcf3ce44SJohn Forte break; 470*fcf3ce44SJohn Forte 471*fcf3ce44SJohn Forte case IOSTAT_LOCAL_REJECT: 472*fcf3ce44SJohn Forte localstat = cmd->un.grsp.perr.statLocalError; 473*fcf3ce44SJohn Forte 474*fcf3ce44SJohn Forte switch (localstat) { 475*fcf3ce44SJohn Forte case IOERR_SEQUENCE_TIMEOUT: 476*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, 477*fcf3ce44SJohn Forte &emlxs_fcp_completion_error_msg, 478*fcf3ce44SJohn Forte "Local reject. %s did=0x%06x sbp=%p " 479*fcf3ce44SJohn Forte "cmd=%02x tmo=%d ", 480*fcf3ce44SJohn Forte emlxs_error_xlate(localstat), did, sbp, 481*fcf3ce44SJohn Forte scsi_opcode, pkt->pkt_timeout); 482*fcf3ce44SJohn Forte break; 483*fcf3ce44SJohn Forte 484*fcf3ce44SJohn Forte default: 485*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, 486*fcf3ce44SJohn Forte &emlxs_fcp_completion_error_msg, 487*fcf3ce44SJohn Forte "Local reject. %s did=0x%06x sbp=%p cmd=%02x", 488*fcf3ce44SJohn Forte emlxs_error_xlate(localstat), did, 489*fcf3ce44SJohn Forte sbp, scsi_opcode); 490*fcf3ce44SJohn Forte } 491*fcf3ce44SJohn Forte 492*fcf3ce44SJohn Forte break; 493*fcf3ce44SJohn Forte 494*fcf3ce44SJohn Forte case IOSTAT_NPORT_RJT: 495*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg, 496*fcf3ce44SJohn Forte "Nport reject. did=0x%06x sbp=%p cmd=%02x", 497*fcf3ce44SJohn Forte did, sbp, scsi_opcode); 498*fcf3ce44SJohn Forte break; 499*fcf3ce44SJohn Forte 500*fcf3ce44SJohn Forte case IOSTAT_FABRIC_RJT: 501*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg, 502*fcf3ce44SJohn Forte "Fabric reject. did=0x%06x sbp=%p cmd=%02x", 503*fcf3ce44SJohn Forte did, sbp, scsi_opcode); 504*fcf3ce44SJohn Forte break; 505*fcf3ce44SJohn Forte 506*fcf3ce44SJohn Forte case IOSTAT_NPORT_BSY: 507*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg, 508*fcf3ce44SJohn Forte "Nport busy. did=0x%06x sbp=%p cmd=%02x", 509*fcf3ce44SJohn Forte did, sbp, scsi_opcode); 510*fcf3ce44SJohn Forte break; 511*fcf3ce44SJohn Forte 512*fcf3ce44SJohn Forte case IOSTAT_FABRIC_BSY: 513*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg, 514*fcf3ce44SJohn Forte "Fabric busy. did=0x%06x sbp=%p cmd=%02x", 515*fcf3ce44SJohn Forte did, sbp, scsi_opcode); 516*fcf3ce44SJohn Forte break; 517*fcf3ce44SJohn Forte 518*fcf3ce44SJohn Forte case IOSTAT_INTERMED_RSP: 519*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg, 520*fcf3ce44SJohn Forte "Intermediate response. did=0x%06x sbp=%p cmd=%02x", 521*fcf3ce44SJohn Forte did, sbp, scsi_opcode); 522*fcf3ce44SJohn Forte break; 523*fcf3ce44SJohn Forte 524*fcf3ce44SJohn Forte case IOSTAT_LS_RJT: 525*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg, 526*fcf3ce44SJohn Forte "LS Reject. did=0x%06x sbp=%p cmd=%02x", 527*fcf3ce44SJohn Forte did, sbp, scsi_opcode); 528*fcf3ce44SJohn Forte break; 529*fcf3ce44SJohn Forte 530*fcf3ce44SJohn Forte case IOSTAT_DATA_UNDERRUN: 531*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg, 532*fcf3ce44SJohn Forte "Underrun. did=0x%06x sbp=%p cmd=%02x dl=%d,%d rx=%d " 533*fcf3ce44SJohn Forte "rsp=%d (%02x,%02x,%02x,%02x)", 534*fcf3ce44SJohn Forte did, sbp, scsi_opcode, pkt->pkt_datalen, scsi_dl, 535*fcf3ce44SJohn Forte data_rx, rsp_data_resid, scsi_status, sense, asc, ascq); 536*fcf3ce44SJohn Forte break; 537*fcf3ce44SJohn Forte 538*fcf3ce44SJohn Forte case IOSTAT_DATA_OVERRUN: 539*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg, 540*fcf3ce44SJohn Forte "Overrun. did=0x%06x sbp=%p cmd=%02x dl=%d,%d rx=%d " 541*fcf3ce44SJohn Forte "rsp=%d (%02x,%02x,%02x,%02x)", 542*fcf3ce44SJohn Forte did, sbp, scsi_opcode, pkt->pkt_datalen, scsi_dl, 543*fcf3ce44SJohn Forte data_rx, rsp_data_resid, scsi_status, sense, asc, ascq); 544*fcf3ce44SJohn Forte break; 545*fcf3ce44SJohn Forte 546*fcf3ce44SJohn Forte default: 547*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fcp_completion_error_msg, 548*fcf3ce44SJohn Forte "Unknown status=%x reason=%x did=0x%06x sbp=%p cmd=%02x", 549*fcf3ce44SJohn Forte iostat, cmd->un.grsp.perr.statLocalError, did, 550*fcf3ce44SJohn Forte sbp, scsi_opcode); 551*fcf3ce44SJohn Forte break; 552*fcf3ce44SJohn Forte } 553*fcf3ce44SJohn Forte 554*fcf3ce44SJohn Forte done: 555*fcf3ce44SJohn Forte 556*fcf3ce44SJohn Forte if (iostat == IOSTAT_SUCCESS) { 557*fcf3ce44SJohn Forte HBASTATS.FcpGood++; 558*fcf3ce44SJohn Forte } else { 559*fcf3ce44SJohn Forte HBASTATS.FcpError++; 560*fcf3ce44SJohn Forte } 561*fcf3ce44SJohn Forte 562*fcf3ce44SJohn Forte mutex_exit(&sbp->mtx); 563*fcf3ce44SJohn Forte 564*fcf3ce44SJohn Forte emlxs_pkt_complete(sbp, iostat, localstat, 0); 565*fcf3ce44SJohn Forte 566*fcf3ce44SJohn Forte return; 567*fcf3ce44SJohn Forte 568*fcf3ce44SJohn Forte } /* emlxs_handle_fcp_event() */ 569*fcf3ce44SJohn Forte 570*fcf3ce44SJohn Forte 571*fcf3ce44SJohn Forte 572*fcf3ce44SJohn Forte /* 573*fcf3ce44SJohn Forte * emlxs_post_buffer 574*fcf3ce44SJohn Forte * 575*fcf3ce44SJohn Forte * This routine will post count buffers to the 576*fcf3ce44SJohn Forte * ring with the QUE_RING_BUF_CN command. This 577*fcf3ce44SJohn Forte * allows 2 buffers / command to be posted. 578*fcf3ce44SJohn Forte * Returns the number of buffers NOT posted. 579*fcf3ce44SJohn Forte */ 580*fcf3ce44SJohn Forte extern int 581*fcf3ce44SJohn Forte emlxs_post_buffer(emlxs_hba_t *hba, RING *rp, int16_t cnt) 582*fcf3ce44SJohn Forte { 583*fcf3ce44SJohn Forte emlxs_port_t *port = &PPORT; 584*fcf3ce44SJohn Forte IOCB *icmd; 585*fcf3ce44SJohn Forte IOCBQ *iocbq; 586*fcf3ce44SJohn Forte MATCHMAP *mp; 587*fcf3ce44SJohn Forte uint16_t tag; 588*fcf3ce44SJohn Forte uint32_t maxqbuf; 589*fcf3ce44SJohn Forte int32_t i; 590*fcf3ce44SJohn Forte int32_t j; 591*fcf3ce44SJohn Forte uint32_t seg; 592*fcf3ce44SJohn Forte uint32_t size; 593*fcf3ce44SJohn Forte 594*fcf3ce44SJohn Forte mp = 0; 595*fcf3ce44SJohn Forte maxqbuf = 2; 596*fcf3ce44SJohn Forte tag = (uint16_t)cnt; 597*fcf3ce44SJohn Forte cnt += rp->fc_missbufcnt; 598*fcf3ce44SJohn Forte 599*fcf3ce44SJohn Forte if (rp->ringno == FC_ELS_RING) { 600*fcf3ce44SJohn Forte seg = MEM_BUF; 601*fcf3ce44SJohn Forte size = MEM_ELSBUF_SIZE; 602*fcf3ce44SJohn Forte } else if (rp->ringno == FC_IP_RING) { 603*fcf3ce44SJohn Forte seg = MEM_IPBUF; 604*fcf3ce44SJohn Forte size = MEM_IPBUF_SIZE; 605*fcf3ce44SJohn Forte } else if (rp->ringno == FC_CT_RING) { 606*fcf3ce44SJohn Forte seg = MEM_CTBUF; 607*fcf3ce44SJohn Forte size = MEM_CTBUF_SIZE; 608*fcf3ce44SJohn Forte } 609*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT 610*fcf3ce44SJohn Forte else if (rp->ringno == FC_FCT_RING) { 611*fcf3ce44SJohn Forte seg = MEM_FCTBUF; 612*fcf3ce44SJohn Forte size = MEM_FCTBUF_SIZE; 613*fcf3ce44SJohn Forte } 614*fcf3ce44SJohn Forte #endif /* SFCT_SUPPORT */ 615*fcf3ce44SJohn Forte else { 616*fcf3ce44SJohn Forte return (0); 617*fcf3ce44SJohn Forte } 618*fcf3ce44SJohn Forte 619*fcf3ce44SJohn Forte /* 620*fcf3ce44SJohn Forte * While there are buffers to post 621*fcf3ce44SJohn Forte */ 622*fcf3ce44SJohn Forte while (cnt) { 623*fcf3ce44SJohn Forte if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == 0) { 624*fcf3ce44SJohn Forte rp->fc_missbufcnt = cnt; 625*fcf3ce44SJohn Forte return (cnt); 626*fcf3ce44SJohn Forte } 627*fcf3ce44SJohn Forte iocbq->ring = (void *)rp; 628*fcf3ce44SJohn Forte iocbq->port = (void *)port; 629*fcf3ce44SJohn Forte iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL); 630*fcf3ce44SJohn Forte 631*fcf3ce44SJohn Forte icmd = &iocbq->iocb; 632*fcf3ce44SJohn Forte 633*fcf3ce44SJohn Forte /* 634*fcf3ce44SJohn Forte * Max buffers can be posted per command 635*fcf3ce44SJohn Forte */ 636*fcf3ce44SJohn Forte for (i = 0; i < maxqbuf; i++) { 637*fcf3ce44SJohn Forte if (cnt <= 0) 638*fcf3ce44SJohn Forte break; 639*fcf3ce44SJohn Forte 640*fcf3ce44SJohn Forte /* fill in BDEs for command */ 641*fcf3ce44SJohn Forte if ((mp = (MATCHMAP *)emlxs_mem_get(hba, seg)) == 0) { 642*fcf3ce44SJohn Forte uint32_t H; 643*fcf3ce44SJohn Forte uint32_t L; 644*fcf3ce44SJohn Forte 645*fcf3ce44SJohn Forte icmd->ulpBdeCount = i; 646*fcf3ce44SJohn Forte for (j = 0; j < i; j++) { 647*fcf3ce44SJohn Forte H = icmd->un.cont64[j].addrHigh; 648*fcf3ce44SJohn Forte L = icmd->un.cont64[j].addrLow; 649*fcf3ce44SJohn Forte mp = emlxs_mem_get_vaddr(hba, rp, 650*fcf3ce44SJohn Forte getPaddr(H, L)); 651*fcf3ce44SJohn Forte if (mp) { 652*fcf3ce44SJohn Forte (void) emlxs_mem_put(hba, seg, 653*fcf3ce44SJohn Forte (uint8_t *)mp); 654*fcf3ce44SJohn Forte } 655*fcf3ce44SJohn Forte } 656*fcf3ce44SJohn Forte 657*fcf3ce44SJohn Forte rp->fc_missbufcnt = cnt + i; 658*fcf3ce44SJohn Forte 659*fcf3ce44SJohn Forte (void) emlxs_mem_put(hba, MEM_IOCB, 660*fcf3ce44SJohn Forte (uint8_t *)iocbq); 661*fcf3ce44SJohn Forte 662*fcf3ce44SJohn Forte return (cnt + i); 663*fcf3ce44SJohn Forte } 664*fcf3ce44SJohn Forte /* 665*fcf3ce44SJohn Forte * map that page and save the address pair for lookup 666*fcf3ce44SJohn Forte * later 667*fcf3ce44SJohn Forte */ 668*fcf3ce44SJohn Forte emlxs_mem_map_vaddr(hba, rp, mp, 669*fcf3ce44SJohn Forte (uint32_t *)&icmd->un.cont64[i].addrHigh, 670*fcf3ce44SJohn Forte (uint32_t *)&icmd->un.cont64[i].addrLow); 671*fcf3ce44SJohn Forte 672*fcf3ce44SJohn Forte icmd->un.cont64[i].tus.f.bdeSize = size; 673*fcf3ce44SJohn Forte icmd->ulpCommand = CMD_QUE_RING_BUF64_CN; 674*fcf3ce44SJohn Forte 675*fcf3ce44SJohn Forte /* 676*fcf3ce44SJohn Forte * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg, 677*fcf3ce44SJohn Forte * "UB Post: ring=%d addr=%08x%08x size=%d", 678*fcf3ce44SJohn Forte * rp->ringno, icmd->un.cont64[i].addrHigh, 679*fcf3ce44SJohn Forte * icmd->un.cont64[i].addrLow, size); 680*fcf3ce44SJohn Forte */ 681*fcf3ce44SJohn Forte 682*fcf3ce44SJohn Forte cnt--; 683*fcf3ce44SJohn Forte } 684*fcf3ce44SJohn Forte 685*fcf3ce44SJohn Forte icmd->ulpIoTag = tag; 686*fcf3ce44SJohn Forte icmd->ulpBdeCount = i; 687*fcf3ce44SJohn Forte icmd->ulpLe = 1; 688*fcf3ce44SJohn Forte icmd->ulpOwner = OWN_CHIP; 689*fcf3ce44SJohn Forte iocbq->bp = (uint8_t *)mp; /* used for delimiter between */ 690*fcf3ce44SJohn Forte /* commands */ 691*fcf3ce44SJohn Forte 692*fcf3ce44SJohn Forte emlxs_issue_iocb_cmd(hba, rp, iocbq); 693*fcf3ce44SJohn Forte } 694*fcf3ce44SJohn Forte 695*fcf3ce44SJohn Forte rp->fc_missbufcnt = 0; 696*fcf3ce44SJohn Forte 697*fcf3ce44SJohn Forte return (0); 698*fcf3ce44SJohn Forte 699*fcf3ce44SJohn Forte } /* emlxs_post_buffer() */ 700*fcf3ce44SJohn Forte 701*fcf3ce44SJohn Forte 702*fcf3ce44SJohn Forte extern int 703*fcf3ce44SJohn Forte emlxs_port_offline(emlxs_port_t *port, uint32_t scope) 704*fcf3ce44SJohn Forte { 705*fcf3ce44SJohn Forte emlxs_hba_t *hba = HBA; 706*fcf3ce44SJohn Forte emlxs_config_t *cfg; 707*fcf3ce44SJohn Forte NODELIST *nlp; 708*fcf3ce44SJohn Forte fc_affected_id_t *aid; 709*fcf3ce44SJohn Forte uint32_t mask; 710*fcf3ce44SJohn Forte uint32_t aff_d_id; 711*fcf3ce44SJohn Forte uint32_t linkdown; 712*fcf3ce44SJohn Forte uint32_t vlinkdown; 713*fcf3ce44SJohn Forte uint32_t action; 714*fcf3ce44SJohn Forte int i; 715*fcf3ce44SJohn Forte uint32_t unreg_vpi; 716*fcf3ce44SJohn Forte uint32_t update; 717*fcf3ce44SJohn Forte uint32_t adisc_support; 718*fcf3ce44SJohn Forte 719*fcf3ce44SJohn Forte /* Target mode only uses this routine for linkdowns */ 720*fcf3ce44SJohn Forte if (port->tgt_mode && (scope != 0xffffffff) && (scope != 0xfeffffff)) { 721*fcf3ce44SJohn Forte return (0); 722*fcf3ce44SJohn Forte } 723*fcf3ce44SJohn Forte cfg = &CFG; 724*fcf3ce44SJohn Forte aid = (fc_affected_id_t *)&scope; 725*fcf3ce44SJohn Forte linkdown = 0; 726*fcf3ce44SJohn Forte vlinkdown = 0; 727*fcf3ce44SJohn Forte unreg_vpi = 0; 728*fcf3ce44SJohn Forte update = 0; 729*fcf3ce44SJohn Forte 730*fcf3ce44SJohn Forte if (!(port->flag & EMLXS_PORT_BOUND)) { 731*fcf3ce44SJohn Forte return (0); 732*fcf3ce44SJohn Forte } 733*fcf3ce44SJohn Forte switch (aid->aff_format) { 734*fcf3ce44SJohn Forte case 0: /* Port */ 735*fcf3ce44SJohn Forte mask = 0x00ffffff; 736*fcf3ce44SJohn Forte break; 737*fcf3ce44SJohn Forte 738*fcf3ce44SJohn Forte case 1: /* Area */ 739*fcf3ce44SJohn Forte mask = 0x00ffff00; 740*fcf3ce44SJohn Forte break; 741*fcf3ce44SJohn Forte 742*fcf3ce44SJohn Forte case 2: /* Domain */ 743*fcf3ce44SJohn Forte mask = 0x00ff0000; 744*fcf3ce44SJohn Forte break; 745*fcf3ce44SJohn Forte 746*fcf3ce44SJohn Forte case 3: /* Network */ 747*fcf3ce44SJohn Forte mask = 0x00000000; 748*fcf3ce44SJohn Forte break; 749*fcf3ce44SJohn Forte 750*fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT 751*fcf3ce44SJohn Forte case 0xfe: /* Virtual link down */ 752*fcf3ce44SJohn Forte mask = 0x00000000; 753*fcf3ce44SJohn Forte vlinkdown = 1; 754*fcf3ce44SJohn Forte break; 755*fcf3ce44SJohn Forte #endif /* DHCHAP_SUPPORT */ 756*fcf3ce44SJohn Forte 757*fcf3ce44SJohn Forte case 0xff: /* link is down */ 758*fcf3ce44SJohn Forte mask = 0x00000000; 759*fcf3ce44SJohn Forte linkdown = 1; 760*fcf3ce44SJohn Forte break; 761*fcf3ce44SJohn Forte 762*fcf3ce44SJohn Forte } 763*fcf3ce44SJohn Forte 764*fcf3ce44SJohn Forte aff_d_id = aid->aff_d_id & mask; 765*fcf3ce44SJohn Forte 766*fcf3ce44SJohn Forte 767*fcf3ce44SJohn Forte /* If link is down then this is a hard shutdown and flush */ 768*fcf3ce44SJohn Forte /* 769*fcf3ce44SJohn Forte * If link not down then this is a soft shutdown and flush (e.g. 770*fcf3ce44SJohn Forte * RSCN) 771*fcf3ce44SJohn Forte */ 772*fcf3ce44SJohn Forte if (linkdown) { 773*fcf3ce44SJohn Forte mutex_enter(&EMLXS_PORT_LOCK); 774*fcf3ce44SJohn Forte 775*fcf3ce44SJohn Forte port->flag &= EMLXS_PORT_LINKDOWN_MASK; 776*fcf3ce44SJohn Forte port->prev_did = port->did; 777*fcf3ce44SJohn Forte port->did = 0; 778*fcf3ce44SJohn Forte 779*fcf3ce44SJohn Forte if (port->ulp_statec != FC_STATE_OFFLINE) { 780*fcf3ce44SJohn Forte port->ulp_statec = FC_STATE_OFFLINE; 781*fcf3ce44SJohn Forte update = 1; 782*fcf3ce44SJohn Forte } 783*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 784*fcf3ce44SJohn Forte 785*fcf3ce44SJohn Forte /* Tell ULP about it */ 786*fcf3ce44SJohn Forte if (update) { 787*fcf3ce44SJohn Forte if (port->flag & EMLXS_PORT_BOUND) { 788*fcf3ce44SJohn Forte if (port->vpi == 0) { 789*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, 790*fcf3ce44SJohn Forte &emlxs_link_down_msg, 791*fcf3ce44SJohn Forte NULL); 792*fcf3ce44SJohn Forte } 793*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT 794*fcf3ce44SJohn Forte if (port->tgt_mode) { 795*fcf3ce44SJohn Forte emlxs_fct_link_down(port); 796*fcf3ce44SJohn Forte 797*fcf3ce44SJohn Forte } else if (port->ini_mode) { 798*fcf3ce44SJohn Forte port->ulp_statec_cb(port->ulp_handle, 799*fcf3ce44SJohn Forte FC_STATE_OFFLINE); 800*fcf3ce44SJohn Forte } 801*fcf3ce44SJohn Forte #else 802*fcf3ce44SJohn Forte port->ulp_statec_cb(port->ulp_handle, 803*fcf3ce44SJohn Forte FC_STATE_OFFLINE); 804*fcf3ce44SJohn Forte #endif /* SFCT_SUPPORT */ 805*fcf3ce44SJohn Forte } else { 806*fcf3ce44SJohn Forte if (port->vpi == 0) { 807*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, 808*fcf3ce44SJohn Forte &emlxs_link_down_msg, 809*fcf3ce44SJohn Forte "*"); 810*fcf3ce44SJohn Forte } 811*fcf3ce44SJohn Forte } 812*fcf3ce44SJohn Forte 813*fcf3ce44SJohn Forte 814*fcf3ce44SJohn Forte } 815*fcf3ce44SJohn Forte unreg_vpi = 1; 816*fcf3ce44SJohn Forte 817*fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT 818*fcf3ce44SJohn Forte /* Stop authentication with all nodes */ 819*fcf3ce44SJohn Forte emlxs_dhc_auth_stop(port, NULL); 820*fcf3ce44SJohn Forte #endif /* DHCHAP_SUPPORT */ 821*fcf3ce44SJohn Forte 822*fcf3ce44SJohn Forte /* Flush the base node */ 823*fcf3ce44SJohn Forte (void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0); 824*fcf3ce44SJohn Forte (void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0); 825*fcf3ce44SJohn Forte 826*fcf3ce44SJohn Forte /* Flush any pending ub buffers */ 827*fcf3ce44SJohn Forte emlxs_ub_flush(port); 828*fcf3ce44SJohn Forte } 829*fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT 830*fcf3ce44SJohn Forte /* virtual link down */ 831*fcf3ce44SJohn Forte else if (vlinkdown) { 832*fcf3ce44SJohn Forte mutex_enter(&EMLXS_PORT_LOCK); 833*fcf3ce44SJohn Forte 834*fcf3ce44SJohn Forte if (port->ulp_statec != FC_STATE_OFFLINE) { 835*fcf3ce44SJohn Forte port->ulp_statec = FC_STATE_OFFLINE; 836*fcf3ce44SJohn Forte update = 1; 837*fcf3ce44SJohn Forte } 838*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 839*fcf3ce44SJohn Forte 840*fcf3ce44SJohn Forte /* Tell ULP about it */ 841*fcf3ce44SJohn Forte if (update) { 842*fcf3ce44SJohn Forte if (port->flag & EMLXS_PORT_BOUND) { 843*fcf3ce44SJohn Forte if (port->vpi == 0) { 844*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, 845*fcf3ce44SJohn Forte &emlxs_link_down_msg, 846*fcf3ce44SJohn Forte "Switch authentication failed."); 847*fcf3ce44SJohn Forte } 848*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT 849*fcf3ce44SJohn Forte if (port->tgt_mode) { 850*fcf3ce44SJohn Forte emlxs_fct_link_down(port); 851*fcf3ce44SJohn Forte } else if (port->ini_mode) { 852*fcf3ce44SJohn Forte port->ulp_statec_cb(port->ulp_handle, 853*fcf3ce44SJohn Forte FC_STATE_OFFLINE); 854*fcf3ce44SJohn Forte } 855*fcf3ce44SJohn Forte #else 856*fcf3ce44SJohn Forte port->ulp_statec_cb(port->ulp_handle, 857*fcf3ce44SJohn Forte FC_STATE_OFFLINE); 858*fcf3ce44SJohn Forte #endif /* SFCT_SUPPORT */ 859*fcf3ce44SJohn Forte } else { 860*fcf3ce44SJohn Forte if (port->vpi == 0) { 861*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, 862*fcf3ce44SJohn Forte &emlxs_link_down_msg, 863*fcf3ce44SJohn Forte "Switch authentication failed. *"); 864*fcf3ce44SJohn Forte } 865*fcf3ce44SJohn Forte } 866*fcf3ce44SJohn Forte 867*fcf3ce44SJohn Forte 868*fcf3ce44SJohn Forte } 869*fcf3ce44SJohn Forte /* Flush the base node */ 870*fcf3ce44SJohn Forte (void) emlxs_tx_node_flush(port, &port->node_base, 0, 0, 0); 871*fcf3ce44SJohn Forte (void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0); 872*fcf3ce44SJohn Forte } 873*fcf3ce44SJohn Forte #endif /* DHCHAP_SUPPORT */ 874*fcf3ce44SJohn Forte 875*fcf3ce44SJohn Forte if (port->tgt_mode) { 876*fcf3ce44SJohn Forte goto done; 877*fcf3ce44SJohn Forte } 878*fcf3ce44SJohn Forte /* Set the node tags */ 879*fcf3ce44SJohn Forte /* We will process all nodes with this tag */ 880*fcf3ce44SJohn Forte rw_enter(&port->node_rwlock, RW_READER); 881*fcf3ce44SJohn Forte for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 882*fcf3ce44SJohn Forte nlp = port->node_table[i]; 883*fcf3ce44SJohn Forte while (nlp != NULL) { 884*fcf3ce44SJohn Forte nlp->nlp_tag = 1; 885*fcf3ce44SJohn Forte nlp = nlp->nlp_list_next; 886*fcf3ce44SJohn Forte } 887*fcf3ce44SJohn Forte } 888*fcf3ce44SJohn Forte rw_exit(&port->node_rwlock); 889*fcf3ce44SJohn Forte 890*fcf3ce44SJohn Forte if (hba->flag & FC_ONLINE_MODE) { 891*fcf3ce44SJohn Forte adisc_support = cfg[CFG_ADISC_SUPPORT].current; 892*fcf3ce44SJohn Forte } else { 893*fcf3ce44SJohn Forte adisc_support = 0; 894*fcf3ce44SJohn Forte } 895*fcf3ce44SJohn Forte 896*fcf3ce44SJohn Forte /* Check ADISC support level */ 897*fcf3ce44SJohn Forte switch (adisc_support) { 898*fcf3ce44SJohn Forte case 0: /* No support - Flush all IO to all matching nodes */ 899*fcf3ce44SJohn Forte 900*fcf3ce44SJohn Forte for (; ; ) { 901*fcf3ce44SJohn Forte /* 902*fcf3ce44SJohn Forte * We need to hold the locks this way because 903*fcf3ce44SJohn Forte * emlxs_mb_unreg_did and the flush routines enter 904*fcf3ce44SJohn Forte * the same locks. Also, when we release the lock the 905*fcf3ce44SJohn Forte * list can change out from under us. 906*fcf3ce44SJohn Forte */ 907*fcf3ce44SJohn Forte 908*fcf3ce44SJohn Forte /* Find first node */ 909*fcf3ce44SJohn Forte rw_enter(&port->node_rwlock, RW_READER); 910*fcf3ce44SJohn Forte action = 0; 911*fcf3ce44SJohn Forte for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 912*fcf3ce44SJohn Forte nlp = port->node_table[i]; 913*fcf3ce44SJohn Forte while (nlp != NULL) { 914*fcf3ce44SJohn Forte if (!nlp->nlp_tag) { 915*fcf3ce44SJohn Forte nlp = nlp->nlp_list_next; 916*fcf3ce44SJohn Forte continue; 917*fcf3ce44SJohn Forte } 918*fcf3ce44SJohn Forte nlp->nlp_tag = 0; 919*fcf3ce44SJohn Forte 920*fcf3ce44SJohn Forte /* 921*fcf3ce44SJohn Forte * Check for any device that matches 922*fcf3ce44SJohn Forte * our mask 923*fcf3ce44SJohn Forte */ 924*fcf3ce44SJohn Forte if ((nlp->nlp_DID & mask) == aff_d_id) { 925*fcf3ce44SJohn Forte if (linkdown) { 926*fcf3ce44SJohn Forte action = 1; 927*fcf3ce44SJohn Forte break; 928*fcf3ce44SJohn Forte } else { /* Must be an RCSN */ 929*fcf3ce44SJohn Forte action = 2; 930*fcf3ce44SJohn Forte break; 931*fcf3ce44SJohn Forte } 932*fcf3ce44SJohn Forte } 933*fcf3ce44SJohn Forte nlp = nlp->nlp_list_next; 934*fcf3ce44SJohn Forte } 935*fcf3ce44SJohn Forte 936*fcf3ce44SJohn Forte if (action) { 937*fcf3ce44SJohn Forte break; 938*fcf3ce44SJohn Forte } 939*fcf3ce44SJohn Forte } 940*fcf3ce44SJohn Forte rw_exit(&port->node_rwlock); 941*fcf3ce44SJohn Forte 942*fcf3ce44SJohn Forte 943*fcf3ce44SJohn Forte /* Check if nothing was found */ 944*fcf3ce44SJohn Forte if (action == 0) { 945*fcf3ce44SJohn Forte break; 946*fcf3ce44SJohn Forte } else if (action == 1) { 947*fcf3ce44SJohn Forte (void) emlxs_mb_unreg_did(port, nlp->nlp_DID, 948*fcf3ce44SJohn Forte NULL, NULL, NULL); 949*fcf3ce44SJohn Forte } else if (action == 2) { 950*fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT 951*fcf3ce44SJohn Forte emlxs_dhc_auth_stop(port, nlp); 952*fcf3ce44SJohn Forte #endif /* DHCHAP_SUPPORT */ 953*fcf3ce44SJohn Forte 954*fcf3ce44SJohn Forte /* Close the node for any further normal IO */ 955*fcf3ce44SJohn Forte /* A PLOGI with reopen the node */ 956*fcf3ce44SJohn Forte emlxs_node_close(port, nlp, FC_FCP_RING, 60); 957*fcf3ce44SJohn Forte emlxs_node_close(port, nlp, FC_IP_RING, 60); 958*fcf3ce44SJohn Forte 959*fcf3ce44SJohn Forte /* Flush tx queue */ 960*fcf3ce44SJohn Forte (void) emlxs_tx_node_flush(port, nlp, 0, 0, 0); 961*fcf3ce44SJohn Forte 962*fcf3ce44SJohn Forte /* Flush chip queue */ 963*fcf3ce44SJohn Forte (void) emlxs_chipq_node_flush(port, 0, nlp, 0); 964*fcf3ce44SJohn Forte } 965*fcf3ce44SJohn Forte } 966*fcf3ce44SJohn Forte 967*fcf3ce44SJohn Forte break; 968*fcf3ce44SJohn Forte 969*fcf3ce44SJohn Forte case 1: /* Partial support - Flush IO for non-FCP2 matching * nodes */ 970*fcf3ce44SJohn Forte 971*fcf3ce44SJohn Forte for (;;) { 972*fcf3ce44SJohn Forte 973*fcf3ce44SJohn Forte /* 974*fcf3ce44SJohn Forte * We need to hold the locks this way because 975*fcf3ce44SJohn Forte * emlxs_mb_unreg_did and the flush routines enter 976*fcf3ce44SJohn Forte * the same locks. Also, when we release the lock the 977*fcf3ce44SJohn Forte * list can change out from under us. 978*fcf3ce44SJohn Forte */ 979*fcf3ce44SJohn Forte rw_enter(&port->node_rwlock, RW_READER); 980*fcf3ce44SJohn Forte action = 0; 981*fcf3ce44SJohn Forte for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 982*fcf3ce44SJohn Forte nlp = port->node_table[i]; 983*fcf3ce44SJohn Forte while (nlp != NULL) { 984*fcf3ce44SJohn Forte if (!nlp->nlp_tag) { 985*fcf3ce44SJohn Forte nlp = nlp->nlp_list_next; 986*fcf3ce44SJohn Forte continue; 987*fcf3ce44SJohn Forte } 988*fcf3ce44SJohn Forte nlp->nlp_tag = 0; 989*fcf3ce44SJohn Forte 990*fcf3ce44SJohn Forte /* 991*fcf3ce44SJohn Forte * Check for special FCP2 target 992*fcf3ce44SJohn Forte * device that matches our mask 993*fcf3ce44SJohn Forte */ 994*fcf3ce44SJohn Forte if ((nlp->nlp_fcp_info & 995*fcf3ce44SJohn Forte NLP_FCP_TGT_DEVICE) && 996*fcf3ce44SJohn Forte (nlp->nlp_fcp_info & 997*fcf3ce44SJohn Forte NLP_FCP_2_DEVICE) && 998*fcf3ce44SJohn Forte (nlp->nlp_DID & mask) == aff_d_id) { 999*fcf3ce44SJohn Forte action = 3; 1000*fcf3ce44SJohn Forte break; 1001*fcf3ce44SJohn Forte } 1002*fcf3ce44SJohn Forte /* 1003*fcf3ce44SJohn Forte * Check for any other device that 1004*fcf3ce44SJohn Forte * matches our mask 1005*fcf3ce44SJohn Forte */ 1006*fcf3ce44SJohn Forte else if ((nlp->nlp_DID & mask) == 1007*fcf3ce44SJohn Forte aff_d_id) { 1008*fcf3ce44SJohn Forte if (linkdown) { 1009*fcf3ce44SJohn Forte action = 1; 1010*fcf3ce44SJohn Forte break; 1011*fcf3ce44SJohn Forte } else { /* Must be an RSCN */ 1012*fcf3ce44SJohn Forte action = 2; 1013*fcf3ce44SJohn Forte break; 1014*fcf3ce44SJohn Forte } 1015*fcf3ce44SJohn Forte } 1016*fcf3ce44SJohn Forte nlp = nlp->nlp_list_next; 1017*fcf3ce44SJohn Forte } 1018*fcf3ce44SJohn Forte 1019*fcf3ce44SJohn Forte if (action) { 1020*fcf3ce44SJohn Forte break; 1021*fcf3ce44SJohn Forte } 1022*fcf3ce44SJohn Forte } 1023*fcf3ce44SJohn Forte rw_exit(&port->node_rwlock); 1024*fcf3ce44SJohn Forte 1025*fcf3ce44SJohn Forte /* Check if nothing was found */ 1026*fcf3ce44SJohn Forte if (action == 0) { 1027*fcf3ce44SJohn Forte break; 1028*fcf3ce44SJohn Forte } else if (action == 1) { 1029*fcf3ce44SJohn Forte (void) emlxs_mb_unreg_did(port, nlp->nlp_DID, 1030*fcf3ce44SJohn Forte NULL, NULL, NULL); 1031*fcf3ce44SJohn Forte } else if (action == 2) { 1032*fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT 1033*fcf3ce44SJohn Forte emlxs_dhc_auth_stop(port, nlp); 1034*fcf3ce44SJohn Forte #endif /* DHCHAP_SUPPORT */ 1035*fcf3ce44SJohn Forte 1036*fcf3ce44SJohn Forte /* Close the node for any further normal IO */ 1037*fcf3ce44SJohn Forte /* A PLOGI with reopen the node */ 1038*fcf3ce44SJohn Forte emlxs_node_close(port, nlp, FC_FCP_RING, 60); 1039*fcf3ce44SJohn Forte emlxs_node_close(port, nlp, FC_IP_RING, 60); 1040*fcf3ce44SJohn Forte 1041*fcf3ce44SJohn Forte /* Flush tx queue */ 1042*fcf3ce44SJohn Forte (void) emlxs_tx_node_flush(port, nlp, 0, 0, 0); 1043*fcf3ce44SJohn Forte 1044*fcf3ce44SJohn Forte /* Flush chip queue */ 1045*fcf3ce44SJohn Forte (void) emlxs_chipq_node_flush(port, 0, nlp, 0); 1046*fcf3ce44SJohn Forte } else if (action == 3) { /* FCP2 devices */ 1047*fcf3ce44SJohn Forte unreg_vpi = 0; 1048*fcf3ce44SJohn Forte 1049*fcf3ce44SJohn Forte #ifdef DHCHAP_SUPPORT 1050*fcf3ce44SJohn Forte emlxs_dhc_auth_stop(port, nlp); 1051*fcf3ce44SJohn Forte #endif /* DHCHAP_SUPPORT */ 1052*fcf3ce44SJohn Forte 1053*fcf3ce44SJohn Forte /* Close the node for any further normal IO */ 1054*fcf3ce44SJohn Forte /* An ADISC or a PLOGI with reopen the node */ 1055*fcf3ce44SJohn Forte emlxs_node_close(port, nlp, FC_FCP_RING, 1056*fcf3ce44SJohn Forte ((linkdown) ? 0 : 60)); 1057*fcf3ce44SJohn Forte emlxs_node_close(port, nlp, FC_IP_RING, 1058*fcf3ce44SJohn Forte ((linkdown) ? 0 : 60)); 1059*fcf3ce44SJohn Forte 1060*fcf3ce44SJohn Forte /* Flush tx queues except for FCP ring */ 1061*fcf3ce44SJohn Forte (void) emlxs_tx_node_flush(port, nlp, 1062*fcf3ce44SJohn Forte &hba->ring[FC_CT_RING], 0, 0); 1063*fcf3ce44SJohn Forte (void) emlxs_tx_node_flush(port, nlp, 1064*fcf3ce44SJohn Forte &hba->ring[FC_ELS_RING], 0, 0); 1065*fcf3ce44SJohn Forte (void) emlxs_tx_node_flush(port, nlp, 1066*fcf3ce44SJohn Forte &hba->ring[FC_IP_RING], 0, 0); 1067*fcf3ce44SJohn Forte 1068*fcf3ce44SJohn Forte /* Clear IP XRI */ 1069*fcf3ce44SJohn Forte nlp->nlp_Xri = 0; 1070*fcf3ce44SJohn Forte 1071*fcf3ce44SJohn Forte /* Flush chip queues except for FCP ring */ 1072*fcf3ce44SJohn Forte (void) emlxs_chipq_node_flush(port, 1073*fcf3ce44SJohn Forte &hba->ring[FC_CT_RING], nlp, 0); 1074*fcf3ce44SJohn Forte (void) emlxs_chipq_node_flush(port, 1075*fcf3ce44SJohn Forte &hba->ring[FC_ELS_RING], nlp, 0); 1076*fcf3ce44SJohn Forte (void) emlxs_chipq_node_flush(port, 1077*fcf3ce44SJohn Forte &hba->ring[FC_IP_RING], nlp, 0); 1078*fcf3ce44SJohn Forte } 1079*fcf3ce44SJohn Forte } 1080*fcf3ce44SJohn Forte break; 1081*fcf3ce44SJohn Forte 1082*fcf3ce44SJohn Forte case 2: /* Full support - Hold FCP IO to FCP target matching nodes */ 1083*fcf3ce44SJohn Forte 1084*fcf3ce44SJohn Forte if (!linkdown && !vlinkdown) { 1085*fcf3ce44SJohn Forte break; 1086*fcf3ce44SJohn Forte } 1087*fcf3ce44SJohn Forte for (;;) { 1088*fcf3ce44SJohn Forte /* 1089*fcf3ce44SJohn Forte * We need to hold the locks this way because 1090*fcf3ce44SJohn Forte * emlxs_mb_unreg_did and the flush routines enter 1091*fcf3ce44SJohn Forte * the same locks. Also, when we release the lock the 1092*fcf3ce44SJohn Forte * list can change out from under us. 1093*fcf3ce44SJohn Forte */ 1094*fcf3ce44SJohn Forte rw_enter(&port->node_rwlock, RW_READER); 1095*fcf3ce44SJohn Forte action = 0; 1096*fcf3ce44SJohn Forte for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) { 1097*fcf3ce44SJohn Forte nlp = port->node_table[i]; 1098*fcf3ce44SJohn Forte while (nlp != NULL) { 1099*fcf3ce44SJohn Forte if (!nlp->nlp_tag) { 1100*fcf3ce44SJohn Forte nlp = nlp->nlp_list_next; 1101*fcf3ce44SJohn Forte continue; 1102*fcf3ce44SJohn Forte } 1103*fcf3ce44SJohn Forte nlp->nlp_tag = 0; 1104*fcf3ce44SJohn Forte 1105*fcf3ce44SJohn Forte /* 1106*fcf3ce44SJohn Forte * Check for FCP target device that 1107*fcf3ce44SJohn Forte * matches our mask 1108*fcf3ce44SJohn Forte */ 1109*fcf3ce44SJohn Forte if ((nlp->nlp_fcp_info & 1110*fcf3ce44SJohn Forte NLP_FCP_TGT_DEVICE) && 1111*fcf3ce44SJohn Forte (nlp->nlp_DID & mask) == aff_d_id) { 1112*fcf3ce44SJohn Forte action = 3; 1113*fcf3ce44SJohn Forte break; 1114*fcf3ce44SJohn Forte } 1115*fcf3ce44SJohn Forte /* 1116*fcf3ce44SJohn Forte * Check for any other device that 1117*fcf3ce44SJohn Forte * matches our mask 1118*fcf3ce44SJohn Forte */ 1119*fcf3ce44SJohn Forte else if ((nlp->nlp_DID & mask) == 1120*fcf3ce44SJohn Forte aff_d_id) { 1121*fcf3ce44SJohn Forte if (linkdown) { 1122*fcf3ce44SJohn Forte action = 1; 1123*fcf3ce44SJohn Forte break; 1124*fcf3ce44SJohn Forte } else { /* Must be an RSCN */ 1125*fcf3ce44SJohn Forte action = 2; 1126*fcf3ce44SJohn Forte break; 1127*fcf3ce44SJohn Forte } 1128*fcf3ce44SJohn Forte } 1129*fcf3ce44SJohn Forte nlp = nlp->nlp_list_next; 1130*fcf3ce44SJohn Forte } 1131*fcf3ce44SJohn Forte if (action) { 1132*fcf3ce44SJohn Forte break; 1133*fcf3ce44SJohn Forte } 1134*fcf3ce44SJohn Forte } 1135*fcf3ce44SJohn Forte rw_exit(&port->node_rwlock); 1136*fcf3ce44SJohn Forte 1137*fcf3ce44SJohn Forte /* Check if nothing was found */ 1138*fcf3ce44SJohn Forte if (action == 0) { 1139*fcf3ce44SJohn Forte break; 1140*fcf3ce44SJohn Forte } else if (action == 1) { 1141*fcf3ce44SJohn Forte (void) emlxs_mb_unreg_did(port, nlp->nlp_DID, 1142*fcf3ce44SJohn Forte NULL, NULL, NULL); 1143*fcf3ce44SJohn Forte } else if (action == 2) { 1144*fcf3ce44SJohn Forte /* Close the node for any further normal IO */ 1145*fcf3ce44SJohn Forte /* A PLOGI with reopen the node */ 1146*fcf3ce44SJohn Forte emlxs_node_close(port, nlp, FC_FCP_RING, 60); 1147*fcf3ce44SJohn Forte emlxs_node_close(port, nlp, FC_IP_RING, 60); 1148*fcf3ce44SJohn Forte 1149*fcf3ce44SJohn Forte /* Flush tx queue */ 1150*fcf3ce44SJohn Forte (void) emlxs_tx_node_flush(port, nlp, 0, 0, 0); 1151*fcf3ce44SJohn Forte 1152*fcf3ce44SJohn Forte /* Flush chip queue */ 1153*fcf3ce44SJohn Forte (void) emlxs_chipq_node_flush(port, 0, nlp, 0); 1154*fcf3ce44SJohn Forte 1155*fcf3ce44SJohn Forte } else if (action == 3) { /* FCP2 devices */ 1156*fcf3ce44SJohn Forte unreg_vpi = 0; 1157*fcf3ce44SJohn Forte 1158*fcf3ce44SJohn Forte /* Close the node for any further normal IO */ 1159*fcf3ce44SJohn Forte /* An ADISC or a PLOGI with reopen the node */ 1160*fcf3ce44SJohn Forte emlxs_node_close(port, nlp, FC_FCP_RING, 1161*fcf3ce44SJohn Forte ((linkdown) ? 0 : 60)); 1162*fcf3ce44SJohn Forte emlxs_node_close(port, nlp, FC_IP_RING, 1163*fcf3ce44SJohn Forte ((linkdown) ? 0 : 60)); 1164*fcf3ce44SJohn Forte 1165*fcf3ce44SJohn Forte /* Flush tx queues except for FCP ring */ 1166*fcf3ce44SJohn Forte (void) emlxs_tx_node_flush(port, nlp, 1167*fcf3ce44SJohn Forte &hba->ring[FC_CT_RING], 0, 0); 1168*fcf3ce44SJohn Forte (void) emlxs_tx_node_flush(port, nlp, 1169*fcf3ce44SJohn Forte &hba->ring[FC_ELS_RING], 0, 0); 1170*fcf3ce44SJohn Forte (void) emlxs_tx_node_flush(port, nlp, 1171*fcf3ce44SJohn Forte &hba->ring[FC_IP_RING], 0, 0); 1172*fcf3ce44SJohn Forte 1173*fcf3ce44SJohn Forte /* Clear IP XRI */ 1174*fcf3ce44SJohn Forte nlp->nlp_Xri = 0; 1175*fcf3ce44SJohn Forte 1176*fcf3ce44SJohn Forte /* Flush chip queues except for FCP ring */ 1177*fcf3ce44SJohn Forte (void) emlxs_chipq_node_flush(port, 1178*fcf3ce44SJohn Forte &hba->ring[FC_CT_RING], nlp, 0); 1179*fcf3ce44SJohn Forte (void) emlxs_chipq_node_flush(port, 1180*fcf3ce44SJohn Forte &hba->ring[FC_ELS_RING], nlp, 0); 1181*fcf3ce44SJohn Forte (void) emlxs_chipq_node_flush(port, 1182*fcf3ce44SJohn Forte &hba->ring[FC_IP_RING], nlp, 0); 1183*fcf3ce44SJohn Forte } 1184*fcf3ce44SJohn Forte } 1185*fcf3ce44SJohn Forte 1186*fcf3ce44SJohn Forte break; 1187*fcf3ce44SJohn Forte 1188*fcf3ce44SJohn Forte 1189*fcf3ce44SJohn Forte } /* switch() */ 1190*fcf3ce44SJohn Forte 1191*fcf3ce44SJohn Forte done: 1192*fcf3ce44SJohn Forte 1193*fcf3ce44SJohn Forte if (unreg_vpi) { 1194*fcf3ce44SJohn Forte (void) emlxs_mb_unreg_vpi(port); 1195*fcf3ce44SJohn Forte } 1196*fcf3ce44SJohn Forte return (0); 1197*fcf3ce44SJohn Forte 1198*fcf3ce44SJohn Forte } /* emlxs_port_offline() */ 1199*fcf3ce44SJohn Forte 1200*fcf3ce44SJohn Forte 1201*fcf3ce44SJohn Forte 1202*fcf3ce44SJohn Forte extern void 1203*fcf3ce44SJohn Forte emlxs_port_online(emlxs_port_t *vport) 1204*fcf3ce44SJohn Forte { 1205*fcf3ce44SJohn Forte emlxs_hba_t *hba = vport->hba; 1206*fcf3ce44SJohn Forte emlxs_port_t *port = &PPORT; 1207*fcf3ce44SJohn Forte uint32_t state; 1208*fcf3ce44SJohn Forte uint32_t update; 1209*fcf3ce44SJohn Forte uint32_t npiv_linkup; 1210*fcf3ce44SJohn Forte char topology[32]; 1211*fcf3ce44SJohn Forte char linkspeed[32]; 1212*fcf3ce44SJohn Forte char mode[32]; 1213*fcf3ce44SJohn Forte 1214*fcf3ce44SJohn Forte /* 1215*fcf3ce44SJohn Forte * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg, "linkup_callback. 1216*fcf3ce44SJohn Forte * vpi=%d fc_flag=%x", vport->vpi, hba->flag); 1217*fcf3ce44SJohn Forte */ 1218*fcf3ce44SJohn Forte 1219*fcf3ce44SJohn Forte if ((vport->vpi > 0) && 1220*fcf3ce44SJohn Forte (!(hba->flag & FC_NPIV_ENABLED) || 1221*fcf3ce44SJohn Forte !(hba->flag & FC_NPIV_SUPPORTED))) { 1222*fcf3ce44SJohn Forte return; 1223*fcf3ce44SJohn Forte } 1224*fcf3ce44SJohn Forte if (!(vport->flag & EMLXS_PORT_BOUND) || 1225*fcf3ce44SJohn Forte !(vport->flag & EMLXS_PORT_ENABLE)) { 1226*fcf3ce44SJohn Forte return; 1227*fcf3ce44SJohn Forte } 1228*fcf3ce44SJohn Forte mutex_enter(&EMLXS_PORT_LOCK); 1229*fcf3ce44SJohn Forte 1230*fcf3ce44SJohn Forte /* Check for mode */ 1231*fcf3ce44SJohn Forte if (port->tgt_mode) { 1232*fcf3ce44SJohn Forte (void) strcpy(mode, ", target"); 1233*fcf3ce44SJohn Forte } else if (port->ini_mode) { 1234*fcf3ce44SJohn Forte (void) strcpy(mode, ", initiator"); 1235*fcf3ce44SJohn Forte } else { 1236*fcf3ce44SJohn Forte (void) strcpy(mode, ""); 1237*fcf3ce44SJohn Forte } 1238*fcf3ce44SJohn Forte 1239*fcf3ce44SJohn Forte /* Check for loop topology */ 1240*fcf3ce44SJohn Forte if (hba->topology == TOPOLOGY_LOOP) { 1241*fcf3ce44SJohn Forte state = FC_STATE_LOOP; 1242*fcf3ce44SJohn Forte (void) strcpy(topology, ", loop"); 1243*fcf3ce44SJohn Forte } else { 1244*fcf3ce44SJohn Forte state = FC_STATE_ONLINE; 1245*fcf3ce44SJohn Forte (void) strcpy(topology, ", fabric"); 1246*fcf3ce44SJohn Forte } 1247*fcf3ce44SJohn Forte 1248*fcf3ce44SJohn Forte /* Set the link speed */ 1249*fcf3ce44SJohn Forte switch (hba->linkspeed) { 1250*fcf3ce44SJohn Forte case 0: 1251*fcf3ce44SJohn Forte (void) strcpy(linkspeed, "Gb"); 1252*fcf3ce44SJohn Forte state |= FC_STATE_1GBIT_SPEED; 1253*fcf3ce44SJohn Forte break; 1254*fcf3ce44SJohn Forte 1255*fcf3ce44SJohn Forte case LA_1GHZ_LINK: 1256*fcf3ce44SJohn Forte (void) strcpy(linkspeed, "1Gb"); 1257*fcf3ce44SJohn Forte state |= FC_STATE_1GBIT_SPEED; 1258*fcf3ce44SJohn Forte break; 1259*fcf3ce44SJohn Forte case LA_2GHZ_LINK: 1260*fcf3ce44SJohn Forte (void) strcpy(linkspeed, "2Gb"); 1261*fcf3ce44SJohn Forte state |= FC_STATE_2GBIT_SPEED; 1262*fcf3ce44SJohn Forte break; 1263*fcf3ce44SJohn Forte case LA_4GHZ_LINK: 1264*fcf3ce44SJohn Forte (void) strcpy(linkspeed, "4Gb"); 1265*fcf3ce44SJohn Forte state |= FC_STATE_4GBIT_SPEED; 1266*fcf3ce44SJohn Forte break; 1267*fcf3ce44SJohn Forte case LA_8GHZ_LINK: 1268*fcf3ce44SJohn Forte (void) strcpy(linkspeed, "8Gb"); 1269*fcf3ce44SJohn Forte state |= FC_STATE_8GBIT_SPEED; 1270*fcf3ce44SJohn Forte break; 1271*fcf3ce44SJohn Forte case LA_10GHZ_LINK: 1272*fcf3ce44SJohn Forte (void) strcpy(linkspeed, "10Gb"); 1273*fcf3ce44SJohn Forte state |= FC_STATE_10GBIT_SPEED; 1274*fcf3ce44SJohn Forte break; 1275*fcf3ce44SJohn Forte default: 1276*fcf3ce44SJohn Forte (void) sprintf(linkspeed, "unknown(0x%x)", hba->linkspeed); 1277*fcf3ce44SJohn Forte break; 1278*fcf3ce44SJohn Forte } 1279*fcf3ce44SJohn Forte 1280*fcf3ce44SJohn Forte npiv_linkup = 0; 1281*fcf3ce44SJohn Forte update = 0; 1282*fcf3ce44SJohn Forte 1283*fcf3ce44SJohn Forte if ((hba->state >= FC_LINK_UP) && 1284*fcf3ce44SJohn Forte !(hba->flag & FC_LOOPBACK_MODE) && 1285*fcf3ce44SJohn Forte (vport->ulp_statec != state)) { 1286*fcf3ce44SJohn Forte update = 1; 1287*fcf3ce44SJohn Forte vport->ulp_statec = state; 1288*fcf3ce44SJohn Forte 1289*fcf3ce44SJohn Forte if ((vport->vpi > 0) && !(hba->flag & FC_NPIV_LINKUP)) { 1290*fcf3ce44SJohn Forte hba->flag |= FC_NPIV_LINKUP; 1291*fcf3ce44SJohn Forte npiv_linkup = 1; 1292*fcf3ce44SJohn Forte } 1293*fcf3ce44SJohn Forte } 1294*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1295*fcf3ce44SJohn Forte 1296*fcf3ce44SJohn Forte /* 1297*fcf3ce44SJohn Forte * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg, "linkup_callback: 1298*fcf3ce44SJohn Forte * update=%d vpi=%d flag=%d fc_flag=%x state=%x statec=%x", update, 1299*fcf3ce44SJohn Forte * vport->vpi, npiv_linkup, hba->flag, hba->state, 1300*fcf3ce44SJohn Forte * vport->ulp_statec); 1301*fcf3ce44SJohn Forte */ 1302*fcf3ce44SJohn Forte if (update) { 1303*fcf3ce44SJohn Forte if (vport->flag & EMLXS_PORT_BOUND) { 1304*fcf3ce44SJohn Forte if (vport->vpi == 0) { 1305*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg, 1306*fcf3ce44SJohn Forte "%s%s%s", 1307*fcf3ce44SJohn Forte linkspeed, topology, mode); 1308*fcf3ce44SJohn Forte } else if (npiv_linkup) { 1309*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, 1310*fcf3ce44SJohn Forte &emlxs_npiv_link_up_msg, 1311*fcf3ce44SJohn Forte "%s%s%s", 1312*fcf3ce44SJohn Forte linkspeed, topology, mode); 1313*fcf3ce44SJohn Forte } 1314*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT 1315*fcf3ce44SJohn Forte if (vport->tgt_mode) { 1316*fcf3ce44SJohn Forte emlxs_fct_link_up(vport); 1317*fcf3ce44SJohn Forte } else if (vport->ini_mode) { 1318*fcf3ce44SJohn Forte vport->ulp_statec_cb(vport->ulp_handle, state); 1319*fcf3ce44SJohn Forte } 1320*fcf3ce44SJohn Forte #else 1321*fcf3ce44SJohn Forte vport->ulp_statec_cb(vport->ulp_handle, state); 1322*fcf3ce44SJohn Forte #endif /* SFCT_SUPPORT */ 1323*fcf3ce44SJohn Forte } else { 1324*fcf3ce44SJohn Forte if (vport->vpi == 0) { 1325*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_up_msg, 1326*fcf3ce44SJohn Forte "%s%s%s *", 1327*fcf3ce44SJohn Forte linkspeed, topology, mode); 1328*fcf3ce44SJohn Forte } else if (npiv_linkup) { 1329*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, 1330*fcf3ce44SJohn Forte &emlxs_npiv_link_up_msg, 1331*fcf3ce44SJohn Forte "%s%s%s *", 1332*fcf3ce44SJohn Forte linkspeed, topology, mode); 1333*fcf3ce44SJohn Forte } 1334*fcf3ce44SJohn Forte } 1335*fcf3ce44SJohn Forte 1336*fcf3ce44SJohn Forte /* Check for waiting threads */ 1337*fcf3ce44SJohn Forte if (vport->vpi == 0) { 1338*fcf3ce44SJohn Forte mutex_enter(&EMLXS_LINKUP_LOCK); 1339*fcf3ce44SJohn Forte if (hba->linkup_wait_flag == TRUE) { 1340*fcf3ce44SJohn Forte hba->linkup_wait_flag = FALSE; 1341*fcf3ce44SJohn Forte cv_broadcast(&EMLXS_LINKUP_CV); 1342*fcf3ce44SJohn Forte } 1343*fcf3ce44SJohn Forte mutex_exit(&EMLXS_LINKUP_LOCK); 1344*fcf3ce44SJohn Forte } 1345*fcf3ce44SJohn Forte /* Flush any pending ub buffers */ 1346*fcf3ce44SJohn Forte emlxs_ub_flush(vport); 1347*fcf3ce44SJohn Forte } 1348*fcf3ce44SJohn Forte return; 1349*fcf3ce44SJohn Forte 1350*fcf3ce44SJohn Forte } /* emlxs_port_online() */ 1351*fcf3ce44SJohn Forte 1352*fcf3ce44SJohn Forte 1353*fcf3ce44SJohn Forte extern void 1354*fcf3ce44SJohn Forte emlxs_linkdown(emlxs_hba_t *hba) 1355*fcf3ce44SJohn Forte { 1356*fcf3ce44SJohn Forte emlxs_port_t *port = &PPORT; 1357*fcf3ce44SJohn Forte int i; 1358*fcf3ce44SJohn Forte 1359*fcf3ce44SJohn Forte mutex_enter(&EMLXS_PORT_LOCK); 1360*fcf3ce44SJohn Forte 1361*fcf3ce44SJohn Forte HBASTATS.LinkDown++; 1362*fcf3ce44SJohn Forte emlxs_ffstate_change_locked(hba, FC_LINK_DOWN); 1363*fcf3ce44SJohn Forte 1364*fcf3ce44SJohn Forte /* Filter hba flags */ 1365*fcf3ce44SJohn Forte hba->flag &= FC_LINKDOWN_MASK; 1366*fcf3ce44SJohn Forte hba->discovery_timer = 0; 1367*fcf3ce44SJohn Forte hba->linkup_timer = 0; 1368*fcf3ce44SJohn Forte 1369*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1370*fcf3ce44SJohn Forte 1371*fcf3ce44SJohn Forte for (i = 0; i < MAX_VPORTS; i++) { 1372*fcf3ce44SJohn Forte port = &VPORT(i); 1373*fcf3ce44SJohn Forte 1374*fcf3ce44SJohn Forte if (!(port->flag & EMLXS_PORT_BOUND)) { 1375*fcf3ce44SJohn Forte continue; 1376*fcf3ce44SJohn Forte } 1377*fcf3ce44SJohn Forte (void) emlxs_port_offline(port, 0xffffffff); 1378*fcf3ce44SJohn Forte 1379*fcf3ce44SJohn Forte } 1380*fcf3ce44SJohn Forte 1381*fcf3ce44SJohn Forte return; 1382*fcf3ce44SJohn Forte 1383*fcf3ce44SJohn Forte } /* emlxs_linkdown() */ 1384*fcf3ce44SJohn Forte 1385*fcf3ce44SJohn Forte 1386*fcf3ce44SJohn Forte extern void 1387*fcf3ce44SJohn Forte emlxs_linkup(emlxs_hba_t *hba) 1388*fcf3ce44SJohn Forte { 1389*fcf3ce44SJohn Forte emlxs_port_t *port = &PPORT; 1390*fcf3ce44SJohn Forte emlxs_config_t *cfg = &CFG; 1391*fcf3ce44SJohn Forte 1392*fcf3ce44SJohn Forte mutex_enter(&EMLXS_PORT_LOCK); 1393*fcf3ce44SJohn Forte 1394*fcf3ce44SJohn Forte HBASTATS.LinkUp++; 1395*fcf3ce44SJohn Forte emlxs_ffstate_change_locked(hba, FC_LINK_UP); 1396*fcf3ce44SJohn Forte 1397*fcf3ce44SJohn Forte #ifdef MENLO_TEST 1398*fcf3ce44SJohn Forte if ((hba->model_info.device_id == PCI_DEVICE_ID_LP21000_M) && 1399*fcf3ce44SJohn Forte (cfg[CFG_HORNET_FLOGI].current == 0)) { 1400*fcf3ce44SJohn Forte hba->flag |= FC_MENLO_MODE; 1401*fcf3ce44SJohn Forte } 1402*fcf3ce44SJohn Forte #endif /* MENLO_TEST */ 1403*fcf3ce44SJohn Forte 1404*fcf3ce44SJohn Forte #ifdef MENLO_SUPPORT 1405*fcf3ce44SJohn Forte if (hba->flag & FC_MENLO_MODE) { 1406*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1407*fcf3ce44SJohn Forte 1408*fcf3ce44SJohn Forte /* 1409*fcf3ce44SJohn Forte * Trigger linkup CV and don't start linkup & discovery 1410*fcf3ce44SJohn Forte * timers 1411*fcf3ce44SJohn Forte */ 1412*fcf3ce44SJohn Forte mutex_enter(&EMLXS_LINKUP_LOCK); 1413*fcf3ce44SJohn Forte cv_broadcast(&EMLXS_LINKUP_CV); 1414*fcf3ce44SJohn Forte mutex_exit(&EMLXS_LINKUP_LOCK); 1415*fcf3ce44SJohn Forte 1416*fcf3ce44SJohn Forte return; 1417*fcf3ce44SJohn Forte } 1418*fcf3ce44SJohn Forte #endif /* MENLO_SUPPORT */ 1419*fcf3ce44SJohn Forte 1420*fcf3ce44SJohn Forte /* Set the linkup & discovery timers */ 1421*fcf3ce44SJohn Forte hba->linkup_timer = hba->timer_tics + cfg[CFG_LINKUP_TIMEOUT].current; 1422*fcf3ce44SJohn Forte hba->discovery_timer = hba->timer_tics + 1423*fcf3ce44SJohn Forte cfg[CFG_LINKUP_TIMEOUT].current + cfg[CFG_DISC_TIMEOUT].current; 1424*fcf3ce44SJohn Forte 1425*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1426*fcf3ce44SJohn Forte 1427*fcf3ce44SJohn Forte return; 1428*fcf3ce44SJohn Forte 1429*fcf3ce44SJohn Forte } /* emlxs_linkup() */ 1430*fcf3ce44SJohn Forte 1431*fcf3ce44SJohn Forte 1432*fcf3ce44SJohn Forte /* 1433*fcf3ce44SJohn Forte * emlxs_reset_link 1434*fcf3ce44SJohn Forte * 1435*fcf3ce44SJohn Forte * Description: 1436*fcf3ce44SJohn Forte * Called to reset the link with an init_link 1437*fcf3ce44SJohn Forte * 1438*fcf3ce44SJohn Forte * Returns: 1439*fcf3ce44SJohn Forte * 1440*fcf3ce44SJohn Forte */ 1441*fcf3ce44SJohn Forte extern int 1442*fcf3ce44SJohn Forte emlxs_reset_link(emlxs_hba_t *hba, uint32_t linkup) 1443*fcf3ce44SJohn Forte { 1444*fcf3ce44SJohn Forte emlxs_port_t *port = &PPORT; 1445*fcf3ce44SJohn Forte emlxs_config_t *cfg; 1446*fcf3ce44SJohn Forte MAILBOX *mb; 1447*fcf3ce44SJohn Forte 1448*fcf3ce44SJohn Forte /* 1449*fcf3ce44SJohn Forte * Get a buffer to use for the mailbox command 1450*fcf3ce44SJohn Forte */ 1451*fcf3ce44SJohn Forte if ((mb = (MAILBOX *)emlxs_mem_get(hba, MEM_MBOX | MEM_PRI)) == NULL) { 1452*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_failed_msg, 1453*fcf3ce44SJohn Forte "Unable to allocate mailbox buffer."); 1454*fcf3ce44SJohn Forte 1455*fcf3ce44SJohn Forte return (1); 1456*fcf3ce44SJohn Forte } 1457*fcf3ce44SJohn Forte cfg = &CFG; 1458*fcf3ce44SJohn Forte 1459*fcf3ce44SJohn Forte if (linkup) { 1460*fcf3ce44SJohn Forte /* 1461*fcf3ce44SJohn Forte * Setup and issue mailbox INITIALIZE LINK command 1462*fcf3ce44SJohn Forte */ 1463*fcf3ce44SJohn Forte 1464*fcf3ce44SJohn Forte emlxs_mb_init_link(hba, (MAILBOX *)mb, 1465*fcf3ce44SJohn Forte cfg[CFG_TOPOLOGY].current, cfg[CFG_LINK_SPEED].current); 1466*fcf3ce44SJohn Forte 1467*fcf3ce44SJohn Forte mb->un.varInitLnk.lipsr_AL_PA = 0; 1468*fcf3ce44SJohn Forte 1469*fcf3ce44SJohn Forte /* Clear the loopback mode */ 1470*fcf3ce44SJohn Forte mutex_enter(&EMLXS_PORT_LOCK); 1471*fcf3ce44SJohn Forte hba->flag &= ~FC_LOOPBACK_MODE; 1472*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1473*fcf3ce44SJohn Forte 1474*fcf3ce44SJohn Forte if (emlxs_mb_issue_cmd(hba, (MAILBOX *)mb, 1475*fcf3ce44SJohn Forte MBX_NOWAIT, 0) != MBX_BUSY) { 1476*fcf3ce44SJohn Forte (void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb); 1477*fcf3ce44SJohn Forte } 1478*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg, NULL); 1479*fcf3ce44SJohn Forte 1480*fcf3ce44SJohn Forte } else { /* hold link down */ 1481*fcf3ce44SJohn Forte emlxs_mb_down_link(hba, (MAILBOX *)mb); 1482*fcf3ce44SJohn Forte 1483*fcf3ce44SJohn Forte if (emlxs_mb_issue_cmd(hba, (MAILBOX *)mb, 1484*fcf3ce44SJohn Forte MBX_NOWAIT, 0) != MBX_BUSY) { 1485*fcf3ce44SJohn Forte (void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb); 1486*fcf3ce44SJohn Forte } 1487*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_link_reset_msg, 1488*fcf3ce44SJohn Forte "Disabling link..."); 1489*fcf3ce44SJohn Forte } 1490*fcf3ce44SJohn Forte 1491*fcf3ce44SJohn Forte return (0); 1492*fcf3ce44SJohn Forte 1493*fcf3ce44SJohn Forte } /* emlxs_reset_link() */ 1494*fcf3ce44SJohn Forte 1495*fcf3ce44SJohn Forte 1496*fcf3ce44SJohn Forte extern int 1497*fcf3ce44SJohn Forte emlxs_online(emlxs_hba_t *hba) 1498*fcf3ce44SJohn Forte { 1499*fcf3ce44SJohn Forte emlxs_port_t *port = &PPORT; 1500*fcf3ce44SJohn Forte int32_t rval = 0; 1501*fcf3ce44SJohn Forte uint32_t i = 0; 1502*fcf3ce44SJohn Forte 1503*fcf3ce44SJohn Forte /* Make sure adapter is offline or exit trying (30 seconds) */ 1504*fcf3ce44SJohn Forte for (; ; ) { 1505*fcf3ce44SJohn Forte /* Check if adapter is already going online */ 1506*fcf3ce44SJohn Forte if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) { 1507*fcf3ce44SJohn Forte return (0); 1508*fcf3ce44SJohn Forte } 1509*fcf3ce44SJohn Forte mutex_enter(&EMLXS_PORT_LOCK); 1510*fcf3ce44SJohn Forte 1511*fcf3ce44SJohn Forte /* Check again */ 1512*fcf3ce44SJohn Forte if (hba->flag & (FC_ONLINE_MODE | FC_ONLINING_MODE)) { 1513*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1514*fcf3ce44SJohn Forte return (0); 1515*fcf3ce44SJohn Forte } 1516*fcf3ce44SJohn Forte /* Check if adapter is offline */ 1517*fcf3ce44SJohn Forte if (hba->flag & FC_OFFLINE_MODE) { 1518*fcf3ce44SJohn Forte /* Mark it going online */ 1519*fcf3ce44SJohn Forte hba->flag &= ~FC_OFFLINE_MODE; 1520*fcf3ce44SJohn Forte hba->flag |= FC_ONLINING_MODE; 1521*fcf3ce44SJohn Forte 1522*fcf3ce44SJohn Forte /* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */ 1523*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1524*fcf3ce44SJohn Forte break; 1525*fcf3ce44SJohn Forte } 1526*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1527*fcf3ce44SJohn Forte 1528*fcf3ce44SJohn Forte if (i++ > 30) { 1529*fcf3ce44SJohn Forte /* Return on timeout */ 1530*fcf3ce44SJohn Forte return (1); 1531*fcf3ce44SJohn Forte } 1532*fcf3ce44SJohn Forte DELAYMS(1000); 1533*fcf3ce44SJohn Forte } 1534*fcf3ce44SJohn Forte 1535*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg, 1536*fcf3ce44SJohn Forte "Going online..."); 1537*fcf3ce44SJohn Forte 1538*fcf3ce44SJohn Forte if (hba->bus_type == SBUS_FC) { 1539*fcf3ce44SJohn Forte (void) READ_SBUS_CSR_REG(hba, FC_SHS_REG(hba, 1540*fcf3ce44SJohn Forte hba->sbus_csr_addr)); 1541*fcf3ce44SJohn Forte } 1542*fcf3ce44SJohn Forte if (rval = emlxs_ffinit(hba)) { 1543*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_failed_msg, 1544*fcf3ce44SJohn Forte "status=%x", 1545*fcf3ce44SJohn Forte rval); 1546*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL); 1547*fcf3ce44SJohn Forte 1548*fcf3ce44SJohn Forte /* Set FC_OFFLINE_MODE */ 1549*fcf3ce44SJohn Forte mutex_enter(&EMLXS_PORT_LOCK); 1550*fcf3ce44SJohn Forte emlxs_diag_state = DDI_OFFDI; 1551*fcf3ce44SJohn Forte hba->flag |= FC_OFFLINE_MODE; 1552*fcf3ce44SJohn Forte hba->flag &= ~FC_ONLINING_MODE; 1553*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1554*fcf3ce44SJohn Forte 1555*fcf3ce44SJohn Forte return (rval); 1556*fcf3ce44SJohn Forte } 1557*fcf3ce44SJohn Forte /* Start the timer */ 1558*fcf3ce44SJohn Forte emlxs_timer_start(hba); 1559*fcf3ce44SJohn Forte 1560*fcf3ce44SJohn Forte /* Set FC_ONLINE_MODE */ 1561*fcf3ce44SJohn Forte mutex_enter(&EMLXS_PORT_LOCK); 1562*fcf3ce44SJohn Forte emlxs_diag_state = DDI_ONDI; 1563*fcf3ce44SJohn Forte hba->flag |= FC_ONLINE_MODE; 1564*fcf3ce44SJohn Forte hba->flag &= ~FC_ONLINING_MODE; 1565*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1566*fcf3ce44SJohn Forte 1567*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_online_msg, NULL); 1568*fcf3ce44SJohn Forte 1569*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT 1570*fcf3ce44SJohn Forte (void) emlxs_fct_port_initialize(port); 1571*fcf3ce44SJohn Forte #endif /* SFCT_SUPPORT */ 1572*fcf3ce44SJohn Forte 1573*fcf3ce44SJohn Forte return (rval); 1574*fcf3ce44SJohn Forte 1575*fcf3ce44SJohn Forte } /* emlxs_online() */ 1576*fcf3ce44SJohn Forte 1577*fcf3ce44SJohn Forte 1578*fcf3ce44SJohn Forte extern int 1579*fcf3ce44SJohn Forte emlxs_offline(emlxs_hba_t *hba) 1580*fcf3ce44SJohn Forte { 1581*fcf3ce44SJohn Forte emlxs_port_t *port = &PPORT; 1582*fcf3ce44SJohn Forte uint32_t i = 0; 1583*fcf3ce44SJohn Forte int rval = 1; 1584*fcf3ce44SJohn Forte 1585*fcf3ce44SJohn Forte /* Make sure adapter is online or exit trying (30 seconds) */ 1586*fcf3ce44SJohn Forte for (; ; ) { 1587*fcf3ce44SJohn Forte /* Check if adapter is already going offline */ 1588*fcf3ce44SJohn Forte if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) { 1589*fcf3ce44SJohn Forte return (0); 1590*fcf3ce44SJohn Forte } 1591*fcf3ce44SJohn Forte mutex_enter(&EMLXS_PORT_LOCK); 1592*fcf3ce44SJohn Forte 1593*fcf3ce44SJohn Forte /* Check again */ 1594*fcf3ce44SJohn Forte if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) { 1595*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1596*fcf3ce44SJohn Forte return (0); 1597*fcf3ce44SJohn Forte } 1598*fcf3ce44SJohn Forte /* Check if adapter is online */ 1599*fcf3ce44SJohn Forte if (hba->flag & FC_ONLINE_MODE) { 1600*fcf3ce44SJohn Forte /* Mark it going offline */ 1601*fcf3ce44SJohn Forte hba->flag &= ~FC_ONLINE_MODE; 1602*fcf3ce44SJohn Forte hba->flag |= FC_OFFLINING_MODE; 1603*fcf3ce44SJohn Forte 1604*fcf3ce44SJohn Forte /* Currently !FC_ONLINE_MODE and !FC_OFFLINE_MODE */ 1605*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1606*fcf3ce44SJohn Forte break; 1607*fcf3ce44SJohn Forte } 1608*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1609*fcf3ce44SJohn Forte 1610*fcf3ce44SJohn Forte if (i++ > 30) { 1611*fcf3ce44SJohn Forte /* Return on timeout */ 1612*fcf3ce44SJohn Forte return (1); 1613*fcf3ce44SJohn Forte } 1614*fcf3ce44SJohn Forte DELAYMS(1000); 1615*fcf3ce44SJohn Forte } 1616*fcf3ce44SJohn Forte 1617*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_trans_msg, "Going offline..."); 1618*fcf3ce44SJohn Forte 1619*fcf3ce44SJohn Forte if (port->ini_mode) { 1620*fcf3ce44SJohn Forte /* Flush all IO */ 1621*fcf3ce44SJohn Forte emlxs_linkdown(hba); 1622*fcf3ce44SJohn Forte 1623*fcf3ce44SJohn Forte } 1624*fcf3ce44SJohn Forte #ifdef SFCT_SUPPORT 1625*fcf3ce44SJohn Forte else { 1626*fcf3ce44SJohn Forte (void) emlxs_fct_port_shutdown(port); 1627*fcf3ce44SJohn Forte } 1628*fcf3ce44SJohn Forte #endif /* SFCT_SUPPORT */ 1629*fcf3ce44SJohn Forte 1630*fcf3ce44SJohn Forte /* Check if adapter was shutdown */ 1631*fcf3ce44SJohn Forte if (hba->flag & FC_HARDWARE_ERROR) { 1632*fcf3ce44SJohn Forte /* Force mailbox cleanup */ 1633*fcf3ce44SJohn Forte /* This will wake any sleeping or polling threads */ 1634*fcf3ce44SJohn Forte emlxs_mb_fini(hba, NULL, MBX_HARDWARE_ERROR); 1635*fcf3ce44SJohn Forte } 1636*fcf3ce44SJohn Forte /* Pause here for the IO to settle */ 1637*fcf3ce44SJohn Forte delay(drv_usectohz(1000000)); /* 1 sec */ 1638*fcf3ce44SJohn Forte 1639*fcf3ce44SJohn Forte /* Unregister all nodes */ 1640*fcf3ce44SJohn Forte emlxs_ffcleanup(hba); 1641*fcf3ce44SJohn Forte 1642*fcf3ce44SJohn Forte 1643*fcf3ce44SJohn Forte if (hba->bus_type == SBUS_FC) { 1644*fcf3ce44SJohn Forte WRITE_SBUS_CSR_REG(hba, 1645*fcf3ce44SJohn Forte FC_SHS_REG(hba, hba->sbus_csr_addr), 0x9A); 1646*fcf3ce44SJohn Forte } 1647*fcf3ce44SJohn Forte /* Stop the timer */ 1648*fcf3ce44SJohn Forte emlxs_timer_stop(hba); 1649*fcf3ce44SJohn Forte 1650*fcf3ce44SJohn Forte /* For safety flush every iotag list */ 1651*fcf3ce44SJohn Forte if (emlxs_iotag_flush(hba)) { 1652*fcf3ce44SJohn Forte /* Pause here for the IO to flush */ 1653*fcf3ce44SJohn Forte DELAYMS(1000); 1654*fcf3ce44SJohn Forte } 1655*fcf3ce44SJohn Forte /* Interlock the adapter to take it down */ 1656*fcf3ce44SJohn Forte (void) emlxs_interlock(hba); 1657*fcf3ce44SJohn Forte 1658*fcf3ce44SJohn Forte /* Free all the shared memory */ 1659*fcf3ce44SJohn Forte (void) emlxs_mem_free_buffer(hba); 1660*fcf3ce44SJohn Forte 1661*fcf3ce44SJohn Forte mutex_enter(&EMLXS_PORT_LOCK); 1662*fcf3ce44SJohn Forte hba->flag |= FC_OFFLINE_MODE; 1663*fcf3ce44SJohn Forte hba->flag &= ~FC_OFFLINING_MODE; 1664*fcf3ce44SJohn Forte emlxs_diag_state = DDI_OFFDI; 1665*fcf3ce44SJohn Forte mutex_exit(&EMLXS_PORT_LOCK); 1666*fcf3ce44SJohn Forte 1667*fcf3ce44SJohn Forte rval = 0; 1668*fcf3ce44SJohn Forte 1669*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_offline_msg, NULL); 1670*fcf3ce44SJohn Forte 1671*fcf3ce44SJohn Forte done: 1672*fcf3ce44SJohn Forte 1673*fcf3ce44SJohn Forte return (rval); 1674*fcf3ce44SJohn Forte 1675*fcf3ce44SJohn Forte } /* emlxs_offline() */ 1676*fcf3ce44SJohn Forte 1677*fcf3ce44SJohn Forte 1678*fcf3ce44SJohn Forte 1679*fcf3ce44SJohn Forte extern int 1680*fcf3ce44SJohn Forte emlxs_power_down(emlxs_hba_t *hba) 1681*fcf3ce44SJohn Forte { 1682*fcf3ce44SJohn Forte int32_t rval = 0; 1683*fcf3ce44SJohn Forte uint32_t *ptr; 1684*fcf3ce44SJohn Forte uint32_t i; 1685*fcf3ce44SJohn Forte 1686*fcf3ce44SJohn Forte if ((rval = emlxs_offline(hba))) { 1687*fcf3ce44SJohn Forte return (rval); 1688*fcf3ce44SJohn Forte } 1689*fcf3ce44SJohn Forte /* Save pci config space */ 1690*fcf3ce44SJohn Forte ptr = (uint32_t *)hba->pm_config; 1691*fcf3ce44SJohn Forte for (i = 0; i < PCI_CONFIG_SIZE; i += 4, ptr++) { 1692*fcf3ce44SJohn Forte *ptr = ddi_get32(hba->pci_acc_handle, 1693*fcf3ce44SJohn Forte (uint32_t *)(hba->pci_addr + i)); 1694*fcf3ce44SJohn Forte } 1695*fcf3ce44SJohn Forte 1696*fcf3ce44SJohn Forte /* Put chip in D3 state */ 1697*fcf3ce44SJohn Forte (void) ddi_put8(hba->pci_acc_handle, 1698*fcf3ce44SJohn Forte (uint8_t *)(hba->pci_addr + PCI_PM_CONTROL_REGISTER), 1699*fcf3ce44SJohn Forte (uint8_t)PCI_PM_D3_STATE); 1700*fcf3ce44SJohn Forte 1701*fcf3ce44SJohn Forte return (0); 1702*fcf3ce44SJohn Forte 1703*fcf3ce44SJohn Forte } /* End emlxs_power_down */ 1704*fcf3ce44SJohn Forte 1705*fcf3ce44SJohn Forte 1706*fcf3ce44SJohn Forte extern int 1707*fcf3ce44SJohn Forte emlxs_power_up(emlxs_hba_t *hba) 1708*fcf3ce44SJohn Forte { 1709*fcf3ce44SJohn Forte int32_t rval = 0; 1710*fcf3ce44SJohn Forte uint32_t *ptr; 1711*fcf3ce44SJohn Forte uint32_t i; 1712*fcf3ce44SJohn Forte 1713*fcf3ce44SJohn Forte 1714*fcf3ce44SJohn Forte /* Take chip out of D3 state */ 1715*fcf3ce44SJohn Forte (void) ddi_put8(hba->pci_acc_handle, 1716*fcf3ce44SJohn Forte (uint8_t *)(hba->pci_addr + PCI_PM_CONTROL_REGISTER), 1717*fcf3ce44SJohn Forte (uint8_t)PCI_PM_D0_STATE); 1718*fcf3ce44SJohn Forte 1719*fcf3ce44SJohn Forte /* Must have at least 10 ms delay here */ 1720*fcf3ce44SJohn Forte DELAYMS(100); 1721*fcf3ce44SJohn Forte 1722*fcf3ce44SJohn Forte /* Restore pci config space */ 1723*fcf3ce44SJohn Forte ptr = (uint32_t *)hba->pm_config; 1724*fcf3ce44SJohn Forte for (i = 0; i < PCI_CONFIG_SIZE; i += 4, ptr++) { 1725*fcf3ce44SJohn Forte (void) ddi_put32(hba->pci_acc_handle, 1726*fcf3ce44SJohn Forte (uint32_t *)(hba->pci_addr + i), *ptr); 1727*fcf3ce44SJohn Forte } 1728*fcf3ce44SJohn Forte 1729*fcf3ce44SJohn Forte /* Bring adapter online */ 1730*fcf3ce44SJohn Forte if ((rval = emlxs_online(hba))) { 1731*fcf3ce44SJohn Forte (void) ddi_put8(hba->pci_acc_handle, 1732*fcf3ce44SJohn Forte (uint8_t *)(hba->pci_addr + PCI_PM_CONTROL_REGISTER), 1733*fcf3ce44SJohn Forte (uint8_t)PCI_PM_D3_STATE); 1734*fcf3ce44SJohn Forte 1735*fcf3ce44SJohn Forte return (rval); 1736*fcf3ce44SJohn Forte } 1737*fcf3ce44SJohn Forte return (rval); 1738*fcf3ce44SJohn Forte 1739*fcf3ce44SJohn Forte } /* End emlxs_power_up */ 1740*fcf3ce44SJohn Forte 1741*fcf3ce44SJohn Forte 1742*fcf3ce44SJohn Forte /* 1743*fcf3ce44SJohn Forte * NAME: emlxs_ffcleanup 1744*fcf3ce44SJohn Forte * 1745*fcf3ce44SJohn Forte * FUNCTION: Cleanup all the Firefly resources used by configuring the adapter 1746*fcf3ce44SJohn Forte * 1747*fcf3ce44SJohn Forte * EXECUTION ENVIRONMENT: process only 1748*fcf3ce44SJohn Forte * 1749*fcf3ce44SJohn Forte * CALLED FROM: CFG_TERM 1750*fcf3ce44SJohn Forte * 1751*fcf3ce44SJohn Forte * INPUT: hba - pointer to the dev_ctl area. 1752*fcf3ce44SJohn Forte * 1753*fcf3ce44SJohn Forte * RETURNS: none 1754*fcf3ce44SJohn Forte */ 1755*fcf3ce44SJohn Forte extern void 1756*fcf3ce44SJohn Forte emlxs_ffcleanup(emlxs_hba_t *hba) 1757*fcf3ce44SJohn Forte { 1758*fcf3ce44SJohn Forte emlxs_port_t *port = &PPORT; 1759*fcf3ce44SJohn Forte uint32_t j; 1760*fcf3ce44SJohn Forte 1761*fcf3ce44SJohn Forte /* Disable all but the mailbox interrupt */ 1762*fcf3ce44SJohn Forte hba->hc_copy = HC_MBINT_ENA; 1763*fcf3ce44SJohn Forte WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr), hba->hc_copy); 1764*fcf3ce44SJohn Forte 1765*fcf3ce44SJohn Forte /* Make sure all port nodes are destroyed */ 1766*fcf3ce44SJohn Forte for (j = 0; j < MAX_VPORTS; j++) { 1767*fcf3ce44SJohn Forte port = &VPORT(j); 1768*fcf3ce44SJohn Forte 1769*fcf3ce44SJohn Forte if (port->node_count) { 1770*fcf3ce44SJohn Forte (void) emlxs_mb_unreg_rpi(port, 0xffff, 0, 0, 0); 1771*fcf3ce44SJohn Forte } 1772*fcf3ce44SJohn Forte } 1773*fcf3ce44SJohn Forte 1774*fcf3ce44SJohn Forte /* Clear all interrupt enable conditions */ 1775*fcf3ce44SJohn Forte hba->hc_copy = 0; 1776*fcf3ce44SJohn Forte WRITE_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr), hba->hc_copy); 1777*fcf3ce44SJohn Forte 1778*fcf3ce44SJohn Forte return; 1779*fcf3ce44SJohn Forte 1780*fcf3ce44SJohn Forte } /* emlxs_ffcleanup() */ 1781*fcf3ce44SJohn Forte 1782*fcf3ce44SJohn Forte 1783*fcf3ce44SJohn Forte extern uint16_t 1784*fcf3ce44SJohn Forte emlxs_register_pkt(RING *rp, emlxs_buf_t *sbp) 1785*fcf3ce44SJohn Forte { 1786*fcf3ce44SJohn Forte emlxs_hba_t *hba; 1787*fcf3ce44SJohn Forte emlxs_port_t *port; 1788*fcf3ce44SJohn Forte uint16_t iotag; 1789*fcf3ce44SJohn Forte uint32_t i; 1790*fcf3ce44SJohn Forte 1791*fcf3ce44SJohn Forte hba = rp->hba; 1792*fcf3ce44SJohn Forte 1793*fcf3ce44SJohn Forte mutex_enter(&EMLXS_FCTAB_LOCK(rp->ringno)); 1794*fcf3ce44SJohn Forte 1795*fcf3ce44SJohn Forte if (sbp->iotag != 0) { 1796*fcf3ce44SJohn Forte port = &PPORT; 1797*fcf3ce44SJohn Forte 1798*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg, 1799*fcf3ce44SJohn Forte "Pkt already registered! ringo=%d iotag=%d sbp=%p", 1800*fcf3ce44SJohn Forte sbp->ring, sbp->iotag, sbp); 1801*fcf3ce44SJohn Forte } 1802*fcf3ce44SJohn Forte iotag = 0; 1803*fcf3ce44SJohn Forte for (i = 0; i < rp->max_iotag; i++) { 1804*fcf3ce44SJohn Forte if (!rp->fc_iotag || rp->fc_iotag >= rp->max_iotag) { 1805*fcf3ce44SJohn Forte rp->fc_iotag = 1; 1806*fcf3ce44SJohn Forte } 1807*fcf3ce44SJohn Forte iotag = rp->fc_iotag++; 1808*fcf3ce44SJohn Forte 1809*fcf3ce44SJohn Forte if (rp->fc_table[iotag] == 0 || 1810*fcf3ce44SJohn Forte rp->fc_table[iotag] == STALE_PACKET) { 1811*fcf3ce44SJohn Forte hba->io_count[rp->ringno]++; 1812*fcf3ce44SJohn Forte rp->fc_table[iotag] = sbp; 1813*fcf3ce44SJohn Forte 1814*fcf3ce44SJohn Forte sbp->iotag = iotag; 1815*fcf3ce44SJohn Forte sbp->ring = rp; 1816*fcf3ce44SJohn Forte 1817*fcf3ce44SJohn Forte break; 1818*fcf3ce44SJohn Forte } 1819*fcf3ce44SJohn Forte iotag = 0; 1820*fcf3ce44SJohn Forte } 1821*fcf3ce44SJohn Forte 1822*fcf3ce44SJohn Forte mutex_exit(&EMLXS_FCTAB_LOCK(rp->ringno)); 1823*fcf3ce44SJohn Forte 1824*fcf3ce44SJohn Forte /* 1825*fcf3ce44SJohn Forte * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg, 1826*fcf3ce44SJohn Forte * "emlxs_register_pkt: ringo=%d iotag=%d sbp=%p", rp->ringno, iotag, 1827*fcf3ce44SJohn Forte * sbp); 1828*fcf3ce44SJohn Forte */ 1829*fcf3ce44SJohn Forte 1830*fcf3ce44SJohn Forte return (iotag); 1831*fcf3ce44SJohn Forte 1832*fcf3ce44SJohn Forte } /* emlxs_register_pkt() */ 1833*fcf3ce44SJohn Forte 1834*fcf3ce44SJohn Forte 1835*fcf3ce44SJohn Forte 1836*fcf3ce44SJohn Forte extern emlxs_buf_t * 1837*fcf3ce44SJohn Forte emlxs_unregister_pkt(RING *rp, uint16_t iotag, uint32_t forced) 1838*fcf3ce44SJohn Forte { 1839*fcf3ce44SJohn Forte emlxs_hba_t *hba; 1840*fcf3ce44SJohn Forte emlxs_buf_t *sbp; 1841*fcf3ce44SJohn Forte uint32_t ringno; 1842*fcf3ce44SJohn Forte 1843*fcf3ce44SJohn Forte /* Check the iotag range */ 1844*fcf3ce44SJohn Forte if ((iotag == 0) || (iotag >= rp->max_iotag)) { 1845*fcf3ce44SJohn Forte return (NULL); 1846*fcf3ce44SJohn Forte } 1847*fcf3ce44SJohn Forte sbp = NULL; 1848*fcf3ce44SJohn Forte hba = rp->hba; 1849*fcf3ce44SJohn Forte ringno = rp->ringno; 1850*fcf3ce44SJohn Forte 1851*fcf3ce44SJohn Forte /* Remove the sbp from the table */ 1852*fcf3ce44SJohn Forte mutex_enter(&EMLXS_FCTAB_LOCK(ringno)); 1853*fcf3ce44SJohn Forte sbp = rp->fc_table[iotag]; 1854*fcf3ce44SJohn Forte 1855*fcf3ce44SJohn Forte if (!sbp || (sbp == STALE_PACKET)) { 1856*fcf3ce44SJohn Forte mutex_exit(&EMLXS_FCTAB_LOCK(ringno)); 1857*fcf3ce44SJohn Forte return (sbp); 1858*fcf3ce44SJohn Forte } 1859*fcf3ce44SJohn Forte rp->fc_table[iotag] = ((forced) ? STALE_PACKET : NULL); 1860*fcf3ce44SJohn Forte hba->io_count[ringno]--; 1861*fcf3ce44SJohn Forte sbp->iotag = 0; 1862*fcf3ce44SJohn Forte 1863*fcf3ce44SJohn Forte mutex_exit(&EMLXS_FCTAB_LOCK(ringno)); 1864*fcf3ce44SJohn Forte 1865*fcf3ce44SJohn Forte 1866*fcf3ce44SJohn Forte /* Clean up the sbp */ 1867*fcf3ce44SJohn Forte mutex_enter(&sbp->mtx); 1868*fcf3ce44SJohn Forte 1869*fcf3ce44SJohn Forte if (sbp->pkt_flags & PACKET_IN_TXQ) { 1870*fcf3ce44SJohn Forte sbp->pkt_flags &= ~PACKET_IN_TXQ; 1871*fcf3ce44SJohn Forte hba->ring_tx_count[ringno]--; 1872*fcf3ce44SJohn Forte } 1873*fcf3ce44SJohn Forte if (sbp->pkt_flags & PACKET_IN_CHIPQ) { 1874*fcf3ce44SJohn Forte sbp->pkt_flags &= ~PACKET_IN_CHIPQ; 1875*fcf3ce44SJohn Forte } 1876*fcf3ce44SJohn Forte if (sbp->bmp) { 1877*fcf3ce44SJohn Forte (void) emlxs_mem_put(hba, MEM_BPL, (uint8_t *)sbp->bmp); 1878*fcf3ce44SJohn Forte sbp->bmp = 0; 1879*fcf3ce44SJohn Forte } 1880*fcf3ce44SJohn Forte mutex_exit(&sbp->mtx); 1881*fcf3ce44SJohn Forte 1882*fcf3ce44SJohn Forte 1883*fcf3ce44SJohn Forte /* 1884*fcf3ce44SJohn Forte * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg, 1885*fcf3ce44SJohn Forte * "emlxs_unregister_pkt: ringo=%d iotag=%d sbp=%p", rp->ringno, 1886*fcf3ce44SJohn Forte * iotag, sbp); 1887*fcf3ce44SJohn Forte */ 1888*fcf3ce44SJohn Forte 1889*fcf3ce44SJohn Forte return (sbp); 1890*fcf3ce44SJohn Forte 1891*fcf3ce44SJohn Forte } /* emlxs_unregister_pkt() */ 1892*fcf3ce44SJohn Forte 1893*fcf3ce44SJohn Forte 1894*fcf3ce44SJohn Forte 1895*fcf3ce44SJohn Forte /* Flush all IO's to all nodes for a given ring */ 1896*fcf3ce44SJohn Forte extern uint32_t 1897*fcf3ce44SJohn Forte emlxs_tx_ring_flush(emlxs_hba_t *hba, RING *rp, emlxs_buf_t *fpkt) 1898*fcf3ce44SJohn Forte { 1899*fcf3ce44SJohn Forte emlxs_port_t *port = &PPORT; 1900*fcf3ce44SJohn Forte emlxs_buf_t *sbp; 1901*fcf3ce44SJohn Forte IOCBQ *iocbq; 1902*fcf3ce44SJohn Forte IOCBQ *next; 1903*fcf3ce44SJohn Forte IOCB *iocb; 1904*fcf3ce44SJohn Forte uint32_t ringno; 1905*fcf3ce44SJohn Forte Q abort; 1906*fcf3ce44SJohn Forte NODELIST *ndlp; 1907*fcf3ce44SJohn Forte IOCB *icmd; 1908*fcf3ce44SJohn Forte MATCHMAP *mp; 1909*fcf3ce44SJohn Forte uint32_t i; 1910*fcf3ce44SJohn Forte 1911*fcf3ce44SJohn Forte ringno = rp->ringno; 1912*fcf3ce44SJohn Forte bzero((void *)&abort, sizeof (Q)); 1913*fcf3ce44SJohn Forte 1914*fcf3ce44SJohn Forte mutex_enter(&EMLXS_RINGTX_LOCK); 1915*fcf3ce44SJohn Forte 1916*fcf3ce44SJohn Forte /* While a node needs servicing */ 1917*fcf3ce44SJohn Forte while (rp->nodeq.q_first) { 1918*fcf3ce44SJohn Forte ndlp = (NODELIST *)rp->nodeq.q_first; 1919*fcf3ce44SJohn Forte 1920*fcf3ce44SJohn Forte /* Check if priority queue is not empty */ 1921*fcf3ce44SJohn Forte if (ndlp->nlp_ptx[ringno].q_first) { 1922*fcf3ce44SJohn Forte /* Transfer all iocb's to local queue */ 1923*fcf3ce44SJohn Forte if (abort.q_first == 0) { 1924*fcf3ce44SJohn Forte abort.q_first = ndlp->nlp_ptx[ringno].q_first; 1925*fcf3ce44SJohn Forte abort.q_last = ndlp->nlp_ptx[ringno].q_last; 1926*fcf3ce44SJohn Forte } else { 1927*fcf3ce44SJohn Forte ((IOCBQ *)abort.q_last)->next = 1928*fcf3ce44SJohn Forte (IOCBQ *)ndlp->nlp_ptx[ringno].q_first; 1929*fcf3ce44SJohn Forte } 1930*fcf3ce44SJohn Forte 1931*fcf3ce44SJohn Forte abort.q_cnt += ndlp->nlp_ptx[ringno].q_cnt; 1932*fcf3ce44SJohn Forte } 1933*fcf3ce44SJohn Forte /* Check if tx queue is not empty */ 1934*fcf3ce44SJohn Forte if (ndlp->nlp_tx[ringno].q_first) { 1935*fcf3ce44SJohn Forte /* Transfer all iocb's to local queue */ 1936*fcf3ce44SJohn Forte if (abort.q_first == 0) { 1937*fcf3ce44SJohn Forte abort.q_first = ndlp->nlp_tx[ringno].q_first; 1938*fcf3ce44SJohn Forte abort.q_last = ndlp->nlp_tx[ringno].q_last; 1939*fcf3ce44SJohn Forte } else { 1940*fcf3ce44SJohn Forte ((IOCBQ *)abort.q_last)->next = 1941*fcf3ce44SJohn Forte (IOCBQ *)ndlp->nlp_tx[ringno].q_first; 1942*fcf3ce44SJohn Forte } 1943*fcf3ce44SJohn Forte 1944*fcf3ce44SJohn Forte abort.q_cnt += ndlp->nlp_tx[ringno].q_cnt; 1945*fcf3ce44SJohn Forte 1946*fcf3ce44SJohn Forte } 1947*fcf3ce44SJohn Forte /* Clear the queue pointers */ 1948*fcf3ce44SJohn Forte ndlp->nlp_ptx[ringno].q_first = NULL; 1949*fcf3ce44SJohn Forte ndlp->nlp_ptx[ringno].q_last = NULL; 1950*fcf3ce44SJohn Forte ndlp->nlp_ptx[ringno].q_cnt = 0; 1951*fcf3ce44SJohn Forte 1952*fcf3ce44SJohn Forte ndlp->nlp_tx[ringno].q_first = NULL; 1953*fcf3ce44SJohn Forte ndlp->nlp_tx[ringno].q_last = NULL; 1954*fcf3ce44SJohn Forte ndlp->nlp_tx[ringno].q_cnt = 0; 1955*fcf3ce44SJohn Forte 1956*fcf3ce44SJohn Forte /* Remove node from service queue */ 1957*fcf3ce44SJohn Forte 1958*fcf3ce44SJohn Forte /* If this is the last node on list */ 1959*fcf3ce44SJohn Forte if (rp->nodeq.q_last == (void *)ndlp) { 1960*fcf3ce44SJohn Forte rp->nodeq.q_last = NULL; 1961*fcf3ce44SJohn Forte rp->nodeq.q_first = NULL; 1962*fcf3ce44SJohn Forte rp->nodeq.q_cnt = 0; 1963*fcf3ce44SJohn Forte } else { 1964*fcf3ce44SJohn Forte /* Remove node from head */ 1965*fcf3ce44SJohn Forte rp->nodeq.q_first = ndlp->nlp_next[ringno]; 1966*fcf3ce44SJohn Forte ((NODELIST *)rp->nodeq.q_last)->nlp_next[ringno] = 1967*fcf3ce44SJohn Forte rp->nodeq.q_first; 1968*fcf3ce44SJohn Forte rp->nodeq.q_cnt--; 1969*fcf3ce44SJohn Forte } 1970*fcf3ce44SJohn Forte 1971*fcf3ce44SJohn Forte /* Clear node */ 1972*fcf3ce44SJohn Forte ndlp->nlp_next[ringno] = NULL; 1973*fcf3ce44SJohn Forte } 1974*fcf3ce44SJohn Forte 1975*fcf3ce44SJohn Forte /* First cleanup the iocb's while still holding the lock */ 1976*fcf3ce44SJohn Forte iocbq = (IOCBQ *)abort.q_first; 1977*fcf3ce44SJohn Forte while (iocbq) { 1978*fcf3ce44SJohn Forte /* Free the IoTag and the bmp */ 1979*fcf3ce44SJohn Forte iocb = &iocbq->iocb; 1980*fcf3ce44SJohn Forte sbp = emlxs_unregister_pkt(iocbq->ring, iocb->ulpIoTag, 0); 1981*fcf3ce44SJohn Forte 1982*fcf3ce44SJohn Forte if (sbp && (sbp != STALE_PACKET)) { 1983*fcf3ce44SJohn Forte mutex_enter(&sbp->mtx); 1984*fcf3ce44SJohn Forte 1985*fcf3ce44SJohn Forte if (sbp->pkt_flags & PACKET_IN_TXQ) { 1986*fcf3ce44SJohn Forte sbp->pkt_flags &= ~PACKET_IN_TXQ; 1987*fcf3ce44SJohn Forte hba->ring_tx_count[ringno]--; 1988*fcf3ce44SJohn Forte } 1989*fcf3ce44SJohn Forte sbp->pkt_flags |= PACKET_IN_FLUSH; 1990*fcf3ce44SJohn Forte 1991*fcf3ce44SJohn Forte /* 1992*fcf3ce44SJohn Forte * If the fpkt is already set, then we will leave it 1993*fcf3ce44SJohn Forte * alone 1994*fcf3ce44SJohn Forte */ 1995*fcf3ce44SJohn Forte /* 1996*fcf3ce44SJohn Forte * This ensures that this pkt is only accounted for 1997*fcf3ce44SJohn Forte * on one fpkt->flush_count 1998*fcf3ce44SJohn Forte */ 1999*fcf3ce44SJohn Forte if (!sbp->fpkt && fpkt) { 2000*fcf3ce44SJohn Forte mutex_enter(&fpkt->mtx); 2001*fcf3ce44SJohn Forte sbp->fpkt = fpkt; 2002*fcf3ce44SJohn Forte fpkt->flush_count++; 2003*fcf3ce44SJohn Forte mutex_exit(&fpkt->mtx); 2004*fcf3ce44SJohn Forte } 2005*fcf3ce44SJohn Forte mutex_exit(&sbp->mtx); 2006*fcf3ce44SJohn Forte } 2007*fcf3ce44SJohn Forte iocbq = (IOCBQ *)iocbq->next; 2008*fcf3ce44SJohn Forte 2009*fcf3ce44SJohn Forte } /* end of while */ 2010*fcf3ce44SJohn Forte 2011*fcf3ce44SJohn Forte mutex_exit(&EMLXS_RINGTX_LOCK); 2012*fcf3ce44SJohn Forte 2013*fcf3ce44SJohn Forte /* Now abort the iocb's */ 2014*fcf3ce44SJohn Forte iocbq = (IOCBQ *)abort.q_first; 2015*fcf3ce44SJohn Forte while (iocbq) { 2016*fcf3ce44SJohn Forte /* Save the next iocbq for now */ 2017*fcf3ce44SJohn Forte next = (IOCBQ *)iocbq->next; 2018*fcf3ce44SJohn Forte 2019*fcf3ce44SJohn Forte /* Unlink this iocbq */ 2020*fcf3ce44SJohn Forte iocbq->next = NULL; 2021*fcf3ce44SJohn Forte 2022*fcf3ce44SJohn Forte /* Get the pkt */ 2023*fcf3ce44SJohn Forte sbp = (emlxs_buf_t *)iocbq->sbp; 2024*fcf3ce44SJohn Forte 2025*fcf3ce44SJohn Forte if (sbp) { 2026*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg, 2027*fcf3ce44SJohn Forte "tx: sbp=%p node=%p", 2028*fcf3ce44SJohn Forte sbp, sbp->node); 2029*fcf3ce44SJohn Forte 2030*fcf3ce44SJohn Forte if (hba->state >= FC_LINK_UP) { 2031*fcf3ce44SJohn Forte emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, 2032*fcf3ce44SJohn Forte IOERR_ABORT_REQUESTED, 1); 2033*fcf3ce44SJohn Forte } else { 2034*fcf3ce44SJohn Forte emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, 2035*fcf3ce44SJohn Forte IOERR_LINK_DOWN, 1); 2036*fcf3ce44SJohn Forte } 2037*fcf3ce44SJohn Forte 2038*fcf3ce44SJohn Forte } 2039*fcf3ce44SJohn Forte /* Free the iocb and its associated buffers */ 2040*fcf3ce44SJohn Forte else { 2041*fcf3ce44SJohn Forte icmd = &iocbq->iocb; 2042*fcf3ce44SJohn Forte if (icmd->ulpCommand == CMD_QUE_RING_BUF64_CN || 2043*fcf3ce44SJohn Forte icmd->ulpCommand == CMD_QUE_RING_BUF_CN || 2044*fcf3ce44SJohn Forte icmd->ulpCommand == CMD_QUE_RING_LIST64_CN) { 2045*fcf3ce44SJohn Forte if ((hba->flag & 2046*fcf3ce44SJohn Forte (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) { 2047*fcf3ce44SJohn Forte /* HBA is detaching or offlining */ 2048*fcf3ce44SJohn Forte if (icmd->ulpCommand != 2049*fcf3ce44SJohn Forte CMD_QUE_RING_LIST64_CN) { 2050*fcf3ce44SJohn Forte uint8_t *tmp; 2051*fcf3ce44SJohn Forte 2052*fcf3ce44SJohn Forte for (i = 0; 2053*fcf3ce44SJohn Forte i < icmd->ulpBdeCount; 2054*fcf3ce44SJohn Forte i++) { 2055*fcf3ce44SJohn Forte 2056*fcf3ce44SJohn Forte mp = EMLXS_GET_VADDR( 2057*fcf3ce44SJohn Forte hba, rp, icmd); 2058*fcf3ce44SJohn Forte 2059*fcf3ce44SJohn Forte tmp = (uint8_t *)mp; 2060*fcf3ce44SJohn Forte if (mp) { 2061*fcf3ce44SJohn Forte (void) emlxs_mem_put(hba, MEM_BUF, tmp); 2062*fcf3ce44SJohn Forte } 2063*fcf3ce44SJohn Forte } 2064*fcf3ce44SJohn Forte } 2065*fcf3ce44SJohn Forte (void) emlxs_mem_put(hba, MEM_IOCB, 2066*fcf3ce44SJohn Forte (uint8_t *)iocbq); 2067*fcf3ce44SJohn Forte } else { 2068*fcf3ce44SJohn Forte /* repost the unsolicited buffer */ 2069*fcf3ce44SJohn Forte emlxs_issue_iocb_cmd(hba, rp, iocbq); 2070*fcf3ce44SJohn Forte } 2071*fcf3ce44SJohn Forte } 2072*fcf3ce44SJohn Forte } 2073*fcf3ce44SJohn Forte 2074*fcf3ce44SJohn Forte iocbq = next; 2075*fcf3ce44SJohn Forte 2076*fcf3ce44SJohn Forte } /* end of while */ 2077*fcf3ce44SJohn Forte 2078*fcf3ce44SJohn Forte return (abort.q_cnt); 2079*fcf3ce44SJohn Forte 2080*fcf3ce44SJohn Forte } /* emlxs_tx_ring_flush() */ 2081*fcf3ce44SJohn Forte 2082*fcf3ce44SJohn Forte 2083*fcf3ce44SJohn Forte /* Flush all IO's on all or a given ring for a given node */ 2084*fcf3ce44SJohn Forte extern uint32_t 2085*fcf3ce44SJohn Forte emlxs_tx_node_flush(emlxs_port_t *port, NODELIST *ndlp, RING *ring, 2086*fcf3ce44SJohn Forte uint32_t shutdown, emlxs_buf_t *fpkt) 2087*fcf3ce44SJohn Forte { 2088*fcf3ce44SJohn Forte emlxs_hba_t *hba = HBA; 2089*fcf3ce44SJohn Forte emlxs_buf_t *sbp; 2090*fcf3ce44SJohn Forte uint32_t ringno; 2091*fcf3ce44SJohn Forte RING *rp; 2092*fcf3ce44SJohn Forte IOCB *icmd; 2093*fcf3ce44SJohn Forte IOCBQ *iocbq; 2094*fcf3ce44SJohn Forte NODELIST *prev; 2095*fcf3ce44SJohn Forte IOCBQ *next; 2096*fcf3ce44SJohn Forte IOCB *iocb; 2097*fcf3ce44SJohn Forte Q abort; 2098*fcf3ce44SJohn Forte uint32_t i; 2099*fcf3ce44SJohn Forte MATCHMAP *mp; 2100*fcf3ce44SJohn Forte 2101*fcf3ce44SJohn Forte 2102*fcf3ce44SJohn Forte bzero((void *)&abort, sizeof (Q)); 2103*fcf3ce44SJohn Forte 2104*fcf3ce44SJohn Forte /* Flush all I/O's on tx queue to this target */ 2105*fcf3ce44SJohn Forte mutex_enter(&EMLXS_RINGTX_LOCK); 2106*fcf3ce44SJohn Forte 2107*fcf3ce44SJohn Forte if (!ndlp->nlp_base && shutdown) { 2108*fcf3ce44SJohn Forte ndlp->nlp_active = 0; 2109*fcf3ce44SJohn Forte } 2110*fcf3ce44SJohn Forte for (ringno = 0; ringno < hba->ring_count; ringno++) { 2111*fcf3ce44SJohn Forte rp = &hba->ring[ringno]; 2112*fcf3ce44SJohn Forte 2113*fcf3ce44SJohn Forte if (ring && rp != ring) { 2114*fcf3ce44SJohn Forte continue; 2115*fcf3ce44SJohn Forte } 2116*fcf3ce44SJohn Forte if (!ndlp->nlp_base || shutdown) { 2117*fcf3ce44SJohn Forte /* Check if priority queue is not empty */ 2118*fcf3ce44SJohn Forte if (ndlp->nlp_ptx[ringno].q_first) { 2119*fcf3ce44SJohn Forte /* Transfer all iocb's to local queue */ 2120*fcf3ce44SJohn Forte if (abort.q_first == 0) { 2121*fcf3ce44SJohn Forte abort.q_first = 2122*fcf3ce44SJohn Forte ndlp->nlp_ptx[ringno].q_first; 2123*fcf3ce44SJohn Forte abort.q_last = 2124*fcf3ce44SJohn Forte ndlp->nlp_ptx[ringno].q_last; 2125*fcf3ce44SJohn Forte } else { 2126*fcf3ce44SJohn Forte emlxs_queue_t *q; 2127*fcf3ce44SJohn Forte 2128*fcf3ce44SJohn Forte q = &ndlp->nlp_ptx[ringno]; 2129*fcf3ce44SJohn Forte ((IOCBQ *)abort.q_last)->next = 2130*fcf3ce44SJohn Forte (IOCBQ *)q->q_first; 2131*fcf3ce44SJohn Forte /* 2132*fcf3ce44SJohn Forte * ((IOCBQ *)abort.q_last)->next = 2133*fcf3ce44SJohn Forte * (IOCBQ *) 2134*fcf3ce44SJohn Forte * ndlp->nlp_ptx[ringno].q_first; 2135*fcf3ce44SJohn Forte */ 2136*fcf3ce44SJohn Forte } 2137*fcf3ce44SJohn Forte 2138*fcf3ce44SJohn Forte abort.q_cnt += ndlp->nlp_ptx[ringno].q_cnt; 2139*fcf3ce44SJohn Forte } 2140*fcf3ce44SJohn Forte } 2141*fcf3ce44SJohn Forte /* Check if tx queue is not empty */ 2142*fcf3ce44SJohn Forte if (ndlp->nlp_tx[ringno].q_first) { 2143*fcf3ce44SJohn Forte /* Transfer all iocb's to local queue */ 2144*fcf3ce44SJohn Forte if (abort.q_first == 0) { 2145*fcf3ce44SJohn Forte abort.q_first = ndlp->nlp_tx[ringno].q_first; 2146*fcf3ce44SJohn Forte abort.q_last = ndlp->nlp_tx[ringno].q_last; 2147*fcf3ce44SJohn Forte } else { 2148*fcf3ce44SJohn Forte ((IOCBQ *)abort.q_last)->next = 2149*fcf3ce44SJohn Forte (IOCBQ *)ndlp->nlp_tx[ringno].q_first; 2150*fcf3ce44SJohn Forte } 2151*fcf3ce44SJohn Forte 2152*fcf3ce44SJohn Forte abort.q_cnt += ndlp->nlp_tx[ringno].q_cnt; 2153*fcf3ce44SJohn Forte } 2154*fcf3ce44SJohn Forte /* Clear the queue pointers */ 2155*fcf3ce44SJohn Forte ndlp->nlp_ptx[ringno].q_first = NULL; 2156*fcf3ce44SJohn Forte ndlp->nlp_ptx[ringno].q_last = NULL; 2157*fcf3ce44SJohn Forte ndlp->nlp_ptx[ringno].q_cnt = 0; 2158*fcf3ce44SJohn Forte 2159*fcf3ce44SJohn Forte ndlp->nlp_tx[ringno].q_first = NULL; 2160*fcf3ce44SJohn Forte ndlp->nlp_tx[ringno].q_last = NULL; 2161*fcf3ce44SJohn Forte ndlp->nlp_tx[ringno].q_cnt = 0; 2162*fcf3ce44SJohn Forte 2163*fcf3ce44SJohn Forte /* If this node was on the ring queue, remove it */ 2164*fcf3ce44SJohn Forte if (ndlp->nlp_next[ringno]) { 2165*fcf3ce44SJohn Forte /* If this is the only node on list */ 2166*fcf3ce44SJohn Forte if (rp->nodeq.q_first == (void *)ndlp && 2167*fcf3ce44SJohn Forte rp->nodeq.q_last == (void *)ndlp) { 2168*fcf3ce44SJohn Forte rp->nodeq.q_last = NULL; 2169*fcf3ce44SJohn Forte rp->nodeq.q_first = NULL; 2170*fcf3ce44SJohn Forte rp->nodeq.q_cnt = 0; 2171*fcf3ce44SJohn Forte } else if (rp->nodeq.q_first == (void *)ndlp) { 2172*fcf3ce44SJohn Forte NODELIST *nd; 2173*fcf3ce44SJohn Forte 2174*fcf3ce44SJohn Forte rp->nodeq.q_first = ndlp->nlp_next[ringno]; 2175*fcf3ce44SJohn Forte nd = (NODELIST *)rp->nodeq.q_last; 2176*fcf3ce44SJohn Forte nd->nlp_next[ringno] = rp->nodeq.q_first; 2177*fcf3ce44SJohn Forte rp->nodeq.q_cnt--; 2178*fcf3ce44SJohn Forte } else { /* This is a little more difficult */ 2179*fcf3ce44SJohn Forte /* 2180*fcf3ce44SJohn Forte * Find the previous node in the circular 2181*fcf3ce44SJohn Forte * ring queue 2182*fcf3ce44SJohn Forte */ 2183*fcf3ce44SJohn Forte prev = ndlp; 2184*fcf3ce44SJohn Forte while (prev->nlp_next[ringno] != ndlp) { 2185*fcf3ce44SJohn Forte prev = prev->nlp_next[ringno]; 2186*fcf3ce44SJohn Forte } 2187*fcf3ce44SJohn Forte 2188*fcf3ce44SJohn Forte prev->nlp_next[ringno] = ndlp->nlp_next[ringno]; 2189*fcf3ce44SJohn Forte 2190*fcf3ce44SJohn Forte if (rp->nodeq.q_last == (void *)ndlp) { 2191*fcf3ce44SJohn Forte rp->nodeq.q_last = (void *)prev; 2192*fcf3ce44SJohn Forte } 2193*fcf3ce44SJohn Forte rp->nodeq.q_cnt--; 2194*fcf3ce44SJohn Forte 2195*fcf3ce44SJohn Forte } 2196*fcf3ce44SJohn Forte 2197*fcf3ce44SJohn Forte /* Clear node */ 2198*fcf3ce44SJohn Forte ndlp->nlp_next[ringno] = NULL; 2199*fcf3ce44SJohn Forte } 2200*fcf3ce44SJohn Forte } 2201*fcf3ce44SJohn Forte 2202*fcf3ce44SJohn Forte /* First cleanup the iocb's while still holding the lock */ 2203*fcf3ce44SJohn Forte iocbq = (IOCBQ *)abort.q_first; 2204*fcf3ce44SJohn Forte while (iocbq) { 2205*fcf3ce44SJohn Forte /* Free the IoTag and the bmp */ 2206*fcf3ce44SJohn Forte iocb = &iocbq->iocb; 2207*fcf3ce44SJohn Forte sbp = emlxs_unregister_pkt(iocbq->ring, iocb->ulpIoTag, 0); 2208*fcf3ce44SJohn Forte 2209*fcf3ce44SJohn Forte if (sbp && (sbp != STALE_PACKET)) { 2210*fcf3ce44SJohn Forte mutex_enter(&sbp->mtx); 2211*fcf3ce44SJohn Forte if (sbp->pkt_flags & PACKET_IN_TXQ) { 2212*fcf3ce44SJohn Forte sbp->pkt_flags &= ~PACKET_IN_TXQ; 2213*fcf3ce44SJohn Forte hba->ring_tx_count[ring->ringno]--; 2214*fcf3ce44SJohn Forte } 2215*fcf3ce44SJohn Forte sbp->pkt_flags |= PACKET_IN_FLUSH; 2216*fcf3ce44SJohn Forte 2217*fcf3ce44SJohn Forte /* 2218*fcf3ce44SJohn Forte * If the fpkt is already set, then we will leave it 2219*fcf3ce44SJohn Forte * alone 2220*fcf3ce44SJohn Forte */ 2221*fcf3ce44SJohn Forte /* 2222*fcf3ce44SJohn Forte * This ensures that this pkt is only accounted for 2223*fcf3ce44SJohn Forte * on one fpkt->flush_count 2224*fcf3ce44SJohn Forte */ 2225*fcf3ce44SJohn Forte if (!sbp->fpkt && fpkt) { 2226*fcf3ce44SJohn Forte mutex_enter(&fpkt->mtx); 2227*fcf3ce44SJohn Forte sbp->fpkt = fpkt; 2228*fcf3ce44SJohn Forte fpkt->flush_count++; 2229*fcf3ce44SJohn Forte mutex_exit(&fpkt->mtx); 2230*fcf3ce44SJohn Forte } 2231*fcf3ce44SJohn Forte mutex_exit(&sbp->mtx); 2232*fcf3ce44SJohn Forte } 2233*fcf3ce44SJohn Forte iocbq = (IOCBQ *)iocbq->next; 2234*fcf3ce44SJohn Forte 2235*fcf3ce44SJohn Forte } /* end of while */ 2236*fcf3ce44SJohn Forte 2237*fcf3ce44SJohn Forte mutex_exit(&EMLXS_RINGTX_LOCK); 2238*fcf3ce44SJohn Forte 2239*fcf3ce44SJohn Forte /* Now abort the iocb's outside the locks */ 2240*fcf3ce44SJohn Forte iocbq = (IOCBQ *)abort.q_first; 2241*fcf3ce44SJohn Forte while (iocbq) { 2242*fcf3ce44SJohn Forte /* Save the next iocbq for now */ 2243*fcf3ce44SJohn Forte next = (IOCBQ *)iocbq->next; 2244*fcf3ce44SJohn Forte 2245*fcf3ce44SJohn Forte /* Unlink this iocbq */ 2246*fcf3ce44SJohn Forte iocbq->next = NULL; 2247*fcf3ce44SJohn Forte 2248*fcf3ce44SJohn Forte /* Get the pkt */ 2249*fcf3ce44SJohn Forte sbp = (emlxs_buf_t *)iocbq->sbp; 2250*fcf3ce44SJohn Forte 2251*fcf3ce44SJohn Forte if (sbp) { 2252*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg, 2253*fcf3ce44SJohn Forte "tx: sbp=%p node=%p", 2254*fcf3ce44SJohn Forte sbp, sbp->node); 2255*fcf3ce44SJohn Forte 2256*fcf3ce44SJohn Forte if (hba->state >= FC_LINK_UP) { 2257*fcf3ce44SJohn Forte emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, 2258*fcf3ce44SJohn Forte IOERR_ABORT_REQUESTED, 1); 2259*fcf3ce44SJohn Forte } else { 2260*fcf3ce44SJohn Forte emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, 2261*fcf3ce44SJohn Forte IOERR_LINK_DOWN, 1); 2262*fcf3ce44SJohn Forte } 2263*fcf3ce44SJohn Forte 2264*fcf3ce44SJohn Forte } 2265*fcf3ce44SJohn Forte /* Free the iocb and its associated buffers */ 2266*fcf3ce44SJohn Forte else { 2267*fcf3ce44SJohn Forte icmd = &iocbq->iocb; 2268*fcf3ce44SJohn Forte if (icmd->ulpCommand == CMD_QUE_RING_BUF64_CN || 2269*fcf3ce44SJohn Forte icmd->ulpCommand == CMD_QUE_RING_BUF_CN || 2270*fcf3ce44SJohn Forte icmd->ulpCommand == CMD_QUE_RING_LIST64_CN) { 2271*fcf3ce44SJohn Forte if ((hba->flag & 2272*fcf3ce44SJohn Forte (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) { 2273*fcf3ce44SJohn Forte /* HBA is detaching or offlining */ 2274*fcf3ce44SJohn Forte if (icmd->ulpCommand != 2275*fcf3ce44SJohn Forte CMD_QUE_RING_LIST64_CN) { 2276*fcf3ce44SJohn Forte uint8_t *tmp; 2277*fcf3ce44SJohn Forte 2278*fcf3ce44SJohn Forte for (i = 0; 2279*fcf3ce44SJohn Forte i < icmd->ulpBdeCount; 2280*fcf3ce44SJohn Forte i++) { 2281*fcf3ce44SJohn Forte mp = EMLXS_GET_VADDR( 2282*fcf3ce44SJohn Forte hba, rp, icmd); 2283*fcf3ce44SJohn Forte 2284*fcf3ce44SJohn Forte tmp = (uint8_t *)mp; 2285*fcf3ce44SJohn Forte if (mp) { 2286*fcf3ce44SJohn Forte (void) emlxs_mem_put(hba, MEM_BUF, tmp); 2287*fcf3ce44SJohn Forte } 2288*fcf3ce44SJohn Forte } 2289*fcf3ce44SJohn Forte } 2290*fcf3ce44SJohn Forte (void) emlxs_mem_put(hba, MEM_IOCB, 2291*fcf3ce44SJohn Forte (uint8_t *)iocbq); 2292*fcf3ce44SJohn Forte } else { 2293*fcf3ce44SJohn Forte /* repost the unsolicited buffer */ 2294*fcf3ce44SJohn Forte emlxs_issue_iocb_cmd(hba, rp, iocbq); 2295*fcf3ce44SJohn Forte } 2296*fcf3ce44SJohn Forte } 2297*fcf3ce44SJohn Forte } 2298*fcf3ce44SJohn Forte 2299*fcf3ce44SJohn Forte iocbq = next; 2300*fcf3ce44SJohn Forte 2301*fcf3ce44SJohn Forte } /* end of while */ 2302*fcf3ce44SJohn Forte 2303*fcf3ce44SJohn Forte return (abort.q_cnt); 2304*fcf3ce44SJohn Forte 2305*fcf3ce44SJohn Forte } /* emlxs_tx_node_flush() */ 2306*fcf3ce44SJohn Forte 2307*fcf3ce44SJohn Forte 2308*fcf3ce44SJohn Forte /* Check for IO's on all or a given ring for a given node */ 2309*fcf3ce44SJohn Forte extern uint32_t 2310*fcf3ce44SJohn Forte emlxs_tx_node_check(emlxs_port_t *port, NODELIST *ndlp, RING *ring) 2311*fcf3ce44SJohn Forte { 2312*fcf3ce44SJohn Forte emlxs_hba_t *hba = HBA; 2313*fcf3ce44SJohn Forte uint32_t ringno; 2314*fcf3ce44SJohn Forte RING *rp; 2315*fcf3ce44SJohn Forte uint32_t count; 2316*fcf3ce44SJohn Forte 2317*fcf3ce44SJohn Forte count = 0; 2318*fcf3ce44SJohn Forte 2319*fcf3ce44SJohn Forte /* Flush all I/O's on tx queue to this target */ 2320*fcf3ce44SJohn Forte mutex_enter(&EMLXS_RINGTX_LOCK); 2321*fcf3ce44SJohn Forte 2322*fcf3ce44SJohn Forte for (ringno = 0; ringno < hba->ring_count; ringno++) { 2323*fcf3ce44SJohn Forte rp = &hba->ring[ringno]; 2324*fcf3ce44SJohn Forte 2325*fcf3ce44SJohn Forte if (ring && rp != ring) { 2326*fcf3ce44SJohn Forte continue; 2327*fcf3ce44SJohn Forte } 2328*fcf3ce44SJohn Forte /* Check if priority queue is not empty */ 2329*fcf3ce44SJohn Forte if (ndlp->nlp_ptx[ringno].q_first) { 2330*fcf3ce44SJohn Forte count += ndlp->nlp_ptx[ringno].q_cnt; 2331*fcf3ce44SJohn Forte } 2332*fcf3ce44SJohn Forte /* Check if tx queue is not empty */ 2333*fcf3ce44SJohn Forte if (ndlp->nlp_tx[ringno].q_first) { 2334*fcf3ce44SJohn Forte count += ndlp->nlp_tx[ringno].q_cnt; 2335*fcf3ce44SJohn Forte } 2336*fcf3ce44SJohn Forte } 2337*fcf3ce44SJohn Forte 2338*fcf3ce44SJohn Forte mutex_exit(&EMLXS_RINGTX_LOCK); 2339*fcf3ce44SJohn Forte 2340*fcf3ce44SJohn Forte return (count); 2341*fcf3ce44SJohn Forte 2342*fcf3ce44SJohn Forte } /* emlxs_tx_node_check() */ 2343*fcf3ce44SJohn Forte 2344*fcf3ce44SJohn Forte 2345*fcf3ce44SJohn Forte 2346*fcf3ce44SJohn Forte /* Flush all IO's on the FCP ring for a given node's lun */ 2347*fcf3ce44SJohn Forte extern uint32_t 2348*fcf3ce44SJohn Forte emlxs_tx_lun_flush(emlxs_port_t *port, NODELIST *ndlp, 2349*fcf3ce44SJohn Forte uint32_t lun, emlxs_buf_t *fpkt) 2350*fcf3ce44SJohn Forte { 2351*fcf3ce44SJohn Forte emlxs_hba_t *hba = HBA; 2352*fcf3ce44SJohn Forte emlxs_buf_t *sbp; 2353*fcf3ce44SJohn Forte uint32_t ringno; 2354*fcf3ce44SJohn Forte IOCBQ *iocbq; 2355*fcf3ce44SJohn Forte IOCBQ *prev; 2356*fcf3ce44SJohn Forte IOCBQ *next; 2357*fcf3ce44SJohn Forte IOCB *iocb; 2358*fcf3ce44SJohn Forte IOCB *icmd; 2359*fcf3ce44SJohn Forte Q abort; 2360*fcf3ce44SJohn Forte uint32_t i; 2361*fcf3ce44SJohn Forte MATCHMAP *mp; 2362*fcf3ce44SJohn Forte RING *rp; 2363*fcf3ce44SJohn Forte 2364*fcf3ce44SJohn Forte ringno = FC_FCP_RING; 2365*fcf3ce44SJohn Forte rp = &hba->ring[ringno]; 2366*fcf3ce44SJohn Forte 2367*fcf3ce44SJohn Forte bzero((void *)&abort, sizeof (Q)); 2368*fcf3ce44SJohn Forte 2369*fcf3ce44SJohn Forte /* Flush I/O's on txQ to this target's lun */ 2370*fcf3ce44SJohn Forte mutex_enter(&EMLXS_RINGTX_LOCK); 2371*fcf3ce44SJohn Forte 2372*fcf3ce44SJohn Forte /* Scan the priority queue first */ 2373*fcf3ce44SJohn Forte prev = NULL; 2374*fcf3ce44SJohn Forte iocbq = (IOCBQ *)ndlp->nlp_ptx[ringno].q_first; 2375*fcf3ce44SJohn Forte 2376*fcf3ce44SJohn Forte while (iocbq) { 2377*fcf3ce44SJohn Forte next = (IOCBQ *)iocbq->next; 2378*fcf3ce44SJohn Forte iocb = &iocbq->iocb; 2379*fcf3ce44SJohn Forte sbp = (emlxs_buf_t *)iocbq->sbp; 2380*fcf3ce44SJohn Forte 2381*fcf3ce44SJohn Forte /* Check if this IO is for our lun */ 2382*fcf3ce44SJohn Forte if (sbp->lun == lun) { 2383*fcf3ce44SJohn Forte /* Remove iocb from the node's tx queue */ 2384*fcf3ce44SJohn Forte if (next == 0) { 2385*fcf3ce44SJohn Forte ndlp->nlp_ptx[ringno].q_last = (uint8_t *)prev; 2386*fcf3ce44SJohn Forte } 2387*fcf3ce44SJohn Forte if (prev == 0) { 2388*fcf3ce44SJohn Forte ndlp->nlp_ptx[ringno].q_first = (uint8_t *)next; 2389*fcf3ce44SJohn Forte } else { 2390*fcf3ce44SJohn Forte prev->next = next; 2391*fcf3ce44SJohn Forte } 2392*fcf3ce44SJohn Forte 2393*fcf3ce44SJohn Forte iocbq->next = NULL; 2394*fcf3ce44SJohn Forte ndlp->nlp_ptx[ringno].q_cnt--; 2395*fcf3ce44SJohn Forte 2396*fcf3ce44SJohn Forte /* Add this iocb to our local abort Q */ 2397*fcf3ce44SJohn Forte /* This way we don't hold the RINGTX lock too long */ 2398*fcf3ce44SJohn Forte if (abort.q_first) { 2399*fcf3ce44SJohn Forte ((IOCBQ *) abort.q_last)->next = iocbq; 2400*fcf3ce44SJohn Forte abort.q_last = (uint8_t *)iocbq; 2401*fcf3ce44SJohn Forte abort.q_cnt++; 2402*fcf3ce44SJohn Forte } else { 2403*fcf3ce44SJohn Forte abort.q_first = (uint8_t *)iocbq; 2404*fcf3ce44SJohn Forte abort.q_last = (uint8_t *)iocbq; 2405*fcf3ce44SJohn Forte abort.q_cnt = 1; 2406*fcf3ce44SJohn Forte } 2407*fcf3ce44SJohn Forte iocbq->next = NULL; 2408*fcf3ce44SJohn Forte } else { 2409*fcf3ce44SJohn Forte prev = iocbq; 2410*fcf3ce44SJohn Forte } 2411*fcf3ce44SJohn Forte 2412*fcf3ce44SJohn Forte iocbq = next; 2413*fcf3ce44SJohn Forte 2414*fcf3ce44SJohn Forte } /* while (iocbq) */ 2415*fcf3ce44SJohn Forte 2416*fcf3ce44SJohn Forte 2417*fcf3ce44SJohn Forte /* Scan the regular queue */ 2418*fcf3ce44SJohn Forte prev = NULL; 2419*fcf3ce44SJohn Forte iocbq = (IOCBQ *)ndlp->nlp_tx[ringno].q_first; 2420*fcf3ce44SJohn Forte 2421*fcf3ce44SJohn Forte while (iocbq) { 2422*fcf3ce44SJohn Forte next = (IOCBQ *)iocbq->next; 2423*fcf3ce44SJohn Forte iocb = &iocbq->iocb; 2424*fcf3ce44SJohn Forte sbp = (emlxs_buf_t *)iocbq->sbp; 2425*fcf3ce44SJohn Forte 2426*fcf3ce44SJohn Forte /* Check if this IO is for our lun */ 2427*fcf3ce44SJohn Forte if (sbp->lun == lun) { 2428*fcf3ce44SJohn Forte /* Remove iocb from the node's tx queue */ 2429*fcf3ce44SJohn Forte if (next == 0) { 2430*fcf3ce44SJohn Forte ndlp->nlp_tx[ringno].q_last = (uint8_t *)prev; 2431*fcf3ce44SJohn Forte } 2432*fcf3ce44SJohn Forte if (prev == 0) { 2433*fcf3ce44SJohn Forte ndlp->nlp_tx[ringno].q_first = (uint8_t *)next; 2434*fcf3ce44SJohn Forte } else { 2435*fcf3ce44SJohn Forte prev->next = next; 2436*fcf3ce44SJohn Forte } 2437*fcf3ce44SJohn Forte 2438*fcf3ce44SJohn Forte iocbq->next = NULL; 2439*fcf3ce44SJohn Forte ndlp->nlp_tx[ringno].q_cnt--; 2440*fcf3ce44SJohn Forte 2441*fcf3ce44SJohn Forte /* Add this iocb to our local abort Q */ 2442*fcf3ce44SJohn Forte /* This way we don't hold the RINGTX lock too long */ 2443*fcf3ce44SJohn Forte if (abort.q_first) { 2444*fcf3ce44SJohn Forte ((IOCBQ *) abort.q_last)->next = iocbq; 2445*fcf3ce44SJohn Forte abort.q_last = (uint8_t *)iocbq; 2446*fcf3ce44SJohn Forte abort.q_cnt++; 2447*fcf3ce44SJohn Forte } else { 2448*fcf3ce44SJohn Forte abort.q_first = (uint8_t *)iocbq; 2449*fcf3ce44SJohn Forte abort.q_last = (uint8_t *)iocbq; 2450*fcf3ce44SJohn Forte abort.q_cnt = 1; 2451*fcf3ce44SJohn Forte } 2452*fcf3ce44SJohn Forte iocbq->next = NULL; 2453*fcf3ce44SJohn Forte } else { 2454*fcf3ce44SJohn Forte prev = iocbq; 2455*fcf3ce44SJohn Forte } 2456*fcf3ce44SJohn Forte 2457*fcf3ce44SJohn Forte iocbq = next; 2458*fcf3ce44SJohn Forte 2459*fcf3ce44SJohn Forte } /* while (iocbq) */ 2460*fcf3ce44SJohn Forte 2461*fcf3ce44SJohn Forte /* First cleanup the iocb's while still holding the lock */ 2462*fcf3ce44SJohn Forte iocbq = (IOCBQ *)abort.q_first; 2463*fcf3ce44SJohn Forte while (iocbq) { 2464*fcf3ce44SJohn Forte /* Free the IoTag and the bmp */ 2465*fcf3ce44SJohn Forte iocb = &iocbq->iocb; 2466*fcf3ce44SJohn Forte sbp = emlxs_unregister_pkt(iocbq->ring, iocb->ulpIoTag, 0); 2467*fcf3ce44SJohn Forte 2468*fcf3ce44SJohn Forte if (sbp && (sbp != STALE_PACKET)) { 2469*fcf3ce44SJohn Forte mutex_enter(&sbp->mtx); 2470*fcf3ce44SJohn Forte if (sbp->pkt_flags & PACKET_IN_TXQ) { 2471*fcf3ce44SJohn Forte sbp->pkt_flags &= ~PACKET_IN_TXQ; 2472*fcf3ce44SJohn Forte hba->ring_tx_count[ringno]--; 2473*fcf3ce44SJohn Forte } 2474*fcf3ce44SJohn Forte sbp->pkt_flags |= PACKET_IN_FLUSH; 2475*fcf3ce44SJohn Forte 2476*fcf3ce44SJohn Forte /* 2477*fcf3ce44SJohn Forte * If the fpkt is already set, then we will leave it 2478*fcf3ce44SJohn Forte * alone 2479*fcf3ce44SJohn Forte */ 2480*fcf3ce44SJohn Forte /* 2481*fcf3ce44SJohn Forte * This ensures that this pkt is only accounted for 2482*fcf3ce44SJohn Forte * on one fpkt->flush_count 2483*fcf3ce44SJohn Forte */ 2484*fcf3ce44SJohn Forte if (!sbp->fpkt && fpkt) { 2485*fcf3ce44SJohn Forte mutex_enter(&fpkt->mtx); 2486*fcf3ce44SJohn Forte sbp->fpkt = fpkt; 2487*fcf3ce44SJohn Forte fpkt->flush_count++; 2488*fcf3ce44SJohn Forte mutex_exit(&fpkt->mtx); 2489*fcf3ce44SJohn Forte } 2490*fcf3ce44SJohn Forte mutex_exit(&sbp->mtx); 2491*fcf3ce44SJohn Forte } 2492*fcf3ce44SJohn Forte iocbq = (IOCBQ *)iocbq->next; 2493*fcf3ce44SJohn Forte 2494*fcf3ce44SJohn Forte } /* end of while */ 2495*fcf3ce44SJohn Forte 2496*fcf3ce44SJohn Forte mutex_exit(&EMLXS_RINGTX_LOCK); 2497*fcf3ce44SJohn Forte 2498*fcf3ce44SJohn Forte /* Now abort the iocb's outside the locks */ 2499*fcf3ce44SJohn Forte iocbq = (IOCBQ *)abort.q_first; 2500*fcf3ce44SJohn Forte while (iocbq) { 2501*fcf3ce44SJohn Forte /* Save the next iocbq for now */ 2502*fcf3ce44SJohn Forte next = (IOCBQ *)iocbq->next; 2503*fcf3ce44SJohn Forte 2504*fcf3ce44SJohn Forte /* Unlink this iocbq */ 2505*fcf3ce44SJohn Forte iocbq->next = NULL; 2506*fcf3ce44SJohn Forte 2507*fcf3ce44SJohn Forte /* Get the pkt */ 2508*fcf3ce44SJohn Forte sbp = (emlxs_buf_t *)iocbq->sbp; 2509*fcf3ce44SJohn Forte 2510*fcf3ce44SJohn Forte if (sbp) { 2511*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg, 2512*fcf3ce44SJohn Forte "tx: sbp=%p node=%p", 2513*fcf3ce44SJohn Forte sbp, sbp->node); 2514*fcf3ce44SJohn Forte 2515*fcf3ce44SJohn Forte if (hba->state >= FC_LINK_UP) { 2516*fcf3ce44SJohn Forte emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, 2517*fcf3ce44SJohn Forte IOERR_ABORT_REQUESTED, 1); 2518*fcf3ce44SJohn Forte } else { 2519*fcf3ce44SJohn Forte emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, 2520*fcf3ce44SJohn Forte IOERR_LINK_DOWN, 1); 2521*fcf3ce44SJohn Forte } 2522*fcf3ce44SJohn Forte } 2523*fcf3ce44SJohn Forte /* Free the iocb and its associated buffers */ 2524*fcf3ce44SJohn Forte else { 2525*fcf3ce44SJohn Forte icmd = &iocbq->iocb; 2526*fcf3ce44SJohn Forte 2527*fcf3ce44SJohn Forte if (icmd->ulpCommand == CMD_QUE_RING_BUF64_CN || 2528*fcf3ce44SJohn Forte icmd->ulpCommand == CMD_QUE_RING_BUF_CN || 2529*fcf3ce44SJohn Forte icmd->ulpCommand == CMD_QUE_RING_LIST64_CN) { 2530*fcf3ce44SJohn Forte if ((hba->flag & 2531*fcf3ce44SJohn Forte (FC_ONLINE_MODE | FC_ONLINING_MODE)) == 0) { 2532*fcf3ce44SJohn Forte /* HBA is detaching or offlining */ 2533*fcf3ce44SJohn Forte if (icmd->ulpCommand != 2534*fcf3ce44SJohn Forte CMD_QUE_RING_LIST64_CN) { 2535*fcf3ce44SJohn Forte uint8_t *tmp; 2536*fcf3ce44SJohn Forte 2537*fcf3ce44SJohn Forte for (i = 0; 2538*fcf3ce44SJohn Forte i < icmd->ulpBdeCount; 2539*fcf3ce44SJohn Forte i++) { 2540*fcf3ce44SJohn Forte mp = EMLXS_GET_VADDR( 2541*fcf3ce44SJohn Forte hba, rp, icmd); 2542*fcf3ce44SJohn Forte 2543*fcf3ce44SJohn Forte tmp = (uint8_t *)mp; 2544*fcf3ce44SJohn Forte if (mp) { 2545*fcf3ce44SJohn Forte (void) emlxs_mem_put(hba, MEM_BUF, tmp); 2546*fcf3ce44SJohn Forte } 2547*fcf3ce44SJohn Forte } 2548*fcf3ce44SJohn Forte } 2549*fcf3ce44SJohn Forte (void) emlxs_mem_put(hba, MEM_IOCB, 2550*fcf3ce44SJohn Forte (uint8_t *)iocbq); 2551*fcf3ce44SJohn Forte } else { 2552*fcf3ce44SJohn Forte /* repost the unsolicited buffer */ 2553*fcf3ce44SJohn Forte emlxs_issue_iocb_cmd(hba, rp, iocbq); 2554*fcf3ce44SJohn Forte } 2555*fcf3ce44SJohn Forte } 2556*fcf3ce44SJohn Forte } 2557*fcf3ce44SJohn Forte 2558*fcf3ce44SJohn Forte iocbq = next; 2559*fcf3ce44SJohn Forte 2560*fcf3ce44SJohn Forte } /* end of while */ 2561*fcf3ce44SJohn Forte 2562*fcf3ce44SJohn Forte 2563*fcf3ce44SJohn Forte return (abort.q_cnt); 2564*fcf3ce44SJohn Forte 2565*fcf3ce44SJohn Forte } /* emlxs_tx_lun_flush() */ 2566*fcf3ce44SJohn Forte 2567*fcf3ce44SJohn Forte 2568*fcf3ce44SJohn Forte extern void 2569*fcf3ce44SJohn Forte emlxs_tx_put(IOCBQ *iocbq, uint32_t lock) 2570*fcf3ce44SJohn Forte { 2571*fcf3ce44SJohn Forte emlxs_hba_t *hba; 2572*fcf3ce44SJohn Forte emlxs_port_t *port; 2573*fcf3ce44SJohn Forte uint32_t ringno; 2574*fcf3ce44SJohn Forte NODELIST *nlp; 2575*fcf3ce44SJohn Forte RING *rp; 2576*fcf3ce44SJohn Forte emlxs_buf_t *sbp; 2577*fcf3ce44SJohn Forte 2578*fcf3ce44SJohn Forte port = (emlxs_port_t *)iocbq->port; 2579*fcf3ce44SJohn Forte hba = HBA; 2580*fcf3ce44SJohn Forte rp = (RING *)iocbq->ring; 2581*fcf3ce44SJohn Forte nlp = (NODELIST *)iocbq->node; 2582*fcf3ce44SJohn Forte ringno = rp->ringno; 2583*fcf3ce44SJohn Forte sbp = (emlxs_buf_t *)iocbq->sbp; 2584*fcf3ce44SJohn Forte 2585*fcf3ce44SJohn Forte if (nlp == NULL) { 2586*fcf3ce44SJohn Forte /* Set node to base node by default */ 2587*fcf3ce44SJohn Forte nlp = &port->node_base; 2588*fcf3ce44SJohn Forte 2589*fcf3ce44SJohn Forte iocbq->node = (void *)nlp; 2590*fcf3ce44SJohn Forte 2591*fcf3ce44SJohn Forte if (sbp) { 2592*fcf3ce44SJohn Forte sbp->node = (void *)nlp; 2593*fcf3ce44SJohn Forte } 2594*fcf3ce44SJohn Forte } 2595*fcf3ce44SJohn Forte if (lock) { 2596*fcf3ce44SJohn Forte mutex_enter(&EMLXS_RINGTX_LOCK); 2597*fcf3ce44SJohn Forte } 2598*fcf3ce44SJohn Forte if (!nlp->nlp_active || (sbp && (sbp->pkt_flags & PACKET_IN_ABORT))) { 2599*fcf3ce44SJohn Forte if (sbp) { 2600*fcf3ce44SJohn Forte mutex_enter(&sbp->mtx); 2601*fcf3ce44SJohn Forte 2602*fcf3ce44SJohn Forte if (sbp->pkt_flags & PACKET_IN_TXQ) { 2603*fcf3ce44SJohn Forte sbp->pkt_flags &= ~PACKET_IN_TXQ; 2604*fcf3ce44SJohn Forte hba->ring_tx_count[ringno]--; 2605*fcf3ce44SJohn Forte } 2606*fcf3ce44SJohn Forte sbp->pkt_flags |= PACKET_IN_FLUSH; 2607*fcf3ce44SJohn Forte 2608*fcf3ce44SJohn Forte mutex_exit(&sbp->mtx); 2609*fcf3ce44SJohn Forte 2610*fcf3ce44SJohn Forte /* Free the ulpIoTag and the bmp */ 2611*fcf3ce44SJohn Forte (void) emlxs_unregister_pkt(rp, sbp->iotag, 0); 2612*fcf3ce44SJohn Forte 2613*fcf3ce44SJohn Forte if (lock) { 2614*fcf3ce44SJohn Forte mutex_exit(&EMLXS_RINGTX_LOCK); 2615*fcf3ce44SJohn Forte } 2616*fcf3ce44SJohn Forte if (hba->state >= FC_LINK_UP) { 2617*fcf3ce44SJohn Forte emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, 2618*fcf3ce44SJohn Forte IOERR_ABORT_REQUESTED, 1); 2619*fcf3ce44SJohn Forte } else { 2620*fcf3ce44SJohn Forte emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, 2621*fcf3ce44SJohn Forte IOERR_LINK_DOWN, 1); 2622*fcf3ce44SJohn Forte } 2623*fcf3ce44SJohn Forte 2624*fcf3ce44SJohn Forte return; 2625*fcf3ce44SJohn Forte } else { 2626*fcf3ce44SJohn Forte if (lock) { 2627*fcf3ce44SJohn Forte mutex_exit(&EMLXS_RINGTX_LOCK); 2628*fcf3ce44SJohn Forte } 2629*fcf3ce44SJohn Forte (void) emlxs_mem_put(hba, MEM_IOCB, (uint8_t *)iocbq); 2630*fcf3ce44SJohn Forte } 2631*fcf3ce44SJohn Forte 2632*fcf3ce44SJohn Forte return; 2633*fcf3ce44SJohn Forte } 2634*fcf3ce44SJohn Forte if (sbp) { 2635*fcf3ce44SJohn Forte 2636*fcf3ce44SJohn Forte mutex_enter(&sbp->mtx); 2637*fcf3ce44SJohn Forte 2638*fcf3ce44SJohn Forte if (sbp->pkt_flags & (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ | 2639*fcf3ce44SJohn Forte PACKET_IN_TXQ)) { 2640*fcf3ce44SJohn Forte mutex_exit(&sbp->mtx); 2641*fcf3ce44SJohn Forte if (lock) { 2642*fcf3ce44SJohn Forte mutex_exit(&EMLXS_RINGTX_LOCK); 2643*fcf3ce44SJohn Forte } 2644*fcf3ce44SJohn Forte return; 2645*fcf3ce44SJohn Forte } 2646*fcf3ce44SJohn Forte sbp->pkt_flags |= PACKET_IN_TXQ; 2647*fcf3ce44SJohn Forte hba->ring_tx_count[ringno]++; 2648*fcf3ce44SJohn Forte 2649*fcf3ce44SJohn Forte mutex_exit(&sbp->mtx); 2650*fcf3ce44SJohn Forte } 2651*fcf3ce44SJohn Forte /* Check iocbq priority */ 2652*fcf3ce44SJohn Forte if (iocbq->flag & IOCB_PRIORITY) { 2653*fcf3ce44SJohn Forte /* Add the iocb to the bottom of the node's ptx queue */ 2654*fcf3ce44SJohn Forte if (nlp->nlp_ptx[ringno].q_first) { 2655*fcf3ce44SJohn Forte ((IOCBQ *)nlp->nlp_ptx[ringno].q_last)->next = iocbq; 2656*fcf3ce44SJohn Forte nlp->nlp_ptx[ringno].q_last = (uint8_t *)iocbq; 2657*fcf3ce44SJohn Forte nlp->nlp_ptx[ringno].q_cnt++; 2658*fcf3ce44SJohn Forte } else { 2659*fcf3ce44SJohn Forte nlp->nlp_ptx[ringno].q_first = (uint8_t *)iocbq; 2660*fcf3ce44SJohn Forte nlp->nlp_ptx[ringno].q_last = (uint8_t *)iocbq; 2661*fcf3ce44SJohn Forte nlp->nlp_ptx[ringno].q_cnt = 1; 2662*fcf3ce44SJohn Forte } 2663*fcf3ce44SJohn Forte 2664*fcf3ce44SJohn Forte iocbq->next = NULL; 2665*fcf3ce44SJohn Forte } else { /* Normal priority */ 2666*fcf3ce44SJohn Forte 2667*fcf3ce44SJohn Forte /* Add the iocb to the bottom of the node's tx queue */ 2668*fcf3ce44SJohn Forte if (nlp->nlp_tx[ringno].q_first) { 2669*fcf3ce44SJohn Forte ((IOCBQ *)nlp->nlp_tx[ringno].q_last)->next = iocbq; 2670*fcf3ce44SJohn Forte nlp->nlp_tx[ringno].q_last = (uint8_t *)iocbq; 2671*fcf3ce44SJohn Forte nlp->nlp_tx[ringno].q_cnt++; 2672*fcf3ce44SJohn Forte } else { 2673*fcf3ce44SJohn Forte nlp->nlp_tx[ringno].q_first = (uint8_t *)iocbq; 2674*fcf3ce44SJohn Forte nlp->nlp_tx[ringno].q_last = (uint8_t *)iocbq; 2675*fcf3ce44SJohn Forte nlp->nlp_tx[ringno].q_cnt = 1; 2676*fcf3ce44SJohn Forte } 2677*fcf3ce44SJohn Forte 2678*fcf3ce44SJohn Forte iocbq->next = NULL; 2679*fcf3ce44SJohn Forte } 2680*fcf3ce44SJohn Forte 2681*fcf3ce44SJohn Forte 2682*fcf3ce44SJohn Forte /* 2683*fcf3ce44SJohn Forte * Check if the node is not already on ring queue and (is not closed 2684*fcf3ce44SJohn Forte * or is a priority request) 2685*fcf3ce44SJohn Forte */ 2686*fcf3ce44SJohn Forte if (!nlp->nlp_next[ringno] && (!(nlp->nlp_flag[ringno] & NLP_CLOSED) || 2687*fcf3ce44SJohn Forte (iocbq->flag & IOCB_PRIORITY))) { 2688*fcf3ce44SJohn Forte /* If so, then add it to the ring queue */ 2689*fcf3ce44SJohn Forte if (rp->nodeq.q_first) { 2690*fcf3ce44SJohn Forte ((NODELIST *)rp->nodeq.q_last)->nlp_next[ringno] = 2691*fcf3ce44SJohn Forte (uint8_t *)nlp; 2692*fcf3ce44SJohn Forte nlp->nlp_next[ringno] = rp->nodeq.q_first; 2693*fcf3ce44SJohn Forte 2694*fcf3ce44SJohn Forte /* 2695*fcf3ce44SJohn Forte * If this is not the base node then add it to the 2696*fcf3ce44SJohn Forte * tail 2697*fcf3ce44SJohn Forte */ 2698*fcf3ce44SJohn Forte if (!nlp->nlp_base) { 2699*fcf3ce44SJohn Forte rp->nodeq.q_last = (uint8_t *)nlp; 2700*fcf3ce44SJohn Forte } else { /* Otherwise, add it to the head */ 2701*fcf3ce44SJohn Forte /* The command node always gets priority */ 2702*fcf3ce44SJohn Forte rp->nodeq.q_first = (uint8_t *)nlp; 2703*fcf3ce44SJohn Forte } 2704*fcf3ce44SJohn Forte 2705*fcf3ce44SJohn Forte rp->nodeq.q_cnt++; 2706*fcf3ce44SJohn Forte } else { 2707*fcf3ce44SJohn Forte rp->nodeq.q_first = (uint8_t *)nlp; 2708*fcf3ce44SJohn Forte rp->nodeq.q_last = (uint8_t *)nlp; 2709*fcf3ce44SJohn Forte nlp->nlp_next[ringno] = nlp; 2710*fcf3ce44SJohn Forte rp->nodeq.q_cnt = 1; 2711*fcf3ce44SJohn Forte } 2712*fcf3ce44SJohn Forte } 2713*fcf3ce44SJohn Forte HBASTATS.IocbTxPut[ringno]++; 2714*fcf3ce44SJohn Forte 2715*fcf3ce44SJohn Forte /* Adjust the ring timeout timer */ 2716*fcf3ce44SJohn Forte rp->timeout = hba->timer_tics + 5; 2717*fcf3ce44SJohn Forte 2718*fcf3ce44SJohn Forte if (lock) { 2719*fcf3ce44SJohn Forte mutex_exit(&EMLXS_RINGTX_LOCK); 2720*fcf3ce44SJohn Forte } 2721*fcf3ce44SJohn Forte return; 2722*fcf3ce44SJohn Forte 2723*fcf3ce44SJohn Forte } /* emlxs_tx_put() */ 2724*fcf3ce44SJohn Forte 2725*fcf3ce44SJohn Forte 2726*fcf3ce44SJohn Forte extern IOCBQ * 2727*fcf3ce44SJohn Forte emlxs_tx_get(RING *rp, uint32_t lock) 2728*fcf3ce44SJohn Forte { 2729*fcf3ce44SJohn Forte emlxs_hba_t *hba; 2730*fcf3ce44SJohn Forte uint32_t ringno; 2731*fcf3ce44SJohn Forte IOCBQ *iocbq; 2732*fcf3ce44SJohn Forte NODELIST *nlp; 2733*fcf3ce44SJohn Forte emlxs_buf_t *sbp; 2734*fcf3ce44SJohn Forte 2735*fcf3ce44SJohn Forte hba = rp->hba; 2736*fcf3ce44SJohn Forte ringno = rp->ringno; 2737*fcf3ce44SJohn Forte 2738*fcf3ce44SJohn Forte if (lock) { 2739*fcf3ce44SJohn Forte mutex_enter(&EMLXS_RINGTX_LOCK); 2740*fcf3ce44SJohn Forte } 2741*fcf3ce44SJohn Forte begin: 2742*fcf3ce44SJohn Forte 2743*fcf3ce44SJohn Forte iocbq = NULL; 2744*fcf3ce44SJohn Forte 2745*fcf3ce44SJohn Forte /* Check if a node needs servicing */ 2746*fcf3ce44SJohn Forte if (rp->nodeq.q_first) { 2747*fcf3ce44SJohn Forte nlp = (NODELIST *)rp->nodeq.q_first; 2748*fcf3ce44SJohn Forte 2749*fcf3ce44SJohn Forte /* Get next iocb from node's priority queue */ 2750*fcf3ce44SJohn Forte 2751*fcf3ce44SJohn Forte if (nlp->nlp_ptx[ringno].q_first) { 2752*fcf3ce44SJohn Forte iocbq = (IOCBQ *)nlp->nlp_ptx[ringno].q_first; 2753*fcf3ce44SJohn Forte 2754*fcf3ce44SJohn Forte /* Check if this is last entry */ 2755*fcf3ce44SJohn Forte if (nlp->nlp_ptx[ringno].q_last == (void *)iocbq) { 2756*fcf3ce44SJohn Forte nlp->nlp_ptx[ringno].q_first = NULL; 2757*fcf3ce44SJohn Forte nlp->nlp_ptx[ringno].q_last = NULL; 2758*fcf3ce44SJohn Forte nlp->nlp_ptx[ringno].q_cnt = 0; 2759*fcf3ce44SJohn Forte } else { 2760*fcf3ce44SJohn Forte /* Remove iocb from head */ 2761*fcf3ce44SJohn Forte nlp->nlp_ptx[ringno].q_first = 2762*fcf3ce44SJohn Forte (void *)iocbq->next; 2763*fcf3ce44SJohn Forte nlp->nlp_ptx[ringno].q_cnt--; 2764*fcf3ce44SJohn Forte } 2765*fcf3ce44SJohn Forte 2766*fcf3ce44SJohn Forte iocbq->next = NULL; 2767*fcf3ce44SJohn Forte } 2768*fcf3ce44SJohn Forte /* Get next iocb from node tx queue if node not closed */ 2769*fcf3ce44SJohn Forte else if (nlp->nlp_tx[ringno].q_first && 2770*fcf3ce44SJohn Forte !(nlp->nlp_flag[ringno] & NLP_CLOSED)) { 2771*fcf3ce44SJohn Forte iocbq = (IOCBQ *)nlp->nlp_tx[ringno].q_first; 2772*fcf3ce44SJohn Forte 2773*fcf3ce44SJohn Forte /* Check if this is last entry */ 2774*fcf3ce44SJohn Forte if (nlp->nlp_tx[ringno].q_last == (void *)iocbq) { 2775*fcf3ce44SJohn Forte nlp->nlp_tx[ringno].q_first = NULL; 2776*fcf3ce44SJohn Forte nlp->nlp_tx[ringno].q_last = NULL; 2777*fcf3ce44SJohn Forte nlp->nlp_tx[ringno].q_cnt = 0; 2778*fcf3ce44SJohn Forte } else { 2779*fcf3ce44SJohn Forte /* Remove iocb from head */ 2780*fcf3ce44SJohn Forte nlp->nlp_tx[ringno].q_first = 2781*fcf3ce44SJohn Forte (void *)iocbq->next; 2782*fcf3ce44SJohn Forte nlp->nlp_tx[ringno].q_cnt--; 2783*fcf3ce44SJohn Forte } 2784*fcf3ce44SJohn Forte 2785*fcf3ce44SJohn Forte iocbq->next = NULL; 2786*fcf3ce44SJohn Forte } 2787*fcf3ce44SJohn Forte /* Now deal with node itself */ 2788*fcf3ce44SJohn Forte 2789*fcf3ce44SJohn Forte /* Check if node still needs servicing */ 2790*fcf3ce44SJohn Forte if ((nlp->nlp_ptx[ringno].q_first) || 2791*fcf3ce44SJohn Forte (nlp->nlp_tx[ringno].q_first && 2792*fcf3ce44SJohn Forte !(nlp->nlp_flag[ringno] & NLP_CLOSED))) { 2793*fcf3ce44SJohn Forte 2794*fcf3ce44SJohn Forte /* 2795*fcf3ce44SJohn Forte * If this is the base node, then don't shift the 2796*fcf3ce44SJohn Forte * pointers 2797*fcf3ce44SJohn Forte */ 2798*fcf3ce44SJohn Forte /* We want to drain the base node before moving on */ 2799*fcf3ce44SJohn Forte if (!nlp->nlp_base) { 2800*fcf3ce44SJohn Forte /* 2801*fcf3ce44SJohn Forte * Just shift ring queue pointers to next 2802*fcf3ce44SJohn Forte * node 2803*fcf3ce44SJohn Forte */ 2804*fcf3ce44SJohn Forte rp->nodeq.q_last = (void *)nlp; 2805*fcf3ce44SJohn Forte rp->nodeq.q_first = nlp->nlp_next[ringno]; 2806*fcf3ce44SJohn Forte } 2807*fcf3ce44SJohn Forte } else { 2808*fcf3ce44SJohn Forte /* Remove node from ring queue */ 2809*fcf3ce44SJohn Forte 2810*fcf3ce44SJohn Forte /* If this is the last node on list */ 2811*fcf3ce44SJohn Forte if (rp->nodeq.q_last == (void *)nlp) { 2812*fcf3ce44SJohn Forte rp->nodeq.q_last = NULL; 2813*fcf3ce44SJohn Forte rp->nodeq.q_first = NULL; 2814*fcf3ce44SJohn Forte rp->nodeq.q_cnt = 0; 2815*fcf3ce44SJohn Forte } else { 2816*fcf3ce44SJohn Forte NODELIST *nd; 2817*fcf3ce44SJohn Forte 2818*fcf3ce44SJohn Forte /* Remove node from head */ 2819*fcf3ce44SJohn Forte rp->nodeq.q_first = nlp->nlp_next[ringno]; 2820*fcf3ce44SJohn Forte nd = (NODELIST *)rp->nodeq.q_last; 2821*fcf3ce44SJohn Forte nd->nlp_next[ringno] = rp->nodeq.q_first; 2822*fcf3ce44SJohn Forte rp->nodeq.q_cnt--; 2823*fcf3ce44SJohn Forte 2824*fcf3ce44SJohn Forte } 2825*fcf3ce44SJohn Forte 2826*fcf3ce44SJohn Forte /* Clear node */ 2827*fcf3ce44SJohn Forte nlp->nlp_next[ringno] = NULL; 2828*fcf3ce44SJohn Forte } 2829*fcf3ce44SJohn Forte 2830*fcf3ce44SJohn Forte /* 2831*fcf3ce44SJohn Forte * If no iocbq was found on this node, then it will have been 2832*fcf3ce44SJohn Forte * removed. So try again. 2833*fcf3ce44SJohn Forte */ 2834*fcf3ce44SJohn Forte if (!iocbq) { 2835*fcf3ce44SJohn Forte goto begin; 2836*fcf3ce44SJohn Forte } 2837*fcf3ce44SJohn Forte sbp = (emlxs_buf_t *)iocbq->sbp; 2838*fcf3ce44SJohn Forte 2839*fcf3ce44SJohn Forte if (sbp) { 2840*fcf3ce44SJohn Forte /* 2841*fcf3ce44SJohn Forte * Check flags before we enter mutex in case this has 2842*fcf3ce44SJohn Forte * been flushed and destroyed 2843*fcf3ce44SJohn Forte */ 2844*fcf3ce44SJohn Forte if ((sbp->pkt_flags & 2845*fcf3ce44SJohn Forte (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) || 2846*fcf3ce44SJohn Forte !(sbp->pkt_flags & PACKET_IN_TXQ)) { 2847*fcf3ce44SJohn Forte goto begin; 2848*fcf3ce44SJohn Forte } 2849*fcf3ce44SJohn Forte mutex_enter(&sbp->mtx); 2850*fcf3ce44SJohn Forte 2851*fcf3ce44SJohn Forte if ((sbp->pkt_flags & 2852*fcf3ce44SJohn Forte (PACKET_IN_COMPLETION | PACKET_IN_CHIPQ)) || 2853*fcf3ce44SJohn Forte !(sbp->pkt_flags & PACKET_IN_TXQ)) { 2854*fcf3ce44SJohn Forte mutex_exit(&sbp->mtx); 2855*fcf3ce44SJohn Forte goto begin; 2856*fcf3ce44SJohn Forte } 2857*fcf3ce44SJohn Forte sbp->pkt_flags &= ~PACKET_IN_TXQ; 2858*fcf3ce44SJohn Forte hba->ring_tx_count[ringno]--; 2859*fcf3ce44SJohn Forte 2860*fcf3ce44SJohn Forte mutex_exit(&sbp->mtx); 2861*fcf3ce44SJohn Forte } 2862*fcf3ce44SJohn Forte } 2863*fcf3ce44SJohn Forte if (iocbq) { 2864*fcf3ce44SJohn Forte HBASTATS.IocbTxGet[ringno]++; 2865*fcf3ce44SJohn Forte } 2866*fcf3ce44SJohn Forte /* Adjust the ring timeout timer */ 2867*fcf3ce44SJohn Forte rp->timeout = (rp->nodeq.q_first) ? (hba->timer_tics + 5) : 0; 2868*fcf3ce44SJohn Forte 2869*fcf3ce44SJohn Forte if (lock) { 2870*fcf3ce44SJohn Forte mutex_exit(&EMLXS_RINGTX_LOCK); 2871*fcf3ce44SJohn Forte } 2872*fcf3ce44SJohn Forte return (iocbq); 2873*fcf3ce44SJohn Forte 2874*fcf3ce44SJohn Forte } /* emlxs_tx_get() */ 2875*fcf3ce44SJohn Forte 2876*fcf3ce44SJohn Forte 2877*fcf3ce44SJohn Forte 2878*fcf3ce44SJohn Forte extern uint32_t 2879*fcf3ce44SJohn Forte emlxs_chipq_node_flush(emlxs_port_t *port, RING *ring, 2880*fcf3ce44SJohn Forte NODELIST *ndlp, emlxs_buf_t *fpkt) 2881*fcf3ce44SJohn Forte { 2882*fcf3ce44SJohn Forte emlxs_hba_t *hba = HBA; 2883*fcf3ce44SJohn Forte emlxs_buf_t *sbp; 2884*fcf3ce44SJohn Forte IOCBQ *iocbq; 2885*fcf3ce44SJohn Forte IOCBQ *next; 2886*fcf3ce44SJohn Forte Q abort; 2887*fcf3ce44SJohn Forte RING *rp; 2888*fcf3ce44SJohn Forte uint32_t ringno; 2889*fcf3ce44SJohn Forte uint8_t flag[MAX_RINGS]; 2890*fcf3ce44SJohn Forte uint32_t iotag; 2891*fcf3ce44SJohn Forte 2892*fcf3ce44SJohn Forte bzero((void *)&abort, sizeof (Q)); 2893*fcf3ce44SJohn Forte bzero((void *)flag, sizeof (flag)); 2894*fcf3ce44SJohn Forte 2895*fcf3ce44SJohn Forte for (ringno = 0; ringno < hba->ring_count; ringno++) { 2896*fcf3ce44SJohn Forte rp = &hba->ring[ringno]; 2897*fcf3ce44SJohn Forte 2898*fcf3ce44SJohn Forte if (ring && rp != ring) { 2899*fcf3ce44SJohn Forte continue; 2900*fcf3ce44SJohn Forte } 2901*fcf3ce44SJohn Forte mutex_enter(&EMLXS_FCTAB_LOCK(ringno)); 2902*fcf3ce44SJohn Forte 2903*fcf3ce44SJohn Forte for (iotag = 1; iotag < rp->max_iotag; iotag++) { 2904*fcf3ce44SJohn Forte sbp = rp->fc_table[iotag]; 2905*fcf3ce44SJohn Forte 2906*fcf3ce44SJohn Forte if (sbp && (sbp != STALE_PACKET) && 2907*fcf3ce44SJohn Forte (sbp->pkt_flags & PACKET_IN_CHIPQ) && 2908*fcf3ce44SJohn Forte (sbp->node == ndlp) && 2909*fcf3ce44SJohn Forte (sbp->ring == rp) && 2910*fcf3ce44SJohn Forte !(sbp->pkt_flags & PACKET_XRI_CLOSED)) { 2911*fcf3ce44SJohn Forte emlxs_sbp_abort_add(port, sbp, &abort, 2912*fcf3ce44SJohn Forte flag, fpkt); 2913*fcf3ce44SJohn Forte } 2914*fcf3ce44SJohn Forte } 2915*fcf3ce44SJohn Forte mutex_exit(&EMLXS_FCTAB_LOCK(ringno)); 2916*fcf3ce44SJohn Forte 2917*fcf3ce44SJohn Forte } /* for */ 2918*fcf3ce44SJohn Forte 2919*fcf3ce44SJohn Forte /* Now put the iocb's on the tx queue */ 2920*fcf3ce44SJohn Forte iocbq = (IOCBQ *)abort.q_first; 2921*fcf3ce44SJohn Forte while (iocbq) { 2922*fcf3ce44SJohn Forte /* Save the next iocbq for now */ 2923*fcf3ce44SJohn Forte next = (IOCBQ *)iocbq->next; 2924*fcf3ce44SJohn Forte 2925*fcf3ce44SJohn Forte /* Unlink this iocbq */ 2926*fcf3ce44SJohn Forte iocbq->next = NULL; 2927*fcf3ce44SJohn Forte 2928*fcf3ce44SJohn Forte /* Send this iocbq */ 2929*fcf3ce44SJohn Forte emlxs_tx_put(iocbq, 1); 2930*fcf3ce44SJohn Forte 2931*fcf3ce44SJohn Forte iocbq = next; 2932*fcf3ce44SJohn Forte } 2933*fcf3ce44SJohn Forte 2934*fcf3ce44SJohn Forte /* Now trigger ring service */ 2935*fcf3ce44SJohn Forte for (ringno = 0; ringno < hba->ring_count; ringno++) { 2936*fcf3ce44SJohn Forte if (!flag[ringno]) { 2937*fcf3ce44SJohn Forte continue; 2938*fcf3ce44SJohn Forte } 2939*fcf3ce44SJohn Forte rp = &hba->ring[ringno]; 2940*fcf3ce44SJohn Forte 2941*fcf3ce44SJohn Forte emlxs_issue_iocb_cmd(hba, rp, 0); 2942*fcf3ce44SJohn Forte } 2943*fcf3ce44SJohn Forte 2944*fcf3ce44SJohn Forte return (abort.q_cnt); 2945*fcf3ce44SJohn Forte 2946*fcf3ce44SJohn Forte } /* emlxs_chipq_node_flush() */ 2947*fcf3ce44SJohn Forte 2948*fcf3ce44SJohn Forte 2949*fcf3ce44SJohn Forte /* Flush all IO's left on all iotag lists */ 2950*fcf3ce44SJohn Forte static uint32_t 2951*fcf3ce44SJohn Forte emlxs_iotag_flush(emlxs_hba_t *hba) 2952*fcf3ce44SJohn Forte { 2953*fcf3ce44SJohn Forte emlxs_port_t *port = &PPORT; 2954*fcf3ce44SJohn Forte emlxs_buf_t *sbp; 2955*fcf3ce44SJohn Forte IOCBQ *iocbq; 2956*fcf3ce44SJohn Forte IOCB *iocb; 2957*fcf3ce44SJohn Forte Q abort; 2958*fcf3ce44SJohn Forte RING *rp; 2959*fcf3ce44SJohn Forte uint32_t ringno; 2960*fcf3ce44SJohn Forte uint32_t iotag; 2961*fcf3ce44SJohn Forte uint32_t count; 2962*fcf3ce44SJohn Forte 2963*fcf3ce44SJohn Forte count = 0; 2964*fcf3ce44SJohn Forte for (ringno = 0; ringno < hba->ring_count; ringno++) { 2965*fcf3ce44SJohn Forte rp = &hba->ring[ringno]; 2966*fcf3ce44SJohn Forte 2967*fcf3ce44SJohn Forte bzero((void *)&abort, sizeof (Q)); 2968*fcf3ce44SJohn Forte 2969*fcf3ce44SJohn Forte mutex_enter(&EMLXS_FCTAB_LOCK(ringno)); 2970*fcf3ce44SJohn Forte 2971*fcf3ce44SJohn Forte for (iotag = 1; iotag < rp->max_iotag; iotag++) { 2972*fcf3ce44SJohn Forte sbp = rp->fc_table[iotag]; 2973*fcf3ce44SJohn Forte 2974*fcf3ce44SJohn Forte if (!sbp || (sbp == STALE_PACKET)) { 2975*fcf3ce44SJohn Forte continue; 2976*fcf3ce44SJohn Forte } 2977*fcf3ce44SJohn Forte /* Unregister the packet */ 2978*fcf3ce44SJohn Forte rp->fc_table[iotag] = STALE_PACKET; 2979*fcf3ce44SJohn Forte hba->io_count[ringno]--; 2980*fcf3ce44SJohn Forte sbp->iotag = 0; 2981*fcf3ce44SJohn Forte 2982*fcf3ce44SJohn Forte /* Clean up the sbp */ 2983*fcf3ce44SJohn Forte mutex_enter(&sbp->mtx); 2984*fcf3ce44SJohn Forte 2985*fcf3ce44SJohn Forte /* Set IOCB status */ 2986*fcf3ce44SJohn Forte iocbq = &sbp->iocbq; 2987*fcf3ce44SJohn Forte iocb = &iocbq->iocb; 2988*fcf3ce44SJohn Forte 2989*fcf3ce44SJohn Forte iocb->ulpStatus = IOSTAT_LOCAL_REJECT; 2990*fcf3ce44SJohn Forte iocb->un.grsp.perr.statLocalError = IOERR_LINK_DOWN; 2991*fcf3ce44SJohn Forte iocb->ulpLe = 1; 2992*fcf3ce44SJohn Forte iocbq->next = NULL; 2993*fcf3ce44SJohn Forte 2994*fcf3ce44SJohn Forte if (sbp->pkt_flags & PACKET_IN_TXQ) { 2995*fcf3ce44SJohn Forte sbp->pkt_flags &= ~PACKET_IN_TXQ; 2996*fcf3ce44SJohn Forte hba->ring_tx_count[ringno]--; 2997*fcf3ce44SJohn Forte } 2998*fcf3ce44SJohn Forte if (sbp->pkt_flags & PACKET_IN_CHIPQ) { 2999*fcf3ce44SJohn Forte sbp->pkt_flags &= ~PACKET_IN_CHIPQ; 3000*fcf3ce44SJohn Forte } 3001*fcf3ce44SJohn Forte if (sbp->bmp) { 3002*fcf3ce44SJohn Forte (void) emlxs_mem_put(hba, MEM_BPL, 3003*fcf3ce44SJohn Forte (uint8_t *)sbp->bmp); 3004*fcf3ce44SJohn Forte sbp->bmp = 0; 3005*fcf3ce44SJohn Forte } 3006*fcf3ce44SJohn Forte /* At this point all nodes are assumed destroyed */ 3007*fcf3ce44SJohn Forte sbp->node = 0; 3008*fcf3ce44SJohn Forte 3009*fcf3ce44SJohn Forte mutex_exit(&sbp->mtx); 3010*fcf3ce44SJohn Forte 3011*fcf3ce44SJohn Forte /* Add this iocb to our local abort Q */ 3012*fcf3ce44SJohn Forte if (abort.q_first) { 3013*fcf3ce44SJohn Forte ((IOCBQ *) abort.q_last)->next = iocbq; 3014*fcf3ce44SJohn Forte abort.q_last = (uint8_t *)iocbq; 3015*fcf3ce44SJohn Forte abort.q_cnt++; 3016*fcf3ce44SJohn Forte } else { 3017*fcf3ce44SJohn Forte abort.q_first = (uint8_t *)iocbq; 3018*fcf3ce44SJohn Forte abort.q_last = (uint8_t *)iocbq; 3019*fcf3ce44SJohn Forte abort.q_cnt = 1; 3020*fcf3ce44SJohn Forte } 3021*fcf3ce44SJohn Forte } 3022*fcf3ce44SJohn Forte 3023*fcf3ce44SJohn Forte mutex_exit(&EMLXS_FCTAB_LOCK(ringno)); 3024*fcf3ce44SJohn Forte 3025*fcf3ce44SJohn Forte /* Trigger deferred completion */ 3026*fcf3ce44SJohn Forte if (abort.q_first) { 3027*fcf3ce44SJohn Forte mutex_enter(&rp->rsp_lock); 3028*fcf3ce44SJohn Forte if (rp->rsp_head == NULL) { 3029*fcf3ce44SJohn Forte rp->rsp_head = (IOCBQ *)abort.q_first; 3030*fcf3ce44SJohn Forte rp->rsp_tail = (IOCBQ *)abort.q_last; 3031*fcf3ce44SJohn Forte } else { 3032*fcf3ce44SJohn Forte rp->rsp_tail->next = (IOCBQ *)abort.q_first; 3033*fcf3ce44SJohn Forte rp->rsp_tail = (IOCBQ *)abort.q_last; 3034*fcf3ce44SJohn Forte } 3035*fcf3ce44SJohn Forte mutex_exit(&rp->rsp_lock); 3036*fcf3ce44SJohn Forte 3037*fcf3ce44SJohn Forte emlxs_thread_trigger2(&rp->intr_thread, 3038*fcf3ce44SJohn Forte emlxs_proc_ring, rp); 3039*fcf3ce44SJohn Forte 3040*fcf3ce44SJohn Forte EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_flush_msg, 3041*fcf3ce44SJohn Forte "Forced iotag completion. ring=%d count=%d", 3042*fcf3ce44SJohn Forte ringno, abort.q_cnt); 3043*fcf3ce44SJohn Forte 3044*fcf3ce44SJohn Forte count += abort.q_cnt; 3045*fcf3ce44SJohn Forte } 3046*fcf3ce44SJohn Forte } 3047*fcf3ce44SJohn Forte 3048*fcf3ce44SJohn Forte return (count); 3049*fcf3ce44SJohn Forte 3050*fcf3ce44SJohn Forte } /* emlxs_iotag_flush() */ 3051*fcf3ce44SJohn Forte 3052*fcf3ce44SJohn Forte 3053*fcf3ce44SJohn Forte 3054*fcf3ce44SJohn Forte /* Checks for IO's on all or a given ring for a given node */ 3055*fcf3ce44SJohn Forte extern uint32_t 3056*fcf3ce44SJohn Forte emlxs_chipq_node_check(emlxs_port_t *port, RING *ring, NODELIST *ndlp) 3057*fcf3ce44SJohn Forte { 3058*fcf3ce44SJohn Forte emlxs_hba_t *hba = HBA; 3059*fcf3ce44SJohn Forte emlxs_buf_t *sbp; 3060*fcf3ce44SJohn Forte RING *rp; 3061*fcf3ce44SJohn Forte uint32_t ringno; 3062*fcf3ce44SJohn Forte uint32_t count; 3063*fcf3ce44SJohn Forte uint32_t iotag; 3064*fcf3ce44SJohn Forte 3065*fcf3ce44SJohn Forte count = 0; 3066*fcf3ce44SJohn Forte 3067*fcf3ce44SJohn Forte for (ringno = 0; ringno < hba->ring_count; ringno++) { 3068*fcf3ce44SJohn Forte rp = &hba->ring[ringno]; 3069*fcf3ce44SJohn Forte 3070*fcf3ce44SJohn Forte if (ring && rp != ring) { 3071*fcf3ce44SJohn Forte continue; 3072*fcf3ce44SJohn Forte } 3073*fcf3ce44SJohn Forte mutex_enter(&EMLXS_FCTAB_LOCK(ringno)); 3074*fcf3ce44SJohn Forte 3075*fcf3ce44SJohn Forte for (iotag = 1; iotag < rp->max_iotag; iotag++) { 3076*fcf3ce44SJohn Forte sbp = rp->fc_table[iotag]; 3077*fcf3ce44SJohn Forte 3078*fcf3ce44SJohn Forte if (sbp && (sbp != STALE_PACKET) && 3079*fcf3ce44SJohn Forte (sbp->pkt_flags & PACKET_IN_CHIPQ) && 3080*fcf3ce44SJohn Forte (sbp->node == ndlp) && 3081*fcf3ce44SJohn Forte (sbp->ring == rp) && 3082*fcf3ce44SJohn Forte !(sbp->pkt_flags & PACKET_XRI_CLOSED)) { 3083*fcf3ce44SJohn Forte count++; 3084*fcf3ce44SJohn Forte } 3085*fcf3ce44SJohn Forte } 3086*fcf3ce44SJohn Forte mutex_exit(&EMLXS_FCTAB_LOCK(ringno)); 3087*fcf3ce44SJohn Forte 3088*fcf3ce44SJohn Forte } /* for */ 3089*fcf3ce44SJohn Forte 3090*fcf3ce44SJohn Forte return (count); 3091*fcf3ce44SJohn Forte 3092*fcf3ce44SJohn Forte } /* emlxs_chipq_node_check() */ 3093*fcf3ce44SJohn Forte 3094*fcf3ce44SJohn Forte 3095*fcf3ce44SJohn Forte 3096*fcf3ce44SJohn Forte /* Flush all IO's for a given node's lun (FC_FCP_RING only) */ 3097*fcf3ce44SJohn Forte extern uint32_t 3098*fcf3ce44SJohn Forte emlxs_chipq_lun_flush(emlxs_port_t *port, NODELIST *ndlp, 3099*fcf3ce44SJohn Forte uint32_t lun, emlxs_buf_t *fpkt) 3100*fcf3ce44SJohn Forte { 3101*fcf3ce44SJohn Forte emlxs_hba_t *hba = HBA; 3102*fcf3ce44SJohn Forte emlxs_buf_t *sbp; 3103*fcf3ce44SJohn Forte RING *rp; 3104*fcf3ce44SJohn Forte IOCBQ *iocbq; 3105*fcf3ce44SJohn Forte IOCBQ *next; 3106*fcf3ce44SJohn Forte Q abort; 3107*fcf3ce44SJohn Forte uint32_t iotag; 3108*fcf3ce44SJohn Forte uint8_t flag[MAX_RINGS]; 3109*fcf3ce44SJohn Forte 3110*fcf3ce44SJohn Forte bzero((void *)flag, sizeof (flag)); 3111*fcf3ce44SJohn Forte bzero((void *)&abort, sizeof (Q)); 3112*fcf3ce44SJohn Forte rp = &hba->ring[FC_FCP_RING]; 3113*fcf3ce44SJohn Forte 3114*fcf3ce44SJohn Forte mutex_enter(&EMLXS_FCTAB_LOCK(FC_FCP_RING)); 3115*fcf3ce44SJohn Forte for (iotag = 1; iotag < rp->max_iotag; iotag++) { 3116*fcf3ce44SJohn Forte sbp = rp->fc_table[iotag]; 3117*fcf3ce44SJohn Forte 3118*fcf3ce44SJohn Forte if (sbp && (sbp != STALE_PACKET) && 3119*fcf3ce44SJohn Forte sbp->pkt_flags & PACKET_IN_CHIPQ && 3120*fcf3ce44SJohn Forte sbp->node == ndlp && 3121*fcf3ce44SJohn Forte sbp->ring == rp && 3122*fcf3ce44SJohn Forte sbp->lun == lun && 3123*fcf3ce44SJohn Forte !(sbp->pkt_flags & PACKET_XRI_CLOSED)) { 3124*fcf3ce44SJohn Forte emlxs_sbp_abort_add(port, sbp, &abort, flag, fpkt); 3125*fcf3ce44SJohn Forte } 3126*fcf3ce44SJohn Forte } 3127*fcf3ce44SJohn Forte mutex_exit(&EMLXS_FCTAB_LOCK(FC_FCP_RING)); 3128*fcf3ce44SJohn Forte 3129*fcf3ce44SJohn Forte /* Now put the iocb's on the tx queue */ 3130*fcf3ce44SJohn Forte iocbq = (IOCBQ *)abort.q_first; 3131*fcf3ce44SJohn Forte while (iocbq) { 3132*fcf3ce44SJohn Forte /* Save the next iocbq for now */ 3133*fcf3ce44SJohn Forte next = (IOCBQ *)iocbq->next; 3134*fcf3ce44SJohn Forte 3135*fcf3ce44SJohn Forte /* Unlink this iocbq */ 3136*fcf3ce44SJohn Forte iocbq->next = NULL; 3137*fcf3ce44SJohn Forte 3138*fcf3ce44SJohn Forte /* Send this iocbq */ 3139*fcf3ce44SJohn Forte emlxs_tx_put(iocbq, 1); 3140*fcf3ce44SJohn Forte 3141*fcf3ce44SJohn Forte iocbq = next; 3142*fcf3ce44SJohn Forte } 3143*fcf3ce44SJohn Forte 3144*fcf3ce44SJohn Forte /* Now trigger ring service */ 3145*fcf3ce44SJohn Forte if (abort.q_cnt) { 3146*fcf3ce44SJohn Forte emlxs_issue_iocb_cmd(hba, rp, 0); 3147*fcf3ce44SJohn Forte } 3148*fcf3ce44SJohn Forte return (abort.q_cnt); 3149*fcf3ce44SJohn Forte 3150*fcf3ce44SJohn Forte } /* emlxs_chipq_lun_flush() */ 3151*fcf3ce44SJohn Forte 3152*fcf3ce44SJohn Forte 3153*fcf3ce44SJohn Forte 3154*fcf3ce44SJohn Forte /* 3155*fcf3ce44SJohn Forte * Issue an ABORT_XRI_CN iocb command to abort an FCP command already issued. 3156*fcf3ce44SJohn Forte * This must be called while holding the EMLXS_FCCTAB_LOCK 3157*fcf3ce44SJohn Forte */ 3158*fcf3ce44SJohn Forte extern IOCBQ * 3159*fcf3ce44SJohn Forte emlxs_create_abort_xri_cn(emlxs_port_t *port, NODELIST *ndlp, uint16_t iotag, 3160*fcf3ce44SJohn Forte RING *rp, uint8_t class, int32_t flag) 3161*fcf3ce44SJohn Forte { 3162*fcf3ce44SJohn Forte emlxs_hba_t *hba = HBA; 3163*fcf3ce44SJohn Forte IOCBQ *iocbq; 3164*fcf3ce44SJohn Forte IOCB *iocb; 3165*fcf3ce44SJohn Forte uint16_t abort_iotag; 3166*fcf3ce44SJohn Forte 3167*fcf3ce44SJohn Forte if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) { 3168*fcf3ce44SJohn Forte return (NULL); 3169*fcf3ce44SJohn Forte } 3170*fcf3ce44SJohn Forte iocbq->ring = (void *)rp; 3171*fcf3ce44SJohn Forte iocbq->port = (void *)port; 3172*fcf3ce44SJohn Forte iocbq->node = (void *)ndlp; 3173*fcf3ce44SJohn Forte iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL); 3174*fcf3ce44SJohn Forte iocb = &iocbq->iocb; 3175*fcf3ce44SJohn Forte 3176*fcf3ce44SJohn Forte /* 3177*fcf3ce44SJohn Forte * set up an iotag using special Abort iotags 3178*fcf3ce44SJohn Forte */ 3179*fcf3ce44SJohn Forte if ((rp->fc_abort_iotag < rp->max_iotag)) { 3180*fcf3ce44SJohn Forte rp->fc_abort_iotag = rp->max_iotag; 3181*fcf3ce44SJohn Forte } 3182*fcf3ce44SJohn Forte abort_iotag = rp->fc_abort_iotag++; 3183*fcf3ce44SJohn Forte 3184*fcf3ce44SJohn Forte 3185*fcf3ce44SJohn Forte iocb->ulpIoTag = abort_iotag; 3186*fcf3ce44SJohn Forte iocb->un.acxri.abortType = flag; 3187*fcf3ce44SJohn Forte iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi; 3188*fcf3ce44SJohn Forte iocb->un.acxri.abortIoTag = iotag; 3189*fcf3ce44SJohn Forte iocb->ulpLe = 1; 3190*fcf3ce44SJohn Forte iocb->ulpClass = class; 3191*fcf3ce44SJohn Forte iocb->ulpCommand = CMD_ABORT_XRI_CN; 3192*fcf3ce44SJohn Forte iocb->ulpOwner = OWN_CHIP; 3193*fcf3ce44SJohn Forte 3194*fcf3ce44SJohn Forte return (iocbq); 3195*fcf3ce44SJohn Forte 3196*fcf3ce44SJohn Forte } /* emlxs_create_abort_xri_cn() */ 3197*fcf3ce44SJohn Forte 3198*fcf3ce44SJohn Forte 3199*fcf3ce44SJohn Forte extern IOCBQ * 3200*fcf3ce44SJohn Forte emlxs_create_abort_xri_cx(emlxs_port_t *port, NODELIST *ndlp, uint16_t xid, 3201*fcf3ce44SJohn Forte RING *rp, uint8_t class, int32_t flag) 3202*fcf3ce44SJohn Forte { 3203*fcf3ce44SJohn Forte emlxs_hba_t *hba = HBA; 3204*fcf3ce44SJohn Forte IOCBQ *iocbq; 3205*fcf3ce44SJohn Forte IOCB *iocb; 3206*fcf3ce44SJohn Forte uint16_t abort_iotag; 3207*fcf3ce44SJohn Forte 3208*fcf3ce44SJohn Forte if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) { 3209*fcf3ce44SJohn Forte return (NULL); 3210*fcf3ce44SJohn Forte } 3211*fcf3ce44SJohn Forte iocbq->ring = (void *)rp; 3212*fcf3ce44SJohn Forte iocbq->port = (void *)port; 3213*fcf3ce44SJohn Forte iocbq->node = (void *)ndlp; 3214*fcf3ce44SJohn Forte iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL); 3215*fcf3ce44SJohn Forte iocb = &iocbq->iocb; 3216*fcf3ce44SJohn Forte 3217*fcf3ce44SJohn Forte /* 3218*fcf3ce44SJohn Forte * set up an iotag using special Abort iotags 3219*fcf3ce44SJohn Forte */ 3220*fcf3ce44SJohn Forte if ((rp->fc_abort_iotag < rp->max_iotag)) { 3221*fcf3ce44SJohn Forte rp->fc_abort_iotag = rp->max_iotag; 3222*fcf3ce44SJohn Forte } 3223*fcf3ce44SJohn Forte abort_iotag = rp->fc_abort_iotag++; 3224*fcf3ce44SJohn Forte 3225*fcf3ce44SJohn Forte iocb->ulpContext = xid; 3226*fcf3ce44SJohn Forte iocb->ulpIoTag = abort_iotag; 3227*fcf3ce44SJohn Forte iocb->un.acxri.abortType = flag; 3228*fcf3ce44SJohn Forte iocb->ulpLe = 1; 3229*fcf3ce44SJohn Forte iocb->ulpClass = class; 3230*fcf3ce44SJohn Forte iocb->ulpCommand = CMD_ABORT_XRI_CX; 3231*fcf3ce44SJohn Forte iocb->ulpOwner = OWN_CHIP; 3232*fcf3ce44SJohn Forte 3233*fcf3ce44SJohn Forte return (iocbq); 3234*fcf3ce44SJohn Forte 3235*fcf3ce44SJohn Forte } /* emlxs_create_abort_xri_cx() */ 3236*fcf3ce44SJohn Forte 3237*fcf3ce44SJohn Forte 3238*fcf3ce44SJohn Forte 3239*fcf3ce44SJohn Forte /* This must be called while holding the EMLXS_FCCTAB_LOCK */ 3240*fcf3ce44SJohn Forte extern IOCBQ * 3241*fcf3ce44SJohn Forte emlxs_create_close_xri_cn(emlxs_port_t *port, NODELIST *ndlp, 3242*fcf3ce44SJohn Forte uint16_t iotag, RING *rp) 3243*fcf3ce44SJohn Forte { 3244*fcf3ce44SJohn Forte emlxs_hba_t *hba = HBA; 3245*fcf3ce44SJohn Forte IOCBQ *iocbq; 3246*fcf3ce44SJohn Forte IOCB *iocb; 3247*fcf3ce44SJohn Forte uint16_t abort_iotag; 3248*fcf3ce44SJohn Forte 3249*fcf3ce44SJohn Forte if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) { 3250*fcf3ce44SJohn Forte return (NULL); 3251*fcf3ce44SJohn Forte } 3252*fcf3ce44SJohn Forte iocbq->ring = (void *)rp; 3253*fcf3ce44SJohn Forte iocbq->port = (void *)port; 3254*fcf3ce44SJohn Forte iocbq->node = (void *)ndlp; 3255*fcf3ce44SJohn Forte iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL); 3256*fcf3ce44SJohn Forte iocb = &iocbq->iocb; 3257*fcf3ce44SJohn Forte 3258*fcf3ce44SJohn Forte /* 3259*fcf3ce44SJohn Forte * set up an iotag using special Abort iotags 3260*fcf3ce44SJohn Forte */ 3261*fcf3ce44SJohn Forte if ((rp->fc_abort_iotag < rp->max_iotag)) { 3262*fcf3ce44SJohn Forte rp->fc_abort_iotag = rp->max_iotag; 3263*fcf3ce44SJohn Forte } 3264*fcf3ce44SJohn Forte abort_iotag = rp->fc_abort_iotag++; 3265*fcf3ce44SJohn Forte 3266*fcf3ce44SJohn Forte iocb->ulpIoTag = abort_iotag; 3267*fcf3ce44SJohn Forte iocb->un.acxri.abortType = 0; 3268*fcf3ce44SJohn Forte iocb->un.acxri.abortContextTag = ndlp->nlp_Rpi; 3269*fcf3ce44SJohn Forte iocb->un.acxri.abortIoTag = iotag; 3270*fcf3ce44SJohn Forte iocb->ulpLe = 1; 3271*fcf3ce44SJohn Forte iocb->ulpClass = 0; 3272*fcf3ce44SJohn Forte iocb->ulpCommand = CMD_CLOSE_XRI_CN; 3273*fcf3ce44SJohn Forte iocb->ulpOwner = OWN_CHIP; 3274*fcf3ce44SJohn Forte 3275*fcf3ce44SJohn Forte return (iocbq); 3276*fcf3ce44SJohn Forte 3277*fcf3ce44SJohn Forte } /* emlxs_create_close_xri_cn() */ 3278*fcf3ce44SJohn Forte 3279*fcf3ce44SJohn Forte 3280*fcf3ce44SJohn Forte /* This must be called while holding the EMLXS_FCCTAB_LOCK */ 3281*fcf3ce44SJohn Forte extern IOCBQ * 3282*fcf3ce44SJohn Forte emlxs_create_close_xri_cx(emlxs_port_t *port, NODELIST *ndlp, 3283*fcf3ce44SJohn Forte uint16_t xid, RING *rp) 3284*fcf3ce44SJohn Forte { 3285*fcf3ce44SJohn Forte emlxs_hba_t *hba = HBA; 3286*fcf3ce44SJohn Forte IOCBQ *iocbq; 3287*fcf3ce44SJohn Forte IOCB *iocb; 3288*fcf3ce44SJohn Forte uint16_t abort_iotag; 3289*fcf3ce44SJohn Forte 3290*fcf3ce44SJohn Forte if ((iocbq = (IOCBQ *)emlxs_mem_get(hba, MEM_IOCB)) == NULL) { 3291*fcf3ce44SJohn Forte return (NULL); 3292*fcf3ce44SJohn Forte } 3293*fcf3ce44SJohn Forte iocbq->ring = (void *)rp; 3294*fcf3ce44SJohn Forte iocbq->port = (void *)port; 3295*fcf3ce44SJohn Forte iocbq->node = (void *)ndlp; 3296*fcf3ce44SJohn Forte iocbq->flag |= (IOCB_PRIORITY | IOCB_SPECIAL); 3297*fcf3ce44SJohn Forte iocb = &iocbq->iocb; 3298*fcf3ce44SJohn Forte 3299*fcf3ce44SJohn Forte /* 3300*fcf3ce44SJohn Forte * set up an iotag using special Abort iotags 3301*fcf3ce44SJohn Forte */ 3302*fcf3ce44SJohn Forte if ((rp->fc_abort_iotag < rp->max_iotag)) { 3303*fcf3ce44SJohn Forte rp->fc_abort_iotag = rp->max_iotag; 3304*fcf3ce44SJohn Forte } 3305*fcf3ce44SJohn Forte abort_iotag = rp->fc_abort_iotag++; 3306*fcf3ce44SJohn Forte 3307*fcf3ce44SJohn Forte iocb->ulpContext = xid; 3308*fcf3ce44SJohn Forte iocb->ulpIoTag = abort_iotag; 3309*fcf3ce44SJohn Forte iocb->ulpLe = 1; 3310*fcf3ce44SJohn Forte iocb->ulpClass = 0; 3311*fcf3ce44SJohn Forte iocb->ulpCommand = CMD_CLOSE_XRI_CX; 3312*fcf3ce44SJohn Forte iocb->ulpOwner = OWN_CHIP; 3313*fcf3ce44SJohn Forte 3314*fcf3ce44SJohn Forte return (iocbq); 3315*fcf3ce44SJohn Forte 3316*fcf3ce44SJohn Forte } /* emlxs_create_close_xri_cx() */ 3317*fcf3ce44SJohn Forte 3318*fcf3ce44SJohn Forte 3319*fcf3ce44SJohn Forte 3320*fcf3ce44SJohn Forte /* This must be called while holding the EMLXS_FCCTAB_LOCK */ 3321*fcf3ce44SJohn Forte static void 3322*fcf3ce44SJohn Forte emlxs_sbp_abort_add(emlxs_port_t *port, emlxs_buf_t *sbp, Q *abort, 3323*fcf3ce44SJohn Forte uint8_t *flag, emlxs_buf_t *fpkt) 3324*fcf3ce44SJohn Forte { 3325*fcf3ce44SJohn Forte emlxs_hba_t *hba = HBA; 3326*fcf3ce44SJohn Forte IOCBQ *iocbq; 3327*fcf3ce44SJohn Forte RING *rp; 3328*fcf3ce44SJohn Forte NODELIST *ndlp; 3329*fcf3ce44SJohn Forte 3330*fcf3ce44SJohn Forte rp = (RING *)sbp->ring; 3331*fcf3ce44SJohn Forte ndlp = sbp->node; 3332*fcf3ce44SJohn Forte 3333*fcf3ce44SJohn Forte /* Create the close XRI IOCB */ 3334*fcf3ce44SJohn Forte iocbq = emlxs_create_close_xri_cn(port, ndlp, sbp->iotag, rp); 3335*fcf3ce44SJohn Forte 3336*fcf3ce44SJohn Forte /* Add this iocb to our local abort Q */ 3337*fcf3ce44SJohn Forte /* This way we don't hold the CHIPQ lock too long */ 3338*fcf3ce44SJohn Forte if (iocbq) { 3339*fcf3ce44SJohn Forte if (abort->q_first) { 3340*fcf3ce44SJohn Forte ((IOCBQ *) abort->q_last)->next = iocbq; 3341*fcf3ce44SJohn Forte abort->q_last = (uint8_t *)iocbq; 3342*fcf3ce44SJohn Forte abort->q_cnt++; 3343*fcf3ce44SJohn Forte } else { 3344*fcf3ce44SJohn Forte abort->q_first = (uint8_t *)iocbq; 3345*fcf3ce44SJohn Forte abort->q_last = (uint8_t *)iocbq; 3346*fcf3ce44SJohn Forte abort->q_cnt = 1; 3347*fcf3ce44SJohn Forte } 3348*fcf3ce44SJohn Forte iocbq->next = NULL; 3349*fcf3ce44SJohn Forte } 3350*fcf3ce44SJohn Forte /* set the flags */ 3351*fcf3ce44SJohn Forte mutex_enter(&sbp->mtx); 3352*fcf3ce44SJohn Forte 3353*fcf3ce44SJohn Forte sbp->pkt_flags |= (PACKET_IN_FLUSH | PACKET_XRI_CLOSED); 3354*fcf3ce44SJohn Forte sbp->ticks = hba->timer_tics + 10; 3355*fcf3ce44SJohn Forte sbp->abort_attempts++; 3356*fcf3ce44SJohn Forte 3357*fcf3ce44SJohn Forte flag[rp->ringno] = 1; 3358*fcf3ce44SJohn Forte 3359*fcf3ce44SJohn Forte /* If the fpkt is already set, then we will leave it alone */ 3360*fcf3ce44SJohn Forte /* 3361*fcf3ce44SJohn Forte * This ensures that this pkt is only accounted for on one 3362*fcf3ce44SJohn Forte * fpkt->flush_count 3363*fcf3ce44SJohn Forte */ 3364*fcf3ce44SJohn Forte if (!sbp->fpkt && fpkt) { 3365*fcf3ce44SJohn Forte mutex_enter(&fpkt->mtx); 3366*fcf3ce44SJohn Forte sbp->fpkt = fpkt; 3367*fcf3ce44SJohn Forte fpkt->flush_count++; 3368*fcf3ce44SJohn Forte mutex_exit(&fpkt->mtx); 3369*fcf3ce44SJohn Forte } 3370*fcf3ce44SJohn Forte mutex_exit(&sbp->mtx); 3371*fcf3ce44SJohn Forte 3372*fcf3ce44SJohn Forte return; 3373*fcf3ce44SJohn Forte 3374*fcf3ce44SJohn Forte } /* emlxs_sbp_abort_add() */ 3375