Exemple #1
0
extern int32_t
emlxs_pkt_send(fc_packet_t *pkt, uint32_t now)
{
	emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private;
	emlxs_hba_t *hba = HBA;
	int32_t rval;

	if (now) {
		rval = emlxs_fca_transport((opaque_t)port, pkt);
	} else {
		/* Spawn a thread to send the pkt */
		emlxs_thread_spawn(hba, emlxs_pkt_thread, (char *)pkt, NULL);

		rval = FC_SUCCESS;
	}

	return (rval);

} /* emlxs_pkt_send() */
Exemple #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() */