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_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() */
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() */