/*******************************************************************
 * This file is part of the Emulex Linux Device Driver for         *
 * Enterprise Fibre Channel Host Bus Adapters.                     *
 * Refer to the README file included with this package for         *
 * driver version and adapter support.                             *
 * Copyright (C) 2003 Emulex Corporation.                          *
 * www.emulex.com                                                  *
 *                                                                 *
 * This program is free software; you can redistribute it and/or   *
 * modify it under the terms of the GNU General Public License     *
 * as published by the Free Software Foundation; either version 2  *
 * of the License, or (at your option) any later version.          *
 *                                                                 *
 * This program is distributed in the hope that it will be useful, *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of  *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   *
 * GNU General Public License for more details, a copy of which    *
 * can be found in the file COPYING included with this package.    *
 *******************************************************************/

#include "fc_os.h"

#include "fc_hw.h"
#include "fc.h"

#include "fcdiag.h"
#include "fcfgparm.h"
#include "fcmsg.h"
#include "fc_crtn.h"
#include "fc_ertn.h"

extern fc_dd_ctl_t      DD_CTL;
extern iCfgParam icfgparam[];
extern int              fc_max_els_sent;

/* Routine Declaration - Local */
_local_ int         fc_addrauth(fc_dev_ctl_t *p_dev_ctl);
_local_ void        fc_clear_fcp_iocbq(fc_dev_ctl_t *p_dev_ctl, NODELIST *nlp);
_local_ void        fc_clear_ip_iocbq(fc_dev_ctl_t *p_dev_ctl, NODELIST *nlp);
_local_ int         fc_matchdid(FC_BRD_INFO *binfo, NODELIST *nlp, uint32 did);
/* End Routine Declaration - Local */

/*
 *  Array of all 126 valid AL_PA's (excluding FL_PORT AL_PA 0)
 */

static uchar staticAlpaArray[] = 
{
   0x01, 0x02, 0x04, 0x08, 0x0F, 0x10, 0x17, 0x18, 0x1B, 0x1D,
   0x1E, 0x1F, 0x23, 0x25, 0x26, 0x27, 0x29, 0x2A, 0x2B, 0x2C,
   0x2D, 0x2E, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x39, 0x3A,
   0x3C, 0x43, 0x45, 0x46, 0x47, 0x49, 0x4A, 0x4B, 0x4C, 0x4D,
   0x4E, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x59, 0x5A, 0x5C,
   0x63, 0x65, 0x66, 0x67, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
   0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x79, 0x7A, 0x7C, 0x80,
   0x81, 0x82, 0x84, 0x88, 0x8F, 0x90, 0x97, 0x98, 0x9B, 0x9D,
   0x9E, 0x9F, 0xA3, 0xA5, 0xA6, 0xA7, 0xA9, 0xAA, 0xAB, 0xAC,
   0xAD, 0xAE, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB9, 0xBA,
   0xBC, 0xC3, 0xC5, 0xC6, 0xC7, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD,
   0xCE, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD9, 0xDA, 0xDC,
   0xE0, 0xE1, 0xE2, 0xE4, 0xE8, 0xEF
};

int fc_fdmi_on = 0;

_local_ int
fc_matchdid(
FC_BRD_INFO *binfo,
NODELIST    *ndlp,
uint32       did)
{
   D_ID mydid;
   D_ID odid;
   D_ID ndid;
   int zero_did;

   if (did == Bcast_DID)
      return(0);

   zero_did = 0;
   if (ndlp->nlp_DID == 0) {
      ndlp->nlp_DID = ndlp->nlp_oldDID;
      zero_did = 1;
   }

   /* First check for Direct match */
   if (ndlp->nlp_DID == did)
      return(1);

   /* Next check for area/domain == 0 match */
   mydid.un.word =  binfo->fc_myDID;
   if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) {
      goto out;
   }

   ndid.un.word = did;
   odid.un.word = ndlp->nlp_DID;
   if (ndid.un.b.id == odid.un.b.id) {
      if ((mydid.un.b.domain == ndid.un.b.domain) && 
          (mydid.un.b.area == ndid.un.b.area)) {
         ndid.un.word = ndlp->nlp_DID;
         odid.un.word = did;
         if ((ndid.un.b.domain == 0) && 
             (ndid.un.b.area == 0)) {
            if (ndid.un.b.id)
               return(1);
         }
         goto out;
      }

      ndid.un.word = ndlp->nlp_DID;
      if ((mydid.un.b.domain == ndid.un.b.domain) && 
          (mydid.un.b.area == ndid.un.b.area)) {
         odid.un.word = ndlp->nlp_DID;
         ndid.un.word = did;
         if ((ndid.un.b.domain == 0) && 
             (ndid.un.b.area == 0)) {
            if (ndid.un.b.id)
               return(1);
         }
      }
   }
out:
   if(zero_did)
      ndlp->nlp_DID = 0;
   return(0);
}       /* End fc_matchdid */


/**************************************************/
/**  fc_nlpadjust                                **/
/**                                              **/
/**  This routine adjusts the timestamp in the   **/
/**  nlplist when the counter wraps              **/
/**************************************************/
_static_ int
fc_nlpadjust(
FC_BRD_INFO *binfo)
{
   NODELIST * ndlp;
   NODELIST * nlphi, *nlpprev;
   uint32 rpts;

   nlphi = 0;
   nlpprev = 0;
   rpts = 0;
   ndlp = binfo->fc_nlpbind_start;
   if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start)
     ndlp = binfo->fc_nlpunmap_start;
   if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
      ndlp = binfo->fc_nlpmap_start;
   while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) {
      if (ndlp->nlp_time > rpts) {
         rpts = ndlp->nlp_time;
         nlpprev = nlphi;
         nlphi = ndlp;
      }

      switch (ndlp->nlp_state) {
      case NLP_LIMBO:
      case NLP_LOGOUT:
         ndlp->nlp_time = 1;
         break;

      case NLP_ALLOC:
         ndlp->nlp_time = 3;
         break;

      default:
         ndlp->nlp_time = 2;
         break;
      }
      ndlp = (NODELIST *)ndlp->nlp_listp_next;
      if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start)
        ndlp = binfo->fc_nlpunmap_start;
      if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
         ndlp = binfo->fc_nlpmap_start;
   }

   if (nlpprev)
      nlpprev->nlp_time = 4;
   if (nlphi)
      nlphi->nlp_time = 5;
   binfo->nlptimer = 6;
   return(0);
}       /* End fc_nlpadjust */


/**************************************************/
/**  fc_findnode_rpi                             **/
/**                                              **/
/**  This routine find a node by rpi             **/
/**************************************************/
_static_ NODELIST *
fc_findnode_rpi(
FC_BRD_INFO *binfo,
uint32      rpi)
{
   NODELIST * ndlp = 0;

   if (rpi < NLP_MAXRPI)
      ndlp = binfo->fc_nlplookup[rpi];
   /* FIND node rpi */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0900,                  /* ptr to msg structure */
           fc_mes0900,                     /* ptr to msg */
            fc_msgBlk0900.msgPreambleStr,  /* begin varargs */
             (ulong)ndlp,
               rpi);                       /* end varargs */
   return(ndlp);
}       /* End fc_findnode_rpi */


/**************************************************/
/**  fc_freenode_did                             **/
/**                                              **/
/**  This routine will free an NODELIST entry    **/
/**  associated with did.                        **/
/**************************************************/
_static_ int
fc_freenode_did(
FC_BRD_INFO *binfo,
uint32      did,
int rm)
{
   NODELIST * ndlp;


   if(((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, did)) == 0) ||
      (ndlp->nlp_state == NLP_SEED)) {
      /* no match found */
      return(0);
   }

   fc_freenode(binfo, ndlp, rm);
   if(rm == 0) {
      ndlp->nlp_state = NLP_LIMBO;
      fc_nlp_bind(binfo, ndlp);
   }
   return(1);
}       /* End fc_freenode_did */


/**************************************************/
/**  fc_free_rpilist                             **/
/**                                              **/
/**  This routine will free all NODELIST entries  **/
/**  and associated buffers.                     **/
/**************************************************/
_static_ int
fc_free_rpilist(
fc_dev_ctl_t *p_dev_ctl,
int keeprpi)
{
   FC_BRD_INFO   * binfo;
   NODELIST      * ndlp;
   NODELIST      * new_ndlp;
   RING          * rp;
   IOCBQ         * xmitiq;
   iCfgParam     * clp;
   struct buf    * bp;
   T_SCSIBUF     * sbp;
   dvi_t         * dev_ptr;
   fc_buf_t      * fcptr;
   node_t        * node_ptr;

   binfo = &BINFO;
   clp = DD_CTL.p_config[binfo->fc_brd_no];

   /* if keeprpi == 0, toss everything on ELS xmitq and xmit pending queue */
   if (keeprpi == 0) {
      rp = &binfo->fc_ring[FC_ELS_RING];
      /* get next command from ring xmit queue */
      while ((xmitiq = fc_ringtx_drain(rp)) != 0) {
         fc_freebufq(p_dev_ctl, rp, xmitiq);
      }

      /* look up xmit next compl */
      while ((xmitiq = fc_ringtxp_get(rp, 0)) != 0) {
         fc_freebufq(p_dev_ctl, rp, xmitiq);
      }
   }

   /* Toss everything on LAN xmitq and xmit pending queue */
   rp = &binfo->fc_ring[FC_IP_RING];
   /* get next command from ring xmit queue */
   while ((xmitiq = fc_ringtx_drain(rp)) != 0) {
      fc_freebufq(p_dev_ctl, rp, xmitiq);
   }

   /* look up xmit next compl */
   while ((xmitiq = fc_ringtxp_get(rp, 0)) != 0) {
      fc_freebufq(p_dev_ctl, rp, xmitiq);
   }

   NDDSTAT.ndd_xmitque_cur = 0;

   if(clp[CFG_FCP_ON].a_current) {
      int i;

      rp = &binfo->fc_ring[FC_FCP_RING];

      for(i=0;i<MAX_FCP_CMDS;i++) {
         if ((binfo->fc_table->fcp_array[i]) &&
            (fcptr = fc_deq_fcbuf_active(rp, (ushort)i))) {
            dev_ptr = fcptr->dev_ptr;

            if(dev_ptr->queue_state == ACTIVE_PASSTHRU) {
              node_t          * map_node_ptr;
              struct dev_info * map_dev_ptr;

              map_node_ptr = (node_t *)dev_ptr->pend_head;
              map_dev_ptr  = (struct dev_info *)dev_ptr->pend_tail;
              dev_ptr->pend_head = 0;
              dev_ptr->pend_tail = 0;
              dev_ptr->queue_state = HALTED;
              dev_ptr->active_io_count--;
              if(map_dev_ptr)
                 map_dev_ptr->active_io_count--;
              if(map_node_ptr)
                 map_node_ptr->num_active_io--;

              dev_ptr->ioctl_event = IOSTAT_LOCAL_REJECT;

              dev_ptr->ioctl_errno = IOERR_SEQUENCE_TIMEOUT;
              dev_ptr->sense_length = 0;
              dev_ptr->clear_count  = 0;
              continue;
            } /* end ACTIVE_PASSTHRU management */

            sbp = fcptr->sc_bufp;
            bp = (struct buf *) sbp;


            /* E_D_TOV timeout */
            bp->b_error = ETIMEDOUT;

            sbp->adap_q_status = SC_DID_NOT_CLEAR_Q; 
            bp->b_flags |= B_ERROR;
            bp->b_resid = bp->b_bcount;
            sbp->status_validity = SC_ADAPTER_ERROR;
        SET_ADAPTER_STATUS(sbp, SC_CMD_TIMEOUT)
   
            if (fcptr->fcp_cmd.fcpCntl2) {
               /* This is a task management command */
               if (bp->b_flags & B_ERROR)
                  dev_ptr->ioctl_errno = bp->b_error;
               else
                  dev_ptr->ioctl_errno = 0;

               if (fcptr->fcp_cmd.fcpCntl2 == ABORT_TASK_SET)
                  dev_ptr->flags &= ~SCSI_ABORT_TSET;

               if (fcptr->fcp_cmd.fcpCntl2 & TARGET_RESET)
                  dev_ptr->flags &= ~SCSI_TARGET_RESET;

               if (fcptr->fcp_cmd.fcpCntl2 & LUN_RESET)
                  dev_ptr->flags &= ~SCSI_LUN_RESET;

               if (dev_ptr->ioctl_wakeup == 1) {
                  dev_ptr->ioctl_wakeup = 0;

                  fc_admin_wakeup(p_dev_ctl, dev_ptr, sbp);
               } else {
                  fc_do_iodone(bp);
               }
            } else {
               fc_do_iodone(bp);
            }
            dev_ptr->active_io_count--;
            dev_ptr->nodep->num_active_io--;
            fc_enq_fcbuf(fcptr);
         }
      }

      fc_failio(p_dev_ctl);

      ndlp = binfo->fc_nlpmap_start;
      while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) {
         fc_freenode(binfo, ndlp, 0);
         ndlp->nlp_state = NLP_LIMBO;
         fc_nlp_bind(binfo, ndlp);

         /* Make sure pendq is empty */
         i = INDEX(ndlp->id.nlp_pan, ndlp->id.nlp_sid);
         if ((node_ptr = binfo->device_queue_hash[i].node_ptr) != NULL) {
            for (dev_ptr = node_ptr->lunlist; dev_ptr != NULL; 
               dev_ptr = dev_ptr->next) {
               while ((sbp = dev_ptr->pend_head) != NULL) {
                  dev_ptr->pend_count--;
                  dev_ptr->pend_head = (T_SCSIBUF *) sbp->bufstruct.av_forw;
                  if (dev_ptr->pend_head == NULL)
                     dev_ptr->pend_tail = NULL;
                  else
                     dev_ptr->pend_head->bufstruct.av_back = NULL;

                  sbp->bufstruct.b_flags |= B_ERROR; 
                  sbp->bufstruct.b_error = EIO;
                  sbp->bufstruct.b_resid = sbp->bufstruct.b_bcount;
                  sbp->status_validity = SC_ADAPTER_ERROR;
          SET_ADAPTER_STATUS(sbp, SC_NO_DEVICE_RESPONSE)

                  sbp->bufstruct.av_forw = 0;
                  fc_do_iodone((struct buf *) sbp); 
               }
            }
         }
         ndlp = binfo->fc_nlpmap_start;
      }
   }

   /* Put all Mapped and unmapped nodes on the bind list */
   ndlp = binfo->fc_nlpunmap_start;
   if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
      ndlp = binfo->fc_nlpmap_start;
   while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) {
      new_ndlp = (NODELIST *)ndlp->nlp_listp_next;

      fc_freenode(binfo, ndlp, 0);
      ndlp->nlp_state = NLP_LIMBO;
      fc_nlp_bind(binfo, ndlp);

      ndlp = new_ndlp;
      if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
         ndlp = binfo->fc_nlpmap_start;
   }

   /* Put adapter into an error state and return all outstanding I/Os */
   fc_linkdown(p_dev_ctl);

   return(0);
}       /* End fc_free_rpilist */


/*
 * Issue an ABORT_XRI_CX iocb command to abort an exchange
 */
_static_ int
fc_rpi_abortxri(
FC_BRD_INFO *binfo,
ushort      xri)
{
   IOCB          * icmd;
   IOCBQ         * temp;
   RING  * rp;

   /* Use IP ring so ABTS comes out after CLEAR_LA */
   rp = &binfo->fc_ring[FC_IP_RING];

   /* Get an iocb buffer */
   if ((temp = (IOCBQ * )fc_mem_get(binfo, MEM_IOCB)) == 0) {
      return(1);
   }
   fc_bzero((void *)temp, sizeof(IOCBQ));
   icmd = &temp->iocb;

   icmd->un.acxri.abortType = ABORT_TYPE_ABTS;
   icmd->ulpContext = xri;

   /* set up an iotag */
   icmd->ulpIoTag = rp->fc_iotag++;
   if (rp->fc_iotag == 0) {
      rp->fc_iotag = 1;
   }

   icmd->ulpLe = 1;
   icmd->ulpClass = CLASS3;
   icmd->ulpCommand = CMD_ABORT_XRI_CX;
   icmd->ulpOwner = OWN_CHIP;

   issue_iocb_cmd(binfo, rp, temp);

   return(0);
}       /* End fc_rpi_abortxri */


/**************************************************/
/**  fc_freenode                                 **/
/**                                              **/
/**  This routine will remove NODELIST entries   **/
/**  rm determines state to leave entry at,      **/
/**  either NLP_UNUSED or NLP_LOGOUT             **/
/**************************************************/
_static_ int
fc_freenode(
FC_BRD_INFO *binfo,
NODELIST    *nlp,
int rm)
{
   MAILBOXQ      * mbox;
   node_t        * node_ptr;
   uint32        data1;

   data1 = ( ((uint32)nlp->nlp_state << 24) |
             ((uint32)nlp->nlp_action << 16) |
             ((uint32)nlp->nlp_type << 8) |
             rm );

   /* Free node tbl */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0901,                    /* ptr to msg structure */
           fc_mes0901,                       /* ptr to msg */
            fc_msgBlk0901.msgPreambleStr,    /* begin varargs */
             nlp->nlp_DID,
              nlp->nlp_flag,
               nlp->nlp_Rpi,
                data1);                      /* end varargs */
   /* FREE node IEEE */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0902,                    /* ptr to msg structure */
           fc_mes0902,                       /* ptr to msg */
            fc_msgBlk0902.msgPreambleStr,    /* begin varargs */
             nlp->nlp_nodename.IEEE[2],
              nlp->nlp_nodename.IEEE[3],
               nlp->nlp_nodename.IEEE[4],
                nlp->nlp_nodename.IEEE[5]);  /* end varargs */


   if(nlp == &binfo->fc_fcpnodev)
      return(1);

   if(nlp->nlp_listp_next) {
      if (nlp->nlp_flag & NLP_MAPPED) {
         nlp->nlp_time = binfo->nlptimer++;
         if (nlp->nlp_time == 0) {
            fc_nlpadjust(binfo);
         }
         nlp->nlp_flag &= ~NLP_MAPPED;
         binfo->fc_map_cnt--;
         fc_deque(nlp);
      }
      else if (nlp->nlp_flag & NLP_UNMAPPED) {
         nlp->nlp_time = binfo->nlptimer++;
         if (nlp->nlp_time == 0) {
            fc_nlpadjust(binfo);
         }
         nlp->nlp_flag &= ~NLP_UNMAPPED;
         binfo->fc_unmap_cnt--;
         fc_deque(nlp);
      }
      else if (nlp->nlp_flag & NLP_BIND) {
         nlp->nlp_flag &= ~NLP_BIND;
         binfo->fc_bind_cnt--;
         fc_deque(nlp);
      }
   }

   /* Unregister login with firmware for this node */
   if (nlp->nlp_Rpi) {
      /* Unregister login */
      if ((mbox = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) {
         fc_unreg_login(binfo, nlp->nlp_Rpi, (MAILBOX * )mbox);
         if (nlp->nlp_flag & NLP_UNREG_LOGO) {
            ((MAILBOX *)mbox)->un.varWords[30] = nlp->nlp_DID;
         }
         if (issue_mb_cmd(binfo, (MAILBOX * )mbox, MBX_NOWAIT) != MBX_BUSY) {
            fc_mem_put(binfo, MEM_MBOX, (uchar * )mbox);
         }
      }
      binfo->fc_nlplookup[nlp->nlp_Rpi] = 0;
      nlp->nlp_Rpi = 0;
   }

   if (nlp->nlp_DID) {
      RING       * rp;
      IOCBQ      * iocbq;
      unsigned long iflag;
      fc_dev_ctl_t *p_dev_ctl;

      /* Look through ELS ring and remove any ELS cmds in progress */
      p_dev_ctl = (fc_dev_ctl_t *)binfo->fc_p_dev_ctl;
      iflag = lpfc_q_disable_lock(p_dev_ctl);
      rp = &binfo->fc_ring[FC_ELS_RING];
      iocbq = (IOCBQ * )(rp->fc_txp.q_first);
      while (iocbq) {
         if (iocbq->iocb.un.elsreq.remoteID == nlp->nlp_DID) {
            iocbq->retry = 0xff;  /* Mark for abort */
            if((binfo->fc_flag & FC_RSCN_MODE) ||
               (binfo->fc_ffstate < FC_READY)) {
               if((nlp->nlp_state >= NLP_PLOGI) &&
                  (nlp->nlp_state <= NLP_PRLI)) {
                  nlp->nlp_action &= ~NLP_DO_RSCN;
                  binfo->fc_nlp_cnt--;
                  if ((nlp->nlp_type & NLP_IP_NODE) && nlp->nlp_bp) {
                     m_freem((fcipbuf_t *)nlp->nlp_bp);
                     nlp->nlp_bp = (uchar * )0;
                  }
               }
            }
         }
         iocbq = (IOCBQ * )iocbq->q;
      }
      lpfc_q_unlock_enable(p_dev_ctl, iflag);
      /* In case its on fc_delay_timeout list */
      fc_abort_delay_els_cmd((fc_dev_ctl_t *)binfo->fc_p_dev_ctl, nlp->nlp_DID);

      nlp->nlp_oldDID = nlp->nlp_DID; /* save the old DID */
   }

   if (nlp->nlp_flag & (NLP_REQ_SND | NLP_REQ_SND_ADISC)) {
      nlp->nlp_flag &= ~(NLP_REQ_SND | NLP_REQ_SND_ADISC);
      /* Goto next entry */
      fc_nextnode((fc_dev_ctl_t * )(binfo->fc_p_dev_ctl), nlp);
   }


   if (nlp->nlp_type & NLP_IP_NODE) {
      if (nlp->nlp_bp) {
         m_freem((fcipbuf_t * )nlp->nlp_bp);
         nlp->nlp_bp = 0;
      }

      /* Go remove all entries for this node from the IP IOCBQ */
      fc_clear_ip_iocbq((fc_dev_ctl_t * )(binfo->fc_p_dev_ctl), nlp);
   }

   if (nlp->nlp_type & NLP_FCP_TARGET) {
      iCfgParam   * clp;

      clp = DD_CTL.p_config[binfo->fc_brd_no];

      /* Go remove all entries for this RPI from the FCP IOCBQ */
      fc_clear_fcp_iocbq((fc_dev_ctl_t *)binfo->fc_p_dev_ctl, nlp);

      if ((node_ptr = (node_t * )(nlp->nlp_targetp)) != NULL) {
         dvi_t   * dev_ptr;

         node_ptr->rpi = 0xfffe;
         node_ptr->flags &= ~FC_FCP2_RECOVERY;
         for (dev_ptr = node_ptr->lunlist; dev_ptr != NULL; 
            dev_ptr = dev_ptr->next) {
            if(binfo->fc_ffstate == FC_READY){
               /*
                *  Cause the standby queue to drain.
                */
               fc_return_standby_queue(dev_ptr,
                  (uchar)((binfo->fc_flag & FC_BUS_RESET) ? EIO : EFAULT), 0);

               fc_fail_pendq(dev_ptr, 
                  (uchar)((binfo->fc_flag & FC_BUS_RESET) ? EIO : EFAULT), 0);
               /* UNREG_LOGIN from freenode should abort txp I/Os */
               fc_fail_cmd(dev_ptr, (char)((binfo->fc_flag & FC_BUS_RESET) ? 
                  EIO : EFAULT), 0);

               /* Call iodone for all the CLEARQ error bufs */
               fc_free_clearq(dev_ptr);
            }
            dev_ptr->queue_state = HALTED;
         }
      }

      /* Is this node, automapped or seeded */
      if(nlp->nlp_type & (NLP_AUTOMAP | NLP_SEED_MASK)) {
         /* If FCP we need to keep entry around for the wwpn - sid mapping */
         nlp->nlp_type = (NLP_FCP_TARGET |
            (nlp->nlp_type & (NLP_AUTOMAP | NLP_SEED_MASK)));
         if(nlp->nlp_type & NLP_SEED_DID) {
               fc_bzero((void *)&nlp->nlp_portname, sizeof(NAME_TYPE));
               fc_bzero((void *)&nlp->nlp_nodename, sizeof(NAME_TYPE));
         }
         else {
            nlp->nlp_DID = 0;
         }
      }
      else {
         nlp->nlp_flag = 0;
         nlp->nlp_action = 0;
         nlp->nlp_type = 0;
         nlp->nlp_targetp = 0;
         nlp->id.nlp_pan = 0;
         nlp->id.nlp_sid = 0;
      }

      if(node_ptr && (clp[CFG_NODEV_TMO].a_current) &&
         ((node_ptr->flags & FC_NODEV_TMO) == 0)) {
         if(node_ptr->nodev_tmr == 0) {
            /* START nodev timer */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0700,                    /* ptr to msg structure */
                    fc_mes0700,                       /* ptr to msg */
                     fc_msgBlk0700.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_flag,
                         nlp->nlp_state,
                          nlp->nlp_DID);              /* end varargs */

            if(binfo->fc_ffstate != FC_LINK_DOWN) {
               node_ptr->nodev_tmr =
                  fc_clk_set((fc_dev_ctl_t * )(binfo->fc_p_dev_ctl),
                  clp[CFG_NODEV_TMO].a_current, fc_nodev_timeout,
                  (void *)node_ptr, 0);
            }
            else {
               node_ptr->nodev_tmr =
                  fc_clk_set((fc_dev_ctl_t * )(binfo->fc_p_dev_ctl),
                  (clp[CFG_NODEV_TMO].a_current + clp[CFG_LINKDOWN_TMO].a_current),
                  fc_nodev_timeout, (void *)node_ptr, 0);
            }
         }
      }
   }
   else {
      nlp->nlp_targetp = 0;
      nlp->id.nlp_pan = 0;
      nlp->id.nlp_sid = 0;
      nlp->nlp_type = 0;
   }

   nlp->nlp_Xri = 0;
   nlp->nlp_action = 0;

   if (rm) {
      fc_bzero((void *)nlp, sizeof(NODELIST));
      fc_mem_put(binfo, MEM_NLP, (uchar *)nlp);
   } else {
      if(nlp->nlp_flag & NLP_NS_REMOVED)
         nlp->nlp_flag = NLP_NS_REMOVED;
      else
         nlp->nlp_flag = 0;

      /* Keep the entry cached */
      nlp->nlp_state = NLP_LIMBO;
      /* Let the caller put it on the appropriate q at the appropriate time */
   }
   return(1);
}       /* End fc_freenode */


/************************************************************************/
/*                                                                      */
/* NAME:        fc_clear_fcp_iocbq                                      */
/*                                                                      */
/* FUNCTION:    Fail All FCP Commands in IOCBQ for one RPI              */
/*                                                                      */
/*      This routine is called to clear out all FCP commands            */
/*      in the IOCBQ for a specific SCSI FCP device RPI.                */
/*                                                                      */
/* EXECUTION ENVIRONMENT:                                               */
/*      This routine can only be called on priority levels              */
/*      equal to that of the interrupt handler.                         */
/*                                                                      */
/* DATA STRUCTURES:                                                     */
/*      sc_buf  - input/output request struct used between the adapter  */
/*                driver and the calling SCSI device driver             */
/*                                                                      */
/* INPUTS:                                                              */
/*      NODELIST structure - pointer to device node structure           */
/*                                                                      */
/* RETURN VALUE DESCRIPTION:                                            */
/*      none                                                            */
/*                                                                      */
/************************************************************************/
_local_ void
fc_clear_fcp_iocbq(
fc_dev_ctl_t *p_dev_ctl,
NODELIST    *ndlp)
{
   FC_BRD_INFO   * binfo;
   T_SCSIBUF     * sbp;
   RING          * rp;
   IOCBQ         * iocb_cmd, *next;
   IOCB          * icmd;
   dvi_t         * dev_ptr;
   fc_buf_t      * fcptr;
   struct buf    * bp;
   Q             tmpq;

   binfo = &BINFO;

   /* Clear out all fc_buf structures in the iocb queue for this RPI */
   rp = &binfo->fc_ring[FC_FCP_RING];
   tmpq.q_first = NULL;

   /* Get next command from ring xmit queue */
   iocb_cmd = fc_ringtx_get(rp);

   while (iocb_cmd) {
      icmd = &iocb_cmd->iocb;
      if ((icmd->ulpCommand != CMD_IOCB_CONTINUE_CN) && 
          (icmd->ulpContext == ndlp->nlp_Rpi)) {

         if ((fcptr = fc_deq_fcbuf_active(rp, icmd->ulpIoTag)) != NULL) {
             dev_ptr = fcptr->dev_ptr;
            /* Reject this command with error */
            if(dev_ptr && (dev_ptr->queue_state == ACTIVE_PASSTHRU)) {
              node_t          * map_node_ptr;
              struct dev_info * map_dev_ptr;

              map_node_ptr = (node_t *)dev_ptr->pend_head;
              map_dev_ptr  = (struct dev_info *)dev_ptr->pend_tail;
              dev_ptr->pend_head = 0;
              dev_ptr->pend_tail = 0;
              dev_ptr->queue_state = HALTED;
              dev_ptr->active_io_count--;
              if(map_dev_ptr)
                 map_dev_ptr->active_io_count--;
              if(map_node_ptr)
                 map_node_ptr->num_active_io--;

              dev_ptr->ioctl_event = IOSTAT_LOCAL_REJECT;

              dev_ptr->ioctl_errno = IOERR_SEQUENCE_TIMEOUT;
              dev_ptr->sense_length = 0;
              dev_ptr->clear_count  = 0;
              while ((iocb_cmd = fc_ringtx_get(rp)) != NULL) {
                    icmd = &iocb_cmd->iocb;
                    if (icmd->ulpCommand != CMD_IOCB_CONTINUE_CN)
                       break;
                    fc_mem_put(binfo, MEM_IOCB, (uchar * )iocb_cmd);
              }
              continue;
            } /* end ACTIVE_PASSTHRU management */

            if (fcptr->fcp_cmd.fcpCntl2) {

               bp = (struct buf *)fcptr->sc_bufp;

               if(dev_ptr) {
                  /* This is a task management command */
                  dev_ptr->ioctl_errno = ENXIO;
                  dev_ptr->active_io_count--;
                  dev_ptr->nodep->num_active_io--;

                  if (fcptr->fcp_cmd.fcpCntl2 == ABORT_TASK_SET)
                     dev_ptr->flags &= ~SCSI_ABORT_TSET;

                  if (fcptr->fcp_cmd.fcpCntl2 & TARGET_RESET)
                     dev_ptr->flags &= ~SCSI_TARGET_RESET;

                  if (fcptr->fcp_cmd.fcpCntl2 & LUN_RESET)
                     dev_ptr->flags &= ~SCSI_LUN_RESET;

                  if (fcptr->dev_ptr->ioctl_wakeup) {
                     fcptr->dev_ptr->ioctl_wakeup = 0;
                     fc_admin_wakeup(((fc_dev_ctl_t *)(binfo->fc_p_dev_ctl)),
                        fcptr->dev_ptr, fcptr->sc_bufp);
                  }
               }
            } else {
               /* This is a regular FCP command */

               bp = (struct buf *)fcptr->sc_bufp;
               bp->b_error = ENXIO;
               bp->b_resid = bp->b_bcount;
               bp->b_flags |= B_ERROR;

               sbp = (T_SCSIBUF *)bp;
               sbp->status_validity = SC_ADAPTER_ERROR;
           SET_ADAPTER_STATUS(sbp, SC_NO_DEVICE_RESPONSE)

               dev_ptr = fcptr->dev_ptr;
               if(dev_ptr) {
                  dev_ptr->active_io_count--;
                  dev_ptr->nodep->num_active_io--;
               }

               fc_delay_iodone(p_dev_ctl, sbp);
            }
            fc_enq_fcbuf(fcptr);
         }

         fc_mem_put(binfo, MEM_IOCB, (uchar * )iocb_cmd);

         while ((iocb_cmd = fc_ringtx_get(rp)) != NULL) {
            icmd = &iocb_cmd->iocb;
            if (icmd->ulpCommand != CMD_IOCB_CONTINUE_CN)
               break;
            fc_mem_put(binfo, MEM_IOCB, (uchar * )iocb_cmd);
         }
      } else {
         /* Queue this iocb to the temporary queue */
         if (tmpq.q_first) {
            ((IOCBQ * )tmpq.q_last)->q = (uchar * )iocb_cmd;
            tmpq.q_last = (uchar * )iocb_cmd;
         } else {
            tmpq.q_first = (uchar * )iocb_cmd;
            tmpq.q_last = (uchar * )iocb_cmd;
         }
         iocb_cmd->q = NULL;

         iocb_cmd = fc_ringtx_get(rp);
      }
   }

   /* Put the temporary queue back in the FCP iocb queue */
   iocb_cmd = (IOCBQ * )tmpq.q_first;
   while (iocb_cmd) {
      next = (IOCBQ * )iocb_cmd->q;
      fc_ringtx_put(rp, iocb_cmd);
      iocb_cmd = next;
   }

   return;
}       /* End fc_clear_fcp_iocbq */


/************************************************************************/
/*                                                                      */
/* NAME:        fc_clear_ip_iocbq                                       */
/*                                                                      */
/* FUNCTION:    Fail All IP Commands in IOCBQ for one RPI               */
/*                                                                      */
/*      This routine is called to clear out all IP commands             */
/*      in the IOCBQ for a specific IP device RPI.                      */
/*                                                                      */
/* EXECUTION ENVIRONMENT:                                               */
/*      This routine can only be called on priority levels              */
/*      equal to that of the interrupt handler.                         */
/*                                                                      */
/* INPUTS:                                                              */
/*      NODELIST structure - pointer to device node structure           */
/*                                                                      */
/* RETURN VALUE DESCRIPTION:                                            */
/*      none                                                            */
/*                                                                      */
/************************************************************************/
_local_ void
fc_clear_ip_iocbq(
fc_dev_ctl_t *p_dev_ctl,
NODELIST    *ndlp)
{
   FC_BRD_INFO * binfo;
   RING          * rp;
   IOCBQ         * xmitiq, *next;
   IOCB          * icmd;
   Q            tmpq;
   fcipbuf_t   * p_mbuf;
   fcipbuf_t   * m_net;
   int  i;
   ULP_BDE64     * bpl;
   MATCHMAP      * bmp;

   binfo = &BINFO;
   /* Clear out all commands in the iocb queue for this RPI */
   rp = &binfo->fc_ring[FC_IP_RING];
   tmpq.q_first = NULL;

   /* Get next command from ring xmit queue */
   xmitiq = fc_ringtx_drain(rp);

   while (xmitiq) {
      icmd = &xmitiq->iocb;
      if (((icmd->ulpCommand == CMD_XMIT_SEQUENCE_CX) || 
          (icmd->ulpCommand == CMD_XMIT_SEQUENCE64_CX) || 
          (icmd->ulpCommand == 0)) && 
          (ndlp == (NODELIST * )xmitiq->info)) {

         /* get mbuf ptr for xmit */
         m_net = (fcipbuf_t * )xmitiq->bp;
         if (ndlp->nlp_DID == NameServer_DID) {
            if (binfo->fc_flag & FC_SLI2) {
               fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl);
            }
            fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq);
            fc_mem_put(binfo, MEM_BUF, (uchar * )m_net);
            goto out;
         }

         /* Loop thru BDEs and unmap memory pages associated with mbuf */
         if (binfo->fc_flag & FC_SLI2) {
            bmp = (MATCHMAP * )xmitiq->bpl;
            bpl = (ULP_BDE64 * )bmp->virt;
            while (bpl && xmitiq->iocb.un.xseq64.bdl.bdeSize) {
               fc_bufunmap(p_dev_ctl, (uchar *)getPaddr(bpl->addrHigh, bpl->addrLow), 0, bpl->tus.f.bdeSize);
               bpl++;
               xmitiq->iocb.un.xseq64.bdl.bdeSize -= sizeof(ULP_BDE64);
            }
            fc_mem_put(binfo, MEM_BPL, (uchar * )bmp);
            fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq);
         } else {
            for (i = 0; i < (int)xmitiq->iocb.ulpBdeCount; i++) {
               fc_bufunmap(p_dev_ctl, (uchar *)((ulong)xmitiq->iocb.un.cont[i].bdeAddress), 0, (uint32)xmitiq->iocb.un.cont[i].bdeSize);
            }
            fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq);
         }

         /* Take care of Continuation IOCBs for this mbuf */
         while ((xmitiq = fc_ringtx_drain(rp)) != NULL) {
            icmd = &xmitiq->iocb;
            if ((icmd->ulpCommand != CMD_IOCB_CONTINUE_CN) && 
                (icmd->ulpCommand != CMD_IOCB_CONTINUE64_CN))
               break;
            /* Loop thru BDEs and unmap memory pages associated with IOCB */
            for (i = 0; i < (int)xmitiq->iocb.ulpBdeCount; i++) {
               if (binfo->fc_flag & FC_SLI2)
                  fc_bufunmap(p_dev_ctl, (uchar *)getPaddr(xmitiq->iocb.un.cont64[i].addrHigh, xmitiq->iocb.un.cont64[i].addrLow), 0, xmitiq->iocb.un.cont64[i].tus.f.bdeSize);
               else
                  fc_bufunmap(p_dev_ctl, (uchar *) ((ulong)xmitiq->iocb.un.cont[i].bdeAddress), 0, (uint32)xmitiq->iocb.un.cont[i].bdeSize); 
            }
            fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq);
         }

         p_mbuf = fcnextdata(m_net);
         fcnextdata(m_net) = 0;
         fcfreehandle(p_dev_ctl, m_net);
         m_freem(m_net);

         if (p_mbuf) {
            /* free mbuf */
            fcfreehandle(p_dev_ctl, p_mbuf);
            m_freem(p_mbuf);
         }

      } else {
         /* Queue this iocb to the temporary queue */
         if (tmpq.q_first) {
            ((IOCBQ * )tmpq.q_last)->q = (uchar * )xmitiq;
            tmpq.q_last = (uchar * )xmitiq;
         } else {
            tmpq.q_first = (uchar * )xmitiq;
            tmpq.q_last = (uchar * )xmitiq;
         }
         xmitiq->q = NULL;

         xmitiq = fc_ringtx_drain(rp);
      }
   }

out:
   /* Put the temporary queue back in the IP iocb queue */
   xmitiq = (IOCBQ * )tmpq.q_first;
   while (xmitiq) {
      next = (IOCBQ * )xmitiq->q;
      fc_ringtx_put(rp, xmitiq);
      xmitiq = next;
   }

   return;
}       /* End fc_clear_ip_iocbq */


/**************************************************/
/**  fc_fanovery                                 **/
/**                                              **/
/**  This routine will recover after a FAN rcvd  **/
/**************************************************/
_static_ int
fc_fanovery(
fc_dev_ctl_t *p_dev_ctl)
{
   FC_BRD_INFO * binfo;
   iCfgParam   * clp;
   NODELIST * ndlp;
   NODELIST * firstndlp;
   MAILBOXQ * mb;
   int  j, addrauth;
   D_ID did;

   binfo = &BINFO;
   clp = DD_CTL.p_config[binfo->fc_brd_no];
   /* Device Discovery Started */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0200,                    /* ptr to msg structure */
           fc_mes0200,                       /* ptr to msg */
            fc_msgBlk0200.msgPreambleStr);   /* begin & end varargs */
   binfo->fc_ffstate = FC_LOOP_DISC;
   binfo->fc_nlp_cnt = 0;
   binfo->fc_flag &= ~(FC_NLP_MORE | FC_DELAY_PLOGI);

   firstndlp = 0;
   addrauth = 0;
   /* Next, lets seed the nodeList with our ALPAmap */
   if (binfo->fc_topology == TOPOLOGY_LOOP) {
      if (binfo->alpa_map[0]) {
         for (j = 1; j <= binfo->alpa_map[0]; j++) {
            if (((binfo->fc_myDID & 0xff) == binfo->alpa_map[j]) || 
                (binfo->alpa_map[j] == 0))
               continue;
            /* Skip if the node is already in the node table */
            if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, binfo->alpa_map[j]))) {
               ndlp->nlp_DID = binfo->alpa_map[j];
               /* Mark slot for address authentication */
               ndlp->nlp_action |= NLP_DO_ADDR_AUTH;
               addrauth++;
               continue;
            }
            if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) {
               fc_bzero((void *)ndlp, sizeof(NODELIST));
               ndlp->sync = binfo->fc_sync;
               ndlp->capabilities = binfo->fc_capabilities;
               ndlp->nlp_DID = binfo->alpa_map[j];
               ndlp->nlp_state = NLP_LIMBO;
               fc_nlp_bind(binfo, ndlp);
            }
            else
               continue;

            ndlp->nlp_action |= NLP_DO_DISC_START;
            if (firstndlp == 0)
               firstndlp = ndlp;
         }
      } else {
         /* No alpamap, so try all alpa's */
         for (j = 0; j < FC_MAXLOOP; j++) {
            int index;

            if (clp[CFG_SCAN_DOWN].a_current)
               index = FC_MAXLOOP - j - 1;
            else
               index = j;
            if ((binfo->fc_myDID & 0xff) == staticAlpaArray[index])
               continue;
            /* Skip if the node is already in the node table */
            if ((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, staticAlpaArray[index]))) {
               /* Mark slot for address authentication */
               ndlp->nlp_action |= NLP_DO_ADDR_AUTH;
               ndlp->nlp_DID = staticAlpaArray[index];
               addrauth++;
               continue;
            }
            if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) {
               fc_bzero((void *)ndlp, sizeof(NODELIST));
               ndlp->sync = binfo->fc_sync;
               ndlp->capabilities = binfo->fc_capabilities;
               ndlp->nlp_DID = staticAlpaArray[index];
               ndlp->nlp_state = NLP_LIMBO;
               fc_nlp_bind(binfo, ndlp);
            }
            else
               continue;
            ndlp->nlp_action |= NLP_DO_DISC_START;
            if (firstndlp == 0)
               firstndlp = ndlp;
         }
      }

      /* Next mark ALL unmarked local nodes for Authentication */
      ndlp = binfo->fc_nlpunmap_start;
      if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
         ndlp = binfo->fc_nlpmap_start;
      while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) {

         /* Skip over Fabric nodes, myself, and nodes partially logged in */
         if ((ndlp->nlp_DID == binfo->fc_myDID) || 
             (ndlp->nlp_type & NLP_FABRIC) ||
             (ndlp->nlp_action & (NLP_DO_DISC_START | NLP_DO_ADDR_AUTH))) {
            ndlp = (NODELIST *)ndlp->nlp_listp_next;
            if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
               ndlp = binfo->fc_nlpmap_start;
            continue;
         }

         /* If it is a local node */
         did.un.word = ndlp->nlp_DID;
         did.un.b.domain = 0;
         did.un.b.area = 0;
         if (fc_matchdid(binfo, ndlp, did.un.word)) {
            /* Mark slot for address authentication */
            ndlp->nlp_action |= NLP_DO_ADDR_AUTH;
            addrauth++;
         }
         ndlp = (NODELIST *)ndlp->nlp_listp_next;
         if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
            ndlp = binfo->fc_nlpmap_start;
      }

      if (addrauth) {
         fc_nextauth(p_dev_ctl, fc_max_els_sent);
         return(0);
      } else {
         if (firstndlp) {
            /* We can start discovery right now */
            fc_nextdisc(p_dev_ctl, fc_max_els_sent);
            return(0);
         }
      }
   }

   /* This should turn off DELAYED ABTS for ELS timeouts */
   if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) {
      fc_set_slim(binfo, (MAILBOX * )mb, 0x052198, 0);
      if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) {
         fc_mem_put(binfo, MEM_MBOX, (uchar * )mb);
      }
   }

   /* This is at init, clear la */
   if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) {
      binfo->fc_ffstate = FC_CLEAR_LA;
      fc_clear_la(binfo, (MAILBOX * )mb);
      if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) {
         fc_mem_put(binfo, MEM_MBOX, (uchar * )mb);
      }
   } else {
      binfo->fc_ffstate = FC_ERROR;
      /* Device Discovery completion error */
      fc_log_printf_msg_vargs( binfo->fc_brd_no,
             &fc_msgBlk0201,                    /* ptr to msg structure */
              fc_mes0201,                       /* ptr to msg */
               fc_msgBlk0201.msgPreambleStr);   /* begin & end varargs */
   }

   if(FABRICTMO) {
      fc_clk_can(p_dev_ctl, FABRICTMO);
      FABRICTMO = 0;
   }
   return(0);
}       /* End fc_fanovery */


/**************************************************/
/**  fc_discovery                                **/
/**                                              **/
/**  This routine will find devices in network   **/
/**************************************************/
_static_ int
fc_discovery(
fc_dev_ctl_t *p_dev_ctl)
{
   FC_BRD_INFO * binfo;
   iCfgParam   * clp;
   NODELIST * ndlp;
   NODELIST * new_ndlp;
   NODELIST * firstndlp;
   MAILBOXQ * mb;
   int  j, addrauth;

   binfo = &BINFO;
   clp = DD_CTL.p_config[binfo->fc_brd_no];
   /* Device Discovery Started */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0202,                    /* ptr to msg structure */
           fc_mes0202,                       /* ptr to msg */
            fc_msgBlk0202.msgPreambleStr);   /* begin & end varargs */

   binfo->fc_ffstate = FC_LOOP_DISC;
   binfo->fc_nlp_cnt = 0;
   binfo->fc_flag &= ~(FC_NLP_MORE | FC_DELAY_PLOGI);

   /* If this is not our first time doing discovery and we don't have
    * a new myDID, then rediscovery (address authentication) is appropriate.
    */
   if ((p_dev_ctl->init_eventTag) && (binfo->fc_prevDID == binfo->fc_myDID)) {
      /* do rediscovery on the loop */
      addrauth = fc_addrauth(p_dev_ctl);
   } else {
      addrauth = 0;
      p_dev_ctl->init_eventTag = 1;
      /* First make sure all nodes in nlplist are free */
      ndlp = binfo->fc_nlpunmap_start;
      if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
         ndlp = binfo->fc_nlpmap_start;
      while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) {
         new_ndlp = (NODELIST *)ndlp->nlp_listp_next;

         /* Skip over FABRIC nodes and myself */
         if ((ndlp->nlp_DID == binfo->fc_myDID) || 
             (ndlp->nlp_type & NLP_FABRIC)) {
            ndlp = new_ndlp;
            if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
               ndlp = binfo->fc_nlpmap_start;
            continue;
         }

         fc_freenode(binfo, ndlp, 0);
         ndlp->nlp_state = NLP_LIMBO;
         fc_nlp_bind(binfo, ndlp);
         ndlp->nlp_action |= NLP_DO_DISC_START;

         ndlp = new_ndlp;
         if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
            ndlp = binfo->fc_nlpmap_start;
      }
   }
   binfo->fc_flag &= ~FC_SCSI_RLIP;

   /* If FCP is not enabled, go right to CLEAR_LA */
   if(!(clp[CFG_FCP_ON].a_current)) {
      if (addrauth) {
         /* Start authentication */
         fc_nextauth(p_dev_ctl, fc_max_els_sent);
         return(0);
      }
      /* Nothing to discover, so goto CLEAR_LA */
      goto cla;
   }

   firstndlp = 0;

   /* If FC_FABRIC is set, we need to do some NameServer stuff
    * to seed the nodeList with additional entries.
    */
   if (binfo->fc_flag & FC_FABRIC) {
      /* We can LOGIN to the NameServer first */
      fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)NameServer_DID,
             (uint32)0, (ushort)0, (NODELIST *)0);
      if(fc_fdmi_on) {
         /* HBA Mgmt */
         fc_els_cmd(binfo, ELS_CMD_PLOGI, (void *)FDMI_DID,
             (uint32)0, (ushort)0, (NODELIST *)0);
      }
      return(0);
   }

   /* No Fabric, just seed the nodeList with our ALPAmap */
   if (binfo->fc_topology == TOPOLOGY_LOOP) {
      if (binfo->alpa_map[0]) {
         for (j = 1; j <= binfo->alpa_map[0]; j++) {
            if (((binfo->fc_myDID & 0xff) == binfo->alpa_map[j]) || 
                (binfo->alpa_map[j] == 0))
               continue;
            /* Skip if the node is already marked address authentication */
            if((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, binfo->alpa_map[j]))) {
               if(ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START)) {
                  ndlp->nlp_DID = binfo->alpa_map[j];
                  if (firstndlp == 0)
                     firstndlp = ndlp;
                  continue;
               }
            }
            else {
               if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) {
                  fc_bzero((void *)ndlp, sizeof(NODELIST));
                  ndlp->sync = binfo->fc_sync;
                  ndlp->capabilities = binfo->fc_capabilities;
                  ndlp->nlp_DID = binfo->alpa_map[j];
                  ndlp->nlp_state = NLP_LIMBO;
                  fc_nlp_bind(binfo, ndlp);
               }
               else
                  continue;
            }
            ndlp->nlp_action |= NLP_DO_DISC_START;
            if (firstndlp == 0)
               firstndlp = ndlp;
         }
      } else {
         /* No alpamap, so try all alpa's */
         for (j = 0; j < FC_MAXLOOP; j++) {
            int index;

            if (clp[CFG_SCAN_DOWN].a_current)
               index = FC_MAXLOOP - j - 1;
            else
               index = j;
            if ((binfo->fc_myDID & 0xff) == staticAlpaArray[index])
               continue;
            /* Skip if the node is already marked address authentication */
            if((ndlp = fc_findnode_odid(binfo, NLP_SEARCH_ALL, staticAlpaArray[index]))) {
               if(ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START)) {
                  ndlp->nlp_DID = staticAlpaArray[index];
                  if (firstndlp == 0)
                     firstndlp = ndlp;
                  continue;
               }
            }
            else {
               if((ndlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) {
                  fc_bzero((void *)ndlp, sizeof(NODELIST));
                  ndlp->sync = binfo->fc_sync;
                  ndlp->capabilities = binfo->fc_capabilities;
                  ndlp->nlp_DID = staticAlpaArray[index];
                  ndlp->nlp_state = NLP_LIMBO;
                  fc_nlp_bind(binfo, ndlp);
               }
               else
                  continue;
            }
            ndlp->nlp_action |= NLP_DO_DISC_START;
            if (firstndlp == 0)
               firstndlp = ndlp;
         }
      }
   }
   /* Device Discovery continues */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0203,                    /* ptr to msg structure */
           fc_mes0203,                       /* ptr to msg */
            fc_msgBlk0203.msgPreambleStr,    /* begin varargs */
             (ulong)firstndlp,
              binfo->fc_ffstate);            /* end varargs */
   if (addrauth) {
      /* Start authentication */
      if(fc_nextauth(p_dev_ctl, fc_max_els_sent))
         return(0);
   }

   if (firstndlp) {
      /* We can start discovery right now */
      fc_nextdisc(p_dev_ctl, fc_max_els_sent);
      return(0);
   }
   else {
      /* Make sure no nodes are marked for discovery */
      /* go through all nodes in nlplist */
      ndlp = binfo->fc_nlpbind_start;
      if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start)
        ndlp = binfo->fc_nlpunmap_start;
      if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
         ndlp = binfo->fc_nlpmap_start;
      while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) {
         if (ndlp->nlp_action & (NLP_DO_ADDR_AUTH | NLP_DO_DISC_START))
            ndlp->nlp_action &= ~(NLP_DO_ADDR_AUTH | NLP_DO_DISC_START);
         ndlp = (NODELIST *)ndlp->nlp_listp_next;
         if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start)
           ndlp = binfo->fc_nlpunmap_start;
         if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
            ndlp = binfo->fc_nlpmap_start;
      }
   }

cla:
   /* This should turn off DELAYED ABTS for ELS timeouts */
   if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX))) {
      fc_set_slim(binfo, (MAILBOX * )mb, 0x052198, 0);
      if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) {
         fc_mem_put(binfo, MEM_MBOX, (uchar * )mb);
      }
   }

   /* This is at init, clear la */
   if ((mb = (MAILBOXQ * )fc_mem_get(binfo, MEM_MBOX | MEM_PRI))) {
      binfo->fc_ffstate = FC_CLEAR_LA;
      fc_clear_la(binfo, (MAILBOX * )mb);
      if (issue_mb_cmd(binfo, (MAILBOX * )mb, MBX_NOWAIT) != MBX_BUSY) {
         fc_mem_put(binfo, MEM_MBOX, (uchar * )mb);
      }
   } else {
      binfo->fc_ffstate = FC_ERROR;
      /* Device Discovery completion error */
      fc_log_printf_msg_vargs( binfo->fc_brd_no,
             &fc_msgBlk0204,                    /* ptr to msg structure */
              fc_mes0204,                       /* ptr to msg */
               fc_msgBlk0204.msgPreambleStr);   /* begin & end varargs */
   }
   if(FABRICTMO) {
      fc_clk_can(p_dev_ctl, FABRICTMO);
      FABRICTMO = 0;
   }
   return(0);
}       /* End fc_discovery */


/**************************************************/
/**  fc_addrauth                                 **/
/**                                              **/
/**  This routine will validate NODELIST entries **/
/**************************************************/
_local_ int
fc_addrauth(
fc_dev_ctl_t *p_dev_ctl)
{
   FC_BRD_INFO * binfo;
   iCfgParam   * clp;
   NODELIST * ndlp;
   NODELIST * new_ndlp;
   int  cnt;
   int  cnt1, cnt2;

   binfo = &BINFO;
   clp = DD_CTL.p_config[binfo->fc_brd_no];

   binfo->fc_nlp_cnt = 0;
   binfo->fc_flag &= ~FC_NLP_MORE;
   cnt = 0;
   cnt1 = 0;
   cnt2 = 0;

   /* go through all nodes in nlplist */
   ndlp = binfo->fc_nlpunmap_start;
   if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
      ndlp = binfo->fc_nlpmap_start;
   while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) {
      new_ndlp = (NODELIST *)ndlp->nlp_listp_next;

      /* Skip over Fabric nodes, myself, and nodes partially logged in */
      if ((ndlp->nlp_DID == binfo->fc_myDID) || 
          (ndlp->nlp_type & NLP_FABRIC)) {
         ndlp = new_ndlp;
         if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
            ndlp = binfo->fc_nlpmap_start;
         continue;
      }

      if ((ndlp->nlp_type & NLP_FCP_TARGET) && 
          ((!clp[CFG_USE_ADISC].a_current) || (ndlp->nlp_Rpi == 0) ||
            (binfo->fc_flag & FC_SCSI_RLIP))) {
         /* Force regular discovery on this node */
         fc_freenode(binfo, ndlp, 0);
         ndlp->nlp_state = NLP_LIMBO;
         fc_nlp_bind(binfo, ndlp);
         ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH;
         ndlp->nlp_action |= NLP_DO_DISC_START;
         cnt1++;
      } else {
         if ((ndlp->nlp_type & NLP_IP_NODE) && (ndlp->nlp_Rpi == 0)) {
            /* Force regular discovery on this node */
            fc_freenode(binfo, ndlp, 0);
            ndlp->nlp_state = NLP_LIMBO;
            fc_nlp_bind(binfo, ndlp);
            ndlp->nlp_action &= ~NLP_DO_ADDR_AUTH;
            ndlp->nlp_action |= NLP_DO_DISC_START;
            cnt2++;
         } else {
            /* Mark slot for address authentication */
            ndlp->nlp_action |= NLP_DO_ADDR_AUTH;
            cnt++;
         }
      }
      ndlp = new_ndlp;
      if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
         ndlp = binfo->fc_nlpmap_start;
   }

   /* Device Discovery authentication */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0205,                    /* ptr to msg structure */
           fc_mes0205,                       /* ptr to msg */
            fc_msgBlk0205.msgPreambleStr,    /* begin varargs */
             cnt,
              cnt1,
               cnt2);                        /* end varargs */
   return(cnt);
}       /* End fc_addrauth */


/**************************************************/
/**  fc_freebufq                                 **/
/**                                              **/
/**  This routine will free a iocb cmd block and **/
/**  all associated memory.                      **/
/**************************************************/
_static_ void
fc_freebufq(
fc_dev_ctl_t *p_dev_ctl,
RING        *rp,
IOCBQ       *xmitiq)
{
   FC_BRD_INFO * binfo;
   fcipbuf_t   * p_mbuf;
   fcipbuf_t   * m_net;
   NODELIST    * ndlp;
   ULP_BDE64     * bpl;
   MATCHMAP      * bmp;
   int  i;

   binfo = &BINFO;
   switch (xmitiq->iocb.ulpCommand) {
   case 0:
   case CMD_XMIT_BCAST_CN:              /* process xmit completion */
   case CMD_XMIT_BCAST_CX:
   case CMD_XMIT_SEQUENCE_CX:
   case CMD_XMIT_BCAST64_CN:            /* process xmit completion */
   case CMD_XMIT_BCAST64_CX:
   case CMD_XMIT_SEQUENCE64_CX:
      /* get mbuf ptr for xmit */
      m_net = (fcipbuf_t * )xmitiq->bp;
      ndlp = (NODELIST * ) xmitiq->info;

      /* Loop thru BDEs and unmap memory pages associated with mbuf */
      if (binfo->fc_flag & FC_SLI2) {
         bmp = (MATCHMAP * )xmitiq->bpl;
         if(bmp) {
            bpl = (ULP_BDE64 * )bmp->virt;
            while (bpl && xmitiq->iocb.un.xseq64.bdl.bdeSize) {
               fc_bufunmap(p_dev_ctl, (uchar *)getPaddr(bpl->addrHigh, bpl->addrLow), 0, bpl->tus.f.bdeSize);
               bpl++;
               xmitiq->iocb.un.xseq64.bdl.bdeSize -= sizeof(ULP_BDE64);
            }
            fc_mem_put(binfo, MEM_BPL, (uchar * )bmp);
         }
         fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq);
      } else {
         for (i = 0; i < (int)xmitiq->iocb.ulpBdeCount; i++) {
            fc_bufunmap(p_dev_ctl, (uchar *)((ulong)xmitiq->iocb.un.cont[i].bdeAddress), 0, (uint32)xmitiq->iocb.un.cont[i].bdeSize);
         }
         fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq);
      }

      if (ndlp && (ndlp->nlp_DID == NameServer_DID)) {
         fc_mem_put(binfo, MEM_BUF, (uchar * )m_net);
      } else {
         /* free mbuf */
         p_mbuf = fcnextdata(m_net);
         fcnextdata(m_net) = 0;
         fcfreehandle(p_dev_ctl, m_net);
         m_freem(m_net);
         if (p_mbuf) {
            fcfreehandle(p_dev_ctl, p_mbuf);
            m_freem(p_mbuf);
         }
      }
      break;

   case CMD_IOCB_CONTINUE_CN:
   case CMD_IOCB_CONTINUE64_CN:
      /* This is valid only for the IP ring, not the ELS ring */
      if (rp->fc_ringno == FC_ELS_RING)
         break;
      /* Loop thru BDEs and unmap memory pages associated with IOCB */
      for (i = 0; i < (int)xmitiq->iocb.ulpBdeCount; i++) {
         if (binfo->fc_flag & FC_SLI2)
            fc_bufunmap(p_dev_ctl, (uchar *)getPaddr(xmitiq->iocb.un.cont64[i].addrHigh, xmitiq->iocb.un.cont64[i].addrLow), 0, xmitiq->iocb.un.cont64[i].tus.f.bdeSize);
         else
            fc_bufunmap(p_dev_ctl, (uchar *)((ulong)xmitiq->iocb.un.cont[i].bdeAddress), 0, (uint32)xmitiq->iocb.un.cont[i].bdeSize); 
      }
      fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq);
      break;

   case CMD_XMIT_ELS_RSP_CX:
   case CMD_XMIT_ELS_RSP64_CX:
      if (xmitiq->bp) {
         fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->bp);
      }
      if (binfo->fc_flag & FC_SLI2) {
         fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl);
      }
      fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq);
      break;

   case CMD_ELS_REQUEST_CR:
   case CMD_ELS_REQUEST64_CR:
      if (xmitiq->bp) {
         fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->bp);
      }
      if (xmitiq->info) {
         fc_mem_put(binfo, MEM_BUF, (uchar * )xmitiq->info);
      }
      if (binfo->fc_flag & FC_SLI2) {
         fc_mem_put(binfo, MEM_BPL, (uchar * )xmitiq->bpl);
      }
      fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq);
      break;

   case CMD_QUE_RING_BUF_CN:
   case CMD_QUE_RING_BUF64_CN:
      /* Loop thru BDEs and return MEM_BUFs associated with IOCB */
      for (i = 0; i < (int)xmitiq->iocb.ulpBdeCount; i++) {
         MATCHMAP     * matp;

         if (binfo->fc_flag & FC_SLI2)
            matp = fc_getvaddr(p_dev_ctl, rp,
                (uchar * )getPaddr(xmitiq->iocb.un.cont64[i].addrHigh, xmitiq->iocb.un.cont64[i].addrLow));
         else
            matp = fc_getvaddr(p_dev_ctl, rp,
                (uchar * )((ulong)xmitiq->iocb.un.cont[i].bdeAddress));
         if (matp) {
            if (rp->fc_ringno == FC_ELS_RING) {
               fc_mem_put(binfo, MEM_BUF, (uchar * )matp);
            }
            if (rp->fc_ringno == FC_IP_RING) {
               p_mbuf = (fcipbuf_t * )matp;
               fcnextdata(p_mbuf) = 0;
               fcnextpkt(p_mbuf) = 0;
               m_freem(p_mbuf);
            }
         }
      }
      fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq);
      break;

   case CMD_CREATE_XRI_CX:
   case CMD_CREATE_XRI_CR:
   default:
      fc_mem_put(binfo, MEM_IOCB, (uchar * )xmitiq);
      break;
   }
}       /* End fc_freebufq */


/**************************************************/
/**  fc_emac_lookup                              **/
/**                                              **/
/**  This routine will find an NODELIST entry     **/
/**  that matches the destination MAC address.   **/
/**  The XID for that entry is returned and rpi  **/
/**  is updated with a ptr to the NODELIST entry. **/
/**************************************************/
_static_ ushort
fc_emac_lookup(
FC_BRD_INFO *binfo,
uchar       *addr,
NODELIST    **ndlpp)
{
   int  j;
   NODELIST * ndlp;

   ndlp = binfo->fc_nlpbind_start;
   if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start)
     ndlp = binfo->fc_nlpunmap_start;
   if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
      ndlp = binfo->fc_nlpmap_start;
   while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) {

      /* IF portname matches IEEE address, return NODELIST entry */
      if ((ndlp->nlp_portname.IEEE[0] == addr[0])) {
         if((ndlp->nlp_state == NLP_SEED) ||
            ((ndlp->nlp_DID != Bcast_DID) &&
            ((ndlp->nlp_DID & CT_DID_MASK) == CT_DID_MASK))) {
            ndlp = (NODELIST *)ndlp->nlp_listp_next;
            if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start)
              ndlp = binfo->fc_nlpunmap_start;
            if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
               ndlp = binfo->fc_nlpmap_start;
            continue;
         }

         /* check rest of bytes in address / portname */
         for (j = 1; j < NADDR_LEN; j++) {
            if (ndlp->nlp_portname.IEEE[j] != addr[j])
               break;
         }
         /* do all NADDR_LEN bytes match? */
         if (j == NADDR_LEN) {
            if ((ndlp->nlp_portname.nameType == NAME_IEEE) && 
                (ndlp->nlp_portname.IEEEextMsn == 0) && 
                (ndlp->nlp_portname.IEEEextLsb == 0)) {
               *ndlpp = ndlp;
               return(ndlp->nlp_Xri);
            }
         }
      }
      ndlp = (NODELIST *)ndlp->nlp_listp_next;
      if(ndlp == (NODELIST *)&binfo->fc_nlpbind_start)
        ndlp = binfo->fc_nlpunmap_start;
      if(ndlp == (NODELIST *)&binfo->fc_nlpunmap_start)
         ndlp = binfo->fc_nlpmap_start;
   }

   /* no match so return 0 */

   *ndlpp = 0;
   return(0);
}       /* End fc_emac_lookup */



/* Put nlp on bind list */
_static_ int
fc_nlp_bind(
FC_BRD_INFO *binfo,
NODELIST    *nlp)
{
   NODELIST *end_nlp;
   uint32        data1;

   data1 = ( ((uint32)nlp->nlp_state << 24) |
             ((uint32)nlp->nlp_action << 16) |
             ((uint32)nlp->nlp_type << 8) |
             ((uint32)nlp->nlp_Rpi & 0xff) );
   /* BIND node tbl */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0903,                    /* ptr to msg structure */
           fc_mes0903,                       /* ptr to msg */
            fc_msgBlk0903.msgPreambleStr,    /* begin varargs */
             (ulong)nlp,
               nlp->nlp_DID,
                nlp->nlp_flag,
                 data1);                     /* end varargs */
   /* First take it off any list its on */
   if(nlp->nlp_listp_next) {
      if (nlp->nlp_flag & NLP_MAPPED) {
         nlp->nlp_time = binfo->nlptimer++;
         if (nlp->nlp_time == 0) {
            fc_nlpadjust(binfo);
         }
         nlp->nlp_flag &= ~NLP_MAPPED;
         binfo->fc_map_cnt--;
         fc_deque(nlp);
      }
      else if (nlp->nlp_flag & NLP_UNMAPPED) {
         nlp->nlp_time = binfo->nlptimer++;
         if (nlp->nlp_time == 0) {
            fc_nlpadjust(binfo);
         }
         nlp->nlp_flag &= ~NLP_UNMAPPED;
         binfo->fc_unmap_cnt--;
         fc_deque(nlp);
      }
      else if (nlp->nlp_flag & NLP_BIND) {
         return(0);  /* Already on bind list */
      }
   }

   /* Put it at the begining of the bind list */
   binfo->fc_bind_cnt++;

   if(binfo->fc_nlpbind_start == (NODELIST *)&binfo->fc_nlpbind_start) {
      nlp->nlp_listp_next = &binfo->fc_nlpbind_start;
      binfo->fc_nlpbind_end = nlp;
   }
   else {
      end_nlp = binfo->fc_nlpbind_start;
      nlp->nlp_listp_next = end_nlp;
      end_nlp->nlp_listp_prev = nlp;
   }
   binfo->fc_nlpbind_start = nlp;;
   nlp->nlp_listp_prev = &binfo->fc_nlpbind_start;

   nlp->nlp_flag |= NLP_BIND;

   return(0);
}

/* Put nlp on unmap list */
_static_ int
fc_nlp_unmap(
FC_BRD_INFO *binfo,
NODELIST    *nlp)
{
   NODELIST   * end_nlp;
   RING       * rp;
   IOCBQ      * iocbq;
   uint32       data1;
   fc_dev_ctl_t * p_dev_ctl;

   data1 = ( ((uint32)nlp->nlp_state << 24) |
             ((uint32)nlp->nlp_action << 16) |
             ((uint32)nlp->nlp_type << 8) |
             ((uint32)nlp->nlp_Rpi & 0xff) );
   /* UNMAP node tbl */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0904,                    /* ptr to msg structure */
           fc_mes0904,                       /* ptr to msg */
            fc_msgBlk0904.msgPreambleStr,    /* begin varargs */
             (ulong)nlp,
               nlp->nlp_DID,
                nlp->nlp_flag,
                 data1);                     /* end varargs */
   /* First take it off any list its on */
   if(nlp->nlp_listp_next) {
      if (nlp->nlp_flag & NLP_MAPPED) {
         nlp->nlp_time = binfo->nlptimer++;
         if (nlp->nlp_time == 0) {
            fc_nlpadjust(binfo);
         }
         nlp->nlp_flag &= ~NLP_MAPPED;
         binfo->fc_map_cnt--;
         fc_deque(nlp);
      }
      else if (nlp->nlp_flag & NLP_BIND) {
         nlp->nlp_time = binfo->nlptimer++;
         if (nlp->nlp_time == 0) {
            fc_nlpadjust(binfo);
         }
         nlp->nlp_flag &= ~NLP_BIND;
         binfo->fc_bind_cnt--;
         fc_deque(nlp);
         /* If we are going from bind to unmapped, check for duplicate
          * WWNN on bind list.
          */
         /* Missing SP */
         p_dev_ctl = (fc_dev_ctl_t * )(binfo->fc_p_dev_ctl);

         /* Fabric nodes are always mapped by DID only */
         if((nlp->nlp_DID & Fabric_DID_MASK) == Fabric_DID_MASK)
            goto out;

         switch(p_dev_ctl->fcp_mapping) {

           case FCP_SEED_DID:
             break;

           case FCP_SEED_WWNN:
             if((end_nlp = fc_findnode_wwnn(binfo, NLP_SEARCH_BIND, &nlp->nlp_nodename))) {
                /* Found one so remove it */
                unsigned long iflag;
                end_nlp->nlp_flag &= ~NLP_BIND;
                binfo->fc_bind_cnt--;
                fc_deque(end_nlp);
                /* Look through ELS ring and remove any ELS cmds in progress for rnlp */
                iflag = lpfc_q_disable_lock(p_dev_ctl);
                rp = &binfo->fc_ring[FC_ELS_RING];
                iocbq = (IOCBQ * )(rp->fc_txp.q_first);
                while (iocbq) {
                   if ((iocbq->iocb.un.elsreq.remoteID == end_nlp->nlp_DID)  ||
                         ((end_nlp->nlp_DID == 0) &&
                         (iocbq->iocb.un.elsreq.remoteID == end_nlp->nlp_oldDID))) {
                      iocbq->retry = 0xff;  /* Mark for abort */
                      if((binfo->fc_flag & FC_RSCN_MODE) ||
                         (binfo->fc_ffstate < FC_READY)) {
                         if((end_nlp->nlp_state >= NLP_PLOGI) &&
                            (end_nlp->nlp_state <= NLP_PRLI)) {
                            end_nlp->nlp_action &= ~NLP_DO_RSCN;
                            binfo->fc_nlp_cnt--;
                            if ((end_nlp->nlp_type & NLP_IP_NODE) && end_nlp->nlp_bp) {
                               m_freem((fcipbuf_t *)end_nlp->nlp_bp);
                               end_nlp->nlp_bp = (uchar * )0;
                            }
                         }
                      }
                   }
                   iocbq = (IOCBQ * )iocbq->q;
                }
                lpfc_q_unlock_enable(p_dev_ctl, iflag);
                /* In case its on fc_delay_timeout list */
                fc_abort_delay_els_cmd(p_dev_ctl, end_nlp->nlp_DID);
                fc_bzero((void *)end_nlp, sizeof(NODELIST));
                fc_mem_put(binfo, MEM_NLP, (uchar *)end_nlp);
             }
             break;

           case FCP_SEED_WWPN:
             if((end_nlp = fc_findnode_wwpn(binfo, NLP_SEARCH_BIND, &nlp->nlp_portname))) {
                /* Found one so remove it */
                unsigned long iflag;
                end_nlp->nlp_flag &= ~NLP_BIND;
                binfo->fc_bind_cnt--;
                fc_deque(end_nlp);
                /* Look through ELS ring and remove any ELS cmds in progress for rnlp */
                iflag = lpfc_q_disable_lock(p_dev_ctl);
                rp = &binfo->fc_ring[FC_ELS_RING];
                iocbq = (IOCBQ * )(rp->fc_txp.q_first);
                while (iocbq) {
                   if ((iocbq->iocb.un.elsreq.remoteID == end_nlp->nlp_DID)  ||
                       ((end_nlp->nlp_DID == 0) && (iocbq->iocb.un.elsreq.remoteID == end_nlp->nlp_oldDID))) {
                      iocbq->retry = 0xff;  /* Mark for abort */
                      if((binfo->fc_flag & FC_RSCN_MODE) ||
                         (binfo->fc_ffstate < FC_READY)) {
                         if((end_nlp->nlp_state >= NLP_PLOGI) &&
                            (end_nlp->nlp_state <= NLP_PRLI)) {
                            end_nlp->nlp_action &= ~NLP_DO_RSCN;
                            binfo->fc_nlp_cnt--;
                            if ((end_nlp->nlp_type & NLP_IP_NODE) && end_nlp->nlp_bp) {
                               m_freem((fcipbuf_t *)end_nlp->nlp_bp);
                               end_nlp->nlp_bp = (uchar * )0;
                            }
                         }
                      }
                   }
                   iocbq = (IOCBQ * )iocbq->q;
                }
                lpfc_q_unlock_enable(p_dev_ctl, iflag);
                /* In case its on fc_delay_timeout list */
                fc_abort_delay_els_cmd(p_dev_ctl, end_nlp->nlp_DID);
                fc_bzero((void *)end_nlp, sizeof(NODELIST));
                fc_mem_put(binfo, MEM_NLP, (uchar *)end_nlp);
             }
             break;
         } /* switch */
      }
      else if (nlp->nlp_flag & NLP_UNMAPPED) {
         return(0);  /* Already on unmap list */
      }
   }

out:
   /* Put it on the end of the unmapped list */
   binfo->fc_unmap_cnt++;
   end_nlp = binfo->fc_nlpunmap_end;
   fc_enque(nlp, end_nlp);
   nlp->nlp_flag |= NLP_UNMAPPED;
   return(0);
}

/* Put nlp on map list */
_static_ int
fc_nlp_map(
FC_BRD_INFO *binfo,
NODELIST    *nlp)
{
   NODELIST *end_nlp;
   uint32    data1;

   data1 = ( ((uint32)nlp->nlp_state << 24) |
             ((uint32)nlp->nlp_action << 16) |
             ((uint32)nlp->nlp_type << 8) |
             ((uint32)nlp->nlp_Rpi & 0xff) );
   /* MAP node tbl */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0905,                    /* ptr to msg structure */
           fc_mes0905,                       /* ptr to msg */
            fc_msgBlk0905.msgPreambleStr,    /* begin varargs */
             (ulong)nlp,
               nlp->nlp_DID,
                nlp->nlp_flag,
                 data1);                     /* end varargs */
   /* First take it off any list its on */
   if(nlp->nlp_listp_next) {
      if (nlp->nlp_flag & NLP_UNMAPPED) {
         nlp->nlp_time = binfo->nlptimer++;
         if (nlp->nlp_time == 0) {
            fc_nlpadjust(binfo);
         }
         nlp->nlp_flag &= ~NLP_UNMAPPED;
         binfo->fc_unmap_cnt--;
         fc_deque(nlp);
      }
      else if (nlp->nlp_flag & NLP_BIND) {
         nlp->nlp_time = binfo->nlptimer++;
         if (nlp->nlp_time == 0) {
            fc_nlpadjust(binfo);
         }
         nlp->nlp_flag &= ~NLP_BIND;
         binfo->fc_bind_cnt--;
         fc_deque(nlp);
      }
      else if (nlp->nlp_flag & NLP_MAPPED) {
         return(0);  /* Already on map list */
      }
   }

   /* Put it on the end of the mapped list */
   binfo->fc_map_cnt++;
   end_nlp = binfo->fc_nlpmap_end;
   fc_enque(nlp, end_nlp);
   nlp->nlp_flag |= NLP_MAPPED;
   return(0);
}

/**************************************************/
/**  fc_findnode_odid                            **/
/**                                              **/
/**  This routine find a node by did             **/
/**************************************************/
_static_ NODELIST *
fc_findnode_odid(
FC_BRD_INFO *binfo,
uint32      order,
uint32      did)
{
   NODELIST * nlp;
   uint32     data1;

   if(order & NLP_SEARCH_UNMAPPED) {
      nlp = binfo->fc_nlpunmap_start;
      while(nlp != (NODELIST *)&binfo->fc_nlpunmap_start) {
         if (fc_matchdid(binfo, nlp, did)) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)nlp->nlp_Rpi & 0xff) );
            /* FIND node DID unmapped */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0906,                    /* ptr to msg structure */
                    fc_mes0906,                       /* ptr to msg */
                     fc_msgBlk0906.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_DID,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
      }
   }
   if(order & NLP_SEARCH_MAPPED) {
      nlp = binfo->fc_nlpmap_start;
      while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) {
         if (fc_matchdid(binfo, nlp, did)) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)nlp->nlp_Rpi & 0xff) );
            /* FIND node did mapped */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0907,                    /* ptr to msg structure */
                    fc_mes0907,                       /* ptr to msg */
                     fc_msgBlk0907.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_DID,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
      }
   }
   if(order & NLP_SEARCH_BIND) {
      nlp = binfo->fc_nlpbind_start;
      while(nlp != (NODELIST *)&binfo->fc_nlpbind_start) {
         if (fc_matchdid(binfo, nlp, did)) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)nlp->nlp_Rpi & 0xff) );
            /* FIND node DID bind */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0908,                    /* ptr to msg structure */
                    fc_mes0908,                       /* ptr to msg */
                     fc_msgBlk0908.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_DID,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
      }
   }
   /* FIND node did <did> NOT FOUND */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
       &fc_msgBlk0909,                    /* ptr to msg structure */
        fc_mes0909,                       /* ptr to msg */
         fc_msgBlk0909.msgPreambleStr,    /* begin varargs */
          did,
           order);                        /* end varargs */
   /* no match found */
   return((NODELIST * )0);
}       /* End fc_findnode_odid */


/**************************************************/
/**  fc_findnode_scsid                           **/
/**                                              **/
/**  This routine find a node by scsid           **/
/**************************************************/
_static_ NODELIST *
fc_findnode_scsid(
FC_BRD_INFO *binfo,
uint32      order,
uint32      scsid)
{
   NODELIST * nlp;
   uint32     data1;

   if(order & NLP_SEARCH_UNMAPPED) {
      nlp = binfo->fc_nlpunmap_start;
      if(nlp == 0) {
         return(0);
      }
      while(nlp != (NODELIST *)&binfo->fc_nlpunmap_start) {
         if ((nlp->nlp_type & NLP_FCP_TARGET) &&
            (INDEX(nlp->id.nlp_pan, nlp->id.nlp_sid) == scsid)) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)scsid & 0xff) );
            /* FIND node scsi_id unmapped */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0910,                    /* ptr to msg structure */
                    fc_mes0910,                       /* ptr to msg */
                     fc_msgBlk0910.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_DID,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
         if(nlp == 0) {
            return(0);
         }
      }
   }
   if(order & NLP_SEARCH_MAPPED) {
      nlp = binfo->fc_nlpmap_start;
      if(nlp == 0) {
         return(0);
      }
      while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) {
         if ((nlp->nlp_type & NLP_FCP_TARGET) &&
            (INDEX(nlp->id.nlp_pan, nlp->id.nlp_sid) == scsid)) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)scsid & 0xff) );
            /* FIND node scsi_id mapped */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0911,                    /* ptr to msg structure */
                    fc_mes0911,                       /* ptr to msg */
                     fc_msgBlk0911.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_DID,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
         if(nlp == 0) {
            return(0);
         }
      }
   }
   if(order & NLP_SEARCH_BIND) {
      nlp = binfo->fc_nlpbind_start;
      if(nlp == 0) {
         return(0);
      }
      while(nlp != (NODELIST *)&binfo->fc_nlpbind_start) {
         if ((nlp->nlp_type & NLP_FCP_TARGET) &&
            (INDEX(nlp->id.nlp_pan, nlp->id.nlp_sid) == scsid)) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)scsid & 0xff) );
            /* FIND node scsi_id bind */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0912,                    /* ptr to msg structure */
                    fc_mes0912,                       /* ptr to msg */
                     fc_msgBlk0912.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_DID,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
         if(nlp == 0) {
            return(0);
         }
      }
   }
   /* FIND node scsi_id NOT FOUND */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0913,                    /* ptr to msg structure */
           fc_mes0913,                       /* ptr to msg */
            fc_msgBlk0913.msgPreambleStr,    /* begin varargs */
             scsid,
              order);                        /* end varargs */
   /* no match found */
   return((NODELIST * )0);
}       /* End fc_findnode_scsid */


/**************************************************/
/**  fc_findnode_wwnn                            **/
/**                                              **/
/**  This routine find a node by WWNN            **/
/**************************************************/
_static_ NODELIST *
fc_findnode_wwnn(
FC_BRD_INFO *binfo,
uint32      order,
NAME_TYPE    * wwnn)
{
   NODELIST * nlp;
   uint32     data1;

   if(order & NLP_SEARCH_UNMAPPED) {
      nlp = binfo->fc_nlpunmap_start;
      while(nlp != (NODELIST *)&binfo->fc_nlpunmap_start) {
         if(fc_geportname(&nlp->nlp_nodename, wwnn) == 2) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)nlp->nlp_Rpi & 0xff) );
            /* FIND node wwnn unmapped */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0914,                    /* ptr to msg structure */
                    fc_mes0914,                       /* ptr to msg */
                     fc_msgBlk0914.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_DID,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
      }
   }
   if(order & NLP_SEARCH_MAPPED) {
      nlp = binfo->fc_nlpmap_start;
      while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) {
         if(fc_geportname(&nlp->nlp_nodename, wwnn) == 2) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)nlp->nlp_Rpi & 0xff) );
            /* FIND node wwnn mapped */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0915,                    /* ptr to msg structure */
                    fc_mes0915,                       /* ptr to msg */
                     fc_msgBlk0915.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_DID,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
      }
   }
   if(order & NLP_SEARCH_BIND) {
      nlp = binfo->fc_nlpbind_start;
      while(nlp != (NODELIST *)&binfo->fc_nlpbind_start) {
         if(fc_geportname(&nlp->nlp_nodename, wwnn) == 2) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)nlp->nlp_Rpi & 0xff) );
            /* FIND node wwnn bind */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0916,                    /* ptr to msg structure */
                    fc_mes0916,                       /* ptr to msg */
                     fc_msgBlk0916.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_DID,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
      }
   }
   /* FIND node wwnn NOT FOUND */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0918,                    /* ptr to msg structure */
           fc_mes0918,                       /* ptr to msg */
            fc_msgBlk0918.msgPreambleStr,    /* begin varargs */
             order);                         /* end varargs */
   /* no match found */
   return((NODELIST * )0);
}       /* End fc_findnode_wwnn */



/**************************************************/
/**  fc_findnode_wwpn                            **/
/**                                              **/
/**  This routine find a node by WWPN            **/
/**************************************************/
_static_ NODELIST *
fc_findnode_wwpn(
FC_BRD_INFO *binfo,
uint32      order,
NAME_TYPE    * wwpn)
{
   NODELIST * nlp;
   uint32     data1;

   if(order & NLP_SEARCH_UNMAPPED) {
      nlp = binfo->fc_nlpunmap_start;
      while(nlp != (NODELIST *)&binfo->fc_nlpunmap_start) {
         if(fc_geportname(&nlp->nlp_portname, wwpn) == 2) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)nlp->nlp_Rpi & 0xff) );
            /* FIND node wwpn unmapped */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0919,                    /* ptr to msg structure */
                    fc_mes0919,                       /* ptr to msg */
                     fc_msgBlk0919.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_DID,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
      }
   }
   if(order & NLP_SEARCH_MAPPED) {
      nlp = binfo->fc_nlpmap_start;
      while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) {
         if(fc_geportname(&nlp->nlp_portname, wwpn) == 2) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)nlp->nlp_Rpi & 0xff) );
            /* FIND node wwpn mapped */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0920,                    /* ptr to msg structure */
                    fc_mes0920,                       /* ptr to msg */
                     fc_msgBlk0920.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_DID,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
      }
   }
   if(order & NLP_SEARCH_BIND) {
      nlp = binfo->fc_nlpbind_start;
      while(nlp != (NODELIST *)&binfo->fc_nlpbind_start) {
         if(fc_geportname(&nlp->nlp_portname, wwpn) == 2) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)nlp->nlp_Rpi & 0xff) );
            /* FIND node wwpn bind */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0921,                    /* ptr to msg structure */
                    fc_mes0921,                       /* ptr to msg */
                     fc_msgBlk0921.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_DID,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
      }
   }
   /* FIND node wwpn NOT FOUND */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0922,                    /* ptr to msg structure */
           fc_mes0922,                       /* ptr to msg */
            fc_msgBlk0922.msgPreambleStr,    /* begin varargs */
             order);                         /* end varargs */
   /* no match found */
   return((NODELIST * )0);
}       /* End fc_findnode_wwpn */


/**************************************************/
/**  fc_findnode_oxri                            **/
/**                                              **/
/**  This routine find a node by OXri            **/
/**************************************************/
_static_ NODELIST *
fc_findnode_oxri(
FC_BRD_INFO *binfo,
uint32      order,
uint32      xri)
{
   NODELIST * nlp;
   uint32     data1;

   if(order & NLP_SEARCH_UNMAPPED) {
      nlp = binfo->fc_nlpunmap_start;
      while(nlp != (NODELIST *)&binfo->fc_nlpunmap_start) {
         if (nlp->nlp_Xri == xri) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)nlp->nlp_Rpi & 0xff) );
            /* FIND node xri unmapped */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0923,                    /* ptr to msg structure */
                    fc_mes0923,                       /* ptr to msg */
                     fc_msgBlk0923.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_Xri,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
      }
   }
   if(order & NLP_SEARCH_MAPPED) {
      nlp = binfo->fc_nlpmap_start;
      while(nlp != (NODELIST *)&binfo->fc_nlpmap_start) {
         if (nlp->nlp_Xri == xri) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)nlp->nlp_Rpi & 0xff) );
            /* FIND node xri mapped */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0924,                    /* ptr to msg structure */
                    fc_mes0924,                       /* ptr to msg */
                     fc_msgBlk0924.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_Xri,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
      }
   }
   if(order & NLP_SEARCH_BIND) {
      nlp = binfo->fc_nlpbind_start;
      while(nlp != (NODELIST *)&binfo->fc_nlpbind_start) {
         if (nlp->nlp_Xri == xri) {

            data1 = ( ((uint32)nlp->nlp_state << 24) |
                      ((uint32)nlp->nlp_action << 16) |
                      ((uint32)nlp->nlp_type << 8) |
                      ((uint32)nlp->nlp_Rpi & 0xff) );
            /* FIND node xri bind */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0925,                    /* ptr to msg structure */
                    fc_mes0925,                       /* ptr to msg */
                     fc_msgBlk0925.msgPreambleStr,    /* begin varargs */
                      (ulong)nlp,
                        nlp->nlp_Xri,
                         nlp->nlp_flag,
                          data1);                     /* end varargs */
            return(nlp);
         }
         nlp = (NODELIST *)nlp->nlp_listp_next;
      }
   }
   /* FIND node xri NOT FOUND */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0926,                    /* ptr to msg structure */
           fc_mes0926,                       /* ptr to msg */
            fc_msgBlk0926.msgPreambleStr,    /* begin varargs */
             xri,
              order);                        /* end varargs */
   /* no match found */
   return((NODELIST * )0);
}       /* End fc_findnode_oxri */

/* Put nlp in PLOGI state */
_static_ int
fc_nlp_logi(
FC_BRD_INFO *binfo,
NODELIST    *nlp,
NAME_TYPE   *wwpnp,
NAME_TYPE   *wwnnp)
{
   fc_dev_ctl_t * p_dev_ctl;
   NODELIST     * rnlp;

   if (nlp->nlp_flag & NLP_UNMAPPED) {
      nlp->nlp_flag &= ~NLP_UNMAPPED;
      binfo->fc_unmap_cnt--;
      fc_deque(nlp);
   }
   else if (nlp->nlp_flag & NLP_BIND) {
      nlp->nlp_flag &= ~NLP_BIND;
      binfo->fc_bind_cnt--;
      fc_deque(nlp);
   }
   else if (nlp->nlp_flag & NLP_MAPPED) {
      nlp->nlp_flag &= ~NLP_MAPPED;
      binfo->fc_map_cnt--;
      fc_deque(nlp);
   }

   p_dev_ctl = (fc_dev_ctl_t * )(binfo->fc_p_dev_ctl);

   /* Fabric nodes are always mapped by DID only */
   if((nlp->nlp_DID & Fabric_DID_MASK) == Fabric_DID_MASK)
      goto out;

   switch(p_dev_ctl->fcp_mapping) {
   case FCP_SEED_DID:
      fc_bcopy(wwpnp, &nlp->nlp_portname, sizeof(NAME_TYPE));
      fc_bcopy(wwnnp, &nlp->nlp_nodename, sizeof(NAME_TYPE));
      break;
   case FCP_SEED_WWNN:
      /* Check to see if this WWNN already has a binding setup */
      if(fc_geportname(&nlp->nlp_nodename, wwnnp) != 2) {
         if (nlp->nlp_type & NLP_SEED_WWNN) {
            /* Get a new entry to save old binding info */
            if((rnlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) {
               fc_bzero((void *)rnlp, sizeof(NODELIST));
               rnlp->nlp_state = NLP_LIMBO;
               fc_nlp_swapinfo(binfo, nlp, rnlp);
               fc_nlp_bind(binfo, rnlp);
            }
         }
         /* Search for existing entry with that binding */
         if((rnlp = fc_findnode_wwnn(binfo, NLP_SEARCH_ALL, wwnnp)) &&
           (rnlp->nlp_type & NLP_SEED_WWNN)) {

            if (rnlp->nlp_flag & NLP_MAPPED) {
               rnlp->nlp_flag &= ~NLP_MAPPED;
               binfo->fc_map_cnt--;
               fc_deque(rnlp);
            }
            else if (rnlp->nlp_flag & NLP_UNMAPPED) {
               rnlp->nlp_flag &= ~NLP_UNMAPPED;
               binfo->fc_unmap_cnt--;
               fc_deque(rnlp);
            }
            else if (rnlp->nlp_flag & NLP_BIND) {
               rnlp->nlp_flag &= ~NLP_BIND;
               binfo->fc_bind_cnt--;
               fc_deque(rnlp);
            }

            /* found, so copy binding info into nlp */
            fc_nlp_swapinfo(binfo, rnlp, nlp);
            if(rnlp->nlp_action || (rnlp->nlp_flag & NLP_REQ_SND)) {
               fc_nlp_bind(binfo, rnlp);
            }
            else {
               fc_freenode(binfo, rnlp, 1);
            }
         }
         fc_bcopy(wwpnp, &nlp->nlp_portname, sizeof(NAME_TYPE));
         fc_bcopy(wwnnp, &nlp->nlp_nodename, sizeof(NAME_TYPE));
      }
      else {
         /* DID and WWNN match existing entry */
         fc_bcopy(wwpnp, &nlp->nlp_portname, sizeof(NAME_TYPE));
      }
      break;
   case FCP_SEED_WWPN:
      /* Check to see if this WWPN already has a binding setup */
      if(fc_geportname(&nlp->nlp_portname, wwpnp) != 2) {
         if (nlp->nlp_type & NLP_SEED_WWPN) {
            /* Get a new entry to save old binding info */
            if((rnlp = (NODELIST *)fc_mem_get(binfo, MEM_NLP))) {
               fc_bzero((void *)rnlp, sizeof(NODELIST));
               rnlp->nlp_state = NLP_LIMBO;
               fc_nlp_swapinfo(binfo, nlp, rnlp);
               fc_nlp_bind(binfo, rnlp);
            }
         }
         /* Search for existing entry with that binding */
         if((rnlp = fc_findnode_wwpn(binfo, NLP_SEARCH_ALL, wwpnp)) &&
           (rnlp->nlp_type & NLP_SEED_WWPN)) {

            if (rnlp->nlp_flag & NLP_MAPPED) {
               rnlp->nlp_flag &= ~NLP_MAPPED;
               binfo->fc_map_cnt--;
               fc_deque(rnlp);
            }
            else if (rnlp->nlp_flag & NLP_UNMAPPED) {
               rnlp->nlp_flag &= ~NLP_UNMAPPED;
               binfo->fc_unmap_cnt--;
               fc_deque(rnlp);
            }
            else if (rnlp->nlp_flag & NLP_BIND) {
               rnlp->nlp_flag &= ~NLP_BIND;
               binfo->fc_bind_cnt--;
               fc_deque(rnlp);
            }
            /* found, so copy binding info into nlp */
            fc_nlp_swapinfo(binfo, rnlp, nlp);
            if(rnlp->nlp_action || (rnlp->nlp_flag & NLP_REQ_SND)) {
               fc_nlp_bind(binfo, rnlp);
            }
            else {
               fc_freenode(binfo, rnlp, 1);
            }
         }
out:
         fc_bcopy(wwpnp, &nlp->nlp_portname, sizeof(NAME_TYPE));
         fc_bcopy(wwnnp, &nlp->nlp_nodename, sizeof(NAME_TYPE));
      }
      else {
         /* DID and WWPN match existing entry */
         fc_bcopy(wwnnp, &nlp->nlp_nodename, sizeof(NAME_TYPE));
      }
      break;
   }

   nlp->nlp_state = NLP_PLOGI;
   fc_nlp_bind(binfo, nlp);
   return(0);
}

_static_ int
fc_nlp_swapinfo(
FC_BRD_INFO *binfo,
NODELIST    *old_nlp,
NODELIST    *new_nlp)
{
   int index;

   fc_bcopy(&old_nlp->nlp_nodename, &new_nlp->nlp_nodename, sizeof(NAME_TYPE));
   fc_bcopy(&old_nlp->nlp_portname, &new_nlp->nlp_portname, sizeof(NAME_TYPE));
   new_nlp->nlp_type = old_nlp->nlp_type;
   new_nlp->id.nlp_pan = old_nlp->id.nlp_pan;
   new_nlp->id.nlp_sid = old_nlp->id.nlp_sid;
   new_nlp->nlp_targetp = old_nlp->nlp_targetp;
   new_nlp->target_scsi_options = old_nlp->target_scsi_options;
   new_nlp->capabilities = old_nlp->capabilities;
   new_nlp->sync = old_nlp->sync;

   if((old_nlp->nlp_type & NLP_FCP_TARGET) && old_nlp->nlp_targetp != NULL) {
      index = INDEX(new_nlp->id.nlp_pan, new_nlp->id.nlp_sid);
      if(binfo->device_queue_hash[index].node_ptr &&
         binfo->device_queue_hash[index].node_ptr->nlp == old_nlp) {
         binfo->device_queue_hash[index].node_ptr->nlp = new_nlp;
         new_nlp->nlp_targetp = (uchar *)binfo->device_queue_hash[index].node_ptr;
      }
   }

   old_nlp->nlp_type = 0;
   old_nlp->id.nlp_pan = 0;
   old_nlp->id.nlp_sid = 0;
   old_nlp->nlp_targetp = 0;
   old_nlp->sync = binfo->fc_sync;
   old_nlp->capabilities = binfo->fc_capabilities;
   fc_bzero(&old_nlp->nlp_nodename, sizeof(NAME_TYPE));
   fc_bzero(&old_nlp->nlp_portname, sizeof(NAME_TYPE));
   return(0);
}

