/*******************************************************************************
Feature API: clTcCkptSvcInit

*******************************************************************************/
int
clTcCkptSvcInit (void)
{
	ClRcT ret_code = CL_OK;

	if (ckpt_svc_hdl == 0)
	{
		ret_code = clCkptInitialize(&ckpt_svc_hdl, NULL, &ckpt_version);	
		if (ret_code != CL_OK)
		{
			printf("clTcCkptSvcInit: Failed %x\n", ret_code);
		}
	}	

	return ret_code;
}
/*******************************************************************************
Feature API: alarmClockCkptInitialize

*******************************************************************************/
ClRcT
alarmClockCkptInitialize (void)
{
    ClRcT ret_code = CL_OK;

    if (ckpt_svc_hdl == 0)
    {
        ret_code = clCkptInitialize(&ckpt_svc_hdl, NULL, &ckpt_version);    
        if (ret_code != CL_OK)
        {
            alarmClockLogWrite(CL_LOG_SEV_ERROR,
                    "alarmClockCkptInitialize(pid=%d): Failed %x\n", 
                    getpid(), ret_code);
        }
    }    
    return ret_code;
}
SaAisErrorT saCkptInitialize(SaCkptHandleT           *saCkptHandle,
                             const SaCkptCallbacksT  *callbacks,
                             SaVersionT              *version)
{
    ClRcT            rc            = CL_OK;
    SaAisErrorT      safRc         = SA_AIS_OK;
    ClCkptCallbacksT ckptCallbacks = {0};
    ClCkptSvcHdlT    ckptHandle    = CL_CKPT_INVALID_HDL;

    /*
     * Validate the input parameters.
     */
    if(saCkptHandle == NULL)
    {
        return SA_AIS_ERR_INVALID_PARAM;
    }

    rc = clASPInitialize();
    if(CL_OK != rc)
    {
        clLogCritical("CKP", "INI",
                      "ASP initialize failed, rc[0x%X]", rc);
        return SA_AIS_ERR_LIBRARY;
    }
    
    /*
     * Copy the callbacks in a global varible and register clovis specific
     * callback functions. These function will inturn call the user 
     * registered callback functions.
     */
    if(callbacks != NULL)
    {
        gSafCallback.saCkptCheckpointOpenCallback = 
            callbacks->saCkptCheckpointOpenCallback; 
        gSafCallback.saCkptCheckpointSynchronizeCallback = 
            callbacks->saCkptCheckpointSynchronizeCallback; 

        if(callbacks->saCkptCheckpointOpenCallback != NULL)
            ckptCallbacks.checkpointOpenCallback = ckptWrapOpenCallback; 
        else
            ckptCallbacks.checkpointOpenCallback = NULL;

        if(callbacks->saCkptCheckpointSynchronizeCallback != NULL)     
            ckptCallbacks.checkpointSynchronizeCallback = 
                ckptWrapSynchronizeCallback; 
        else
            ckptCallbacks.checkpointSynchronizeCallback = NULL;

        /*
         * Call the ckpt client library callback function.
         */
        rc = clCkptInitialize( &ckptHandle,
                &ckptCallbacks, 
                (ClVersionT *) version);
    }    
    else
    {
        /*
         * Call the ckpt client library callback function.
         */
        rc = clCkptInitialize( &ckptHandle,
                NULL, 
                (ClVersionT *) version);

    }

    /*
     * Copy th ckpt handle back to output buffer.
     */
    *saCkptHandle = ckptHandle;                       

    /*
     * Translate the clovis error type to SAF error type.
     */
    clErrorTxlate(rc, &safRc);
    
    return safRc;
}
/**
 * INIT: The below function initializes the checkpoint service client
 * and opens a checkpoint to store data.
 */
ClRcT clCachedCkptInitialize(ClCachedCkptSvcInfoT *serviceInfo,
                             const SaNameT *ckptName,
                             const SaCkptCheckpointCreationAttributesT *ckptAttributes,
                             SaCkptCheckpointOpenFlagsT openFlags,
                             ClUint32T cachSize)
{
    ClRcT			rc = CL_OK;
    SaCkptHandleT		ckptSvcHandle = 0;
    SaCkptCheckpointHandleT	ckptHandle = 0;
    SaVersionT			ckptVersion = {'B', 0x01, 0x01};
    ClTimerTimeOutT		delay = { 0, 500};
    ClInt32T			tries = 0;
    ClCharT cacheName[CL_MAX_NAME_LENGTH];
    ClUint32T                   shmSize = clCachedCkptShmSizeGet(cachSize);
    ClUint32T  *numberOfSections;
    ClUint32T  *sizeOfCache;

    serviceInfo->cachSize = shmSize;

    if(serviceInfo->ckptHandle != CL_HANDLE_INVALID_VALUE)
    {
        clLogWarning("CCK", "INI", "Checkpoint already initialized. Skipping initialization");
        return CL_ERR_ALREADY_EXIST;
    }

    snprintf(cacheName, sizeof(cacheName), "%s_%d", ckptName->value, gIocLocalBladeAddress);

    rc = clOsalSemCreate((ClUint8T*)cacheName, 1, &serviceInfo->cacheSem);
    if(rc != CL_OK)
    {
        ClOsalSemIdT semId = 0;

        if(clOsalSemIdGet((ClUint8T*)cacheName, &semId) != CL_OK)
        {
            clLogError("CCK", "INI", "cache semaphore creation error while fetching semaphore id");
            goto out1;
        }

        if(clOsalSemDelete(semId) != CL_OK)
        {
            clLogError("CCK", "INI", "cache semaphore creation error while deleting old semaphore id");
            goto out1;
        }

        rc = clOsalSemCreate((ClUint8T*)cacheName, 1, &serviceInfo->cacheSem);
    }

    if(ckptAttributes || openFlags)
    {
        if(serviceInfo->ckptSvcHandle == CL_HANDLE_INVALID_VALUE)
        {
            /* Initialize checkpoint service instance */
            do
            {
                rc = clCkptInitialize(&ckptSvcHandle, NULL, (ClVersionT *)&ckptVersion);
            } while(rc != CL_OK && tries++ < 100 && clOsalTaskDelay(delay) == CL_OK);

            if(rc != CL_OK)
            {
                clLogError("CCK", "INI", "Failed to initialize checkpoint service instance. error code [0x%x].", rc);
                goto out2;
            }

            serviceInfo->ckptSvcHandle = ckptSvcHandle;
        }

        /* Create the checkpoint for read and write. */
        do
        {
            rc = clCkptCheckpointOpen(serviceInfo->ckptSvcHandle,
                                      (SaNameT *)ckptName,
                                      (ClCkptCheckpointCreationAttributesT *)ckptAttributes,
                                      openFlags,
                                      0L,
                                      &ckptHandle);
        } while(rc != CL_OK && tries++ < 100 && clOsalTaskDelay(delay) == CL_OK);

        if(rc != CL_OK)
        {
            clLogError("CCK", "INI", "Failed to open checkpoint. error code [0x%x].", rc);
            goto out3;
        }

        serviceInfo->ckptHandle = ckptHandle;
    }

    /* Create shm */

    rc = clOsalShmOpen((ClCharT *)cacheName, CL_CACHED_CKPT_SHM_EXCL_CREATE_FLAGS,
                       CL_CACHED_CKPT_SHM_MODE, &serviceInfo->fd);
    if( CL_ERR_ALREADY_EXIST == CL_GET_ERROR_CODE(rc) )
    {
        rc = clOsalShmOpen((ClCharT *)cacheName, CL_CACHED_CKPT_SHM_OPEN_FLAGS,
                           CL_CACHED_CKPT_SHM_MODE, &serviceInfo->fd);
        if( CL_OK != rc )
        {
            clLogError("CCK", "INI", "Could not open shared memory.");
            goto out4;
        }
    }

    rc = clOsalFtruncate(serviceInfo->fd, shmSize);
    if( CL_OK != rc )
    {
        clLogError("CCK", "INI", "clOsalFtruncate(): error code [0x%x].", rc);
        goto out5;
    }

    rc = clOsalMmap(0, shmSize, CL_CACHED_CKPT_MMAP_PROT_FLAGS,
                    CL_CACHED_CKPT_MMAP_FLAGS, serviceInfo->fd, 0, (void **) &serviceInfo->cache);
    if( CL_OK != rc )
    {
        clLogError("CCK", "INI", "clOsalMmap(): error code [0x%x].", rc);
        goto out5;
    }

    numberOfSections = (ClUint32T *)(serviceInfo->cache);
    sizeOfCache = (ClUint32T *)(numberOfSections + 1);
    *numberOfSections = 0;
    *sizeOfCache = 0;

    clOsalMsync(serviceInfo->cache, shmSize, MS_SYNC);

    goto out1;

out5:
    clOsalShmClose(&serviceInfo->fd);
out4:
    if(serviceInfo->ckptHandle)
    {
        clCkptCheckpointClose(serviceInfo->ckptHandle);
        serviceInfo->ckptHandle =  CL_HANDLE_INVALID_VALUE;
    }
out3:
    if(serviceInfo->ckptSvcHandle)
    {
        clCkptFinalize(serviceInfo->ckptSvcHandle);
        serviceInfo->ckptSvcHandle =  CL_HANDLE_INVALID_VALUE;
    }
out2:
    clOsalSemDelete(serviceInfo->cacheSem);
out1:
    return rc;
}