root/sys/dev/pms/RefTisa/tisa/sassata/sas/tgt/ttdinit.c
/*******************************************************************************
 *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
 *
 * $RCSfile: ttdinit.c,v $
 *
 * Copyright 2006 PMC-Sierra, Inc.
 *
 * $Author: vempatin $
 * $Revision: 113679 $
 * $Date: 2012-04-16 14:35:19 -0700 (Mon, 16 Apr 2012) $
 *
 * This file contains initiator IO related functions in TD layer
 *
 */
#include <osenv.h>
#include <ostypes.h>
#include <osdebug.h>

#include <sa.h>
#include <saapi.h>
#include <saosapi.h>

#include <titypes.h>
#include <ostiapi.h>
#include <tiapi.h>
#include <tiglobal.h>

#include <tdtypes.h>
#include <osstring.h>
#include <tdutil.h>

#ifdef INITIATOR_DRIVER
#include <itdtypes.h>
#include <itddefs.h>
#include <itdglobl.h>
#endif

#ifdef TARGET_DRIVER
#include "ttdglobl.h"
#include "ttdtxchg.h"
#include "ttdtypes.h"
#endif

#include <tdsatypes.h>
#include <tdproto.h>

/* io trace only */
extern void TDTraceInit(void);
/* io trace only */


osGLOBAL bit32
ttdssInit(
        tiRoot_t              *tiRoot,
        tiTargetResource_t    *targetResource,
        tiTdSharedMem_t       *tdSharedMem
)
{
    tdsaRoot_t                *tdsaRoot  = (tdsaRoot_t *)tiRoot->tdData;
    tiTargetMem_t             *tgtMem;
    ttdsaTgt_t                *Target;
    ttdssOperatingOption_t    *OperatingOption;
    char                      *buffer;
    bit32                     buffLen;
    bit32                     lenRecv = 0;
    char                      *pLastUsedChar = agNULL;
    char                      tmpBuffer[DEFAULT_KEY_BUFFER_SIZE];
    char                      globalStr[]     = "OSParms";

    TI_DBG5(("ttdssInit: start\n"));

    /*
     first set the values to Default values
     Then, overwrite them using ostiGetTransportParam()
     */

    /* to remove compiler warnings */
    buffer          = &tmpBuffer[0];
    buffLen         = sizeof (tmpBuffer);

    osti_memset(buffer, 0, buffLen);

    tgtMem = &targetResource->targetMem;

    /*
     * Cached mem for target Transport Dependent Layer main functionality
     */
    Target = tgtMem->tdMem[0].virtPtr;

    OperatingOption = &Target->OperatingOption;
    /*
     * Get default parameters from the OS Specific area
     * and reads parameters from the configuration file
     */
    ttdssGetOperatingOptionParams(tiRoot, OperatingOption);


    /*
     * Update TD operating options
     */
    OperatingOption->UsecsPerTick =
            targetResource->targetOption.usecsPerTick;
    OperatingOption->numXchgs = tgtMem->tdMem[1].numElements;


    if (ttdsaXchgInit(tiRoot,
            &Target->ttdsaXchgData,
            tgtMem,
            OperatingOption->numXchgs
    ) == agFALSE)
    {
        TI_DBG1(("ttdInit: ttdsaXchgInit failed\n"));
        return tiError;
    }

    /* Get number of AutoGoodResponse entry */
    if ((ostiGetTransportParam(
                                tiRoot,
                                globalStr,
                                agNULL,
                                agNULL,
                                agNULL,
                                agNULL,
                                agNULL,
                                "AutoGoodResponse",
                                buffer,
                                buffLen,
                                &lenRecv
                              ) == tiSuccess) && (lenRecv != 0))
    {
        if (osti_strncmp(buffer, "0x", 2) == 0)
        {
            tdsaRoot->autoGoodRSP = osti_strtoul (buffer, &pLastUsedChar, 0);
        }
        else
        {
            tdsaRoot->autoGoodRSP = osti_strtoul (buffer, &pLastUsedChar, 10);
        }

    }

    return tiSuccess;
}

/*
  this combines ttdGetDefaultParams and ttdGetTargetParms

 */
osGLOBAL void
ttdssGetOperatingOptionParams(
        tiRoot_t                *tiRoot,
        ttdssOperatingOption_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[]   = "TargetParms";

    TI_DBG5(("ttdssGetOperatingOptionParams: 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);


    /* in ttgglobl.h */
    OperatingOption->numXchgs = DEFAULT_XCHGS;
    OperatingOption->UsecsPerTick = DEFAULT_TGT_TIMER_TICK; /* 1 sec */
    OperatingOption->MaxTargets = DEFAULT_MAX_TARGETS;
    OperatingOption->BlockSize = DEFAULT_BLOCK_SIZE;


    /* defaults are overwritten in the following */
    /* Get number of exchanges */
    if ((ostiGetTransportParam(
            tiRoot,
            globalStr,
            iniParmsStr,
            agNULL,
            agNULL,
            agNULL,
            agNULL,
            "NumberExchanges",
            buffer,
            buffLen,
            &lenRecv
    ) == tiSuccess) && (lenRecv != 0))
    {
        if (osti_strncmp(buffer, "0x", 2) == 0)
        {
            OperatingOption->numXchgs = osti_strtoul (buffer, &pLastUsedChar, 0);
        }
        else
        {
            OperatingOption->numXchgs = osti_strtoul (buffer, &pLastUsedChar, 10);
        }

    }

    osti_memset(buffer, 0, buffLen);
    lenRecv = 0;

    /* Get number of 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);
        }

    }
    osti_memset(buffer, 0, buffLen);
    lenRecv = 0;

    /* Get number of BlockSize */
    if ((ostiGetTransportParam(
            tiRoot,
            globalStr,
            iniParmsStr,
            agNULL,
            agNULL,
            agNULL,
            agNULL,
            "BlockSize",
            buffer,
            buffLen,
            &lenRecv
    ) == tiSuccess) && (lenRecv != 0))
    {
        if (osti_strncmp(buffer, "0x", 2) == 0)
        {
            OperatingOption->BlockSize = osti_strtoul (buffer, &pLastUsedChar, 0);
        }
        else
        {
            OperatingOption->BlockSize = osti_strtoul (buffer, &pLastUsedChar, 10);
        }
    }
    osti_memset(buffer, 0, buffLen);
    lenRecv = 0;



    TI_DBG5(("ttdssGetOperatingOptionParams: NumberExchanges %d UsecsPerTick %d MaxTargets %d BlockSize %d\n", OperatingOption->numXchgs, OperatingOption->UsecsPerTick, OperatingOption->MaxTargets, OperatingOption->BlockSize));

    return;
}

/* not yet */
osGLOBAL void
ttdssGetResource(
        tiRoot_t              *tiRoot,
        tiTargetResource_t    *targetResource
)
{
    tiTargetMem_t            *tgtMem;
    int i;
    ttdssOperatingOption_t   OperatingOption;
    bit32                     xchgSize;
    bit32                     respSize;
    bit32                     smprespSize;

    TI_DBG4(("ttdssGetResource: start\n"));

    tgtMem = &targetResource->targetMem;

    /*
    only 4 memory descriptors are used
     */
    tgtMem->count = 4;

    /* initiailization */
    for (i = 0 ; i < 10 ; i++)
    {
        tgtMem->tdMem[i].singleElementLength  = 0;
        tgtMem->tdMem[i].numElements          = 0;
        tgtMem->tdMem[i].totalLength          = 0;
        tgtMem->tdMem[i].alignment            = 0;
        tgtMem->tdMem[i].type                 = TI_CACHED_MEM;
        tgtMem->tdMem[i].reserved             = 0;
        tgtMem->tdMem[i].virtPtr               = agNULL;
        tgtMem->tdMem[i].osHandle              = agNULL;
        tgtMem->tdMem[i].physAddrUpper         = 0;
        tgtMem->tdMem[i].physAddrLower         = 0;
    }

    /*
     * Get default parameters from the OS Specific area
     * and reads parameters from the configuration file
     */
    ttdssGetOperatingOptionParams(tiRoot, &OperatingOption);

    /* target */
    tgtMem->tdMem[0].singleElementLength  = sizeof(ttdsaTgt_t);
    tgtMem->tdMem[0].numElements          = 1;
    tgtMem->tdMem[0].totalLength          =
            tgtMem->tdMem[0].singleElementLength *
            tgtMem->tdMem[0].numElements;
    tgtMem->tdMem[0].alignment            = sizeof (void *);
    tgtMem->tdMem[0].type                 = TI_CACHED_MEM;
    tgtMem->tdMem[0].reserved             = 0;
    tgtMem->tdMem[0].virtPtr               = agNULL;
    tgtMem->tdMem[0].osHandle              = agNULL;
    tgtMem->tdMem[0].physAddrUpper         = 0;
    tgtMem->tdMem[0].physAddrLower         = 0;

    /*
     * Cached memory for I/O exchange structures
     */
    xchgSize = sizeof(ttdsaXchg_t);
    xchgSize = AG_ALIGNSIZE(xchgSize, 8);

    tgtMem->tdMem[1].singleElementLength = xchgSize;
    tgtMem->tdMem[1].numElements         = OperatingOption.numXchgs;
    tgtMem->tdMem[1].totalLength         = tgtMem->tdMem[1].singleElementLength *
            tgtMem->tdMem[1].numElements;
    tgtMem->tdMem[1].alignment           = sizeof(void *);
    tgtMem->tdMem[1].type                = TI_CACHED_MEM;
    tgtMem->tdMem[1].reserved             = 0;
    tgtMem->tdMem[1].virtPtr               = agNULL;
    tgtMem->tdMem[1].osHandle              = agNULL;
    tgtMem->tdMem[1].physAddrUpper         = 0;
    tgtMem->tdMem[1].physAddrLower         = 0;

    /*
     * Uncached memory for response buffer structures
     */
    TI_DBG4(("ttdssGetResource: sas_resp_t size 0x%x %d\n",
            (unsigned int)sizeof(sas_resp_t), (int)sizeof(sas_resp_t)));

    respSize = (sizeof(sas_resp_t) + AG_WORD_ALIGN_ADD) & AG_WORD_ALIGN_MASK;
    TI_DBG4(("ttdssGetResource: response size 0x%x %d\n", respSize,respSize));
    respSize = AG_ALIGNSIZE(respSize, 8);
    TI_DBG4(("ttdssGetResource: response size 0x%x %d\n", respSize,respSize));
    tgtMem->tdMem[2].singleElementLength = 0x1000; /* respSize; 0x1000;  */
    tgtMem->tdMem[2].numElements         = OperatingOption.numXchgs;  /* Same as num of xchg */
    tgtMem->tdMem[2].totalLength         = tgtMem->tdMem[2].singleElementLength *
            tgtMem->tdMem[2].numElements;
    /* 8;4;16;256;sizeof(void *); all worked */
    tgtMem->tdMem[2].alignment           = 16;
    tgtMem->tdMem[2].type                = TI_DMA_MEM;  /* uncached memory */
    tgtMem->tdMem[2].reserved             = 0;
    tgtMem->tdMem[2].virtPtr               = agNULL;
    tgtMem->tdMem[2].osHandle              = agNULL;
    tgtMem->tdMem[2].physAddrUpper         = 0;
    tgtMem->tdMem[2].physAddrLower         = 0;

    /*
     * Uncached memory for SMP response buffer structures
     */
    smprespSize = sizeof(smp_resp_t);
    smprespSize = AG_ALIGNSIZE(smprespSize, 8);
    TI_DBG4(("ttdssGetResource: SMP response size 0x%x %d\n", smprespSize,smprespSize));

    tgtMem->tdMem[3].singleElementLength = smprespSize; /*0x1000; smprespSize; */
    tgtMem->tdMem[3].numElements         = OperatingOption.numXchgs;  /* Same as num of xchg */
    tgtMem->tdMem[3].totalLength
    = tgtMem->tdMem[3].singleElementLength * tgtMem->tdMem[3].numElements;
    tgtMem->tdMem[3].alignment           = 16; /* 4; 256; 16; sizeof(void *); */
    tgtMem->tdMem[3].type                = TI_DMA_MEM;  /* uncached memory */
    tgtMem->tdMem[3].reserved             = 0;
    tgtMem->tdMem[3].virtPtr               = agNULL;
    tgtMem->tdMem[3].osHandle              = agNULL;
    tgtMem->tdMem[3].physAddrUpper         = 0;
    tgtMem->tdMem[3].physAddrLower         = 0;



    targetResource->targetOption.usecsPerTick = OperatingOption.UsecsPerTick;
    targetResource->targetOption.pageSize     = 0; /* not applicable to SAS/SATA */
    targetResource->targetOption.numLgns      = 0; /* not applicable to SAS/SATA */
    targetResource->targetOption.numSessions  = 0; /* not applicable to SAS/SATA */
    targetResource->targetOption.numXchgs     = OperatingOption.numXchgs;


    /*
    This is not used in OS like Linux which supports dynamic memeory allocation
    In short, this is for Windows
     */
    /* Estimate dynamic DMA memory */
    targetResource->targetOption.dynamicDmaMem.alignment = sizeof(void *);

    targetResource->targetOption.dynamicDmaMem.numElements = 128;
    targetResource->targetOption.dynamicDmaMem.singleElementLength = sizeof(tdssSMPRequestBody_t);
    targetResource->targetOption.dynamicDmaMem.totalLength =
            targetResource->targetOption.dynamicDmaMem.numElements *
            targetResource->targetOption.dynamicDmaMem.singleElementLength;

    /* Estimate dynamic cached memory */
    targetResource->targetOption.dynamicCachedMem.alignment =  sizeof(void *);
    targetResource->targetOption.dynamicCachedMem.numElements = 128;
    targetResource->targetOption.dynamicCachedMem.singleElementLength = sizeof(tdssSMPRequestBody_t);
    targetResource->targetOption.dynamicCachedMem.totalLength =
            targetResource->targetOption.dynamicCachedMem.numElements *
            targetResource->targetOption.dynamicCachedMem.singleElementLength;


    return;
}

/* not in use */
osGLOBAL void
ttdssGetTargetParams(
        tiRoot_t          *tiRoot
)
{
    TI_DBG6(("ttdssGetTargetParams: start\n"));
    return;
}

osGLOBAL agBOOLEAN
ttdsaXchgInit(
        tiRoot_t           *tiRoot,
        ttdsaXchgData_t    *ttdsaXchgData,
        tiTargetMem_t      *tgtMem,
        bit32              maxNumXchgs
)
{
    ttdsaXchg_t       *ttdsaXchg;
    bit32             i, respLen;
    bit8              *virtualAddr;
    bit32             phyAddrLower, phyAddrUpper;
    bit32             smprespLen;
    bit32             smpphyAddrLower, smpphyAddrUpper;
    bit8              *smpvirtualAddr;



    TI_DBG5(("ttdsaXchgInit: start\n"));
    /* io trace only */
    TDTraceInit();
    /* io trace only */

    /*
     * Set and initialize some global exchange information
     */
    TDLIST_INIT_HDR(&ttdsaXchgData->xchgFreeList);
    TDLIST_INIT_HDR(&ttdsaXchgData->xchgBusyList);

    ttdsaXchgData->maxNumXchgs = maxNumXchgs;

    /* Initialize exchange and response buffer structures */
    ttdsaXchg = (ttdsaXchg_t *) tgtMem->tdMem[1].virtPtr;

    /* Initialize response buffer */
    virtualAddr  = tgtMem->tdMem[2].virtPtr;
    phyAddrUpper = tgtMem->tdMem[2].physAddrUpper;
    phyAddrLower = tgtMem->tdMem[2].physAddrLower;
    respLen      = tgtMem->tdMem[2].singleElementLength;

    ttdsaXchg->resp.virtAddr      = virtualAddr;
    ttdsaXchg->resp.phyAddrUpper = phyAddrUpper;
    ttdsaXchg->resp.phyAddrLower = phyAddrLower;
    ttdsaXchg->resp.length = respLen;

    /* Initialize SMP response buffer */
    smpvirtualAddr  = tgtMem->tdMem[3].virtPtr;
    smpphyAddrUpper = tgtMem->tdMem[3].physAddrUpper;
    smpphyAddrLower = tgtMem->tdMem[3].physAddrLower;
    smprespLen      = tgtMem->tdMem[3].singleElementLength;

    ttdsaXchg->smpresp.virtAddr      = smpvirtualAddr;
    ttdsaXchg->smpresp.phyAddrUpper = smpphyAddrUpper;
    ttdsaXchg->smpresp.phyAddrLower = smpphyAddrLower;
    ttdsaXchg->smpresp.length = smprespLen;

    /* Initialization of callback and etc */
    for (i=0;i<maxNumXchgs;i++)
    {
        ttdsaXchg->id = i;
        ttdsaXchg->usedEsgl = agFALSE;
        ttdsaXchg->io_found = agTRUE;
        ttdsaXchg->DeviceData = agNULL;
        /* callback for IO(ssp) and SMP */
        ttdsaXchg->IORequestBody.IOCompletionFunc = ttdsaIOCompleted;
        ttdsaXchg->SMPRequestBody.SMPCompletionFunc = ttdsaSMPCompleted;


        TDLIST_INIT_ELEMENT(&ttdsaXchg->XchgLinks );

        ttdsaXchg->IORequestBody.agIORequest.osData = (void *)ttdsaXchg;
        ttdsaXchg->IORequestBody.tiIORequest
        = &(ttdsaXchg->IORequestBody.IOType.TargetIO.tiIORequest);

        /* Init the tdData portion of tiIORequest context for this exchange */
        ttdsaXchg->IORequestBody.tiIORequest->tdData = ttdsaXchg;

        /* SMP */
        ttdsaXchg->SMPRequestBody.agIORequest.osData = (void *)ttdsaXchg;
        /* ttdsaXchg->SMPRequestBody.agIORequest.osData = (void *)&ttdsaXchg->SMPRequestBody; */
        /*ttdsaXchg->SMPRequestBody.tiIORequest.tdData = (void *)&ttdsaXchg->SMPRequestBody; */




        /* Initialize the CDB and LUN addresses */
        ttdsaXchg->tiTgtScsiCmnd.reqCDB  = &(ttdsaXchg->agSSPCmndIU.cdb[0]);
        ttdsaXchg->tiTgtScsiCmnd.scsiLun = &(ttdsaXchg->agSSPCmndIU.lun[0]);

        ttdsaXchg->index = i;
        ttdsaXchg->respLen = respLen; /* 100 */
        ttdsaXchg->smprespLen = smprespLen; /* 100 */
        ttdsaXchg->TLR = 0;
        TD_XCHG_SET_STATE(ttdsaXchg, TD_XCHG_STATE_INACTIVE);
        ttdsaXchg->retries = 0;

        ttdsaXchgLinkInit(tiRoot,ttdsaXchg);

        /* Save current response payload/buffer address */
        virtualAddr  = ttdsaXchg->resp.virtAddr;
        phyAddrLower = ttdsaXchg->resp.phyAddrLower;
        smpvirtualAddr  = ttdsaXchg->smpresp.virtAddr;
        smpphyAddrLower = ttdsaXchg->smpresp.phyAddrLower;

        TI_DBG5(("ttdsaXchgInit: +1 before\n"));
        if (i == (maxNumXchgs - 1))
        {
            /* at the last one */
            TI_DBG5(("ttdsaXchgInit: last one break\n"));
            break;
        }

        /* Advance to next exchange */
        ttdsaXchg = ttdsaXchg + 1;
        TI_DBG5(("ttdsaXchgInit: +1 after\n"));

        /* Update response payload/buffer address */
        ttdsaXchg->resp.virtAddr      = virtualAddr + respLen;
        TI_DBG5(("ttdsaXchgInit: pos 1\n"));
        ttdsaXchg->resp.phyAddrUpper = phyAddrUpper;
        TI_DBG5(("ttdsaXchgInit: pos 2\n"));
        ttdsaXchg->resp.phyAddrLower = phyAddrLower + respLen;
        TI_DBG5(("ttdsaXchgInit: pos 3\n"));
        ttdsaXchg->resp.length = respLen;
        TI_DBG5(("ttdsaXchgInit: pos 4\n"));

        /* Update SMP response payload/buffer address */
        ttdsaXchg->smpresp.virtAddr      = smpvirtualAddr + smprespLen;
        ttdsaXchg->smpresp.phyAddrUpper = smpphyAddrUpper;
        ttdsaXchg->smpresp.phyAddrLower = smpphyAddrLower + smprespLen;
        ttdsaXchg->smpresp.length = smprespLen;

    }

    /* Reinitialize counters.
     * This must be done at the end
     */
    TD_XCHG_CONTEXT_NO_USED(tiRoot)            = 0;
    TD_XCHG_CONTEXT_NO_FREED(tiRoot)           = 0;
    TD_XCHG_CONTEXT_NO_CMD_RCVD(tiRoot)        = 0;
    TD_XCHG_CONTEXT_NO_START_IO(tiRoot)        = 0;
    TD_XCHG_CONTEXT_NO_SEND_RSP(tiRoot)        = 0;
    TD_XCHG_CONTEXT_NO_IO_COMPLETED(tiRoot)    = 0;

    TI_DBG5(("ttdsaXchgInit: end\n"));
    return agTRUE;
}

osGLOBAL void
ttdsaXchgLinkInit(
        tiRoot_t           *tiRoot,
        ttdsaXchg_t        *ttdsaXchg
)
{
    tdsaRoot_t        *tdsaRoot    = (tdsaRoot_t *)tiRoot->tdData;
    tdsaContext_t     *tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared;
    ttdsaTgt_t         *Target = (ttdsaTgt_t *)tdsaAllShared->ttdsaTgt;
    bit32              i;
    bit8               *data;

    TI_DBG5(("ttdsaXchgLinkInit: start\n"));
    TI_DBG5(("ttdsaXchgLinkInit: xchg %p\n",ttdsaXchg));
    TI_DBG5(("ttdsaXchgLinkInit: resp %p\n",ttdsaXchg->resp.virtAddr));
    TI_DBG5(("ttdsaXchgLinkInit: smpresp %p\n",ttdsaXchg->smpresp.virtAddr));

    if (TD_XCHG_GET_STATE(ttdsaXchg) == TD_XCHG_STATE_ACTIVE)
    {
        TI_DBG1(("ttdsaXchgLinkInit: active xchg *****************; wrong\n"));
        return;
    }

    ttdsaXchg->tag = 0xFFFF;
    ttdsaXchg->IORequestBody.agIORequest.sdkData  = agNULL;
    ttdsaXchg->SMPRequestBody.agIORequest.sdkData  = agNULL;
    ttdsaXchg->statusSent        = agFALSE;
    ttdsaXchg->responseSent      = agFALSE;
    ttdsaXchg->readRspCollapsed  = agFALSE;
    ttdsaXchg->wrtRspCollapsed  = agFALSE;
    ttdsaXchg->pTMResp           = agNULL;
    ttdsaXchg->oustandingIos     = 0;
    ttdsaXchg->isAborting        = agFALSE;
    ttdsaXchg->oslayerAborting   = agFALSE;
    ttdsaXchg->isTMRequest       = agFALSE;
    ttdsaXchg->io_found          = agTRUE;
    ttdsaXchg->tiIOToBeAbortedRequest          = agNULL;
    ttdsaXchg->XchgToBeAborted          = agNULL;

    osti_memset((void *)ttdsaXchg->resp.virtAddr, 0, ttdsaXchg->respLen);
    osti_memset((void *)ttdsaXchg->smpresp.virtAddr, 0, ttdsaXchg->smprespLen);

    data = (bit8 *)ttdsaXchg->resp.virtAddr;
    for (i = 0; i< ttdsaXchg->respLen; i++)
    {
        if (data[i] != 0)
        {
            TI_DBG5(("!! ttdsaXchgLinkInit: data[%d] 0x%x\n", i, data[i]));
        }
    }

    ttdsaXchg->resp.length       = 0;

    ttdsaXchg->DeviceData = agNULL;
    TI_DBG5(("ttdsaXchgLinkInit: id %d\n", ttdsaXchg->id));

    TD_XCHG_SET_STATE(ttdsaXchg, TD_XCHG_STATE_INACTIVE);
    tdsaSingleThreadedEnter(tiRoot, TD_TGT_LOCK);
    TDLIST_ENQUEUE_AT_TAIL( &ttdsaXchg->XchgLinks, &Target->ttdsaXchgData.xchgFreeList);
    tdsaSingleThreadedLeave(tiRoot, TD_TGT_LOCK);


    TD_XCHG_CONTEXT_NO_FREED(tiRoot)           = TD_XCHG_CONTEXT_NO_FREED(tiRoot) +1;
    TI_DBG5(("ttdsaXchgLinkInit: end\n"));
    return;
}

/*
   before: ttdsaXchg is in xchgBusyList
   after: ttdsaXchg is in xchgFreeList
 */
osGLOBAL void
ttdsaXchgFreeStruct(
        tiRoot_t           *tiRoot,
        ttdsaXchg_t        *ttdsaXchg
)
{
    tdsaRoot_t        *tdsaRoot    = (tdsaRoot_t *)tiRoot->tdData;
    tdsaContext_t     *tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared;
    ttdsaTgt_t        *Target = (ttdsaTgt_t *)tdsaAllShared->ttdsaTgt;
    bit32             i;
    bit8              *data;

    TI_DBG5(("ttdsaXchgFreeStruct: start\n"));
    TI_DBG5(("ttdsaXchgFreeStruct: xchg %p\n",ttdsaXchg));
    TI_DBG5(("ttdsaXchgFreeStruct: resp %p\n",ttdsaXchg->resp.virtAddr));
    TI_DBG5(("ttdsaXchgFreeStruct: smpresp %p\n",ttdsaXchg->smpresp.virtAddr));

    if (TD_XCHG_GET_STATE(ttdsaXchg) == TD_XCHG_STATE_INACTIVE)
    {
        TI_DBG1(("tdsaXchgFreeStruct: INACTIVE xchg *****************, wrong\n"));
        return;
    }

    ttdsaXchg->tag = 0xFFFF;
    ttdsaXchg->IORequestBody.agIORequest.sdkData  = agNULL;
    ttdsaXchg->SMPRequestBody.agIORequest.sdkData  = agNULL;
    ttdsaXchg->statusSent        = agFALSE;
    ttdsaXchg->responseSent      = agFALSE;
    ttdsaXchg->readRspCollapsed  = agFALSE;
    ttdsaXchg->wrtRspCollapsed  = agFALSE;
    ttdsaXchg->pTMResp           = agNULL;
    ttdsaXchg->oustandingIos     = 0;
    ttdsaXchg->isAborting        = agFALSE;
    ttdsaXchg->oslayerAborting   = agFALSE;
    ttdsaXchg->isTMRequest       = agFALSE;
    ttdsaXchg->io_found          = agTRUE;
    ttdsaXchg->tiIOToBeAbortedRequest          = agNULL;
    ttdsaXchg->XchgToBeAborted          = agNULL;

    osti_memset((void *)ttdsaXchg->resp.virtAddr, 0, ttdsaXchg->respLen);
    osti_memset((void *)ttdsaXchg->smpresp.virtAddr, 0, ttdsaXchg->smprespLen);

    data = (bit8 *)ttdsaXchg->resp.virtAddr;
    for (i = 0; i< ttdsaXchg->respLen; i++)
    {
        if (data[i] != 0)
        {
            TI_DBG5(("!! ttdsaXchgFreeStruct: data[%d] 0x%x\n", i, data[i]));
        }
    }

    ttdsaXchg->resp.length       = 0;

    ttdsaXchg->DeviceData = agNULL;
    TI_DBG5(("ttdsaXchgFreeStruct: id %d\n", ttdsaXchg->id));

    tdsaSingleThreadedEnter(tiRoot, TD_TGT_LOCK);
    TD_XCHG_SET_STATE(ttdsaXchg, TD_XCHG_STATE_INACTIVE);
    TDLIST_DEQUEUE_THIS(&ttdsaXchg->XchgLinks);
    TDLIST_ENQUEUE_AT_TAIL( &ttdsaXchg->XchgLinks, &Target->ttdsaXchgData.xchgFreeList);
    tdsaSingleThreadedLeave(tiRoot, TD_TGT_LOCK);

    TD_XCHG_CONTEXT_NO_FREED(tiRoot)           = TD_XCHG_CONTEXT_NO_FREED(tiRoot) +1;
    TI_DBG5(("ttdsaXchgFreeStruct: end\n"));
    return;
}


/*
   before: ttdsaXchg is in xchgFreeList
   after: ttdsaXchg is in xchgBusyList
 */
osGLOBAL ttdsaXchg_t *ttdsaXchgGetStruct(agsaRoot_t *agRoot)
{
    tdsaRootOsData_t       *osData = (tdsaRootOsData_t *)agRoot->osData;
    tiRoot_t               *tiRoot = (tiRoot_t *)osData->tiRoot;
    ttdsaTgt_t             *Target = (ttdsaTgt_t *)osData->ttdsaTgt;
    tdList_t               *Link;
    ttdsaXchg_t            *ttdsaXchg = agNULL;

    TI_DBG3 (("ttdsaXchgGetStruct: enter\n"));

    tdsaSingleThreadedEnter(tiRoot, TD_TGT_LOCK);
    if (TDLIST_EMPTY(&(Target->ttdsaXchgData.xchgFreeList)))
    {
        tdsaSingleThreadedLeave(tiRoot, TD_TGT_LOCK);
        TI_DBG1(("ttdsaXchgGetStruct: no free ttdsaXchgData\n"));
        //    ttdsaDumpallXchg(tiRoot);
        return agNULL;
    }

    TDLIST_DEQUEUE_FROM_HEAD(&Link, &Target->ttdsaXchgData.xchgFreeList);
    if ( Link == agNULL )
    {
        tdsaSingleThreadedLeave(tiRoot, TD_TGT_LOCK);
        TI_DBG1(("ttdsaXchgGetStruct: Link NULL: PRBLM \n"));
        return agNULL;
    }

    ttdsaXchg = TDLIST_OBJECT_BASE(ttdsaXchg_t, XchgLinks, Link);

    if (TD_XCHG_GET_STATE(ttdsaXchg) == TD_XCHG_STATE_ACTIVE)
    {
        TI_DBG1(("ttdsaXchgGetStruct: ACTIVE xchg *****************, wrong\n"));
        TDLIST_DEQUEUE_THIS(&ttdsaXchg->XchgLinks);
        TDLIST_ENQUEUE_AT_TAIL(&ttdsaXchg->XchgLinks, &Target->ttdsaXchgData.xchgFreeList);
        TD_XCHG_SET_STATE(ttdsaXchg, TD_XCHG_STATE_INACTIVE);
        tdsaSingleThreadedLeave(tiRoot, TD_TGT_LOCK);

        return agNULL;
    }

    TDLIST_DEQUEUE_THIS(&ttdsaXchg->XchgLinks);
    TDLIST_ENQUEUE_AT_TAIL(&ttdsaXchg->XchgLinks, &Target->ttdsaXchgData.xchgBusyList);
    TD_XCHG_SET_STATE(ttdsaXchg, TD_XCHG_STATE_ACTIVE);
    tdsaSingleThreadedLeave(tiRoot, TD_TGT_LOCK);

    TD_XCHG_CONTEXT_NO_USED(tiRoot)           = TD_XCHG_CONTEXT_NO_USED(tiRoot) +1;
    TI_DBG5(("ttdsaXchgGetStruct: id %d\n", ttdsaXchg->id));
    return ttdsaXchg;
}

/* for debugging */
osGLOBAL void
ttdsaDumpallXchg(tiRoot_t           *tiRoot)
{
    tdsaRoot_t        *tdsaRoot        = (tdsaRoot_t *) tiRoot->tdData;
    tdsaContext_t     *tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared;
    ttdsaTgt_t        *Target = (ttdsaTgt_t *)tdsaAllShared->ttdsaTgt;
    ttdsaTgt_t        *tmpTarget;
    tdList_t          *XchgList;
#ifdef TD_DEBUG_ENABLE
    ttdsaXchg_t       *ttdsaXchg = agNULL;
#endif

    tmpTarget = Target;

    tdsaSingleThreadedEnter(tiRoot, TD_TGT_LOCK);
    if (TDLIST_EMPTY(&(tmpTarget->ttdsaXchgData.xchgFreeList)))
    {
        tdsaSingleThreadedLeave(tiRoot, TD_TGT_LOCK);
        TI_DBG1(("ttdsaDumpallXchg: no FREE ttdsaXchgData\n"));
    }
    else
    {
        tdsaSingleThreadedLeave(tiRoot, TD_TGT_LOCK);
        XchgList = tmpTarget->ttdsaXchgData.xchgFreeList.flink;

        while(XchgList != &(tmpTarget->ttdsaXchgData.xchgFreeList))
        {
#ifdef TD_DEBUG_ENABLE
            ttdsaXchg = TDLIST_OBJECT_BASE(ttdsaXchg_t, XchgLinks, XchgList);
#endif
            TI_DBG1(("ttdsaDumpallXchg: FREE id %d state %d\n", ttdsaXchg->id, TD_XCHG_GET_STATE(ttdsaXchg)));
            XchgList = XchgList->flink;
        }
    }

    tdsaSingleThreadedEnter(tiRoot, TD_TGT_LOCK);
    if (TDLIST_EMPTY(&(tmpTarget->ttdsaXchgData.xchgBusyList)))
    {
        tdsaSingleThreadedLeave(tiRoot, TD_TGT_LOCK);
        TI_DBG1(("ttdsaDumpallXchg: no BUSY ttdsaXchgData\n"));
    }
    else
    {
        tdsaSingleThreadedLeave(tiRoot, TD_TGT_LOCK);
        XchgList = tmpTarget->ttdsaXchgData.xchgBusyList.flink;

        while(XchgList != &(tmpTarget->ttdsaXchgData.xchgBusyList))
        {
#ifdef TD_DEBUG_ENABLE
            ttdsaXchg = TDLIST_OBJECT_BASE(ttdsaXchg_t, XchgLinks, XchgList);
#endif
            TI_DBG1(("ttdsaDumpallXchg: BUSY id %d state %d\n", ttdsaXchg->id, TD_XCHG_GET_STATE(ttdsaXchg)));
            XchgList = XchgList->flink;
        }
    }


    return;
}


#ifdef PASSTHROUGH

osGLOBAL bit32
tiTGTPassthroughCmndRegister(
        tiRoot_t                        *tiRoot,
        tiPortalContext_t               *tiportalContext,
        tiPassthroughProtocol_t        tiProtocol,
        tiPassthroughSubProtocol_t        tiSubProtocol,
        tiPassthroughFrameType_t        tiFrameType,
        ostiProcessPassthroughCmnd_t    agPasthroughCB
)
{
    tdsaRoot_t                *tdsaRoot        = (tdsaRoot_t *) tiRoot->tdData;
    tdsaContext_t             *tdsaAllShared = (tdsaContext_t *)&tdsaRoot->tdsaAllShared;
    ttdsaTgt_t                *Target = (ttdsaTgt_t *)tdsaAllShared->ttdsaTgt;

    TI_DBG1(("tiTGTPassthroughCmndRegister: start\n"));
    /* error checking */
    if (tiProtocol != tiSASATA)
    {
        TI_DBG1(("tiTGTPassthroughCmndRegister: not supported protocol %d\n", tiProtocol));
        return tiError;
    }

    if (tiSubProtocol != tiSSP || tiSubProtocol != tiSTP || tiSubProtocol != tiSMP)
    {
        TI_DBG1(("tiTGTPassthroughCmndRegister: not supported sub protocol %d\n", tiSubProtocol));
        return tiError;
    }


    if (tiFrameType == tiSMPResponse)
    {
        TI_DBG1(("tiTGTPassthroughCmndRegister: SMP response frametype %d\n"));
        Target->PasthroughCB = agPasthroughCB;
    }

    else if (tiFrameType == tiSSPPMC)
    {
        TI_DBG1(("tiTGTPassthroughCmndRegister: RMC response frametype %d\n"));
        Target->PasthroughCB = agPasthroughCB;
    }
    else
    {
        TI_DBG1(("tiTGTPassthroughCmndRegister: not supported frametype %d\n", tiFrameType));
        return tiError;
    }


    return tiSuccess;
}

#endif