Exemple #1
0
static void
emlxs_timer_check_heartbeat(emlxs_hba_t *hba)
{
    emlxs_port_t *port = &PPORT;
    MAILBOXQ *mbq;
    emlxs_config_t *cfg = &CFG;
    int rc;

    if (!cfg[CFG_HEARTBEAT_ENABLE].current) {
        return;
    }

    if (hba->timer_tics < hba->heartbeat_timer) {
        return;
    }

    hba->heartbeat_timer = hba->timer_tics + 5;

    /* Return if adapter interrupts have occurred */
    if (hba->heartbeat_flag) {
        hba->heartbeat_flag = 0;
        return;
    }
    /* No adapter interrupts have occured for 5 seconds now */

    /* Return if mailbox is busy */
    /* This means the mailbox timer routine is watching for problems */
    if (hba->mbox_timer) {
        return;
    }

    /* Return if heartbeat is still outstanding */
    if (hba->heartbeat_active) {
        return;
    }

    if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1)) == 0) {
        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
                   "Unable to allocate heartbeat mailbox.");
        return;
    }

    emlxs_mb_heartbeat(hba, mbq);
    hba->heartbeat_active = 1;

    rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_NOWAIT, 0);
    if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
        (void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbq);
    }

    return;

} /* emlxs_timer_check_heartbeat() */
extern void
emlxs_node_rm(emlxs_port_t *port, NODELIST *ndlp)
{
	emlxs_hba_t *hba = HBA;
	NODELIST *np;
	NODELIST *prevp;
	RPIobj_t *rp;
	uint8_t *wwn;
	uint32_t hash;

	rw_enter(&port->node_rwlock, RW_WRITER);
	hash = EMLXS_DID_HASH(ndlp->nlp_DID);
	np = port->node_table[hash];
	prevp = NULL;
	while (np != NULL) {
		if (np->nlp_DID == ndlp->nlp_DID) {
			if (prevp == NULL) {
				port->node_table[hash] = np->nlp_list_next;
			} else {
				prevp->nlp_list_next = np->nlp_list_next;
			}

			if (port->node_count) {
				port->node_count--;
			}

			wwn = (uint8_t *)&ndlp->nlp_portname;
			EMLXS_MSGF(EMLXS_CONTEXT,
			    &emlxs_node_destroy_msg, "did=%06x "
			    "rpi=%x wwpn=%02x%02x%02x%02x%02x%02x%02x%02x "
			    "count=%d", ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0],
			    wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6],
			    wwn[7], port->node_count);

			(void) emlxs_tx_node_flush(port, ndlp, 0, 1, 0);

			ndlp->nlp_active = 0;

			/* Break Node/RPI binding */
			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
				rp = EMLXS_NODE_TO_RPI(hba, ndlp);
				ndlp->RPIp = NULL;

				if (rp) {
					rp->node = NULL;
					(void) emlxs_sli4_free_rpi(hba, rp);
				}
			}

			(void) emlxs_mem_put(hba, MEM_NLP, (uint8_t *)ndlp);

			break;
		}
		prevp = np;
		np = np->nlp_list_next;
	}
	rw_exit(&port->node_rwlock);

	return;

} /* emlxs_node_rm() */
extern void
emlxs_node_destroy_all(emlxs_port_t *port)
{
	emlxs_hba_t *hba = HBA;
	NODELIST *next;
	NODELIST *ndlp;
	RPIobj_t *rp;
	uint8_t *wwn;
	uint32_t i;

	/* Flush and free the nodes */
	rw_enter(&port->node_rwlock, RW_WRITER);
	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
		ndlp = port->node_table[i];
		port->node_table[i] = 0;
		while (ndlp != NULL) {
			next = ndlp->nlp_list_next;
			ndlp->nlp_list_next = NULL;
			ndlp->nlp_list_prev = NULL;
			ndlp->nlp_active = 0;

			if (port->node_count) {
				port->node_count--;
			}

			wwn = (uint8_t *)&ndlp->nlp_portname;
			EMLXS_MSGF(EMLXS_CONTEXT,
			    &emlxs_node_destroy_msg, "did=%06x "
			    "rpi=%x wwpn=%02x%02x%02x%02x%02x%02x%02x%02x "
			    "count=%d", ndlp->nlp_DID, ndlp->nlp_Rpi, wwn[0],
			    wwn[1], wwn[2], wwn[3], wwn[4], wwn[5], wwn[6],
			    wwn[7], port->node_count);

			(void) emlxs_tx_node_flush(port, ndlp, 0, 0, 0);

			/* Break Node/RPI binding */
			if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
				rp = EMLXS_NODE_TO_RPI(hba, ndlp);
				ndlp->RPIp = NULL;

				if (rp) {
					rp->node = NULL;
					(void) emlxs_sli4_free_rpi(hba, rp);
				}
			}

			(void) emlxs_mem_put(hba, MEM_NLP, (uint8_t *)ndlp);

			ndlp = next;
		}
	}
	port->node_count = 0;
	rw_exit(&port->node_rwlock);

	/* Clean the base node */
	mutex_enter(&EMLXS_PORT_LOCK);
	port->node_base.nlp_list_next = NULL;
	port->node_base.nlp_list_prev = NULL;
	port->node_base.nlp_active = 1;
	mutex_exit(&EMLXS_PORT_LOCK);

	/* Flush the base node */
	(void) emlxs_tx_node_flush(port, &port->node_base, 0, 1, 0);
	(void) emlxs_chipq_node_flush(port, 0, &port->node_base, 0);

	return;

} /* emlxs_node_destroy_all() */
extern void
emlxs_node_open(emlxs_port_t *port, NODELIST *ndlp, uint32_t channelno)
{
	emlxs_hba_t *hba = HBA;
	CHANNEL *cp;
	uint32_t found;
	NODELIST *nlp;
	MAILBOXQ *mbox;
	uint32_t i;
	int rc;

	/* If node needs servicing, then add it to the channel queues */
	mutex_enter(&EMLXS_TX_CHANNEL_LOCK);

	/* Return if node destroyed */
	if (!ndlp || !ndlp->nlp_active) {
		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);

		return;
	}

	/* Return if node already open */
	if (!(ndlp->nlp_flag[channelno] & NLP_CLOSED)) {
		mutex_exit(&EMLXS_TX_CHANNEL_LOCK);

		return;
	}

	/* Set the node open (not closed) */
	ndlp->nlp_flag[channelno] &= ~(NLP_CLOSED|NLP_OFFLINE);

	/* Clear the timer */
	ndlp->nlp_tics[channelno] = 0;

	/*
	 * If the ptx or the tx queue needs servicing and
	 * the node is not already on the channel queue
	 */
	if ((ndlp->nlp_ptx[channelno].q_first ||
	    ndlp->nlp_tx[channelno].q_first) && !ndlp->nlp_next[channelno]) {
		cp = &hba->chan[channelno];

		/* If so, then add it to the channel queue */
		if (cp->nodeq.q_first) {
			((NODELIST *)cp->nodeq.q_last)->nlp_next[channelno] =
			    (uint8_t *)ndlp;
			ndlp->nlp_next[channelno] = cp->nodeq.q_first;

			/* If this is not the base node then */
			/* add it to the tail */
			if (!ndlp->nlp_base) {
				cp->nodeq.q_last = (uint8_t *)ndlp;
			} else {	/* Otherwise, add it to the head */

				/* The command node always gets priority */
				cp->nodeq.q_first = (uint8_t *)ndlp;
			}

			cp->nodeq.q_cnt++;
		} else {
			cp->nodeq.q_first = (uint8_t *)ndlp;
			cp->nodeq.q_last = (uint8_t *)ndlp;
			ndlp->nlp_next[channelno] = ndlp;
			cp->nodeq.q_cnt = 1;
		}
	}

	mutex_exit(&EMLXS_TX_CHANNEL_LOCK);

	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_opened_msg,
	    "node=%p did=%06x channel=%d", ndlp, ndlp->nlp_DID, channelno);

	/* If link attention needs to be cleared */
	if ((hba->state == FC_LINK_UP) && (channelno == hba->channel_fcp)) {
		if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
		/* re Think this code path. For SLI4 channel fcp == els */
			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
			    "ADD CODE to RESUME RPIs node=%p did=%06x chan=%d",
			    ndlp, ndlp->nlp_DID, channelno);

			goto done;
		}

		/* Scan to see if any FCP2 devices are still closed */
		found = 0;
		rw_enter(&port->node_rwlock, RW_READER);
		for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
			nlp = port->node_table[i];
			while (nlp != NULL) {
				if ((nlp->nlp_fcp_info & NLP_FCP_2_DEVICE) &&
				    (nlp->nlp_flag[hba->channel_fcp] &
				    NLP_CLOSED)) {
					found = 1;
					break;

				}
				nlp = nlp->nlp_list_next;
			}

			if (found) {
				break;
			}
		}

		rw_exit(&port->node_rwlock);

		if (!found) {
			/* Clear link attention */
			if ((mbox = (MAILBOXQ *)emlxs_mem_get(hba,
			    MEM_MBOX, 1))) {
				mutex_enter(&EMLXS_PORT_LOCK);

				/*
				 * If state is not FC_LINK_UP, then either the
				 * link has gone down or a FC_CLEAR_LA has
				 * already been issued
				 */
				if (hba->state != FC_LINK_UP) {
					mutex_exit(&EMLXS_PORT_LOCK);
					(void) emlxs_mem_put(hba, MEM_MBOX,
					    (uint8_t *)mbox);
					goto done;
				}

				EMLXS_STATE_CHANGE_LOCKED(hba, FC_CLEAR_LA);
				hba->discovery_timer = 0;
				mutex_exit(&EMLXS_PORT_LOCK);

				emlxs_mb_clear_la(hba, mbox);

				rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba,
				    mbox, MBX_NOWAIT, 0);
				if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
					(void) emlxs_mem_put(hba, MEM_MBOX,
					    (uint8_t *)mbox);
				}
			} else {
				/* Close the node and try again */
				/* in a few seconds */
				emlxs_node_close(port, ndlp, channelno, 5);
				return;
			}
		}
	}

done:

	/* Wake any sleeping threads */
	mutex_enter(&EMLXS_PKT_LOCK);
	cv_broadcast(&EMLXS_PKT_CV);
	mutex_exit(&EMLXS_PKT_LOCK);

	return;

} /* emlxs_node_open() */
extern int32_t
emlxs_ip_handle_rcv_seq_list(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
{
	emlxs_port_t *port = &PPORT;
	IOCB *cmd;
	uint64_t bdeAddr;
	MATCHMAP *mp = NULL;
	HBQE_t *hbqE;
	uint32_t hbq_id;
	uint32_t hbqe_tag;
	RING *rp;

	/*
	 * No action required for now.
	 */
	cmd = &iocbq->iocb;
	rp = &hba->sli.sli3.ring[cp->channelno];

	HBASTATS.IpRcvEvent++;

	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
	    "Receive sequence list: cmd=0x%x iotag=0x%x status=0x%x "
	    "w4=0x%x channelno=0x%x", cmd->ULPCOMMAND, cmd->ULPIOTAG,
	    cmd->ULPSTATUS, cmd->un.ulpWord[4], cp->channelno);

	if (cmd->ULPSTATUS) {
		goto out;
	}

	hbqE = (HBQE_t *)&iocbq->iocb;
	hbq_id = hbqE->unt.ext.HBQ_tag;
	hbqe_tag = hbqE->unt.ext.HBQE_tag;

	if (hba->flag & FC_HBQ_ENABLED) {
		HBQ_INIT_t *hbq;

		hbq = &hba->sli.sli3.hbq_table[hbq_id];

		HBASTATS.IpUbPosted--;

		if (hbqe_tag >= hbq->HBQ_numEntries) {
			mp = NULL;
		} else {
			mp = hba->sli.sli3.hbq_table
			    [hbq_id].HBQ_PostBufs[hbqe_tag];
		}
	} else {
		/* Check for valid buffer */
		if (!(cmd->un.cont64[0].tus.f.bdeFlags & BUFF_TYPE_INVALID)) {
			bdeAddr =
			    PADDR(cmd->un.cont64[0].addrHigh,
			    cmd->un.cont64[0].addrLow);
			mp = emlxs_mem_get_vaddr(hba, rp, bdeAddr);
		}
	}

out:

	if (hba->flag & FC_HBQ_ENABLED) {
		emlxs_update_HBQ_index(hba, hbq_id);
	} else {
		if (mp) {
			(void) emlxs_mem_put(hba, MEM_IPBUF, (uint8_t *)mp);
		}
		(void) emlxs_post_buffer(hba, rp, 1);
	}

	HBASTATS.IpDropped++;

	return (0);

} /* emlxs_ip_handle_rcv_seq_list() */
Exemple #6
0
static void
emlxs_timer_check_discovery(emlxs_port_t *port)
{
    emlxs_hba_t *hba = HBA;
    emlxs_config_t *cfg = &CFG;
    int32_t send_clear_la;
    uint32_t found;
    uint32_t i;
    NODELIST *nlp;
    MAILBOXQ *mbox;
    int rc;

    if (!cfg[CFG_TIMEOUT_ENABLE].current) {
        return;
    }

    /* Check the discovery timer for expiration */
    send_clear_la = 0;
    mutex_enter(&EMLXS_PORT_LOCK);
    while (hba->discovery_timer &&
            (hba->timer_tics >= hba->discovery_timer) &&
            (hba->state == FC_LINK_UP)) {
        send_clear_la = 1;

        /* Perform a flush on fcp2 nodes that are still closed */
        found = 0;
        rw_enter(&port->node_rwlock, RW_READER);
        for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
            nlp = port->node_table[i];
            while (nlp != NULL) {
                if ((nlp->nlp_fcp_info & NLP_FCP_2_DEVICE) &&
                        (nlp->nlp_flag[hba->channel_fcp] &
                         NLP_CLOSED)) {
                    found = 1;
                    break;

                }
                nlp = nlp->nlp_list_next;
            }

            if (found) {
                break;
            }
        }
        rw_exit(&port->node_rwlock);

        if (!found) {
            break;
        }

        EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_node_missing_msg,
                   "FCP2 device (did=%06x) missing. Flushing...",
                   nlp->nlp_DID);

        mutex_exit(&EMLXS_PORT_LOCK);

        (void) emlxs_mb_unreg_did(port, nlp->nlp_DID, NULL, NULL, NULL);

        mutex_enter(&EMLXS_PORT_LOCK);

    }
    mutex_exit(&EMLXS_PORT_LOCK);

    /* Try to send clear link attention, if needed */
    if ((send_clear_la == 1) &&
            (mbox = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX, 1))) {
        mutex_enter(&EMLXS_PORT_LOCK);

        /*
         * If state is not FC_LINK_UP, then either the link has gone
         * down or a FC_CLEAR_LA has already been issued
         */
        if (hba->state != FC_LINK_UP) {
            mutex_exit(&EMLXS_PORT_LOCK);
            (void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbox);
        } else {
            /* Change state and clear discovery timer */
            EMLXS_STATE_CHANGE_LOCKED(hba, FC_CLEAR_LA);

            hba->discovery_timer = 0;

            mutex_exit(&EMLXS_PORT_LOCK);

            /* Prepare and send the CLEAR_LA command */
            emlxs_mb_clear_la(hba, mbox);

            rc = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_NOWAIT, 0);
            if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
                (void) emlxs_mem_put(hba, MEM_MBOX,
                                     (uint8_t *)mbox);
            }
        }
    }

    return;

} /* emlxs_timer_check_discovery()  */