extern int32_t emlxs_ip_handle_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq) { emlxs_port_t *port = &PPORT; IOCB *cmd; emlxs_buf_t *sbp; NODELIST *ndlp; cmd = &iocbq->iocb; HBASTATS.IpEvent++; sbp = (emlxs_buf_t *)iocbq->sbp; if (!sbp) { HBASTATS.IpStray++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ip_completion_msg, "cmd=0x%x iotag=0x%x status=0x%x perr=0x%x", (uint32_t)cmd->ULPCOMMAND, (uint32_t)cmd->ULPIOTAG, cmd->ULPSTATUS, cmd->un.ulpWord[4]); return (EIO); } if (cp->channelno != hba->channel_ip) { HBASTATS.IpStray++; return (0); } port = sbp->iocbq.port; switch (cmd->ULPCOMMAND) { /* * Error: Abnormal BCAST command completion (Local error) */ case CMD_XMIT_BCAST_CN: case CMD_XMIT_BCAST64_CN: HBASTATS.IpBcastCompleted++; HBASTATS.IpBcastError++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg, "XMIT BCAST completion error cmd=0x%x status=0x%x " "[%08x,%08x]", cmd->ULPCOMMAND, cmd->ULPSTATUS, cmd->un.ulpWord[4], cmd->un.ulpWord[5]); emlxs_pkt_complete(sbp, cmd->ULPSTATUS, cmd->un.grsp.perr.statLocalError, 1); break; /* * Error: Abnormal XMIT SEQUENCE command completion * (Local error) */ case CMD_XMIT_SEQUENCE_CR: case CMD_XMIT_SEQUENCE64_CR: HBASTATS.IpSeqCompleted++; HBASTATS.IpSeqError++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg, "XMIT SEQUENCE CR completion error: cmd=%x status=0x%x " "[%08x,%08x]", cmd->ULPCOMMAND, cmd->ULPSTATUS, cmd->un.ulpWord[4], cmd->un.ulpWord[5]); emlxs_pkt_complete(sbp, cmd->ULPSTATUS, cmd->un.grsp.perr.statLocalError, 1); break; /* * Normal BCAST completion */ case CMD_XMIT_BCAST_CX: case CMD_XMIT_BCAST64_CX: HBASTATS.IpBcastCompleted++; HBASTATS.IpBcastGood++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg, "XMIT BCAST CN completion: cmd=%x status=0x%x [%08x,%08x]", cmd->ULPCOMMAND, cmd->ULPSTATUS, cmd->un.ulpWord[4], cmd->un.ulpWord[5]); emlxs_pkt_complete(sbp, cmd->ULPSTATUS, cmd->un.grsp.perr.statLocalError, 1); break; /* * Normal XMIT SEQUENCE completion */ case CMD_XMIT_SEQUENCE_CX: case CMD_XMIT_SEQUENCE64_CX: HBASTATS.IpSeqCompleted++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg, "XMIT SEQUENCE CR completion: cmd=%x status=0x%x" "[%08x,%08x]", cmd->ULPCOMMAND, cmd->ULPSTATUS, cmd->un.ulpWord[4], cmd->un.ulpWord[5]); if (cmd->ULPSTATUS) { HBASTATS.IpSeqError++; if ((cmd->ULPSTATUS == IOSTAT_LOCAL_REJECT) && ((cmd->un.ulpWord[4] & 0xff) == IOERR_NO_XRI)) { ndlp = (NODELIST *)sbp->node; if ((cmd->ULPCONTEXT == ndlp->nlp_Xri) && !(ndlp->nlp_flag[hba->channel_ip] & NLP_RPI_XRI)) { ndlp->nlp_Xri = 0; (void) emlxs_create_xri(port, cp, ndlp); } } } else { HBASTATS.IpSeqGood++; } emlxs_pkt_complete(sbp, cmd->ULPSTATUS, cmd->un.grsp.perr.statLocalError, 1); break; default: HBASTATS.IpStray++; EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_ip_msg, "Invalid iocb: cmd=0x%x", cmd->ULPCOMMAND); break; } /* switch(cmd->ULPCOMMAND) */ return (0); } /* emlxs_ip_handle_event() */
static uint32_t emlxs_timer_check_pkts(emlxs_hba_t *hba, uint8_t *flag) { emlxs_port_t *port = &PPORT; emlxs_config_t *cfg = &CFG; Q tmo; int32_t channelno; CHANNEL *cp; NODELIST *nlp; IOCBQ *prev; IOCBQ *next; IOCB *iocb; IOCBQ *iocbq; emlxs_buf_t *sbp; fc_packet_t *pkt; Q abort; uint32_t iotag; uint32_t rc; if (!cfg[CFG_TIMEOUT_ENABLE].current) { return (0); } if (hba->pkt_timer > hba->timer_tics) { return (0); } hba->pkt_timer = hba->timer_tics + EMLXS_PKT_PERIOD; bzero((void *)&tmo, sizeof (Q)); /* * We must hold the locks here because we never know when an iocb * will be removed out from under us */ mutex_enter(&EMLXS_TX_CHANNEL_LOCK); for (channelno = 0; channelno < hba->chan_count; channelno++) { cp = &hba->chan[channelno]; /* Scan the tx queues for each active node on the channel */ /* Get the first node */ nlp = (NODELIST *)cp->nodeq.q_first; while (nlp) { /* Scan the node's priority tx queue */ prev = NULL; iocbq = (IOCBQ *)nlp->nlp_ptx[channelno].q_first; while (iocbq) { next = (IOCBQ *)iocbq->next; iocb = &iocbq->iocb; sbp = (emlxs_buf_t *)iocbq->sbp; /* Check if iocb has timed out */ if (sbp && hba->timer_tics >= sbp->ticks) { /* iocb timed out, now deque it */ if (next == NULL) { nlp->nlp_ptx[channelno].q_last = (uint8_t *)prev; } if (prev == NULL) { nlp->nlp_ptx[channelno]. q_first = (uint8_t *)next; } else { prev->next = next; } iocbq->next = NULL; nlp->nlp_ptx[channelno].q_cnt--; /* Add this iocb to our local */ /* timout queue */ /* * This way we don't hold the TX_CHANNEL * lock too long */ if (tmo.q_first) { ((IOCBQ *)tmo.q_last)->next = iocbq; tmo.q_last = (uint8_t *)iocbq; tmo.q_cnt++; } else { tmo.q_first = (uint8_t *)iocbq; tmo.q_last = (uint8_t *)iocbq; tmo.q_cnt = 1; } iocbq->next = NULL; } else { prev = iocbq; } iocbq = next; } /* while (iocbq) */ /* Scan the node's tx queue */ prev = NULL; iocbq = (IOCBQ *)nlp->nlp_tx[channelno].q_first; while (iocbq) { next = (IOCBQ *)iocbq->next; iocb = &iocbq->iocb; sbp = (emlxs_buf_t *)iocbq->sbp; /* Check if iocb has timed out */ if (sbp && hba->timer_tics >= sbp->ticks) { /* iocb timed out, now deque it */ if (next == NULL) { nlp->nlp_tx[channelno].q_last = (uint8_t *)prev; } if (prev == NULL) { nlp->nlp_tx[channelno].q_first = (uint8_t *)next; } else { prev->next = next; } iocbq->next = NULL; nlp->nlp_tx[channelno].q_cnt--; /* Add this iocb to our local */ /* timout queue */ /* * This way we don't hold the TX_CHANNEL * lock too long */ if (tmo.q_first) { ((IOCBQ *)tmo.q_last)->next = iocbq; tmo.q_last = (uint8_t *)iocbq; tmo.q_cnt++; } else { tmo.q_first = (uint8_t *)iocbq; tmo.q_last = (uint8_t *)iocbq; tmo.q_cnt = 1; } iocbq->next = NULL; } else { prev = iocbq; } iocbq = next; } /* while (iocbq) */ if (nlp == (NODELIST *)cp->nodeq.q_last) { nlp = NULL; } else { nlp = nlp->nlp_next[channelno]; } } /* while (nlp) */ } /* end of for */ /* Now cleanup the iocb's */ iocbq = (IOCBQ *)tmo.q_first; while (iocbq) { /* Free the IoTag and the bmp */ iocb = &iocbq->iocb; channelno = ((CHANNEL *)iocbq->channel)->channelno; sbp = iocbq->sbp; if (sbp && (sbp != STALE_PACKET)) { if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) { hba->fc_table[sbp->iotag] = NULL; emlxs_sli4_free_xri(hba, sbp, sbp->xp); } else { (void) emlxs_unregister_pkt( (CHANNEL *)iocbq->channel, iocb->ULPIOTAG, 0); } mutex_enter(&sbp->mtx); sbp->pkt_flags |= PACKET_IN_TIMEOUT; mutex_exit(&sbp->mtx); } iocbq = (IOCBQ *)iocbq->next; } /* end of while */ mutex_exit(&EMLXS_TX_CHANNEL_LOCK); /* Now complete the transmit timeouts outside the locks */ iocbq = (IOCBQ *)tmo.q_first; while (iocbq) { /* Save the next iocbq for now */ next = (IOCBQ *)iocbq->next; /* Unlink this iocbq */ iocbq->next = NULL; /* Get the pkt */ sbp = (emlxs_buf_t *)iocbq->sbp; if (sbp) { /* Warning: Some FCT sbp's don't have */ /* fc_packet objects */ pkt = PRIV2PKT(sbp); EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_timeout_msg, "TXQ abort: sbp=%p iotag=%x tmo=%d", sbp, sbp->iotag, (pkt) ? pkt->pkt_timeout : 0); if (hba->state >= FC_LINK_UP) { emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, IOERR_ABORT_TIMEOUT, 1); } else { emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, IOERR_LINK_DOWN, 1); } } iocbq = next; } /* end of while */ /* Now check the chip */ bzero((void *)&abort, sizeof (Q)); /* Check the HBA for outstanding IOs */ rc = 0; mutex_enter(&EMLXS_FCTAB_LOCK); for (iotag = 1; iotag < hba->max_iotag; iotag++) { sbp = hba->fc_table[iotag]; if (sbp && (sbp != STALE_PACKET) && (sbp->pkt_flags & PACKET_IN_CHIPQ) && !(sbp->pkt_flags & (PACKET_IN_FLUSH | PACKET_XRI_CLOSED)) && (hba->timer_tics >= sbp->ticks)) { rc = emlxs_pkt_chip_timeout(sbp->iocbq.port, sbp, &abort, flag); if (rc) { break; } } } mutex_exit(&EMLXS_FCTAB_LOCK); /* Now put the iocb's on the tx queue */ iocbq = (IOCBQ *)abort.q_first; while (iocbq) { /* Save the next iocbq for now */ next = (IOCBQ *)iocbq->next; /* Unlink this iocbq */ iocbq->next = NULL; /* Send this iocbq */ emlxs_tx_put(iocbq, 1); iocbq = next; } /* Now trigger IO channel service to send these abort iocbq */ for (channelno = 0; channelno < hba->chan_count; channelno++) { if (!flag[channelno]) { continue; } cp = &hba->chan[channelno]; EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, 0); } if (rc == 1) { /* Spawn a thread to reset the link */ emlxs_thread_spawn(hba, emlxs_reset_link_thread, NULL, NULL); } else if (rc == 2) { /* Spawn a thread to reset the adapter */ emlxs_thread_spawn(hba, emlxs_restart_thread, NULL, NULL); } return (rc); } /* emlxs_timer_check_pkts() */