/*******************************************************************
 * 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 <linux/unistd.h> 
#include <linux/init.h>  
#include "fc_hw.h"
#include "fc.h"

#include "fcdiag.h"
#include "hbaapi.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[];
/* Can be used to map driver instance number and hardware adapter number */
extern int fcinstance[MAX_FC_BRDS];
extern int fcinstcnt;

_static_ FCCLOCK *fc_clkgetb(fc_dev_ctl_t *p_dev_ctl);
_static_ ulong  fc_clk_rem(fc_dev_ctl_t *p_dev_ctl, FCCLOCK *cb);
_static_ int    que_tin(FCLINK *blk, FCLINK *hdr);

#include "lp6000.c"
#include "dfcdd.c"
/*
*** boolean to test if block is linked into specific queue
***  (intended for assertions)
*/
#define inque(x,hdr)  que_tin( (FCLINK *)(x), (FCLINK *)(hdr) )

#define FC_MAX_CLK_TIMEOUT 0xfffffff

/*****************************************************************
*** fc_clkgetb() Get a clock block
*****************************************************************/
_static_ FCCLOCK *
fc_clkgetb(fc_dev_ctl_t *p_dev_ctl)
{
   FC_BRD_INFO * binfo;
   FCCLOCK_INFO * clock_info;
   FCCLOCK * cb;
   int i;

   clock_info = &DD_CTL.fc_clock_info;

   if(p_dev_ctl) {
      binfo = &BINFO;
      cb = (FCCLOCK * ) fc_mem_get(binfo, MEM_CLOCK);
   }
   else {
      for(i=0;i<FC_NUM_GLBL_CLK;i++) {
         cb = &clock_info->clk_block[i];
         if(cb->cl_tix == -1)
            break;
         cb = 0;
      }
   }

   if(cb)
      cb->cl_p_dev_ctl = (void *)p_dev_ctl;

   return (cb);
}


/*****************************************************************
*** fc_clkrelb() Release a clock block
*****************************************************************/
_static_ void 
fc_clkrelb(fc_dev_ctl_t *p_dev_ctl, FCCLOCK *cb)
{
   FC_BRD_INFO * binfo;
   FCCLOCK_INFO * clock_info;

   clock_info = &DD_CTL.fc_clock_info;

   if(p_dev_ctl) {
      binfo = &BINFO;
      fc_mem_put(binfo, MEM_CLOCK, (uchar * )cb);
   }
   else {
      cb->cl_tix = (uint32)-1;
   }
}


/*****************************************************************
*** fc_clk_can() Cancel a clock request
*** fc_clk_can will cancel a previous request to fc_clk_set or
*** fc_clk_res.
*** The request must not have expired so far.  A request that has been
*** cancelled cannot be reset.
*****************************************************************/
_static_ int 
fc_clk_can(fc_dev_ctl_t *p_dev_ctl, FCCLOCK *cb)
{
   FCCLOCK_INFO * clock_info;
   int  ipri;

   clock_info = &DD_CTL.fc_clock_info;
   ipri = disable_lock(CLK_LVL, &CLOCK_LOCK);

   /*  Make sure timer has not expired */
   if (!inque(cb, &clock_info->fc_clkhdr)) {
      unlock_enable(ipri, &CLOCK_LOCK);
      return(0);
   }

   fc_clock_deque(cb);

   /* Release clock block */
   fc_clkrelb(p_dev_ctl, cb);
   unlock_enable(ipri, &CLOCK_LOCK);

   return(1);
}


/*****************************************************************
*** fc_clk_rem()  get amount of time remaining in a clock request
*** fc_clk_rem() returns the number of tix remaining in
*** a clock request generated by fc_clk_set or fc_clk_res.  The timer must
*** not have expired or be cancelled.
*****************************************************************/
_static_ ulong 
fc_clk_rem(fc_dev_ctl_t *p_dev_ctl, FCCLOCK *cb)
{
   FCCLOCK_INFO * clock_info;
   FCCLOCK * x;
   ulong tix;
   int  ipri;

   clock_info = &DD_CTL.fc_clock_info;
   ipri = disable_lock(CLK_LVL, &CLOCK_LOCK);

   tix = 0;
   /* get top of clock queue */
   x = (FCCLOCK * ) & clock_info->fc_clkhdr;
   /*
   ***  Add up ticks in blocks upto specified request
   */
   do {
      x = x->cl_fw;
      if (x == (FCCLOCK * ) & clock_info->fc_clkhdr) {
         unlock_enable(ipri, &CLOCK_LOCK);
         return(0);
      }
      tix += x->cl_tix;
   } while (x != cb);

   unlock_enable(ipri, &CLOCK_LOCK);
   return(tix);
}


/*****************************************************************
*** fc_clk_res() clock reset
***   fc_clk_res() resets a clock previously assigned by fc_clk_set().
*** That clock must not have expired.  The new sec time is
*** used, measured from now.  The original function/argument
*** are not changed.
*** Note: code parrallels fc_clk_can() and fc_clk_set().
*****************************************************************/
_static_ ulong 
fc_clk_res(fc_dev_ctl_t *p_dev_ctl, ulong tix, FCCLOCK *cb)
{
   FCCLOCK_INFO * clock_info;
   FCCLOCK * x;
   int  ipri;

   clock_info = &DD_CTL.fc_clock_info;
   ipri = disable_lock(CLK_LVL, &CLOCK_LOCK);

   /*  Make sure timer has not expired */
   if (!inque(cb, &clock_info->fc_clkhdr)) {
      unlock_enable(ipri, &CLOCK_LOCK);
      return(0);
   }
   if (tix <= 0) {
      unlock_enable(ipri, &CLOCK_LOCK);
      return(0);
   }
   tix++;  /* round up 1 sec to account for partial first tick */

   fc_clock_deque(cb);

   /*
   ***  Insert block into queue by order of amount of clock ticks,
   ***  each block contains difference in ticks between itself and
   ***  its predacessor.
   */

   /* get top of list */
   x = clock_info->fc_clkhdr.cl_f;
   while (x != (FCCLOCK * ) & clock_info->fc_clkhdr) {
      if (x->cl_tix >= tix) {
         /* if inserting in middle of que, adjust next tix */
         x->cl_tix -= tix;
         break;
      }
      tix -= x->cl_tix;
      x = x->cl_fw;
   }

   /* back up one in que */
   x = x->cl_bw;
   fc_enque(cb, x);
   clock_info->fc_clkhdr.count++;
   cb->cl_tix = tix;

   unlock_enable(ipri, &CLOCK_LOCK);
   return((ulong)1);
}


/*****************************************************************
*** fc_clk_set() request a clock service
*** fc_clk_set will cause specific functions to be executed at a fixed
*** time into the future.  At a duration guaranteed to not be less
*** than, but potentially is longer than the given number of secs,
*** the given function is called with the given single argument.
*** Interlock is performed at a processor status level not lower
*** than the given value.  The returned value is needed if the request
*** is to be cancelled or reset.
*****************************************************************/
_static_ FCCLOCK *
fc_clk_set(fc_dev_ctl_t *p_dev_ctl, ulong tix,
void (*func)(fc_dev_ctl_t*, void*, void*), void *arg1, void *arg2)
{
   FCCLOCK_INFO * clock_info;
   FCCLOCK * x;
   FCCLOCK * cb;
   int  ipri;

   clock_info = &DD_CTL.fc_clock_info;
   ipri = disable_lock(CLK_LVL, &CLOCK_LOCK);

   if (tix > FC_MAX_CLK_TIMEOUT) {
      return(0);
   }
   tix++;  /* round up 1 sec to account for partial first tick */

   /*
   ***  Allocate a CLOCK block
   */
   if ((cb = fc_clkgetb(p_dev_ctl)) == 0) {
      unlock_enable(ipri, &CLOCK_LOCK);
      return(0);
   }

   /*
   ***  Insert block into queue by order of amount of clock ticks,
   ***  each block contains difference in ticks between itself and
   ***  its predecessor.
   */

   /* get top of list */
   x = clock_info->fc_clkhdr.cl_f;
   while (x != (FCCLOCK * ) & clock_info->fc_clkhdr) {
      if (x->cl_tix >= tix) {
         /* if inserting in middle of que, adjust next tix */
         if (x->cl_tix > tix) {
            x->cl_tix -= tix;
            break;
         }
         /*
         *** Another clock expires at same time.
         *** Maintain the order of requests.
         */
         for (x = x->cl_fw; 
             x != (FCCLOCK * ) & clock_info->fc_clkhdr; 
             x = x->cl_fw) {
            if (x->cl_tix != 0)
               break;
         }

         /* I'm at end of list */
         tix = 0;
         break;
      }

      tix -= x->cl_tix;
      x = x->cl_fw;
   }

   /* back up one in que */
   x = x->cl_bw;

   /* Count the current number of unexpired clocks */
   clock_info->fc_clkhdr.count++;
   fc_enque(cb, x);
   cb->cl_func = (void(*)(void*, void*, void*))func;
   cb->cl_arg1  = arg1;
   cb->cl_arg2  = arg2;
   cb->cl_tix  = tix;
   unlock_enable(ipri, &CLOCK_LOCK);

   return((FCCLOCK * ) cb);
}


/*****************************************************************
*** fc_timer
*** This function will be called by the driver every second.
*****************************************************************/
_static_ void 
fc_timer(void *p)
{
   fc_dev_ctl_t * p_dev_ctl;
   FCCLOCK_INFO * clock_info;
   ulong tix;
   FCCLOCK * x;
   int  ipri;

   clock_info = &DD_CTL.fc_clock_info;
   ipri = disable_lock(CLK_LVL, &CLOCK_LOCK);

   /*
   ***  Increment time_sample value
   */
   clock_info->ticks++;

   x = clock_info->fc_clkhdr.cl_f;

   /* counter for propagating negative values */
   tix = 0;
   /* If there are expired clocks */
   if (x != (FCCLOCK * ) & clock_info->fc_clkhdr) {
      x->cl_tix = x->cl_tix - 1;
      if (x->cl_tix <= 0) {
         /* Loop thru all clock blocks */
         while (x != (FCCLOCK * ) & clock_info->fc_clkhdr) {
            x->cl_tix += tix;
            /* If # of ticks left > 0, break out of loop */
            if (x->cl_tix > 0) 
               break;
            tix = x->cl_tix;

            /* Deque expired clock */
            fc_deque(x);
            /* Decrement count of unexpired clocks */
            clock_info->fc_clkhdr.count--;

            unlock_enable(ipri, &CLOCK_LOCK);

            p_dev_ctl = x->cl_p_dev_ctl;

            if(p_dev_ctl) {
               ipri = disable_lock(FC_LVL, &CMD_LOCK);

               /* Call timeout routine */
               (*x->cl_func) (p_dev_ctl, x->cl_arg1, x->cl_arg2);
               /* Release clock block */
               fc_clkrelb(p_dev_ctl, x);

               unlock_enable(ipri, &CMD_LOCK);
            }
            else {
               /* Call timeout routine */
               (*x->cl_func) (p_dev_ctl, x->cl_arg1, x->cl_arg2);
               /* Release clock block */
               fc_clkrelb(p_dev_ctl, x);
            }

            ipri = disable_lock(CLK_LVL, &CLOCK_LOCK);

            /* start over */
            x = clock_info->fc_clkhdr.cl_f;
         }
      }
   }
   unlock_enable(ipri, &CLOCK_LOCK);
   fc_reset_timer();
}


/*****************************************************************
*** fc_clock_deque()
*****************************************************************/
_static_ void
fc_clock_deque(FCCLOCK *cb)
{
   FCCLOCK_INFO * clock_info;
   FCCLOCK * x;

   clock_info = &DD_CTL.fc_clock_info;
   /*
   ***  Remove the block from its present spot, but first adjust
   ***  tix field of any successor.
   */
   if (cb->cl_fw != (FCCLOCK * ) & clock_info->fc_clkhdr) {
      x = cb->cl_fw;
      x->cl_tix += cb->cl_tix;
   }

   /* Decrement count of unexpired clocks */
   clock_info->fc_clkhdr.count--;

   fc_deque(cb);
}


/*****************************************************************
*** fc_clock_init()
*****************************************************************/
_static_ void
fc_clock_init()
{
   FCCLOCK_INFO * clock_info;
   FCCLOCK * cb;
   int i;

   clock_info = &DD_CTL.fc_clock_info;

   /* Initialize clock queue */
   clock_info->fc_clkhdr.cl_f = 
       clock_info->fc_clkhdr.cl_b = (FCCLOCK * ) & clock_info->fc_clkhdr;
   clock_info->fc_clkhdr.count = 0;

   /* Initialize clock globals */
   clock_info->ticks = 0;
   clock_info->Tmr_ct = 0;

   for(i=0;i<FC_NUM_GLBL_CLK;i++) {
      cb = &clock_info->clk_block[i];
      cb->cl_tix = (uint32)-1;
   }
}


_static_ int
que_tin(FCLINK *blk, FCLINK *hdr)
{
   FCLINK * x;

   x = hdr->_f;
   while (x != hdr) {
      if (x == blk) {
         return (1);
      }
      x = x->_f;
   }
   return(0);
}


_static_ void
fc_flush_clk_set(
fc_dev_ctl_t *p_dev_ctl,
void (*func)(fc_dev_ctl_t*, void*, void*))
{
   FC_BRD_INFO * binfo;
   FCCLOCK_INFO * clock_info;
   FCCLOCK * x, * xmatch;
   IOCBQ *iocbq;
   int  ipri;

   binfo = &BINFO;
   clock_info = &DD_CTL.fc_clock_info;
   ipri = disable_lock(CLK_LVL, &CLOCK_LOCK);

   x = clock_info->fc_clkhdr.cl_f;

   /* If there are clocks */
   while (x != (FCCLOCK * ) & clock_info->fc_clkhdr) {
      if((p_dev_ctl == x->cl_p_dev_ctl) && ((void *)func == (void *)(*x->cl_func))) {
         xmatch = x;
         x = x->cl_fw;

         /*
         ***  Remove the block from its present spot, but first adjust 
         ***  tix field of any successor.
         */
         if (xmatch->cl_fw != (FCCLOCK * ) & clock_info->fc_clkhdr) {
            x->cl_tix += xmatch->cl_tix;
         }

         clock_info->fc_clkhdr.count--;
         fc_deque(xmatch);

         if((void *)func == (void *)lpfc_scsi_selto_timeout) {
            (*xmatch->cl_func) (p_dev_ctl, xmatch->cl_arg1, xmatch->cl_arg2);
         }
         if(func == fc_delay_timeout) {
            iocbq = (IOCBQ *)xmatch->cl_arg1;
            if(iocbq->bp) {
               fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->bp);
            }
            if(iocbq->info) {
               fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->info);
            }
            if(iocbq->bpl) {
               fc_mem_put(binfo, MEM_BPL, (uchar * )iocbq->bpl);
            }
            fc_mem_put(binfo, MEM_IOCB, (uchar * )iocbq);
         }
         fc_clkrelb(p_dev_ctl, xmatch);
      }
      else {
         x = x->cl_fw;
      }
   }
   unlock_enable(ipri, &CLOCK_LOCK);
   return;
}

_static_ int
fc_abort_clk_blk(
fc_dev_ctl_t *p_dev_ctl,
void (*func)(fc_dev_ctl_t*, void*, void*),
void *arg1,
void *arg2)
{
   FC_BRD_INFO * binfo;
   FCCLOCK_INFO * clock_info;
   FCCLOCK * x, * xmatch;
   IOCBQ *iocbq;
   int  ipri;

   binfo = &BINFO;
   clock_info = &DD_CTL.fc_clock_info;
   ipri = disable_lock(CLK_LVL, &CLOCK_LOCK);

   x = clock_info->fc_clkhdr.cl_f;

   /* If there are clocks */
   while (x != (FCCLOCK * ) & clock_info->fc_clkhdr) {
      if((p_dev_ctl == x->cl_p_dev_ctl) && 
         ((void *)func == (void *)(*x->cl_func)) &&
         (arg1 == x->cl_arg1) &&
         (arg2 == x->cl_arg2)) {
         xmatch = x;
         x = x->cl_fw;

         /*
         ***  Remove the block from its present spot, but first adjust 
         ***  tix field of any successor.
         */
         if (xmatch->cl_fw != (FCCLOCK * ) & clock_info->fc_clkhdr) {
            x->cl_tix += xmatch->cl_tix;
         }

         clock_info->fc_clkhdr.count--;
         fc_deque(xmatch);
         if((void *)func == (void *)lpfc_scsi_selto_timeout) {
            (*xmatch->cl_func) (p_dev_ctl, xmatch->cl_arg1, xmatch->cl_arg2);
         }
         if(func == fc_delay_timeout) {
            iocbq = (IOCBQ *)xmatch->cl_arg1;
            if(iocbq->bp) {
               fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->bp);
            }
            if(iocbq->info) {
               fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->info);
            }
            if(iocbq->bpl) {
               fc_mem_put(binfo, MEM_BPL, (uchar * )iocbq->bpl);
            }
            fc_mem_put(binfo, MEM_IOCB, (uchar * )iocbq);
         }
         fc_clkrelb(p_dev_ctl, xmatch);
         unlock_enable(ipri, &CLOCK_LOCK);
         return(1);
      }
      else {
         x = x->cl_fw;
      }
   }
   unlock_enable(ipri, &CLOCK_LOCK);
   return(0);
}

_static_ int
fc_abort_delay_els_cmd(
fc_dev_ctl_t *p_dev_ctl,
uint32 did)
{
   FC_BRD_INFO * binfo;
   FCCLOCK_INFO * clock_info;
   FCCLOCK * x, * xmatch;
   IOCBQ *iocbq, *saveiocbq, *next_iocbq;
   int  ipri;

   binfo = &BINFO;
   clock_info = &DD_CTL.fc_clock_info;
   ipri = disable_lock(CLK_LVL, &CLOCK_LOCK);

   x = clock_info->fc_clkhdr.cl_f;

   /* If there are clocks */
   while (x != (FCCLOCK * ) & clock_info->fc_clkhdr) {
      if((p_dev_ctl == x->cl_p_dev_ctl) && 
         ((void *)(x->cl_func) == (void *)fc_delay_timeout)) {
         xmatch = x;
         x = x->cl_fw;
         iocbq = (IOCBQ *)xmatch->cl_arg1;

         if((iocbq->iocb.un.elsreq.remoteID != did) &&
            (did != 0xffffffff))
            continue;
         /* Abort delay xmit clock */
         fc_log_printf_msg_vargs( binfo->fc_brd_no,
                &fc_msgBlk0100,                  /* ptr to msg structure */
                 fc_mes0100,                     /* ptr to msg */
                  fc_msgBlk0100.msgPreambleStr,  /* begin varargs */
                   did,
                     iocbq->iocb.un.elsreq.remoteID, 
                      iocbq->iocb.ulpIoTag);     /* end varargs */
         /*
         ***  Remove the block from its present spot, but first adjust 
         ***  tix field of any successor.
         */
         if (xmatch->cl_fw != (FCCLOCK * ) & clock_info->fc_clkhdr) {
            x->cl_tix += xmatch->cl_tix;
         }

         clock_info->fc_clkhdr.count--;
         fc_deque(xmatch);
         if(iocbq->bp) {
            fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->bp);
         }
         if(iocbq->info) {
            fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->info);
         }
         if(iocbq->bpl) {
            fc_mem_put(binfo, MEM_BPL, (uchar * )iocbq->bpl);
         }
         fc_mem_put(binfo, MEM_IOCB, (uchar * )iocbq);

         fc_clkrelb(p_dev_ctl, xmatch);

         if(did != 0xffffffff)
            break;
      }
      else {
         x = x->cl_fw;
      }
   }
   unlock_enable(ipri, &CLOCK_LOCK);

   if(binfo->fc_delayxmit) {
      iocbq = binfo->fc_delayxmit;
      saveiocbq = 0;
      while(iocbq) {

         if((iocbq->iocb.un.elsreq.remoteID == did) ||
            (did == 0xffffffff)) {

            next_iocbq = (IOCBQ *)iocbq->q;
            /* Abort delay xmit context */
            fc_log_printf_msg_vargs( binfo->fc_brd_no,
                   &fc_msgBlk0101,                  /* ptr to msg structure */
                    fc_mes0101,                     /* ptr to msg */
                     fc_msgBlk0101.msgPreambleStr,  /* begin varargs */
                      did,
                       iocbq->iocb.un.elsreq.remoteID, 
                        iocbq->iocb.ulpIoTag);      /* end varargs */
            if(saveiocbq) {
               saveiocbq->q = iocbq->q;
            }
            else {
               binfo->fc_delayxmit = (IOCBQ *)iocbq->q;
            }
            if(iocbq->bp) {
               fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->bp);
            }
            if(iocbq->info) {
               fc_mem_put(binfo, MEM_BUF, (uchar * )iocbq->info);
            }
            if(iocbq->bpl) {
               fc_mem_put(binfo, MEM_BPL, (uchar * )iocbq->bpl);
            }
            fc_mem_put(binfo, MEM_IOCB, (uchar * )iocbq);

            if(did != 0xffffffff)
               break;
            iocbq = next_iocbq;
         }
         else {
            saveiocbq = iocbq;
            iocbq = (IOCBQ *)iocbq->q;
         }
      }
   }
   return(0);
}
/* DQFULL */
/*****************************************************************************
 *
 * NAME:     fc_q_depth_up
 * FUNCTION: Increment current Q depth for LUNs
 *
 *****************************************************************************/

_static_ void
fc_q_depth_up(
fc_dev_ctl_t  * p_dev_ctl,
void *n1,
void *n2)
{
   node_t       *nodep;
   NODELIST     * ndlp;
   iCfgParam    * clp;
   FC_BRD_INFO  *binfo;
   struct dev_info * dev_ptr;

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

   if (clp[CFG_DFT_LUN_Q_DEPTH].a_current <= FC_MIN_QFULL) {
      return;
   }

   if(binfo->fc_ffstate != FC_READY)
      goto out;

   /*
    * Find the target from the nlplist based on SCSI ID
    */
   ndlp = binfo->fc_nlpmap_start;
   while(ndlp != (NODELIST *)&binfo->fc_nlpmap_start) {
      nodep = (node_t *)ndlp->nlp_targetp;
      if (nodep) {
         for (dev_ptr = nodep->lunlist; dev_ptr != NULL;
             dev_ptr = dev_ptr->next) {
            if ((dev_ptr->stop_send_io == 0) &&
                (dev_ptr->fcp_cur_queue_depth < clp[CFG_DFT_LUN_Q_DEPTH].a_current)) {
                dev_ptr->fcp_cur_queue_depth += (ushort)clp[CFG_DQFULL_THROTTLE_UP_INC].a_current;
                if (dev_ptr->fcp_cur_queue_depth > clp[CFG_DFT_LUN_Q_DEPTH].a_current) 
                   dev_ptr->fcp_cur_queue_depth = clp[CFG_DFT_LUN_Q_DEPTH].a_current;
            } else {
              /*
               * Try to reset stop_send_io
               */
              if (dev_ptr->stop_send_io)
                dev_ptr->stop_send_io--;
            }
         }
      }
      ndlp = (NODELIST *)ndlp->nlp_listp_next;
   }

out:
   fc_clk_set(p_dev_ctl, clp[CFG_DQFULL_THROTTLE_UP_TIME].a_current, fc_q_depth_up,
      0, 0);

   return;
}

/* QFULL_RETRY */
_static_ void
fc_qfull_retry(
void *n1)
{
   fc_buf_t  * fcptr;
   dvi_t         * dev_ptr;
   T_SCSIBUF     * sbp;
   struct buf    * bp;
   fc_dev_ctl_t  * p_dev_ctl;

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

   if(dev_ptr->nodep) {
      p_dev_ctl = dev_ptr->nodep->ap;
      fc_fcp_bufunmap(p_dev_ctl, sbp);
   }
   /*
    * Queue this command to the head of the device's
    * pending queue for processing by fc_issue_cmd.
    */
   if (dev_ptr->pend_head == NULL) { /* Is queue empty? */
      dev_ptr->pend_head = sbp;
      dev_ptr->pend_tail = sbp;
      bp->av_forw = NULL;
      fc_enq_wait(dev_ptr);
   } else {                    /* Queue not empty */
      bp->av_forw = (struct buf *) dev_ptr->pend_head;
      dev_ptr->pend_head = sbp;
   }
   dev_ptr->pend_count++;
}

_static_ void
fc_establish_link_tmo(
fc_dev_ctl_t  * p_dev_ctl,
void *n1,
void *n2)
{
   FC_BRD_INFO * binfo;     
   iCfgParam     * clp;  

   binfo = &BINFO;
   clp = DD_CTL.p_config[binfo->fc_brd_no];
   /* Re-establishing Link, timer expired */
   fc_log_printf_msg_vargs( binfo->fc_brd_no,
          &fc_msgBlk1300,                 /* ptr to msg structure */
           fc_mes1300,                    /* ptr to msg */
            fc_msgBlk1300.msgPreambleStr, /* begin varargs */
             binfo->fc_flag,
              binfo->fc_ffstate);         /* end varargs */
   binfo->fc_flag &= ~FC_ESTABLISH_LINK;
}
