diff options
Diffstat (limited to 'sys/dev/pms/RefTisa/sallsdk/spc/saphy.c')
-rw-r--r-- | sys/dev/pms/RefTisa/sallsdk/spc/saphy.c | 1302 |
1 files changed, 1302 insertions, 0 deletions
diff --git a/sys/dev/pms/RefTisa/sallsdk/spc/saphy.c b/sys/dev/pms/RefTisa/sallsdk/spc/saphy.c new file mode 100644 index 0000000..3603129 --- /dev/null +++ b/sys/dev/pms/RefTisa/sallsdk/spc/saphy.c @@ -0,0 +1,1302 @@ +/******************************************************************************* +*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 saphy.c + * \brief The file implements the functions to Start, Stop a phy + * + * + */ +/******************************************************************************/ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); +#include <dev/pms/config.h> + +#include <dev/pms/RefTisa/sallsdk/spc/saglobal.h> +#ifdef SA_ENABLE_TRACE_FUNCTIONS +#ifdef siTraceFileID +#undef siTraceFileID +#endif +#define siTraceFileID 'K' +#endif + + +extern bit32 gFPGA_TEST; +/******************************************************************************/ +/*! \brief Start a Phy + * + * Start a Phy + * + * \param agRoot handles for this instance of SAS/SATA hardware + * \param agContext + * \param phyId the phy id of the link will be started + * \param agPhyConfig the phy configuration + * \param agSASIdentify the SAS identify frame will be sent by the phy + * + * \return If phy is started successfully + * - \e AGSA_RC_SUCCESS phy is started successfully + * - \e AGSA_RC_BUSY phy is already started or starting + * - \e AGSA_RC_FAILURE phy is not started successfully + */ +/*******************************************************************************/ +GLOBAL bit32 saPhyStart( + agsaRoot_t *agRoot, + agsaContext_t *agContext, + bit32 queueNum, + bit32 phyId, + agsaPhyConfig_t *agPhyConfig, + agsaSASIdentify_t *agSASIdentify + ) +{ + agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); + agsaIORequestDesc_t *pRequest; + bit32 ret = AGSA_RC_SUCCESS; + bit32 using_reserved = agFALSE; + + smTraceFuncEnter(hpDBG_VERY_LOUD, "7a"); + + /* sanity check */ + SA_ASSERT((agNULL != agRoot), ""); + SA_ASSERT((agNULL != agSASIdentify), ""); + + SA_DBG3(("saPhyStart: phy%d started with ID %08X:%08X\n", + phyId, + SA_IDFRM_GET_SAS_ADDRESSHI(agSASIdentify), + SA_IDFRM_GET_SAS_ADDRESSLO(agSASIdentify))); + + /* If phyId is invalid, return failure */ + if ( phyId >= saRoot->phyCount ) + { + ret = AGSA_RC_FAILURE; + } + /* If phyId is valid */ + else + { + /* Get request from free IORequests */ + ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK); + pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests)); /* */ + /* If no LL Control request entry available */ + if ( agNULL == pRequest ) + { + pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeReservedRequests)); + /* If no LL Control request entry available */ + if(agNULL != pRequest) + { + using_reserved = agTRUE; + SA_DBG1(("saPhyStart, using saRoot->freeReservedRequests\n")); + } + else + { + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + SA_DBG1(("saPhyStart, No request from free list Not using saRoot->freeReservedRequests\n")); + smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "7a"); + return AGSA_RC_BUSY; + } + } + SA_ASSERT((!pRequest->valid), "The pRequest is in use"); + pRequest->valid = agTRUE; + /* If LL Control request entry avaliable */ + if( using_reserved ) + { + saLlistIORemove(&(saRoot->freeReservedRequests), &(pRequest->linkNode)); + } + else + { + /* Remove the request from free list */ + saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode)); + } + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + + saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag; + saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest; + saRoot->IOMap[pRequest->HTag].agContext = agContext; + pRequest->valid = agTRUE; + + /* Build the Phy Start IOMB command and send to SPC */ + + smTrace(hpDBG_VERY_LOUD,"P2", phyId); + /* TP:P2 phyId */ + + ret = mpiPhyStartCmd(agRoot, pRequest->HTag, phyId, agPhyConfig, agSASIdentify, queueNum); + if (AGSA_RC_SUCCESS != ret) + { + /* remove the request from IOMap */ + saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF; + saRoot->IOMap[pRequest->HTag].IORequest = agNULL; + saRoot->IOMap[pRequest->HTag].agContext = agNULL; + pRequest->valid = agFALSE; + + ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK); + /* return the request to free pool */ + if(saLlistIOGetCount(&(saRoot->freeReservedRequests)) < SA_RESERVED_REQUEST_COUNT) + { + SA_DBG1(("saPhyStart: saving pRequest (%p) for later use\n", pRequest)); + saLlistIOAdd(&(saRoot->freeReservedRequests), &(pRequest->linkNode)); + } + else + { + /* return the request to free pool */ + saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode)); + } + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + SA_DBG1(("saPhyStart, sending IOMB failed\n" )); + } + } + + smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "7a"); + + return ret; +} + +/******************************************************************************/ +/*! \brief Stop a Phy + * + * Stop a Phy + * + * \param agRoot handles for this instance of SAS/SATA hardware + * \param agContext the context of this API + * \param phyId the phy id of the link will be stopped + * + * \return If phy is stopped successfully + * - \e AGSA_RC_SUCCESS phy is stopped successfully + * - \e AGSA_RC_FAILURE phy is not stopped successfully + */ +/*******************************************************************************/ +GLOBAL bit32 saPhyStop( + agsaRoot_t *agRoot, + agsaContext_t *agContext, + bit32 queueNum, + bit32 phyId + ) +{ + agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); + agsaIORequestDesc_t *pRequest; + bit32 ret = AGSA_RC_SUCCESS; + bit32 using_reserved = agFALSE; + + smTraceFuncEnter(hpDBG_VERY_LOUD,"7b"); + + /* sanity check */ + SA_ASSERT((agNULL != agRoot), ""); + + SA_DBG2(("saPhyStop: phy%d stop\n", phyId)); + + if(1) + { + mpiOCQueue_t *circularQ; + int i; + SA_DBG4(("saPhyStop:\n")); + for ( i = 0; i < saRoot->QueueConfig.numOutboundQueues; i++ ) + { + circularQ = &saRoot->outboundQueue[i]; + OSSA_READ_LE_32(circularQ->agRoot, &circularQ->producerIdx, circularQ->piPointer, 0); + if(circularQ->producerIdx != circularQ->consumerIdx) + { + SA_DBG1(("saPhyStop: PI 0x%03x CI 0x%03x\n",circularQ->producerIdx, circularQ->consumerIdx )); + } + } + } + + if(smIS_SPC(agRoot)) + { + phyId &= 0xF; + } + /* If phyId is invalid, return failure */ + if ( (phyId & 0xF) >= saRoot->phyCount ) + { + ret = AGSA_RC_FAILURE; + SA_DBG1(("saPhyStop: phy%d - failure with phyId\n", phyId)); + } + else + { + /* If phyId is valid */ + /* Get request from free IORequests */ + ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK); + pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests)); /**/ + /* If no LL Control request entry available */ + if ( agNULL == pRequest ) + { + pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeReservedRequests)); + /* If no LL Control request entry available */ + if(agNULL != pRequest) + { + using_reserved = agTRUE; + SA_DBG1(("saPhyStop: using saRoot->freeReservedRequests\n")); + } + else + { + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + SA_DBG1(("saPhyStop, No request from free list Not using saRoot->freeReservedRequests\n")); + smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "7b"); + return AGSA_RC_BUSY; + } + } + /* Remove the request from free list */ + if( using_reserved ) + { + saLlistIORemove(&(saRoot->freeReservedRequests), &(pRequest->linkNode)); + } + else + { + saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode)); + } + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + SA_ASSERT((!pRequest->valid), "The pRequest is in use"); + saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag; + saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest; + saRoot->IOMap[pRequest->HTag].agContext = agContext; + pRequest->valid = agTRUE; + + /* build IOMB command and send to SPC */ + ret = mpiPhyStopCmd(agRoot, pRequest->HTag, phyId, queueNum); + if (AGSA_RC_SUCCESS != ret) + { + /* remove the request from IOMap */ + saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF; + saRoot->IOMap[pRequest->HTag].IORequest = agNULL; + saRoot->IOMap[pRequest->HTag].agContext = agNULL; + + ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK); + /* return the request to free pool */ + if(saLlistIOGetCount(&(saRoot->freeReservedRequests)) < SA_RESERVED_REQUEST_COUNT) + { + SA_DBG2(("saPhyStop: saving pRequest (%p) for later use\n", pRequest)); + saLlistIOAdd(&(saRoot->freeReservedRequests), &(pRequest->linkNode)); + } + else + { + /* return the request to free pool */ + saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode)); + } + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + SA_DBG1(("saPhyStop, sending IOMB failed\n" )); + } + } + + smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "7b"); + + return ret; +} + +/******************************************************************************/ +/*! \brief CallBack Routine to stop a Phy + * + * CallBack for Stop a Phy + * + * \param agRoot handles for this instance of SAS/SATA hardware + * \param phyId the phy id of the link will be stopped + * \param status the status of the phy + * \param agContext the context of the saPhyStop + * + * \return If phy is stopped successfully + * - \e AGSA_RC_SUCCESS phy is stopped successfully + * - \e AGSA_RC_FAILURE phy is not stopped successfully + */ +/*******************************************************************************/ +GLOBAL bit32 siPhyStopCB( + agsaRoot_t *agRoot, + bit32 phyId, + bit32 status, + agsaContext_t *agContext, + bit32 portId, + bit32 npipps + ) +{ + agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); + agsaPhy_t *pPhy; + agsaPort_t *pPort; + bit32 ret = AGSA_RC_SUCCESS; + bit32 iomb_status = status; + + smTraceFuncEnter(hpDBG_VERY_LOUD,"7c"); + + /* sanity check */ + SA_ASSERT((agNULL != agRoot), ""); + + /* If phyId is invalid, return failure */ + if ( phyId >= saRoot->phyCount ) + { + ret = AGSA_RC_FAILURE; + SA_DBG1(("siPhyStopCB: phy%d - failure with phyId\n", phyId)); + /* makeup for CB */ + status = (status << SHIFT8) | phyId; + status |= ((npipps & PORT_STATE_MASK) << SHIFT16); + ossaHwCB(agRoot, agNULL, OSSA_HW_EVENT_PHY_STOP_STATUS, status, agContext, agNULL); + } + /* If phyId is valid */ + else + { + pPhy = &(saRoot->phys[phyId]); + + /* get the port of the phy */ + pPort = pPhy->pPort; + + /* makeup for CB */ + status = (status << SHIFT8) | phyId; + status |= ((npipps & PORT_STATE_MASK) << SHIFT16); + /* Callback to stop phy */ + if ( agNULL != pPort ) + { + if ( iomb_status == OSSA_SUCCESS && (OSSA_PORT_INVALID == (npipps & PORT_STATE_MASK) )) + { + SA_DBG1(("siPhyStopCB: phy%d invalidating port\n", phyId)); + /* invalid port state, remove the port */ + pPort->status |= PORT_INVALIDATING; + saRoot->PortMap[portId].PortStatus |= PORT_INVALIDATING; + /* invalid the port */ + siPortInvalid(agRoot, pPort); + /* map out the portmap */ + saRoot->PortMap[pPort->portId].PortContext = agNULL; + saRoot->PortMap[pPort->portId].PortID = PORT_MARK_OFF; + saRoot->PortMap[pPort->portId].PortStatus |= PORT_INVALIDATING; + } + ossaHwCB(agRoot, &(pPort->portContext), OSSA_HW_EVENT_PHY_STOP_STATUS, status, agContext, agNULL); + } + else + { + SA_DBG1(("siPhyStopCB: phy%d - Port is not established\n", phyId)); + ossaHwCB(agRoot, agNULL, OSSA_HW_EVENT_PHY_STOP_STATUS, status, agContext, agNULL); + } + + /* set PHY_STOPPED status */ + PHY_STATUS_SET(pPhy, PHY_STOPPED); + + /* Exclude the phy from a port */ + if ( agNULL != pPort ) + { + /* Acquire port list lock */ + ossaSingleThreadedEnter(agRoot, LL_PORT_LOCK); + + /* Delete the phy from the port */ + pPort->phyMap[phyId] = agFALSE; + saRoot->phys[phyId].pPort = agNULL; + + /* Release port list lock */ + ossaSingleThreadedLeave(agRoot, LL_PORT_LOCK); + } + } + + smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "7c"); + + /* return */ + return ret; +} + +/******************************************************************************/ +/*! \brief Initiate a Local PHY control command + * + * This function is called to initiate a PHY control command to the local PHY. + * The completion of this function is reported in ossaLocalPhyControlCB() + + * + * \param agRoot handles for this instance of SAS/SATA hardware + * \param agContext the context of this API + * \param phyId phy number + * \param phyOperation + * one of AGSA_PHY_LINK_RESET, AGSA_PHY_HARD_RESET, AGSA_PHY_ENABLE_SPINUP + * + * \return + * - none + */ +/*******************************************************************************/ +GLOBAL bit32 saLocalPhyControl( + agsaRoot_t *agRoot, + agsaContext_t *agContext, + bit32 queueNum, + bit32 phyId, + bit32 phyOperation, + ossaLocalPhyControlCB_t agCB + ) +{ + agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); + agsaIORequestDesc_t *pRequest; + agsaPhyErrCounters_t errorParam; + bit32 ret = AGSA_RC_SUCCESS; + bit32 value, value1, value2, copyPhyId; + bit32 count = 100; + bit32 using_reserved = agFALSE; + + + /* sanity check */ + SA_ASSERT((agNULL != saRoot), ""); + if(saRoot == agNULL) + { + SA_DBG1(("saLocalPhyControl: saRoot == agNULL\n")); + return(AGSA_RC_FAILURE); + } + smTraceFuncEnter(hpDBG_VERY_LOUD,"7d"); + + si_memset(&errorParam,0,sizeof(agsaPhyErrCounters_t)); + SA_DBG2(("saLocalPhyControl: phy%d operation %08X\n", phyId, phyOperation)); + + switch(phyOperation) + { + case AGSA_PHY_LINK_RESET: + case AGSA_PHY_HARD_RESET: + case AGSA_PHY_NOTIFY_ENABLE_SPINUP: + case AGSA_PHY_BROADCAST_ASYNCH_EVENT: + case AGSA_PHY_COMINIT_OOB: + { + /* Get request from free IORequests */ + ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK); + pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests)); /**/ + + /* If no LL Control request entry available */ + if ( agNULL == pRequest ) + { + pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeReservedRequests)); + /* If no LL Control request entry available */ + if(agNULL != pRequest) + { + using_reserved = agTRUE; + SA_DBG1(("saLocalPhyControl, using saRoot->freeReservedRequests\n")); + } + else + { + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + SA_DBG1(("saLocalPhyControl, No request from free list Not using saRoot->freeReservedRequests\n")); + smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "7d"); + return AGSA_RC_BUSY; + } + } + if( using_reserved ) + { + saLlistIORemove(&(saRoot->freeReservedRequests), &(pRequest->linkNode)); + } + else + { + saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode)); + } + /* Remove the request from free list */ + SA_ASSERT((!pRequest->valid), "The pRequest is in use"); + pRequest->completionCB = (void*)agCB; + // pRequest->abortCompletionCB = agCB; + saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag; + saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest; + saRoot->IOMap[pRequest->HTag].agContext = agContext; + pRequest->valid = agTRUE; + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + + /* Build the local phy control IOMB command and send to SPC */ + ret = mpiLocalPhyControlCmd(agRoot, pRequest->HTag, phyId, phyOperation, queueNum); + if (AGSA_RC_SUCCESS != ret) + { + /* remove the request from IOMap */ + saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF; + saRoot->IOMap[pRequest->HTag].IORequest = agNULL; + saRoot->IOMap[pRequest->HTag].agContext = agNULL; + pRequest->valid = agFALSE; + + ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK); + /* return the request to free pool */ + if(saLlistIOGetCount(&(saRoot->freeReservedRequests)) < SA_RESERVED_REQUEST_COUNT) + { + SA_DBG1(("saLocalPhyControl: saving pRequest (%p) for later use\n", pRequest)); + saLlistIOAdd(&(saRoot->freeReservedRequests), &(pRequest->linkNode)); + } + else + { + /* return the request to free pool */ + saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode)); + } + SA_DBG1(("saLocalPhyControl, sending IOMB failed\n" )); + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + return ret; + } + } + break; + case AGSA_PHY_GET_ERROR_COUNTS: + { + if(smIS_SPCV(agRoot)) + { + + SA_ASSERT((smIS_SPC(agRoot)), "SPC only"); + SA_DBG1(("saLocalPhyControl: V AGSA_PHY_GET_ERROR_COUNTS\n" )); + smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "7d"); + return AGSA_RC_FAILURE; + } + /* If phyId is invalid, return failure */ + if ( phyId >= saRoot->phyCount ) + { + ret = AGSA_RC_FAILURE; + si_memset(&errorParam, 0, sizeof(agsaPhyErrCounters_t)); + SA_DBG1(("saLocalPhyControl: phy%d - failure with phyId\n", phyId)); + /* call back with the status */ + + if( agCB == agNULL ) + { + ossaLocalPhyControlCB(agRoot, agContext, phyId, phyOperation, OSSA_FAILURE, (void *)&errorParam); + } + else + { + agCB(agRoot, agContext, phyId, phyOperation, OSSA_FAILURE, (void *)&errorParam); + } + smTraceFuncExit(hpDBG_VERY_LOUD, 'c', "7d"); + return ret; + } + /* save phyId */ + copyPhyId = phyId; + /* map 0x030000 or 0x040000 based on phyId to BAR4(0x20), BAT2(win) to access the register */ + if (phyId < 4) + { + /* for phyId = 0, 1, 2, 3 */ + value = 0x030000; + } + else + { + /* for phyId = 4, 5, 6, 7 */ + phyId = phyId - 4; + value = 0x040000; + } + + /* Need to make sure DEVICE_LCLK_GENERATION register bit 6 is 0 */ + value1 = ossaHwRegReadExt(agRoot, PCIBAR2, SPC_REG_DEVICE_LCLK); + + SA_DBG3(("saLocalPhyControl: TOP DEVICE LCLK Register value = %08X\n", value1)); + /* If LCLK_CLEAR bit set then disable it */ + if (value1 & DEVICE_LCLK_CLEAR) + { + ossaHwRegWriteExt(agRoot, PCIBAR2, SPC_REG_DEVICE_LCLK, (value1 & 0xFFFFFFBF) ); + SA_DBG3(("saLocalPhyControl: TOP DEVICE LCLK value = %08X\n", (value1 & 0xFFFFFFBF))); + } + + if (AGSA_RC_FAILURE == siBar4Shift(agRoot, value)) + { + SA_DBG1(("saLocalPhyControl:Shift Bar4 to 0x%x failed\n", value)); + phyId = copyPhyId; + /* call back with the status */ + + if( agCB == agNULL ) + { + ossaLocalPhyControlCB(agRoot, agContext, phyId, phyOperation, OSSA_FAILURE, (void *)&errorParam); + } + else + { + agCB(agRoot, agContext, phyId, phyOperation, OSSA_FAILURE, (void *)&errorParam); + } + + smTraceFuncExit(hpDBG_VERY_LOUD, 'd', "7d"); + return AGSA_RC_FAILURE; + } + + /* set LCLK = 1 and LCLK_CLEAR = 0 */ + SPC_WRITE_COUNTER_CNTL(phyId, LCLK); + + /* LCLK bit should be low to be able to read error registers */ + while((value = SPC_READ_COUNTER_CNTL(phyId)) & LCLK) + { + if(--count == 0) + { + SA_DBG1(("saLocalPhyControl: Timeout,SPC_COUNTER_CNTL value = %08X\n", value)); + ret = AGSA_RC_FAILURE; + break; + } + } /* while */ + + value = SPC_READ_COUNTER_CNTL(phyId); + SA_DBG3(("saLocalPhyControl: SPC_COUNTER_CNTL value = %08X\n", value)); + + /* invalidDword */ + errorParam.invalidDword = SPC_READ_INV_DW_COUNT(phyId); + /* runningDisparityError */ + errorParam.runningDisparityError = SPC_READ_DISP_ERR_COUNT(phyId); + /* lossOfDwordSynch */ + errorParam.lossOfDwordSynch = SPC_READ_LOSS_DW_COUNT(phyId); + /* phyResetProblem */ + errorParam.phyResetProblem = SPC_READ_PHY_RESET_COUNT(phyId); + /* codeViolation */ + errorParam.codeViolation = SPC_READ_CODE_VIO_COUNT(phyId); + /* never occurred in SPC8x6G */ + errorParam.elasticityBufferOverflow = 0; + errorParam.receivedErrorPrimitive = 0; + errorParam.inboundCRCError = 0; + + SA_DBG3(("saLocalPhyControl:INV_DW_COUNT 0x%x\n", SPC_READ_INV_DW_COUNT(phyId))); + SA_DBG3(("saLocalPhyControl:DISP_ERR_COUNT 0x%x\n", SPC_READ_DISP_ERR_COUNT(phyId))); + SA_DBG3(("saLocalPhyControl:LOSS_DW_COUNT 0x%x\n", SPC_READ_LOSS_DW_COUNT(phyId))); + SA_DBG3(("saLocalPhyControl:PHY_RESET_COUNT 0x%x\n", SPC_READ_PHY_RESET_COUNT(phyId))); + SA_DBG3(("saLocalPhyControl:CODE_VIOLATION_COUNT 0x%x\n", SPC_READ_CODE_VIO_COUNT(phyId))); + + /* Shift back to BAR4 original address */ + if (AGSA_RC_FAILURE == siBar4Shift(agRoot, 0x0)) + { + SA_DBG1(("saLocalPhyControl:Shift Bar4 to 0x%x failed\n", 0x0)); + ret = AGSA_RC_FAILURE; + } + + /* restore back the Top Device LCLK generation register value */ + ossaHwRegWriteExt(agRoot, PCIBAR2, SPC_REG_DEVICE_LCLK, value1); + + /* restore phyId */ + phyId = copyPhyId; + /* call back with the status */ + + if (AGSA_RC_SUCCESS == ret) + { + if( agCB == agNULL ) + { + ossaLocalPhyControlCB(agRoot, agContext, copyPhyId, phyOperation, OSSA_SUCCESS, (void *)&errorParam); + } + else + { + agCB(agRoot, agContext, copyPhyId, phyOperation, OSSA_SUCCESS, (void *)&errorParam); + } + } + else + { + if( agCB == agNULL ) + { + ossaLocalPhyControlCB(agRoot, agContext, phyId, phyOperation, OSSA_FAILURE, (void *)&errorParam); + } + else + { + agCB(agRoot, agContext, phyId, phyOperation, OSSA_FAILURE, (void *)&errorParam); + } + } + break; + } + case AGSA_PHY_CLEAR_ERROR_COUNTS: + { + if(smIS_SPCV(agRoot)) + { + + SA_ASSERT((smIS_SPC(agRoot)), "SPC only"); + SA_DBG1(("saLocalPhyControl: V AGSA_PHY_CLEAR_ERROR_COUNTS\n" )); + smTraceFuncExit(hpDBG_VERY_LOUD, 'e', "7d"); + return AGSA_RC_FAILURE; + } + /* If phyId is invalid, return failure */ + if ( phyId >= saRoot->phyCount ) + { + si_memset(&errorParam, 0, sizeof(agsaPhyErrCountersPage_t)); + SA_DBG3(("saLocalPhyControl(CLEAR): phy%d - failure with phyId\n", phyId)); + /* call back with the status */ + if( agCB == agNULL ) + { + ossaLocalPhyControlCB(agRoot, agContext, phyId, phyOperation, OSSA_FAILURE, (void *)&errorParam); + } + else + { + agCB(agRoot, agContext, phyId, phyOperation, OSSA_FAILURE, (void *)&errorParam); + } + smTraceFuncExit(hpDBG_VERY_LOUD, 'f', "7d"); + return AGSA_RC_FAILURE; + } + /* save phyId */ + copyPhyId = phyId; + /* map 0x030000 or 0x040000 based on phyId to BAR4(0x20), BAT2(win) to access the register */ + if (phyId < 4) + { + /* for phyId = 0, 1, 2, 3 */ + value = 0x030000; + } + else + { + /* for phyId = 4, 5, 6, 7 */ + phyId = phyId - 4; + value = 0x040000; + } + /* Need to make sure DEVICE_LCLK_GENERATION register bit 6 is 1 */ + value2 = ossaHwRegReadExt(agRoot, PCIBAR2, SPC_REG_DEVICE_LCLK); + + SA_DBG3(("saLocalPhyControl: TOP DEVICE LCLK Register value = %08X\n", value2)); + /* If LCLK_CLEAR bit not set then set it */ + if ((value2 & DEVICE_LCLK_CLEAR) == 0) + { + ossaHwRegWriteExt(agRoot, PCIBAR2, SPC_REG_DEVICE_LCLK, (value2 | DEVICE_LCLK_CLEAR) ); + SA_DBG3(("saLocalPhyControl: TOP DEVICE LCLK value = %08X\n", (value2 & 0xFFFFFFBF))); + } + + if (AGSA_RC_FAILURE == siBar4Shift(agRoot, value)) + { + SA_DBG1(("saLocalPhyControl(CLEAR):Shift Bar4 to 0x%x failed\n", value)); + phyId = copyPhyId; + /* call back with the status */ + if( agCB == agNULL ) + { + ossaLocalPhyControlCB(agRoot, agContext, phyId, phyOperation, OSSA_FAILURE, (void *)&errorParam); + } + else + { + agCB(agRoot, agContext, phyId, phyOperation, OSSA_FAILURE, (void *)&errorParam); + } + smTraceFuncExit(hpDBG_VERY_LOUD, 'g', "7d"); + return AGSA_RC_FAILURE; + } + + /* read Counter Control register */ + value1 = SPC_READ_COUNTER_CNTL(phyId); + SA_DBG3(("saLocalPhyControl(CLEAR): SPC_COUNTER_CNTL value = %08X\n", value1)); + /* set LCLK and LCLK_CLEAR */ + SPC_WRITE_COUNTER_CNTL(phyId, (LCLK_CLEAR | LCLK)); + /* read back the value of register */ + /* poll LCLK bit = 0 */ + while((value = SPC_READ_COUNTER_CNTL(phyId)) & LCLK) + { + if(--count == 0) + { + SA_DBG1(("saLocalPhyControl: Timeout,SPC_COUNTER_CNTL value = %08X\n", value)); + ret = AGSA_RC_FAILURE; + break; + } + } /* while */ + + value = SPC_READ_COUNTER_CNTL(phyId); + SA_DBG3(("saLocalPhyControl(CLEAR): SPC_COUNTER_CNTL value = %08X\n", value)); + + /* restore the value */ + SPC_WRITE_COUNTER_CNTL(phyId, value1); + + /* Shift back to BAR4 original address */ + if (AGSA_RC_FAILURE == siBar4Shift(agRoot, 0x0)) + { + SA_DBG1(("saLocalPhyControl:Shift Bar4 to 0x%x failed\n", 0x0)); + ret = AGSA_RC_FAILURE; + } + + /* restore back the Top Device LCLK generation register value */ + ossaHwRegWriteExt(agRoot, PCIBAR2, SPC_REG_DEVICE_LCLK, value2); + + /* restore phyId */ + phyId = copyPhyId; + /* call back with the status */ + if (AGSA_RC_SUCCESS == ret) + { + if( agCB == agNULL ) + { + ossaLocalPhyControlCB(agRoot, agContext, phyId, phyOperation, OSSA_SUCCESS, agNULL); + } + else + { + agCB(agRoot, agContext, phyId, phyOperation, OSSA_SUCCESS, agNULL); + } + } + else + { + if( agCB == agNULL ) + { + ossaLocalPhyControlCB(agRoot, agContext, phyId, phyOperation, OSSA_FAILURE, (void *)&errorParam); + } + else + { + agCB(agRoot, agContext, phyId, phyOperation, OSSA_FAILURE, (void *)&errorParam); + } + } + break; + } + case AGSA_PHY_GET_BW_COUNTS: + { + SA_ASSERT((smIS_SPC(agRoot)), "SPCv only"); + SA_DBG1(("saLocalPhyControl: AGSA_PHY_GET_BW_COUNTS\n" )); + break; + } + + default: + ret = AGSA_RC_FAILURE; + SA_ASSERT(agFALSE, "(saLocalPhyControl) Unknown operation"); + break; + } + + smTraceFuncExit(hpDBG_VERY_LOUD, 'h', "7d"); + return ret; +} + + +GLOBAL bit32 saGetPhyProfile( + agsaRoot_t *agRoot, + agsaContext_t *agContext, + bit32 queueNum, + bit32 ppc, + bit32 phyId + ) +{ + bit32 ret = AGSA_RC_SUCCESS; + + agsaLLRoot_t *saRoot = agNULL; + agsaPhyErrCountersPage_t errorParam; + + ossaLocalPhyControlCB_t agCB = ossaGetPhyProfileCB; + + /* sanity check */ + SA_ASSERT((agNULL != agRoot), ""); + saRoot = (agsaLLRoot_t *) (agRoot->sdkData); + SA_ASSERT((agNULL != saRoot), ""); + + if(saRoot == agNULL) + { + SA_DBG3(("saGetPhyProfile : saRoot is NULL")); + return AGSA_RC_FAILURE; + } + + SA_DBG1(("saGetPhyProfile: ppc 0x%x phyID %d\n", ppc,phyId)); + + switch(ppc) + { + case AGSA_SAS_PHY_ERR_COUNTERS_PAGE: + { + if(smIS_SPCV(agRoot)) + { + + SA_DBG1(("saGetPhyProfile: V AGSA_SAS_PHY_ERR_COUNTERS_PAGE\n" )); + + ret = mpiGetPhyProfileCmd( agRoot,agContext,ppc ,phyId,agCB); + smTraceFuncExit(hpDBG_VERY_LOUD, 'i', "7d"); + return ret; + } + } + case AGSA_SAS_PHY_ERR_COUNTERS_CLR_PAGE: + { + /* If phyId is invalid, return failure */ + if ( phyId >= saRoot->phyCount ) + { + si_memset(&errorParam, 0, sizeof(agsaPhyErrCountersPage_t)); + SA_DBG3(("saGetPhyProfile(CLEAR): phy%d - failure with phyId\n", phyId)); + /* call back with the status */ + ossaGetPhyProfileCB(agRoot, agContext, phyId, ppc, OSSA_FAILURE, (void *)&errorParam); + smTraceFuncExit(hpDBG_VERY_LOUD, 'j', "7d"); + return AGSA_RC_FAILURE; + } + if(smIS_SPCV(agRoot)) + { + SA_DBG1(("saGetPhyProfile: V AGSA_SAS_PHY_ERR_COUNTERS_CLR_PAGE\n" )); + + ret = mpiGetPhyProfileCmd( agRoot,agContext, ppc,phyId,agCB); + smTraceFuncExit(hpDBG_VERY_LOUD, 'k', "7d"); + return ret; + } + + } + case AGSA_SAS_PHY_BW_COUNTERS_PAGE: + { + SA_DBG1(("saGetPhyProfile: AGSA_SAS_PHY_BW_COUNTERS_PAGE\n" )); + ret = mpiGetPhyProfileCmd( agRoot,agContext,ppc ,phyId,agCB); + break; + } + case AGSA_SAS_PHY_ANALOG_SETTINGS_PAGE: + { + SA_DBG1(("saGetPhyProfile: AGSA_SAS_PHY_ANALOG_SETTINGS_PAGE\n" )); + ret = mpiGetPhyProfileCmd( agRoot,agContext,ppc ,phyId,agCB); + break; + } + + case AGSA_SAS_PHY_GENERAL_STATUS_PAGE: + { + SA_DBG1(("saGetPhyProfile: AGSA_SAS_PHY_GENERAL_STATUS_PAGE\n" )); + ret = mpiGetPhyProfileCmd( agRoot,agContext,ppc ,phyId,agCB); + break; + } + case AGSA_PHY_SNW3_PAGE: + { + SA_DBG1(("saGetPhyProfile: AGSA_PHY_SNW3_PAGE\n" )); + ret = mpiGetPhyProfileCmd( agRoot,agContext,ppc ,phyId,agCB); + break; + } + case AGSA_PHY_RATE_CONTROL_PAGE: + { + SA_DBG1(("saGetPhyProfile: AGSA_PHY_RATE_CONTROL_PAGE\n" )); + ret = mpiGetPhyProfileCmd( agRoot,agContext,ppc ,phyId,agCB); + break; + } + case AGSA_SAS_PHY_OPEN_REJECT_RETRY_BACKOFF_THRESHOLD_PAGE: + { + SA_DBG1(("saGetPhyProfile: AGSA_SAS_PHY_OPEN_REJECT_RETRY_BACKOFF_THRESHOLD_PAGE\n" )); + ret = mpiGetPhyProfileCmd( agRoot,agContext,ppc ,phyId,agCB); + break; + } + + default: + SA_DBG1(("saGetPhyProfile: Unknown operation 0x%X\n",ppc )); + SA_ASSERT(agFALSE, "saGetPhyProfile Unknown operation " ); + break; + + } + return ret; + +} + + +GLOBAL bit32 saSetPhyProfile ( + agsaRoot_t *agRoot, + agsaContext_t *agContext, + bit32 queueNum, + bit32 ppc, + bit32 length, + void *buffer, + bit32 phyID + ) +{ + bit32 ret = AGSA_RC_SUCCESS; + + SA_DBG1(("saSetPhyProfile: ppc 0x%x length 0x%x phyID %d\n", ppc,length,phyID)); + + switch(ppc) + { + case AGSA_SAS_PHY_ANALOG_SETTINGS_PAGE: + { + SA_DBG1(("saSetPhyProfile: AGSA_SAS_PHY_ANALOG_SETTINGS_PAGE\n" )); + ret = mpiSetPhyProfileCmd( agRoot,agContext,ppc ,phyID,length,buffer); + break; + } + case AGSA_PHY_SNW3_PAGE: + { + SA_DBG1(("saSetPhyProfile: AGSA_PHY_SNW3_PAGE\n" )); + ret = mpiSetPhyProfileCmd( agRoot,agContext,ppc ,phyID,length,buffer); + break; + } + case AGSA_PHY_RATE_CONTROL_PAGE: + { + SA_DBG1(("saSetPhyProfile: AGSA_PHY_RATE_CONTROL_PAGE\n" )); + ret = mpiSetPhyProfileCmd( agRoot,agContext,ppc ,phyID,length,buffer); + break; + } + case AGSA_SAS_PHY_MISC_PAGE: + { + SA_DBG1(("saSetPhyProfile: AGSA_SAS_PHY_MISC_PAGE\n")); + ret = mpiSetPhyProfileCmd( agRoot,agContext,ppc ,phyID,length,buffer); + break; + } + + default: + SA_DBG1(("saSetPhyProfile: Unknown operation 0x%X\n",ppc )); + SA_ASSERT(agFALSE, "saSetPhyProfile Unknown operation " ); + ret = AGSA_RC_FAILURE; + break; + } + return ret; +} + + +/******************************************************************************/ +/*! \brief Initiate a HW Event Ack command + * + * This function is called to initiate a HW Event Ack command to the SPC. + * The completion of this function is reported in ossaHwEventAckCB(). + * + * \param agRoot handles for this instance of SAS/SATA hardware + * \param agContext the context of this API + * \param queueNum queue number + * \param eventSource point to the event source structure + * \param param0 + * \param param1 + * + * \return + * - none + */ +/*******************************************************************************/ +GLOBAL bit32 saHwEventAck( + agsaRoot_t *agRoot, + agsaContext_t *agContext, + bit32 queueNum, + agsaEventSource_t *eventSource, + bit32 param0, + bit32 param1 + ) +{ + agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); + agsaIORequestDesc_t *pRequest; + agsaPortContext_t *agPortContext; + agsaPort_t *pPort = agNULL; + agsaSASHwEventAckCmd_t payload; + bit32 phyportid; + bit32 ret = AGSA_RC_SUCCESS; + bit32 using_reserved = agFALSE; + + smTraceFuncEnter(hpDBG_VERY_LOUD,"7e"); + + /* sanity check */ + SA_ASSERT((agNULL != saRoot), ""); + if(saRoot == agNULL) + { + SA_DBG1(("saHwEventAck: saRoot == agNULL\n")); + return(AGSA_RC_FAILURE); + } + + SA_DBG2(("saHwEventAck: agContext %p eventSource %p\n", agContext, eventSource)); + SA_DBG1(("saHwEventAck: event 0x%x param0 0x%x param1 0x%x\n", eventSource->event, param0, param1)); + + agPortContext = eventSource->agPortContext; + + /* Get request from free IORequests */ + ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK); + pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests)); /**/ + + /* If no LL Control request entry available */ + if ( agNULL == pRequest ) + { + pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeReservedRequests)); /**/ + if(agNULL != pRequest) + { + using_reserved = agTRUE; + SA_DBG1(("saHwEventAck, using saRoot->freeReservedRequests\n")); + } + else + { + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + /* If no LL Control request entry available */ + SA_DBG1(("saHwEventAck, No request from free list Not using saRoot->freeReservedRequests\n")); + smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "7e"); + return AGSA_RC_BUSY; + } + } + if( using_reserved ) + { + saLlistIORemove(&(saRoot->freeReservedRequests), &(pRequest->linkNode)); + } + else + { + /* Remove the request from free list */ + saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode)); + } + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + SA_ASSERT((!pRequest->valid), "The pRequest is in use"); + + SA_DBG2(("saHwEventAck: queueNum 0x%x HTag 0x%x\n",queueNum ,pRequest->HTag)); + + saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag; + saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest; + saRoot->IOMap[pRequest->HTag].agContext = agContext; + pRequest->valid = agTRUE; + + /* build IOMB command and send to SPC */ + /* set payload to zeros */ + si_memset(&payload, 0, sizeof(agsaSASHwEventAckCmd_t)); + + /* find port id */ + if (agPortContext) + { + pPort = (agsaPort_t *) (agPortContext->sdkData); + if (pPort) + { + if(eventSource->event == OSSA_HW_EVENT_PHY_DOWN) + { + pPort->tobedeleted = agTRUE; + } + SA_DBG3(("saHwEventAck,pPort->portId %X\n",pPort->portId)); + + if(smIS_SPC(agRoot)) + { + /* fillup PORT_ID field */ + phyportid = pPort->portId & 0xF; + } + else + { + /* fillup PORT_ID field */ + phyportid = pPort->portId & 0xFF; + + } + } + else + { + /* pPort is NULL - set PORT_ID to not intialized */ + if(smIS_SPC(agRoot)) + { + phyportid = 0xF; + } + else + { + phyportid = 0xFF; + } + } + } + else + { + /* agPortContext is NULL - set PORT_ID to not intialized */ + if(smIS_SPC(agRoot)) + { + phyportid = 0xF; + } + else + { + phyportid = 0xFF; + } + } + + pRequest->pPort = pPort; + + SA_DBG3(("saHwEventAck,eventSource->param 0x%X\n",eventSource->param)); + SA_DBG3(("saHwEventAck,eventSource->event 0x%X\n",eventSource->event)); + + if(smIS_SPC(agRoot)) + { + /* fillup up PHY_ID */ + phyportid |= ((eventSource->param & 0x0000000F) << 4); + /* fillup SEA field */ + phyportid |= (eventSource->event & 0x0000FFFF) << 8; + SA_DBG3(("saHwEventAck: portId 0x%x phyId 0x%x SEA 0x%x\n", phyportid & 0xF, + eventSource->param & 0x0000000F, eventSource->event & 0x0000FFFF)); + } + else + { + /* fillup up PHY_ID */ + phyportid |= ((eventSource->param & 0x000000FF) << SHIFT24); + /* fillup SEA field */ + phyportid |= (eventSource->event & 0x00FFFFFF) << SHIFT8; + SA_DBG3(("saHwEventAck: portId 0x%x phyId 0x%x SEA 0x%x\n", phyportid & 0xFF, + eventSource->param & 0x0000000F, eventSource->event & 0x0000FFFF)); + } + + pRequest->HwAckType = (bit16)phyportid; + + SA_DBG1(("saHwEventAck,phyportid 0x%X HwAckType 0x%X\n",phyportid,pRequest->HwAckType)); + /* set tag */ + OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSASHwEventAckCmd_t, tag), pRequest->HTag); + OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSASHwEventAckCmd_t, sEaPhyIdPortId), phyportid); + OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSASHwEventAckCmd_t, Param0), param0); + OSSA_WRITE_LE_32(agRoot, &payload, OSSA_OFFSET_OF(agsaSASHwEventAckCmd_t, Param1), param1); + + /* build IOMB command and send to SPC */ + + if(smIS_SPC(agRoot)) + { + ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_SPC_SAS_HW_EVENT_ACK, IOMB_SIZE64, queueNum); + } + else + { + ret = mpiBuildCmd(agRoot, (bit32 *)&payload, MPI_CATEGORY_SAS_SATA, OPC_INB_SAS_HW_EVENT_ACK, IOMB_SIZE64, queueNum); + } + + if (AGSA_RC_SUCCESS != ret) + { + /* remove the request from IOMap */ + saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF; + saRoot->IOMap[pRequest->HTag].IORequest = agNULL; + saRoot->IOMap[pRequest->HTag].agContext = agNULL; + pRequest->valid = agFALSE; + + ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK); + /* return the request to free pool */ + if(saLlistIOGetCount(&(saRoot->freeReservedRequests)) < SA_RESERVED_REQUEST_COUNT) + { + SA_DBG1(("saHwEventAck: saving pRequest (%p) for later use\n", pRequest)); + saLlistIOAdd(&(saRoot->freeReservedRequests), &(pRequest->linkNode)); + } + else + { + /* return the request to free pool */ + saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode)); + } + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + SA_DBG1(("saHwEventAck, sending IOMB failed\n" )); + } + smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "7e"); + + return ret; +} + + +GLOBAL bit32 saVhistCapture( + agsaRoot_t *agRoot, + agsaContext_t *agContext, + bit32 queueNum, + bit32 Channel, + bit32 NumBitLo, + bit32 NumBitHi, + bit32 PcieAddrLo, + bit32 PcieAddrHi, + bit32 ByteCount ) +{ + + agsaLLRoot_t *saRoot = (agsaLLRoot_t *)(agRoot->sdkData); + agsaIORequestDesc_t *pRequest; + bit32 ret = AGSA_RC_SUCCESS; + bit32 using_reserved = agFALSE; + + smTraceFuncEnter(hpDBG_VERY_LOUD,"3N"); + + /* sanity check */ + SA_ASSERT((agNULL != agRoot), ""); + + SA_DBG1(("saVhistCapture:Channel 0x%08X 0x%08X%08X 0x%08X%08X count 0x%X\n",Channel, NumBitHi, NumBitLo ,PcieAddrHi,PcieAddrLo,ByteCount)); + + { + /* Get request from free IORequests */ + ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK); + pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeIORequests)); /* */ + /* If no LL Control request entry available */ + if ( agNULL == pRequest ) + { + pRequest = (agsaIORequestDesc_t *)saLlistIOGetHead(&(saRoot->freeReservedRequests)); + /* If no LL Control request entry available */ + if(agNULL != pRequest) + { + using_reserved = agTRUE; + SA_DBG1((", using saRoot->freeReservedRequests\n")); + } + else + { + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + SA_DBG1(("saVhistCapture: No request from free list Not using saRoot->freeReservedRequests\n")); + smTraceFuncExit(hpDBG_VERY_LOUD, 'a', "3N"); + return AGSA_RC_BUSY; + } + } + SA_ASSERT((!pRequest->valid), "The pRequest is in use"); + pRequest->valid = agTRUE; + /* If LL Control request entry avaliable */ + if( using_reserved ) + { + saLlistIORemove(&(saRoot->freeReservedRequests), &(pRequest->linkNode)); + } + else + { + /* Remove the request from free list */ + saLlistIORemove(&(saRoot->freeIORequests), &(pRequest->linkNode)); + } + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + + saRoot->IOMap[pRequest->HTag].Tag = pRequest->HTag; + saRoot->IOMap[pRequest->HTag].IORequest = (void *)pRequest; + saRoot->IOMap[pRequest->HTag].agContext = agContext; + pRequest->valid = agTRUE; + + /* Build the VhisCapture IOMB command and send to SPCv */ + + ret = mpiVHistCapCmd(agRoot,agContext, queueNum, Channel, NumBitLo, NumBitHi ,PcieAddrLo, PcieAddrHi, ByteCount); + if (AGSA_RC_SUCCESS != ret) + { + /* remove the request from IOMap */ + saRoot->IOMap[pRequest->HTag].Tag = MARK_OFF; + saRoot->IOMap[pRequest->HTag].IORequest = agNULL; + saRoot->IOMap[pRequest->HTag].agContext = agNULL; + pRequest->valid = agFALSE; + + ossaSingleThreadedEnter(agRoot, LL_IOREQ_LOCKEQ_LOCK); + /* return the request to free pool */ + if(saLlistIOGetCount(&(saRoot->freeReservedRequests)) < SA_RESERVED_REQUEST_COUNT) + { + SA_DBG1(("saPhyStart: saving pRequest (%p) for later use\n", pRequest)); + saLlistIOAdd(&(saRoot->freeReservedRequests), &(pRequest->linkNode)); + } + else + { + /* return the request to free pool */ + saLlistIOAdd(&(saRoot->freeIORequests), &(pRequest->linkNode)); + } + ossaSingleThreadedLeave(agRoot, LL_IOREQ_LOCKEQ_LOCK); + SA_DBG1(("saVhistCapture: sending IOMB failed\n" )); + } + } + + smTraceFuncExit(hpDBG_VERY_LOUD, 'b', "3N"); + + return ret; +} + |