コード例 #1
0
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() */
コード例 #2
0
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() */