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