#!/usr/bin/python2
# INTEL CONFIDENTIAL
# Copyright 2014-2016 Intel Corporation All Rights Reserved.
#
# The source code contained or described herein and all
# documents related to the source code ("Material") are
# owned by Intel Corporation or its suppliers or licensors.
# Title to the Material remains with Intel Corporation or
# its suppliers and licensors. The Material may contain trade
# secrets and proprietary and confidential information of Intel
# Corporation and its suppliers and licensors, and is protected
# by worldwide copyright and trade secret laws and treaty
# provisions. No part of the Material may be used, copied,
# reproduced, modified, published, uploaded, posted, transmitted,
# distributed, or disclosed in any way without Intel's prior express
# written permission.
#
# No license under any patent, copyright, trade secret or other
# intellectual property right is granted to or conferred upon you
# by disclosure or delivery of the Materials, either expressly, by
# implication, inducement, estoppel or otherwise. Any license under
# such intellectual property rights must be express and approved by
# Intel in writing.
#
# Unless otherwise agreed by Intel in writing, you may not remove or
# alter this notice or any other notice embedded in Materials by Intel
# or Intel's suppliers or licensors in any way.
import os
import sys
import getopt

__version__ = (0, 10, 1)
__module_path__ = "/usr/libexec/hfidiags"
__banner__ = ["Omni-Path HFI Diags", "Intel Corporation"]

try:
    import lib.hw
    import lib.ui
    import lib.diags
    import lib.logger
except ImportError:
    if __module_path__:
        sys.path.append(__module_path__)
        try:
            import lib.hw
            import lib.ui
            import lib.diags
            import lib.logger
        except ImportError:
            sys.stderr.write("ERROR: Failed to import HfiDiags modules\n")
            sys.exit(1)
    else:
        sys.stderr.write("ERROR: Failed to import HfiDiags modules\n")
        sys.exit(1)

def show_usage():
    exe = os.path.basename(sys.argv[0])
    print exe, "[-e <cmd>] [-s <script filename>] [-DNth] [--hwrev=<HWRev>]"
    print
    print "    -e    - Evaluate single command as if it was entered through the"
    print "            interface."
    print "    -t    - Test mode."
    print "    -N    - This option will start the interface without opening any device"
    print "            files. Commands that interact with the actual "
    print "            devices will not work."
    print "    -s    - Read commands from script file (one per line) and execute them."
    print "            If the filename is '-', commands are read from stdin. The '-e'"
    print "            and '-s' options are mutually exclusive."
    print "    -D    - Enable logging of debug information."
    print " --hwrev  - Don't check the HW Rev of the installed HW but assume this"
    print "            revision. Supported revisions are:", \
          ",".join([str(x) for x in lib.hw.SupportedHWRevs])
    print


def show_diag_banner():
    def make_line(t, s, c):
        if not t: t = ""
        m = c - ((len(s) * 2) + 2)
        mh = (m/2) - (len(t)/2+len(t)%2)
        f = "%%s|%%%ds%%-%ds|" % (mh, m-mh)
        return f % (s, " ", t)
    cols, lines = lib.ui.getTerminalSize()
    spacer = " " * 3
    hbar = spacer + "+" + "-" * (cols - (len(spacer)*2 + 2)) + "+"
    lines = [None] + __banner__ + ["Version: %2d.%02d.%02d" % __version__] + [None]
    print hbar
    for line in lines: print make_line(line, spacer, cols)
    print hbar

def diags_main():
    cmdval = None
    ret = 0
    test_mode = False
    nodev_mode = False
    script_filename = None
    logfile = None
    hwver = None
    hwver_set = False
    assume = None
    debug = False
    unit = 0
    topdir = __module_path__ if __module_path__ else \
             os.path.abspath(os.path.expanduser(os.path.dirname(sys.argv[0])))

    try: opts, args = getopt.getopt(sys.argv[1:], "e:Dhts:Nl:u:", ["hwrev="])
    except getopt.GetoptError, e:
        print e
        return 1

    for opt, val in opts:
        if opt == "-e": cmdval = val
        elif opt == "-D": debug = True
        elif opt == "-t": test_mode = True
        elif opt == "-N": nodev_mode = True
        elif opt == "-s": script_filename = val
        elif opt == "-l": logfile = val
        elif opt == "-u": unit = int(val)
        elif opt == "-h":
            show_usage()
            return 0
        elif opt == "--hwrev":
            val = val.upper()
            if val in lib.hw.SupportedHWRevs:
                hwver = eval("lib.hw.SupportedHWRevs.%s" % val)
                hwver_set = True
            else:
                sys.stderr.write("ERROR: Unsupported HW Revision: %s\n" % val)
                return 1

    if logfile:
        if debug: lib.logger.initLogging(level=lib.logger.DEBUG, filename=logfile)
        else: lib.logger.initLogging(filename=logfile)
    logger = lib.logger.initModuleLogging("main")

    if hwver_set:
        logger.log(lib.logger.INFO, "Assuming HW Rev: %s", hwver)

    devs = lib.hw.Devices()
    if nodev_mode:
        hfi = devs.createDefaultDevice(tests=test_mode)
    else:
        hfi = devs.createDevice(unit, tests=test_mode)
        if not hfi:
            sys.stderr.write("ERROR: No devices found matching unit!\n")
            return 1

        try: hfi.open()
        except lib.hw.HwError, e:
            sys.stderr.write("ERROR: Could not open device.\n")
            sys.stderr.write("ERROR: \t%s\n" % e)
            return 1

    try:
        ret = hfi.load_hw_data(version=hwver)
        if ret != 0:
            sys.stderr.write("ERROR: Loading HW data failed:")
            if ret == lib.hw.DB_ERR_VER:
                sys.stderr.write("unrecognized version format.\n")
            elif ret == lib.hw.DB_ERR_UNPACK:
                sys.stderr.write("failed to unpack DB. File could be corrupted.\n")
            elif ret == lib.hw.DB_ERR_FORMAT:
                sys.stderr.write("unknown DB format. DB version could be old.\n")
            elif ret == lib.hw.DB_ERR_HWREV:
                sys.stderr.write("DB file rev does not match HW. See the '--hwrev' option.\n")
            elif ret == lib.hw.DB_ERR_HWREV_UNSUP:
                sys.stderr.write("DB file contains data for unsupported HW Revision.\n")
            elif ret == lib.hw.DB_ERR_NO_DB_LOADED:
                sys.stderr.write("No DB file was successfully loaded.\n")
            return 1
    except lib.hw.HwError, e:
        sys.stderr.write("HW ERROR: %s\n" % e)
        return 1

    interface = lib.ui.CommandLine(hw=hfi)
    interface.load_commands(topdir)
    if test_mode: interface.enable_tests()

    try:
        if cmdval:
            interface.interactive = False
            interface.onecmd(cmdval)
        elif script_filename:
            interface.interactive = False
            if script_filename != "-":
                try:
                    with open(script_filename, 'r') as script:
                        for line in script:
                            if line.strip():
                                interface.onecmd(line.strip())
                except IOError, e:
                    sys.stderr.write("Failed opening file '%s': %s\n" % \
                                     (script_filename, e))
                    return e.errno
            else:
                while True:
                    line = sys.stdin.readline().strip()
                    if not line: break
                    interface.onecmd(line)
                return 0
        else:
            show_diag_banner()
            if not nodev_mode:
                info = hfi.hw_revision()
                output = ["Using %s unit %d" % (hfi.get_hw(), info["unit"]),
                          "Implementation: %s, revision: %#x" % \
                          (info["impl_str"], info["impl_rev"]),
                          "HFI Chip version %d.%d" % \
                          (info["chip_rev_major"], info["chip_rev_minor"])]
                if info["status"]:
                    output += [ lib.diags.SPACER, "!!!!! WARNING !!!!!",
                               "\tFollowing bits in CceStatus are set:",
                               "\t\t%s" % (", ".join(info["status"].keys()))]
                interface.show_cmd_output(output)
            interface.cmdloop()
    finally:
            hfi.close()
    return 0

if __name__ == "__main__":
    sys.exit(diags_main())
