/*******************************************************************************
*Copyright (c) 2014 PMC-Sierra, Inc.  All rights reserved. 
*
*Redistribution and use in source and binary forms, with or without modification, are permitted provided 
*that the following conditions are met: 
*1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
*following disclaimer. 
*2. Redistributions in binary form must reproduce the above copyright notice, 
*this list of conditions and the following disclaimer in the documentation and/or other materials provided
*with the distribution. 
*
*THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED 
*WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
*FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
*NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
*BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
*SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE

********************************************************************************/
/*******************************************************************************/
/** \file
 *
 *
 * This file contains initiator initialization functions
 *
 */
#include <sys/cdefs.h>
#include <dev/pms/config.h>

#include <dev/pms/freebsd/driver/common/osenv.h>
#include <dev/pms/freebsd/driver/common/ostypes.h>
#include <dev/pms/freebsd/driver/common/osdebug.h>

#include <dev/pms/RefTisa/sallsdk/api/sa.h>
#include <dev/pms/RefTisa/sallsdk/api/saapi.h>
#include <dev/pms/RefTisa/sallsdk/api/saosapi.h>

#include <dev/pms/RefTisa/tisa/api/titypes.h>
#include <dev/pms/RefTisa/tisa/api/ostiapi.h>
#include <dev/pms/RefTisa/tisa/api/tiapi.h>
#include <dev/pms/RefTisa/tisa/api/tiglobal.h>

#ifdef FDS_SM
#include <dev/pms/RefTisa/sat/api/sm.h>
#include <dev/pms/RefTisa/sat/api/smapi.h>
#include <dev/pms/RefTisa/sat/api/tdsmapi.h>
#endif

#ifdef FDS_DM
#include <dev/pms/RefTisa/discovery/api/dm.h>
#include <dev/pms/RefTisa/discovery/api/dmapi.h>
#include <dev/pms/RefTisa/discovery/api/tddmapi.h>
#endif

#include <dev/pms/RefTisa/tisa/sassata/sas/common/tdtypes.h>
#include <dev/pms/freebsd/driver/common/osstring.h>
#include <dev/pms/RefTisa/tisa/sassata/common/tdutil.h>

#ifdef INITIATOR_DRIVER
#include <dev/pms/RefTisa/tisa/sassata/sas/ini/itdtypes.h>
#include <dev/pms/RefTisa/tisa/sassata/sas/ini/itddefs.h>
#include <dev/pms/RefTisa/tisa/sassata/sas/ini/itdglobl.h>
#endif

#ifdef TARGET_DRIVER
#include <dev/pms/RefTisa/tisa/sassata/sas/tgt/ttdglobl.h>
#include <dev/pms/RefTisa/tisa/sassata/sas/tgt/ttdxchg.h>
#include <dev/pms/RefTisa/tisa/sassata/sas/tgt/ttdtypes.h>
#endif

#include <dev/pms/RefTisa/tisa/sassata/common/tdsatypes.h>
#include <dev/pms/RefTisa/tisa/sassata/common/tdproto.h>

/*****************************************************************************
*! \brief itdssGetResource
*
*  Purpose:  This function is called to determine the Transport 
*            Dependent Layer internal resource requirement for the initiator
*            side.
*
*  /param   tiRoot:            Pointer to driver/port instance.
*  /param   initiatorResource: Pointer to initiator functionality memory and 
*                              option requirement.
*
*  /return: None
*
*  /note - This function only return the memory requirement in the tiMem_t 
*          structure in initiatorResource. It does not allocated memory, so the
*          address fields in tiMem_t are not used.
*
*****************************************************************************/
osGLOBAL void 
itdssGetResource(
                 tiRoot_t * tiRoot, 
                 tiInitiatorResource_t * initiatorResource 
                 ) 
{
  itdssOperatingOption_t    OperatingOption;
  tiInitiatorMem_t          *iniMem;
  bit32 i;

  iniMem                  = &initiatorResource->initiatorMem;
  iniMem->count           = 1;          /* Only 1 memory descriptors are used */
  
  TI_DBG6(("itdssGetResource: start\n"));
  
  /*  other than [0], nothing is used 
   *  tdCachedMem[0]: cached mem for initiator TD Layer main functionality :
   *                  itdssIni_t
   *  tdCachedMem[1-5]: is availalbe 
  */
  
  /* 
   * Get default parameters from the OS Specific area
   * and reads parameters from the configuration file
   */ 
  itdssGetOperatingOptionParams(tiRoot, &OperatingOption);
  
  /* 
   * Cached mem for initiator Transport Dependent Layer main functionality 
   */
  
  iniMem->tdCachedMem[0].singleElementLength  = sizeof(itdsaIni_t);
  iniMem->tdCachedMem[0].numElements          = 1;
  iniMem->tdCachedMem[0].totalLength          =
    iniMem->tdCachedMem[0].singleElementLength *
    iniMem->tdCachedMem[0].numElements;
  iniMem->tdCachedMem[0].alignment            = sizeof (void *); /* 4 bytes */
  iniMem->tdCachedMem[0].type                 = TI_CACHED_MEM;
  iniMem->tdCachedMem[0].reserved             = 0;
  iniMem->tdCachedMem[0].virtPtr               = agNULL;
  iniMem->tdCachedMem[0].osHandle              = agNULL;
  iniMem->tdCachedMem[0].physAddrUpper         = 0;
  iniMem->tdCachedMem[0].physAddrLower         = 0;
  
  
  /*
   * Not used mem structure. Initialize them.
   */ 
  for (i = iniMem->count; i < 6; i++)
  {
    iniMem->tdCachedMem[i].singleElementLength  = 0;
    iniMem->tdCachedMem[i].numElements          = 0;
    iniMem->tdCachedMem[i].totalLength          = 0;
    iniMem->tdCachedMem[i].alignment            = 0;
    iniMem->tdCachedMem[i].type                 = TI_CACHED_MEM;
    iniMem->tdCachedMem[i].reserved             = 0;

    iniMem->tdCachedMem[i].virtPtr               = agNULL;
    iniMem->tdCachedMem[i].osHandle              = agNULL;
    iniMem->tdCachedMem[i].physAddrUpper         = 0;
    iniMem->tdCachedMem[i].physAddrLower         = 0;
    
  }
  
  /* 
   * Operating option of TISA
   * fills in tiInitiatorOption 
   */
  initiatorResource->initiatorOption.usecsPerTick       = OperatingOption.UsecsPerTick;  /* default value 1 sec*/

  initiatorResource->initiatorOption.pageSize           = 0;

  /* initialization */
  initiatorResource->initiatorOption.dynamicDmaMem.numElements          = 0;
  initiatorResource->initiatorOption.dynamicDmaMem.singleElementLength  = 0;
  initiatorResource->initiatorOption.dynamicDmaMem.totalLength          = 0;
  initiatorResource->initiatorOption.dynamicDmaMem.alignment            = 0;
  
  /* initialization */
  initiatorResource->initiatorOption.dynamicCachedMem.numElements         = 0;
  initiatorResource->initiatorOption.dynamicCachedMem.singleElementLength = 0;
  initiatorResource->initiatorOption.dynamicCachedMem.totalLength         = 0;
  initiatorResource->initiatorOption.dynamicCachedMem.alignment           = 0;

  
  /* This is not used in OS like Linux which supports dynamic memeory allocation
     In short, this is for Windows, which does not support dynamic memory allocation */
  /* ostiallocmemory(..... ,agFALSE) is supported by the following code eg) sat.c
     The memory is DMA capable(uncached)
   */
#ifdef CCBUILD_EncryptionDriver
  /* extend the DMA memory for supporting two encryption DEK tables */
  initiatorResource->initiatorOption.dynamicDmaMem.numElements          = 128 + DEK_MAX_TABLE_ENTRIES / 2;
#else
  initiatorResource->initiatorOption.dynamicDmaMem.numElements          = 128;
#endif
  /* worked 
     initiatorResource->initiatorOption.dynamicDmaMem.singleElementLength  = sizeof(tdIORequestBody_t);
  */
  initiatorResource->initiatorOption.dynamicDmaMem.singleElementLength  = 512;
  initiatorResource->initiatorOption.dynamicDmaMem.totalLength          =
    initiatorResource->initiatorOption.dynamicDmaMem.numElements *
    initiatorResource->initiatorOption.dynamicDmaMem.singleElementLength;
  initiatorResource->initiatorOption.dynamicDmaMem.alignment            = sizeof(void *);

  
  /* This is not used in OS like Linux which supports dynamic memeory allocation
     In short, this is for Windows, which does not support dynamic memory allocation */
  /* ostiallocmemory(..... ,agTRUE) is supported by the following code eg) sat.c
     The memory is DMA incapable(cached)
   */
  initiatorResource->initiatorOption.dynamicCachedMem.numElements = 1024 + 256;
  /* worked 
  initiatorResource->initiatorOption.dynamicCachedMem.singleElementLength = sizeof(tdIORequestBody_t);
  initiatorResource->initiatorOption.dynamicCachedMem.singleElementLength = sizeof(tdssSMPRequestBody_t);
  */
  initiatorResource->initiatorOption.dynamicCachedMem.singleElementLength = 512;
  initiatorResource->initiatorOption.dynamicCachedMem.totalLength         = 
        initiatorResource->initiatorOption.dynamicCachedMem.numElements *
        initiatorResource->initiatorOption.dynamicCachedMem.singleElementLength;
  initiatorResource->initiatorOption.dynamicCachedMem.alignment           = sizeof(void *);
  
  /*
   * set the I/O request body size
   */
  initiatorResource->initiatorOption.ioRequestBodySize  = sizeof(tdIORequestBody_t);
  TI_DBG6(("itdssGetResource: sizeof(tdssSMPRequestBody_t) %d\n", (int)sizeof(tdssSMPRequestBody_t)));
  TI_DBG6(("itdssGetResource: end\n"));
  
  return;
}


/*****************************************************************************
*! \brief  itdssGetOperatingOptionParams
*
*  Purpose: This function is called to get default parameters from the 
*           OS Specific area. This function is called in the context of 
*           tiCOMGetResource() and tiCOMInit().
*
*
*  \param  tiRoot:   Pointer to initiator driver/port instance.
*  \param  option:   Pointer to the Transport Dependent options.
*
*  \return: None
*
*  \note -
*
*****************************************************************************/
osGLOBAL void 
itdssGetOperatingOptionParams(
                      tiRoot_t                *tiRoot, 
                      itdssOperatingOption_t  *OperatingOption
                      ) 
{
  char    *key = agNULL;
  char    *subkey1 = agNULL;
  char    *subkey2 = agNULL;
  char    *buffer;
  bit32   buffLen;
  bit32   lenRecv = 0;
  char    *pLastUsedChar = agNULL;
  char    tmpBuffer[DEFAULT_KEY_BUFFER_SIZE];
  char    globalStr[]     = "Global";
  char    iniParmsStr[]   = "InitiatorParms";

  TI_DBG6(("itdssGetOperatingOptionParams: start\n"));
  
  /* 
     first set the values to Default values
     Then, overwrite them using ostiGetTransportParam()
  */


  /* to remove compiler warnings */ 
  pLastUsedChar   = pLastUsedChar;
  lenRecv         = lenRecv;
  subkey2         = subkey2;
  subkey1         = subkey1;
  key             = key;
  buffer          = &tmpBuffer[0];
  buffLen         = sizeof (tmpBuffer);

  osti_memset(buffer, 0, buffLen);

  
  
  /* default values */
  OperatingOption->MaxTargets = DEFAULT_MAX_DEV; /* DEFAULT_MAX_TARGETS; */ /* 256 */
  OperatingOption->UsecsPerTick = DEFAULT_INI_TIMER_TICK; /* 1 sec */

  osti_memset(buffer, 0, buffLen);
  lenRecv = 0;
  
  /* defaults are overwritten in the following */
  /* Get MaxTargets */ 
  if ((ostiGetTransportParam(
                             tiRoot, 
                             globalStr,
                             iniParmsStr,
                             agNULL,
                             agNULL,
                             agNULL, 
                             agNULL, 
                             "MaxTargets",
                             buffer, 
                             buffLen, 
                             &lenRecv
                             ) == tiSuccess) && (lenRecv != 0))
  {
    if (osti_strncmp(buffer, "0x", 2) == 0)
    { 
      OperatingOption->MaxTargets = osti_strtoul (buffer, &pLastUsedChar, 0);
    }
    else
    {
      OperatingOption->MaxTargets = osti_strtoul (buffer, &pLastUsedChar, 10);
    }
    TI_DBG2(("itdssGetOperatingOptionParams: MaxTargets  %d\n",  OperatingOption->MaxTargets ));
  }
  
#ifdef REMOVED
  /* get UsecsPerTick */
  if ((ostiGetTransportParam(
                             tiRoot, 
                             globalStr,
                             iniParmsStr,
                             agNULL,
                             agNULL,
                             agNULL, 
                             agNULL, 
                             "UsecsPerTick",
                             buffer, 
                             buffLen, 
                             &lenRecv
                             ) == tiSuccess) && (lenRecv != 0))
  {
    if (osti_strncmp(buffer, "0x", 2) == 0)
    { 
      OperatingOption->UsecsPerTick = osti_strtoul (buffer, &pLastUsedChar, 0);
    }
    else
    {
      OperatingOption->UsecsPerTick = osti_strtoul (buffer, &pLastUsedChar, 10);
    }
  }
  osti_memset(buffer, 0, buffLen);
  lenRecv = 0;
#endif

  return;
}


/*****************************************************************************
*! \brief  itdssInit
*
*  Purpose: This function is called to initialize the initiator specific 
*           Transport Dependent Layer. 
*           This function is not directly called by OS Specific module, 
*           as it is internally called by tiCOMInit().
*
*  /param tiRoot:            Pointer to driver/port instance.
*  /param initiatorResource: Pointer to initiator functionality memory
*                            and option requirement.
*  /param tdSharedMem:       Pointer to cached memory required by the 
*                            target/initiator shared functionality.
*
*  /return: 
*   tiSuccess   OK
*   others      not OK
*
*  /note -
*
*****************************************************************************/
osGLOBAL bit32 
itdssInit(
          tiRoot_t              *tiRoot, 
          tiInitiatorResource_t *initiatorResource,
          tiTdSharedMem_t       *tdSharedMem 
          ) 
{
  tiInitiatorMem_t          *iniMem;
  itdsaIni_t                *Initiator;
  itdssOperatingOption_t    *OperatingOption;
  tdsaRoot_t                *tdsaRoot;

  TI_DBG6(("itdssInit: start\n"));
  iniMem = &initiatorResource->initiatorMem;
  tdsaRoot = (tdsaRoot_t *)tiRoot->tdData;
  /* 
   * Cached mem for initiator Transport Dependent Layer main functionality 
   */ 
  Initiator = iniMem->tdCachedMem[0].virtPtr;

  /* 
   * Get default parameters from the OS Specific area 
   */ 
  OperatingOption = &Initiator->OperatingOption;

  /* 
   * Get default parameters from the OS Specific area
   * and reads parameters from the configuration file
   */ 

  itdssGetOperatingOptionParams(tiRoot, OperatingOption);
  /*
   * Update TD operating options with OS-layer-saved value
   * Only UsecsPerTick is updated
   */
  OperatingOption->UsecsPerTick =
    initiatorResource->initiatorOption.usecsPerTick;
    
  Initiator->NumIOsActive             = 0;

  /* 
   *  tdCachedMem[0]: cached mem for initiator TD Layer main functionality :
   *                   itdssIni_t
   *  tdCachedMem[1-5]: not in use
  */

  /* initialize the timerlist */
  itdssInitTimers(tiRoot);

  
  /* Initialize the tdsaAllShared, tdssSASShared pointers */
  
  Initiator->tdsaAllShared = &(tdsaRoot->tdsaAllShared);
    
  TI_DBG6(("itdssInit: end\n"));
  return (tiSuccess);

}

/*****************************************************************************
*! \brief
*  itdssInitTimers
*
*  Purpose: This function is called to initialize the timers
*           for initiator
*
*  \param   tiRoot: pointer to the driver instance
*
*  \return: None
*
*  \note -
*
*****************************************************************************/
osGLOBAL void 
itdssInitTimers( 
                tiRoot_t *tiRoot 
                ) 
{
  tdsaRoot_t     *tdsaRoot = (tdsaRoot_t *)(tiRoot->tdData);
  tdsaContext_t  *tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared;
  itdsaIni_t     *Initiator = (itdsaIni_t *)tdsaAllShared->itdsaIni;
  
  /* initialize the timerlist */
  TDLIST_INIT_HDR(&(Initiator->timerlist));

  return;
}