#include <emlxs.h>
EMLXS_MSG_DEF(EMLXS_IP_C);
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) {
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;
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;
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;
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;
}
return (0);
}
extern int32_t
emlxs_ip_handle_unsol_req(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
MATCHMAP *mp, uint32_t size)
{
emlxs_hba_t *hba = HBA;
fc_unsol_buf_t *ubp;
IOCB *cmd;
NETHDR *nd;
NODELIST *ndlp;
uint8_t *mac;
emlxs_ub_priv_t *ub_priv;
uint32_t sid;
uint32_t i;
uint32_t IpDropped = 1;
uint32_t IpBcastReceived = 0;
uint32_t IpSeqReceived = 0;
cmd = &iocbq->iocb;
ubp = NULL;
for (i = 0; i < MAX_VPORTS; i++) {
port = &VPORT(i);
if (!(port->flag & EMLXS_INI_BOUND) ||
!(port->flag & EMLXS_PORT_IP_UP)) {
continue;
}
ubp =
(fc_unsol_buf_t *)emlxs_ub_get(port, size,
FC_TYPE_IS8802_SNAP, 0);
if (!ubp) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ip_dropped_msg,
"Buffer not found. paddr=%lx",
PADDR(cmd->un.cont64[0].addrHigh,
cmd->un.cont64[0].addrLow));
continue;
}
bcopy(mp->virt, ubp->ub_buffer, size);
ub_priv = ubp->ub_fca_private;
nd = (NETHDR *)ubp->ub_buffer;
mac = nd->fc_srcname.IEEE;
ndlp = emlxs_node_find_mac(port, mac);
if (ndlp) {
sid = ndlp->nlp_DID;
if ((ndlp->nlp_Xri == 0) &&
!(ndlp->nlp_flag[hba->channel_ip] & NLP_RPI_XRI)) {
(void) emlxs_create_xri(port, cp, ndlp);
}
}
else if (cmd->un.xrseq.w5.hcsw.Fctl & BC) {
sid = cmd->un.ulpWord[4] & 0x00ffffff;
}
else {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ip_dropped_msg,
"Node not found. mac=%02x%02x%02x%02x%02x%02x",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
(void) emlxs_fca_ub_release((opaque_t)port, 1,
&ubp->ub_token);
continue;
}
if (cmd->un.xrseq.w5.hcsw.Fctl & BC) {
IpBcastReceived++;
} else {
IpSeqReceived++;
}
ubp->ub_frame.r_ctl = cmd->un.xrseq.w5.hcsw.Rctl;
ubp->ub_frame.type = cmd->un.xrseq.w5.hcsw.Type;
ubp->ub_frame.s_id = sid;
ubp->ub_frame.ox_id = ub_priv->token;
ubp->ub_frame.rx_id = cmd->ULPCONTEXT;
ubp->ub_class = FC_TRAN_CLASS3;
emlxs_ub_callback(port, ubp);
IpDropped = 0;
}
port = &PPORT;
if (IpDropped) {
HBASTATS.IpDropped++;
}
if (IpBcastReceived) {
HBASTATS.IpBcastReceived++;
}
if (IpSeqReceived) {
HBASTATS.IpSeqReceived++;
}
return (0);
}
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;
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 {
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) {
emlxs_mem_put(hba, MEM_IPBUF, (void *)mp);
}
(void) emlxs_post_buffer(hba, rp, 1);
}
HBASTATS.IpDropped++;
return (0);
}
extern int32_t
emlxs_handle_create_xri(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
{
emlxs_port_t *port = &PPORT;
IOCB *cmd;
NODELIST *ndlp;
fc_packet_t *pkt;
emlxs_buf_t *sbp;
int32_t rval = 0;
cmd = &iocbq->iocb;
sbp = (emlxs_buf_t *)iocbq->sbp;
if (!sbp) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ip_completion_msg,
"create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x. "
"NULL sbp found.",
cmd->ULPCOMMAND, cmd->ULPIOTAG, cmd->ULPSTATUS,
cmd->un.ulpWord[4]);
return (EIO);
}
ndlp = (NODELIST *)sbp->node;
if (!ndlp) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_bad_ip_completion_msg,
"create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x. "
"NULL node found.",
cmd->ULPCOMMAND, cmd->ULPIOTAG, cmd->ULPSTATUS,
cmd->un.ulpWord[4]);
rval = EIO;
goto done;
}
if (cmd->ULPSTATUS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_bad_ip_completion_msg,
"create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x. "
"Completion error.",
cmd->ULPCOMMAND, cmd->ULPIOTAG, cmd->ULPSTATUS,
cmd->un.ulpWord[4]);
mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
ndlp->nlp_flag[cp->channelno] &= ~NLP_RPI_XRI;
mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
rval = EIO;
goto done;
}
mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
ndlp->nlp_Xri = cmd->ULPCONTEXT;
ndlp->nlp_flag[cp->channelno] &= ~NLP_RPI_XRI;
mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
"create_xri completed: DID=0x%x Xri=0x%x iotag=0x%x",
ndlp->nlp_DID, ndlp->nlp_Xri, cmd->ULPIOTAG);
done:
pkt = sbp->pkt;
if (pkt) {
emlxs_pkt_free(pkt);
}
return (rval);
}
extern int32_t
emlxs_create_xri(emlxs_port_t *port, CHANNEL *cp, NODELIST *ndlp)
{
emlxs_hba_t *hba = HBA;
IOCB *icmd;
IOCBQ *iocbq;
fc_packet_t *pkt;
emlxs_buf_t *sbp;
uint16_t iotag;
mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
if (ndlp->nlp_Xri != 0 ||
(ndlp->nlp_flag[cp->channelno] & NLP_RPI_XRI)) {
mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
return (0);
}
ndlp->nlp_flag[cp->channelno] |= NLP_RPI_XRI;
mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
if (!(pkt = emlxs_pkt_alloc(port, 0, 0, 0, KM_NOSLEEP))) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
"create_xri failed: Unable to allocate pkt. did=0x%x",
ndlp->nlp_DID);
goto fail;
}
sbp = (emlxs_buf_t *)pkt->pkt_fca_private;
iocbq = &sbp->iocbq;
sbp->pkt_flags &= ~PACKET_ULP_OWNED;
iotag = emlxs_register_pkt(cp, sbp);
if (!iotag) {
emlxs_pkt_free(pkt);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
"create_xri failed: Unable to allocate IOTAG. did=0x%x",
ndlp->nlp_DID);
goto fail;
}
icmd = &iocbq->iocb;
icmd->ULPIOTAG = iotag;
icmd->ULPCONTEXT = ndlp->nlp_Rpi;
icmd->ULPLE = 1;
icmd->ULPCOMMAND = CMD_CREATE_XRI_CR;
icmd->ULPOWNER = OWN_CHIP;
iocbq->port = (void *)port;
iocbq->node = (void *)ndlp;
iocbq->channel = (void *)cp;
mutex_enter(&sbp->mtx);
sbp->node = (void *)ndlp;
sbp->channel = cp;
mutex_exit(&sbp->mtx);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg,
"create_xri sent: DID=0x%x Xri=0x%x iotag=0x%x", ndlp->nlp_DID,
ndlp->nlp_Xri, iotag);
EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
return (0);
fail:
mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
ndlp->nlp_flag[cp->channelno] &= ~NLP_RPI_XRI;
mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
return (1);
}