/*******************************************************************
 * 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[];

/* Routine Declaration - Local */
/* There currently are no local routine declarations */
/* End Routine Declaration - Local */


/**********************************************/
/**  fc_restart  Issue a RESTART             **/
/**              mailbox command             **/
/**********************************************/
_static_ void
fc_restart(
FC_BRD_INFO *binfo,
MAILBOX     *mb,
int doit)
{
   void *ioa;
   MAILBOX * mbox;
   fc_dev_ctl_t    *p_dev_ctl; 

   fc_bzero((void *)mb, sizeof(MAILBOXQ));
   mb->mbxCommand = MBX_RESTART;
   mb->mbxHc = OWN_CHIP;
   mb->mbxOwner = OWN_HOST;

   if (doit) {
      /* use REAL SLIM !!! */
      p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl);   
      binfo->fc_mboxaddr = 0;
      binfo->fc_flag &= ~FC_SLI2;

      ioa = (void *)FC_MAP_MEM(&binfo->fc_iomap_mem);  /* map in SLIM */
      mbox = FC_MAILBOX(binfo, ioa);
      WRITE_SLIM_COPY(binfo, (uint32 *)&mb->un.varWords, (uint32 *)&mbox->un.varWords,
          (MAILBOX_CMD_WSIZE - 1));
      FC_UNMAP_MEMIO(ioa);
   }
   return;
}       /* End fc_restart */


/**********************************************/
/**  fc_dump_mem  Issue a DUMP MEMORY        **/
/**              mailbox command             **/
/**********************************************/
_static_ void
fc_dump_mem(
FC_BRD_INFO *binfo,
MAILBOX     *mb)
{
   /* Setup to dump VPD region */
   fc_bzero((void *)mb, sizeof(MAILBOXQ));
   mb->mbxCommand = MBX_DUMP_MEMORY;
   mb->un.varDmp.cv = 1;
   mb->un.varDmp.type = DMP_NV_PARAMS;
   mb->un.varDmp.region_id = DMP_REGION_VPD;
   mb->un.varDmp.word_cnt = (DMP_VPD_SIZE / sizeof(uint32));

   mb->un.varDmp.co = 0;
   mb->un.varDmp.resp_offset = 0;
   mb->mbxOwner = OWN_HOST;
   return;
}       /* End fc_dump_mem */


/**********************************************/
/**  fc_read_nv  Issue a READ NVPARAM        **/
/**              mailbox command             **/
/**********************************************/
_static_ void
fc_read_nv(
FC_BRD_INFO *binfo,
MAILBOX     *mb)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));
   mb->mbxCommand = MBX_READ_NV;
   mb->mbxOwner = OWN_HOST;
   return;
}       /* End fc_read_nv */

/**********************************************/
/**  fc_read_rev  Issue a READ REV           **/
/**               mailbox command            **/
/**********************************************/
_static_ void
fc_read_rev(
FC_BRD_INFO *binfo,
MAILBOX     *mb)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));
   mb->un.varRdRev.cv = 1; 
   mb->mbxCommand = MBX_READ_REV;
   mb->mbxOwner = OWN_HOST;
   return;
}       /* End fc_read_rev */

/**********************************************/
/**  fc_runBIUdiag  Issue a RUN_BIU_DIAG     **/
/**              mailbox command             **/
/**********************************************/
_static_ int
fc_runBIUdiag(
FC_BRD_INFO *binfo,
MAILBOX     *mb,
uchar       *in,
uchar       *out)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   if (binfo->fc_flag & FC_SLI2) {
      mb->mbxCommand = MBX_RUN_BIU_DIAG64;
      mb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize = FCELSSIZE;
      mb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = (uint32)putPaddrHigh(in);
      mb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = (uint32)putPaddrLow(in);
      mb->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeSize = FCELSSIZE;
      mb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = (uint32)putPaddrHigh(out);
      mb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = (uint32)putPaddrLow(out);
   } else {
      mb->mbxCommand = MBX_RUN_BIU_DIAG;
      mb->un.varBIUdiag.un.s1.xmit_bde.bdeSize = FCELSSIZE;
      mb->un.varBIUdiag.un.s1.xmit_bde.bdeAddress = (uint32)putPaddrLow(in);
      mb->un.varBIUdiag.un.s1.rcv_bde.bdeSize = FCELSSIZE;
      mb->un.varBIUdiag.un.s1.rcv_bde.bdeAddress = (uint32)putPaddrLow(out);
   }

   mb->mbxOwner = OWN_HOST;
   return(0);
}       /* End fc_runBIUdiag */


/**********************************************/
/**  fc_read_la  Issue a READ LA             **/
/**              mailbox command             **/
/**********************************************/
_static_ int
fc_read_la(
fc_dev_ctl_t *p_dev_ctl,
MAILBOX     *mb)
{
   FC_BRD_INFO * binfo;
   MATCHMAP * mp;

   binfo = &BINFO;
   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   if ((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF)) == 0) {

      if (binfo->fc_flag & FC_SLI2)
         mb->mbxCommand = MBX_READ_LA64;
      else
         mb->mbxCommand = MBX_READ_LA;
      /* READ_LA: no buffers */
      fc_log_printf_msg_vargs( binfo->fc_brd_no,
             &fc_msgBlk0300,                  /* ptr to msg structure */
              fc_mes0300,                     /* ptr to msg */
               fc_msgBlk0300.msgPreambleStr); /* begin & end varargs */
      return(1);
   }

   if (binfo->fc_flag & FC_SLI2) {
      mb->mbxCommand = MBX_READ_LA64;
      mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize = 128;
      mb->un.varReadLA.un.lilpBde64.addrHigh = (uint32)putPaddrHigh(mp->phys);
      mb->un.varReadLA.un.lilpBde64.addrLow = (uint32)putPaddrLow(mp->phys);
   } else {
      mb->mbxCommand = MBX_READ_LA;
      mb->un.varReadLA.un.lilpBde.bdeSize = 128;
      mb->un.varReadLA.un.lilpBde.bdeAddress = (uint32)putPaddrLow(mp->phys);
   }

   /* save address for completion */
   ((MAILBOXQ * )mb)->bp = (uchar * )mp;

   mb->mbxOwner = OWN_HOST;
   return(0);
}       /* End fc_read_la */


/**********************************************/
/**  fc_clear_la  Issue a CLEAR LA           **/
/**              mailbox command             **/
/**********************************************/
_static_ void
fc_clear_la(
FC_BRD_INFO *binfo,
MAILBOX     *mb)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));
   mb->un.varClearLA.eventTag = binfo->fc_eventTag;
   mb->mbxCommand = MBX_CLEAR_LA;
   mb->mbxOwner = OWN_HOST;
   return;
}       /* End fc_clear_la */


/**********************************************/
/**  fc_read_status  Issue a READ STATUS     **/
/**              mailbox command             **/
/**********************************************/
_static_ void
fc_read_status(
FC_BRD_INFO *binfo,
MAILBOX     *mb)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));
   mb->mbxCommand = MBX_READ_STATUS;
   mb->mbxOwner = OWN_HOST;
   return;
}       /* End fc_read_status */

/**********************************************/
/**  fc_read_lnk_stat  Issue a LINK STATUS   **/
/**              mailbox command             **/
/**********************************************/
_static_ void
fc_read_lnk_stat(
FC_BRD_INFO *binfo,
MAILBOX     *mb)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));
   mb->mbxCommand = MBX_READ_LNK_STAT;
   mb->mbxOwner = OWN_HOST;
   return;
}       /* End fc_read_lnk_stat */


/**************************************************/
/**  fc_config_ring  Issue a CONFIG RING         **/
/**                  mailbox command             **/
/**************************************************/
_static_ void
fc_config_ring(
FC_BRD_INFO *binfo,
int ring,
int profile,
MAILBOX     *mb)
{
   int  i;
   int  j;

   fc_bzero((void *)mb, sizeof(MAILBOXQ));
   mb->un.varCfgRing.ring = ring;
   mb->un.varCfgRing.profile = profile;
   mb->un.varCfgRing.maxOrigXchg = 0;
   mb->un.varCfgRing.maxRespXchg = 0;
   mb->un.varCfgRing.recvNotify = 1;
   mb->un.varCfgRing.numMask = binfo->fc_nummask[ring];

   j = 0;
   for (i = 0; i < ring; i++)
      j += binfo->fc_nummask[i];

   for (i = 0; i < binfo->fc_nummask[ring]; i++) {
      mb->un.varCfgRing.rrRegs[i].rval = binfo->fc_rval[j + i];
      if (mb->un.varCfgRing.rrRegs[i].rval != FC_ELS_REQ) /* ELS request */
         mb->un.varCfgRing.rrRegs[i].rmask = 0xff;
      else
         mb->un.varCfgRing.rrRegs[i].rmask = 0xfe;
      mb->un.varCfgRing.rrRegs[i].tval = binfo->fc_tval[j + i];
      mb->un.varCfgRing.rrRegs[i].tmask = 0xff;
   }

   mb->mbxCommand = MBX_CONFIG_RING;
   mb->mbxOwner = OWN_HOST;
   return;
}       /* End fc_config_ring */


/**************************************************/
/**  fc_config_link  Issue a CONFIG LINK         **/
/**                  mailbox command             **/
/**************************************************/
_static_ void
fc_config_link(
fc_dev_ctl_t *p_dev_ctl,
MAILBOX     *mb)
{
   FC_BRD_INFO * binfo;
   iCfgParam     * clp;

   binfo = &BINFO;
   clp = DD_CTL.p_config[binfo->fc_brd_no];
   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   if(clp[CFG_CR_DELAY].a_current) {
     mb->un.varCfgLnk.cr = 1;
     mb->un.varCfgLnk.ci = 1;
     mb->un.varCfgLnk.cr_delay = clp[CFG_CR_DELAY].a_current;
     mb->un.varCfgLnk.cr_count = clp[CFG_CR_COUNT].a_current;
   }

   mb->un.varCfgLnk.myId = binfo->fc_myDID;
   mb->un.varCfgLnk.edtov = binfo->fc_edtov;
   mb->un.varCfgLnk.arbtov = binfo->fc_arbtov;
   mb->un.varCfgLnk.ratov = binfo->fc_ratov;
   mb->un.varCfgLnk.rttov = binfo->fc_rttov;
   mb->un.varCfgLnk.altov = binfo->fc_altov;
   mb->un.varCfgLnk.crtov = binfo->fc_crtov;
   mb->un.varCfgLnk.citov = binfo->fc_citov;
   if(clp[CFG_ACK0].a_current)
      mb->un.varCfgLnk.ack0_enable = 1;

   mb->mbxCommand = MBX_CONFIG_LINK;
   mb->mbxOwner = OWN_HOST;
   return;
}       /* End fc_config_link */


/**********************************************/
/**  fc_init_link  Issue an INIT LINK        **/
/**                mailbox command           **/
/**********************************************/
_static_ void
fc_init_link(
FC_BRD_INFO *binfo,
MAILBOX     *mb,
uint32 topology,
uint32 linkspeed)
{
   iCfgParam     * clp;
   fc_vpd_t      * vpd;

   clp = DD_CTL.p_config[binfo->fc_brd_no];
   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   switch (topology) {
      case FLAGS_TOPOLOGY_MODE_LOOP_PT:
         mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
         mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER;
         break;
      case FLAGS_TOPOLOGY_MODE_PT_PT:
         mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT;
         break;
      case FLAGS_TOPOLOGY_MODE_LOOP:
         mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP;
         break;
      case FLAGS_TOPOLOGY_MODE_PT_LOOP:
         mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT;
         mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER;
         break;
   }

   vpd = &((fc_dev_ctl_t *)(binfo->fc_p_dev_ctl))->vpd;
   if (binfo->fc_flag & FC_2G_CAPABLE) {
      if ((vpd->rev.feaLevelHigh >= 0x02) && (linkspeed > 0)) {
         mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED;
         mb->un.varInitLnk.link_speed = linkspeed;
      }
   }

   mb->mbxCommand = (volatile uchar)MBX_INIT_LINK;
   mb->mbxOwner = OWN_HOST;
   mb->un.varInitLnk.fabric_AL_PA = binfo->fc_pref_ALPA;
   return;
}       /* End fc_init_link */


/**********************************************/
/**  fc_down_link  Issue a DOWN LINK         **/
/**                mailbox command           **/
/**********************************************/
_static_ void
fc_down_link(
FC_BRD_INFO *binfo,
MAILBOX     *mb)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   mb->mbxCommand = MBX_DOWN_LINK;
   mb->mbxOwner = OWN_HOST;
   return;
}


/**********************************************/
/**  fc_read_sparam  Issue a READ SPARAM     **/
/**                  mailbox command         **/
/**********************************************/
_static_ int
fc_read_sparam(
fc_dev_ctl_t *p_dev_ctl,
MAILBOX     *mb)
{
   FC_BRD_INFO * binfo;
   MATCHMAP * mp;

   binfo = &BINFO;
   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   mb->mbxOwner = OWN_HOST;

   if ((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF)) == 0) {

      if (binfo->fc_flag & FC_SLI2)
         mb->mbxCommand = MBX_READ_SPARM64;
      else
         mb->mbxCommand = MBX_READ_SPARM;
      /* READ_SPARAM: no buffers */
      fc_log_printf_msg_vargs( binfo->fc_brd_no,
             &fc_msgBlk0301,                  /* ptr to msg structure */
              fc_mes0301,                     /* ptr to msg */
               fc_msgBlk0301.msgPreambleStr); /* begin & end varargs */
      return(1);
   }

   if (binfo->fc_flag & FC_SLI2) {
      mb->mbxCommand = MBX_READ_SPARM64;
      mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof(SERV_PARM);
      mb->un.varRdSparm.un.sp64.addrHigh = (uint32)putPaddrHigh(mp->phys);
      mb->un.varRdSparm.un.sp64.addrLow = (uint32)putPaddrLow(mp->phys);
   } else {
      mb->mbxCommand = MBX_READ_SPARM;
      mb->un.varRdSparm.un.sp.bdeSize = sizeof(SERV_PARM);
      mb->un.varRdSparm.un.sp.bdeAddress = (uint32)putPaddrLow(mp->phys);
   }

   /* save address for completion */
   ((MAILBOXQ * )mb)->bp = (uchar * )mp;

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


/**********************************************/
/**  fc_read_rpi    Issue a READ RPI         **/
/**                  mailbox command         **/
/**********************************************/
_static_ int 
fc_read_rpi(
FC_BRD_INFO *binfo,
uint32      rpi,
MAILBOX     *mb,
uint32      flag)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   mb->un.varRdRPI.reqRpi = (volatile ushort)rpi;

   if (binfo->fc_flag & FC_SLI2) {
      mb->mbxCommand = MBX_READ_RPI64;
   } else {
      mb->mbxCommand = MBX_READ_RPI;
   }

   mb->mbxOwner = OWN_HOST;

   mb->un.varWords[30] = flag;  /* Set flag to issue action on cmpl */

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


/**********************************************/
/**  fc_read_xri    Issue a READ XRI         **/
/**                  mailbox command         **/
/**********************************************/
_static_ int 
fc_read_xri(
FC_BRD_INFO *binfo,
uint32      xri,
MAILBOX     *mb,
uint32      flag)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   mb->un.varRdXRI.reqXri = (volatile ushort)xri;

   mb->mbxCommand = MBX_READ_XRI;
   mb->mbxOwner = OWN_HOST;

   mb->un.varWords[30] = flag;  /* Set flag to issue action on cmpl */

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


/**********************************************/
/**  fc_reg_login  Issue a REG_LOGIN         **/
/**                  mailbox command         **/
/**********************************************/
_static_ int
fc_reg_login(
FC_BRD_INFO *binfo,
uint32      did,
uchar       *param,
MAILBOX     *mb,
uint32      flag)
{
   uchar * sparam;
   MATCHMAP * mp;
   fc_dev_ctl_t    *p_dev_ctl;

   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   mb->un.varRegLogin.rpi = 0;
   mb->un.varRegLogin.did = did;
   mb->un.varWords[30] = flag;  /* Set flag to issue action on cmpl */

   mb->mbxOwner = OWN_HOST;

   if ((mp = (MATCHMAP * )fc_mem_get(binfo, MEM_BUF)) == 0) {

      if (binfo->fc_flag & FC_SLI2)
         mb->mbxCommand = MBX_REG_LOGIN64;
      else
         mb->mbxCommand = MBX_REG_LOGIN;
      /* REG_LOGIN: no buffers */
      fc_log_printf_msg_vargs( binfo->fc_brd_no,
             &fc_msgBlk0302,                  /* ptr to msg structure */
              fc_mes0302,                     /* ptr to msg */
               fc_msgBlk0302.msgPreambleStr,  /* begin varargs */
                (uint32)did,
                 (uint32)flag);               /* end varargs */
      return(1);
   }

   sparam = mp->virt;

   /* Copy param's into a new buffer */
   fc_bcopy((void *)param, (void *)sparam, sizeof(SERV_PARM));

   p_dev_ctl = (fc_dev_ctl_t *)(binfo->fc_p_dev_ctl);
   fc_mpdata_sync(mp->dma_handle, 0, 0, DDI_DMA_SYNC_FORDEV);

   /* save address for completion */
   ((MAILBOXQ * )mb)->bp = (uchar * )mp;

   if (binfo->fc_flag & FC_SLI2) {
      mb->mbxCommand = MBX_REG_LOGIN64;
      mb->un.varRegLogin.un.sp64.tus.f.bdeSize = sizeof(SERV_PARM);
      mb->un.varRegLogin.un.sp64.addrHigh = (uint32)putPaddrHigh(mp->phys);
      mb->un.varRegLogin.un.sp64.addrLow = (uint32)putPaddrLow(mp->phys);
   } else {
      mb->mbxCommand = MBX_REG_LOGIN;
      mb->un.varRegLogin.un.sp.bdeSize = sizeof(SERV_PARM);
      mb->un.varRegLogin.un.sp.bdeAddress = (uint32)putPaddrLow(mp->phys);
   }

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


/**********************************************/
/**  fc_unreg_login  Issue a UNREG_LOGIN     **/
/**                  mailbox command         **/
/**********************************************/
_static_ void
fc_unreg_login(
FC_BRD_INFO *binfo,
uint32      rpi,
MAILBOX     *mb)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   mb->un.varUnregLogin.rpi = (ushort)rpi;
   mb->un.varUnregLogin.rsvd1 = 0;

   mb->mbxCommand = MBX_UNREG_LOGIN;
   mb->mbxOwner = OWN_HOST;
   return;
}       /* End fc_unreg_login */


/**********************************************/
/**  fc_unreg_did  Issue a UNREG_DID         **/
/**                  mailbox command         **/
/**********************************************/
_static_ void
fc_unreg_did(
FC_BRD_INFO *binfo,
uint32      did,
MAILBOX     *mb)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   mb->un.varUnregDID.did = did;

   mb->mbxCommand = MBX_UNREG_D_ID;
   mb->mbxOwner = OWN_HOST;
   return;
}       /* End fc_unreg_did */


/**********************************************/
/**  fc_set_slim   Issue a special debug mbox */
/**                command to write slim      */
/**********************************************/
_static_ void
fc_set_slim(
FC_BRD_INFO *binfo,
MAILBOX     *mb,
uint32      addr,
uint32      value)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   /* addr = 0x090597 is AUTO ABTS disable for ELS commands */
   /* addr = 0x052198 is DELAYED ABTS enable for ELS commands */

   /*
    * Always turn on DELAYED ABTS for ELS timeouts 
    */
   if ((addr == 0x052198) && (value == 0))
      value = 1;

   mb->un.varWords[0] = addr;
   mb->un.varWords[1] = value;

   mb->mbxCommand = MBX_SET_SLIM;
   mb->mbxOwner = OWN_HOST;
   return;
}       /* End fc_set_slim */


/* Disable Traffic Cop */
_static_ void
fc_disable_tc(
FC_BRD_INFO *binfo,
MAILBOX *mb)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));
   mb->un.varWords[0] = 0x50797;
   mb->un.varWords[1] = 0;
   mb->un.varWords[2] = 0xfffffffe;

   mb->mbxCommand = MBX_SET_SLIM;
   mb->mbxOwner = OWN_HOST;
}       /* End fc_set_tc */


/**********************************************/
/**  fc_config_port  Issue a CONFIG_PORT     **/
/**                  mailbox command         **/
/**********************************************/
_static_ int
fc_config_port(
FC_BRD_INFO *binfo,
MAILBOX     *mb,
uint32    *hbainit)
{
   RING  * rp;
   fc_dev_ctl_t    * p_dev_ctl;
   iCfgParam       * clp;
   int     ring_3_active; /* 4th ring */
   struct pci_dev  *pdev;

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

   clp = DD_CTL.p_config[binfo->fc_brd_no];
   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   mb->mbxCommand = MBX_CONFIG_PORT;
   mb->mbxOwner = OWN_HOST;

   ring_3_active = 0; /* Preset to inactive */

   mb->un.varCfgPort.pcbLen = sizeof(PCB);
   mb->un.varCfgPort.pcbLow =
      (uint32)putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->pcb);
   mb->un.varCfgPort.pcbHigh =
      (uint32)putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->pcb);
   if((pdev->device == PCI_DEVICE_ID_TFLY)||
      (pdev->device == PCI_DEVICE_ID_PFLY))
   fc_bcopy((uchar*) hbainit, (uchar*) mb->un.varCfgPort.hbainit, 20);
   else
   fc_bcopy((uchar*) hbainit, (uchar*) mb->un.varCfgPort.hbainit, 4);
   
   /* Now setup pcb */
   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.type = TYPE_NATIVE_SLI2;
   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.feature = FEATURE_INITIAL_SLI2;
   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.maxRing = (binfo->fc_ffnumrings-1);
   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.mailBoxSize = sizeof(MAILBOX);
   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.mbAddrHigh = (uint32)
      putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->mbx);
   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.mbAddrLow = (uint32)
      putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->mbx);

   /* SLIM POINTER */
   if (binfo->fc_busflag & FC_HOSTPTR) {
     ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.hgpAddrHigh = (uint32)
       putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->mbx.us.s2.host);
     ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.hgpAddrLow = (uint32)
       putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->mbx.us.s2.host);
   } else {
      uint32 Laddr;

     ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.hgpAddrHigh = (uint32)
       fc_rdpci_32((fc_dev_ctl_t *)binfo->fc_p_dev_ctl, PCI_BAR_1_REGISTER);
     Laddr = fc_rdpci_32((fc_dev_ctl_t *)binfo->fc_p_dev_ctl, PCI_BAR_0_REGISTER);
     Laddr &= ~0x4;
     ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.hgpAddrLow = (uint32)(Laddr + (SLIMOFF*4));
   }

   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.pgpAddrHigh = (uint32)
      putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->mbx.us.s2.port);
   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.pgpAddrLow = (uint32)
      putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->mbx.us.s2.port);

   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[0].cmdEntries = SLI2_IOCB_CMD_R0_ENTRIES;
   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[0].rspEntries = SLI2_IOCB_RSP_R0_ENTRIES;
   if(clp[CFG_NETWORK_ON].a_current == 0) {
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].cmdEntries =
         (SLI2_IOCB_CMD_R1_ENTRIES - SLI2_IOCB_CMD_R1XTRA_ENTRIES);
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].rspEntries =
         (SLI2_IOCB_RSP_R1_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES);
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].cmdEntries =
         (SLI2_IOCB_CMD_R2_ENTRIES + SLI2_IOCB_CMD_R2XTRA_ENTRIES);
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].rspEntries =
         (SLI2_IOCB_RSP_R2_ENTRIES + SLI2_IOCB_RSP_R2XTRA_ENTRIES);
   }
   else {
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].cmdEntries = SLI2_IOCB_CMD_R1_ENTRIES;
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].rspEntries = SLI2_IOCB_RSP_R1_ENTRIES;
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].cmdEntries = SLI2_IOCB_CMD_R2_ENTRIES;
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].rspEntries = SLI2_IOCB_RSP_R2_ENTRIES;
   }
   if( ring_3_active == 0) {
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[3].cmdEntries = 0;
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[3].rspEntries = 0;
   }

   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[0].cmdAddrHigh = (uint32)
       putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[0]);
   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[0].cmdAddrLow = (uint32)
       putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[0]);
   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[0].rspAddrHigh = (uint32)
       putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES]);
   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[0].rspAddrLow = (uint32)
       putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES]);
   rp = &binfo->fc_ring[0];
   rp->fc_cmdringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[0];
   rp->fc_rspringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES];

   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].cmdAddrHigh = (uint32)
       putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES]);
   ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].cmdAddrLow = (uint32)
       putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES]);
   if(clp[CFG_NETWORK_ON].a_current == 0) {
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].rspAddrHigh = (uint32)
       putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES - SLI2_IOCB_CMD_R1XTRA_ENTRIES]);
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].rspAddrLow = (uint32)
       putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES - SLI2_IOCB_CMD_R1XTRA_ENTRIES]);
      rp = &binfo->fc_ring[1];
      rp->fc_cmdringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES];
      rp->fc_rspringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES - SLI2_IOCB_CMD_R1XTRA_ENTRIES];

      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].cmdAddrHigh = (uint32)
       putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES -
        SLI2_IOCB_CMD_R1XTRA_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES]);
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].cmdAddrLow = (uint32)
       putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES -
        SLI2_IOCB_CMD_R1XTRA_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES]);
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].rspAddrHigh = (uint32)
       putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES + 
        SLI2_IOCB_CMD_R2_ENTRIES + SLI2_IOCB_CMD_R2XTRA_ENTRIES -
        SLI2_IOCB_CMD_R1XTRA_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES]);
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].rspAddrLow = (uint32)
       putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES + 
        SLI2_IOCB_CMD_R2_ENTRIES + SLI2_IOCB_CMD_R2XTRA_ENTRIES -
        SLI2_IOCB_CMD_R1XTRA_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES]);
      rp = &binfo->fc_ring[2];
      rp->fc_cmdringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES -
        SLI2_IOCB_CMD_R1XTRA_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES];
      rp->fc_rspringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES + 
        SLI2_IOCB_CMD_R2_ENTRIES + SLI2_IOCB_CMD_R2XTRA_ENTRIES -
        SLI2_IOCB_CMD_R1XTRA_ENTRIES - SLI2_IOCB_RSP_R1XTRA_ENTRIES];
   }
   else {
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].rspAddrHigh = (uint32)
       putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES]);
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[1].rspAddrLow = (uint32)
       putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES]);
      rp = &binfo->fc_ring[1];
      rp->fc_cmdringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES];
      rp->fc_rspringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES];

      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].cmdAddrHigh = (uint32)
       putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES]);
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].cmdAddrLow = (uint32)
       putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES]);
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].rspAddrHigh = (uint32)
       putPaddrHigh( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES + 
        SLI2_IOCB_CMD_R2_ENTRIES]);
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[2].rspAddrLow = (uint32)
       putPaddrLow( & ((SLI2_SLIM * )binfo->fc_slim2.phys)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES + 
        SLI2_IOCB_CMD_R2_ENTRIES]);
      rp = &binfo->fc_ring[2];
      rp->fc_cmdringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES];
      rp->fc_rspringaddr = (void *) & ((SLI2_SLIM * )binfo->fc_slim2.virt)->IOCBs[
        SLI2_IOCB_CMD_R0_ENTRIES + SLI2_IOCB_RSP_R0_ENTRIES + 
        SLI2_IOCB_CMD_R1_ENTRIES + SLI2_IOCB_RSP_R1_ENTRIES + 
        SLI2_IOCB_CMD_R2_ENTRIES];
   }

   if( ring_3_active == 0) {
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[3].cmdAddrHigh = 0;
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[3].rspAddrHigh = 0;
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[3].cmdAddrLow = 0;
      ((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb.rdsc[3].rspAddrLow = 0;
   }

   fc_pcimem_bcopy((uint32 * )(&((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb),
       (uint32 * )(&((SLI2_SLIM * )binfo->fc_slim2.virt)->pcb), sizeof(PCB));

   fc_mpdata_sync(binfo->fc_slim2.dma_handle, (off_t)0, (size_t)0,
       DDI_DMA_SYNC_FORDEV);
   /* Service Level Interface (SLI) 2 selected */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk0405,                  /* ptr to msg structure */
           fc_mes0405,                     /* ptr to msg */
            fc_msgBlk0405.msgPreambleStr); /* begin & end varargs */
   return(0);
}       /* End fc_config_port */

/**********************************************/
/**  fc_config_farp  Issue a CONFIG FARP     **/
/**                mailbox command           **/
/**********************************************/
_static_ void
fc_config_farp(
FC_BRD_INFO *binfo,
MAILBOX     *mb)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));

   mb->un.varCfgFarp.filterEnable = 1;
   mb->un.varCfgFarp.portName = 1;
   mb->un.varCfgFarp.nodeName = 1;

   fc_bcopy((uchar * )&binfo->fc_portname, (uchar *)&mb->un.varCfgFarp.portname, sizeof(NAME_TYPE));
   fc_bcopy((uchar * )&binfo->fc_portname, (uchar *)&mb->un.varCfgFarp.nodename, sizeof(NAME_TYPE));

   mb->mbxCommand = MBX_CONFIG_FARP;
   mb->mbxOwner = OWN_HOST;
   return;
}


/**********************************************/
/**  fc_read_nv  Issue a READ CONFIG         **/
/**              mailbox command             **/
/**********************************************/
_static_ void
fc_read_config(
FC_BRD_INFO *binfo,
MAILBOX     *mb)
{
   fc_bzero((void *)mb, sizeof(MAILBOXQ));
   mb->mbxCommand = MBX_READ_CONFIG;
   mb->mbxOwner = OWN_HOST;
   return;
}       /* End fc_read_config */

/*****************************************************************************/
/*
 * NAME:     fc_mbox_put
 *
 * FUNCTION: put mailbox cmd onto the mailbox queue.
 *
 * EXECUTION ENVIRONMENT: process and interrupt level.
 *
 * NOTES:
 *
 * CALLED FROM:
 *      issue_mb_cmd
 *
 * INPUT:
 *      binfo           - pointer to the device info area
 *      mbp             - pointer to mailbox queue entry of mailbox cmd
 *
 * RETURNS:  
 *      NULL - command queued
 */
/*****************************************************************************/
_static_ void
fc_mbox_put(
FC_BRD_INFO *binfo,
MAILBOXQ    *mbq)               /* pointer to mbq entry */
{
   if (binfo->fc_mbox.q_first) {
      /* queue command to end of list */
      ((MAILBOXQ * )binfo->fc_mbox.q_last)->q = (uchar * )mbq;
      binfo->fc_mbox.q_last = (uchar * )mbq;
   } else {
      /* add command to empty list */
      binfo->fc_mbox.q_first = (uchar * )mbq;
      binfo->fc_mbox.q_last = (uchar * )mbq;
   }

   mbq->q = NULL;
   binfo->fc_mbox.q_cnt++;

   return;

}       /* End fc_mbox_put */


/*****************************************************************************/
/*
 * NAME:     fc_mbox_get
 *
 * FUNCTION: get a mailbox command from mailbox command queue
 *
 * EXECUTION ENVIRONMENT: interrupt level.
 *
 * NOTES:
 *
 * CALLED FROM:
 *      handle_mb_event
 *
 * INPUT:
 *      binfo       - pointer to the device info area
 *
 * RETURNS:  
 *      NULL - no match found
 *      mb pointer - pointer to a mailbox command
 */
/*****************************************************************************/
_static_ MAILBOXQ *
fc_mbox_get(
FC_BRD_INFO *binfo)
{
   MAILBOXQ * p_first = NULL;

   if (binfo->fc_mbox.q_first) {
      p_first = (MAILBOXQ * )binfo->fc_mbox.q_first;
      if ((binfo->fc_mbox.q_first = p_first->q) == 0) {
         binfo->fc_mbox.q_last = 0;
      }
      p_first->q = NULL;
      binfo->fc_mbox.q_cnt--;
   }

   return(p_first);

}       /* End fc_mbox_get */


