@echo off
REM #******************************************************************************
REM #   COPYRIGHT (C) 2013-2014 PMC-SIERRA, INC. ALL RIGHTS RESERVED.
REM # -----------------------------------------------------------------------------
REM #  This software embodies materials and concepts which are proprietary and
REM #  confidential to PMC-Sierra, Inc.  PMC-Sierra distributes this software to
REM #  its customers pursuant to the terms and conditions of the Software License
REM #  Agreement contained in the text file software.lic that is distributed along
REM #  with the software. This software can only be utilized if all terms and
REM #  conditions of the Software License Agreement are accepted. If there are any
REM #  questions, concerns, or if the Software License Agreement text file,
REM #  software.lic, is missing please contact PMC-Sierra for assistance.
REM # -----------------------------------------------------------------------------
REM # $RCSfile: fw_tool.bat,v $
REM #
REM # $Date: 2014-06-05 18:23:34 +0800 (Thu, 05 Jun 2014) $
REM #
REM # $Revision: 94026 $
REM #
REM # DESCRIPTION:    The script provides following functions:
REM #                 1) Update SAS expander's firmware by Write Buffer Mode 07h
REM #                 2) Update SAS expander's CPLD
REM #
REM # NOTES: 
REM #    1, Tools are used by this script:
REM #       1) sg_inq.exe, sg_turs.exe, sg_ses.exe, sg_write_buffer.exe
REM #       2) dd.exe,od.exe, cygconv-2.dll, cygintl-8.dll, cygwin1.dll
REM #
REM #*****************************************************************************/
@echo off

set device_types="RES3FV288 RES3FV288-R RES3TV360 AEC-82885T AEC-83600"

if "%1" == "" goto usage
if "%1" == "--help"  goto usage
if "%1" == "-h"  goto usage
if "%1" == "--fw_update"  goto fw_update
if "%1" == "-f"  goto fw_update
if "%1" == "--cpld_update"   goto cpld_update
if "%1" == "-c"   goto cpld_update

echo.
echo Invalid argument: %1
echo.
goto usage

REM ----------------------------------------------------------------------------------
REM  Function name: Usage
REM
REM  Description: This function prints usage message.
REM
REM  Arguments: None
REM ----------------------------------------------------------------------------------
:usage
    echo.
    echo  Usage:
    echo      fw_tool.bat [--help] [--fw_update] [--cpld_update] DEVICE
    echo.
    echo  Where:
    echo     -h, --help                               Print out usage message
    echo     -f, --fw_update  firmware_image          Update SAS Expander's firmware
    echo     -c, --cpld_update  cpld_image            Update SAS Expander's CPLD
    echo.
    echo  Example:
    echo      fw_tool.bat  -h
    echo      fw_tool.bat  -f  firmware_image.bin  "scsi4:1,14,0"
    echo      fw_tool.bat  -c  cpld_image.bin  "scsi4:1,14,0"
    echo.
    echo  Notes:
    echo      DEVICE can be got by 'sg_scan -s' on Windows.
    echo.
goto:eof

REM -------------------------------------------------------------------------
REM  Function name: fw_update
REM
REM  Description: This function updates SAS expander's firmware.
REM
REM  Arguments: 
REM     %2 --- firmware image name
REM     %3 --- device name
REM -------------------------------------------------------------------------
:fw_update
    setlocal EnableDelayedExpansion
    REM Get firmware image name and size.
    set file_name=%~2
    set file_size=%~z2
    REM Get SAS expander device name
    set device_name_flag=%~3
    set all_input=%*
    if "%device_name_flag%" == "" (
        set device_name=%device_name_flag%
    ) else (
        for /F "tokens=2* delims= " %%a in ("%all_input%") do set dev=%%b
        REM - There is a limitation. If the input device name has spaces, the extra comma would be inserted. 
        set device_string=!dev: =,!
        set device_name=!device_string:"=!
    )
    REM Check the input parameters
    if "%file_name%" == "" (
        echo.
        echo No firmware image argument is given.
        goto:eof
    )
    if not exist "%file_name%" (
        echo.
        echo "%file_name%" does not exist.
        goto:eof
    )
    set file_postfix=%file_name:~-4%
    if not "%file_postfix%" == ".bin" (
        echo.
        echo "%file_name%" is not a file with the extension .bin.
        goto:eof
    )
    if "%device_name%" == "" (
        echo.
        echo No device argument is given.
        goto:eof
    )
    sg_inq.exe %device_name% 1> NUL 2>NUL
    if errorlevel 1 (
        echo.
        echo sg_inq "%device_name%" failed.
        goto:eof
    )
    sg_inq.exe %device_name% | findstr %device_types% >NUL
    if errorlevel 1 (
        echo.
        echo "%device_name%" is not %device_types%
        goto:eof
    )

    REM Check the device is ready or not
    sg_turs.exe %device_name% >NUL
    sg_turs.exe %device_name%
    if errorlevel 1 (
         echo.
         echo sg_tur "%device_name%" failed.
         goto:eof
    )

    REM Set download arguments
    set buffer_length=1024
    set file_off_set=0
    set download_finish_flag=0

    REM Download firmware
    attrib -r %~f0
    for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
    echo.
    :while_fw_update
        set /a remain_length=%file_size%-%file_off_set%

        if %buffer_length% GTR %remain_length% (
          set /a download_finish_flag=1
          set /a buffer_length=%remain_length%
        )

        REM  Download by write buffer command
        sg_write_buffer.exe -m 7 -I %file_name% -l %buffer_length% -o %file_off_set% -s %file_off_set% %device_name%
        if errorlevel 1 (
            echo.
            echo Firmware update fail - sg_write_buffer error
            goto  wend_fw_update
        )

        REM Update file_off_set
        set /a file_off_set+=%buffer_length%
        REM Print download percentage
        set /a finished_percentage=%file_off_set% * 100 / %file_size
        <NUL set /p "=Finish: %finished_percentage%%% !CR!"

        if %download_finish_flag% EQU 0  (goto while_fw_update)
        echo Firmware update finished!
    :wend_fw_update
    endlocal
goto:eof

REM -------------------------------------------------------------------------
REM  Function name: dec2hex
REM
REM  Description:  Convert a decimal value into a hex string.
REM
REM  Arguments:
REM     %1 --- Decimal value
REM     %2 --- String length - 4 or 8  
REM  Return:
REM     hex string
REM -------------------------------------------------------------------------
:dec2hex
    set val=%1
    set string_len=%2

    set hex_val=
    set loop_count=0

    :hexloop
        set /A loop_count="%loop_count% + 1"
        set /A _P="%val% %% 16"
        if %_P% LEQ 9 set hex_val=%_P%%hex_val%
        if "%_P%" == "10" set hex_val=A%hex_val%
        if "%_P%" == "11" set hex_val=B%hex_val%
        if "%_P%" == "12" set hex_val=C%hex_val%
        if "%_P%" == "13" set hex_val=D%hex_val%
        if "%_P%" == "14" set hex_val=E%hex_val%
        if "%_P%" == "15" set hex_val=F%hex_val%
        set /A space="%loop_count% %% 2"
        if "%space%" == "0" set hex_val= %hex_val%

        set /A val="%val% / 16"
        if "%val%" == "0" (
            if %loop_count% LSS %string_len% goto :hexloop
            goto :endloop
        )
        goto :hexloop
    :endloop

    set _P=
    set val=
goto:eof

REM -------------------------------------------------------------------------
REM  Function name: cpld_update
REM
REM  Description: This function updates SAS expander's CPLD.
REM
REM  Arguments: 
REM     %2 --- CPLD file name
REM     %3 --- device name
REM -------------------------------------------------------------------------
:cpld_update
    setlocal EnableDelayedExpansion
    REM Get CPLD file name and size
    set cpld_file_name=%~2
    set cpld_file_size=%~z2
    REM Get SAS expander device name
    set device_name_flag=%~3
    set all_input=%*
    if "%device_name_flag%" == "" (
        set device_name=%device_name_flag%
    ) else (
        for /F "tokens=2* delims= " %%a in ("%all_input%") do set dev=%%b
        REM - There is a limitation. If the input device name has spaces, the extra comma would be inserted. 
        set device_string=!dev: =,!
        set device_name=!device_string:"=!
    )
    
    REM Check the input parameters
    if "%cpld_file_name%" == "" (
        echo.
        echo No CPLD image argument is given.
        goto:eof
    )
    if not exist "%cpld_file_name%" (
        echo.
        echo "%cpld_file_name%" does not exist.
        goto:eof
    )
    set cpld_postfix=%cpld_file_name:~-4%
    if not "%cpld_postfix%" == ".bin" (
        echo.
        echo "%cpld_file_name%" is not a file with the extension .bin 
        goto:eof
    )
    if "%device_name%" == "" (
        echo.
        echo No device argument is given.
        goto:eof
    )
    sg_inq.exe %device_name% 1>NUL 2>NUL
    if errorlevel 1 (
        echo.
        echo sg_inq "%device_name%" failed.
        goto:eof
    )
    sg_inq.exe %device_name% | findstr %device_types% >NUL
    if errorlevel 1 (
        echo.
        echo "%device_name%" is not %device_types%
        goto:eof
    )
    
    REM Check the device is ready or not
    sg_turs.exe %device_name% > NUL
    sg_turs.exe %device_name%
    if errorlevel 1 (
        echo.
        echo sg_tur "%device_name%" failed.
        goto:eof
    )

    REM Set CPLD download arguments
    REM - The CPLD image uses 6 bytes as its head.
    REM - First 2 bytes are IEA file length and other 4 bytes are IED file length.
    set /a cpld_head_length=6
    set /a file_size=%cpld_file_size%-%cpld_head_length%

    set finish_flag=0
    set image_offset=%cpld_head_length%
    set download_bytes=0
    set rw_bytes=1024

    set command_field=05
    set cdb_offset=00 00 00 00
    set data_size=00 00
    set remain_size=0

    REM Init data_size 
    if %file_size% LSS %rw_bytes%  (
        call :dec2hex %file_size% 4
        set data_size=!hex_val!
    ) else (
        call :dec2hex %rw_bytes% 4
        set data_size=!hex_val!
    )

    REM Get CPLD file head
    dd if=%cpld_file_name% of=temp.bin bs=1 count=%cpld_head_length% skip=0 2>NUL
    if errorlevel 1 (
        echo.
        echo Error was reported by dd.
        goto:eof
    )
    REM  Convert binary file to string of ASCII hex bytes
    od -A n -t x1 -v temp.bin > cpld_head.txt
    if errorlevel 1 (
        echo.
        echo Error was reported by od.
        goto:eof
    )

    REM Download CPLD
    attrib -r %~f0
    for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
    echo.
    :while_cpld_update
        REM  Read rw_bytes bytes from image
        dd if=%cpld_file_name% of=temp.bin bs=1 count=%rw_bytes% skip=%image_offset% 2>NUL
        if errorlevel 1 (
            echo.
            echo Error was reported by dd.
            goto:eof
        )
        REM  Convert binary file to string of ASCII hex bytes
        od -A n -t x1 -v temp.bin > temp.txt
        if errorlevel 1 (
            echo.
            echo Error was reported by od.
            goto:eof
        )
        REM  Populate the SES string out page
        set /p=%command_field% %cdb_offset% %data_size%<nul > download_temp
        type  temp.txt >> download_temp
        REM  Download by SES string out page
        sg_ses --page=0x04 --control --data=- %device_name% < download_temp  > NUL
        if errorlevel 1 (
            echo.
            echo Error was reported by sg_ses.
            goto:eof
        )
        REM
        erase temp.bin

        set /a image_offset=%image_offset%+%rw_bytes%
        set /a download_bytes=%image_offset%-%cpld_head_length%
        if  %file_size% LSS %download_bytes%  (
            set /a finish_flag=1
            set /a download_bytes=%file_size%
        )
        set /a remain_size=%file_size%-%download_bytes%

        REM Print download percentage
        set /a finished_percentage=%download_bytes% * 100 / %file_size%
        <NUL set /p "=Finish: %finished_percentage%%% !CR!"

        REM Update cdb_offset filed
        call :dec2hex %download_bytes% 8
        set cdb_offset=!hex_val!

        REM Update data_size filed if it is last page
        if %remain_size% LSS %rw_bytes% (
            call :dec2hex %remain_size% 4
            set data_size=!hex_val!
        )

        if %finish_flag% EQU 0 (
            goto while_cpld_update
        )
    :wend_cpld_update
    REM  Send a complete flag page
    set cdb_offset=ff ff ff ff
    set data_size=00 06
    set /p=%command_field% %cdb_offset% %data_size%<nul > download_temp
    type  cpld_head.txt >> download_temp
    sg_ses --page=0x04 --control --data=- %device_name% < download_temp  > NUL
    if errorlevel 1 (
         echo.
         echo CPLD update failed - Error was reported by sg_ses.
         goto:eof
    )
    echo CPLD update finished!
    erase temp.bin temp.txt download_temp cpld_head.txt
goto:eof
