File: //lib64/mft/python_tools/resourcedump/fetchers/ResourceDumpFetcher.py
# Copyright (C) Jan 2020 Mellanox Technologies Ltd. All rights reserved.
#
# This software is available to you under a choice of one of two
# licenses. You may choose to be licensed under the terms of the GNU
# General Public License (GPL) Version 2, available from the file
# COPYING in the main directory of this source tree, or the
# OpenIB.org BSD license below:
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# - Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# - 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.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# --
#######################################################
#
# ResourceDumpFetcher.py
# Python implementation of the Class CoreDumpFetcher
# Generated by Enterprise Architect
# Created on: 14-Aug-2019 10:12:01 AM
# Original author: talve
#
#######################################################
from segments.SegmentCreator import SegmentCreator
from utils import constants
from utils import constants as cs
import sys
import os
import math
sys.path.append(os.path.join("mtcr_py"))
sys.path.append(os.path.join("reg_access"))
import mtcr # noqa
import regaccess # noqa
class ResourceDumpFetcher:
"""this class is responsible for getting all the segments of a the required dump.
"""
# very big number that represent the inf number 2^32 - 1 (we will not reach that number)
INF_DEPTH = 4294967295
def __init__(self, device_name):
self._sequence_number = ResourceDumpFetcher._sequence_incrementor()
self._device_name = device_name
self._start_seq_number = 0
try:
mst_device = mtcr.MstDevice(self._device_name)
if mst_device.is_cable() or mst_device.is_linkx():
raise Exception("Device is not supported")
self.reg_access_obj = regaccess.RegAccess(mst_device)
except Exception as e:
raise Exception("{0}".format(e))
@staticmethod
def _create_segments(segments_data):
"""convert the data into a list of segments by calling the SegmentCreator.
"""
return SegmentCreator().create(segments_data)
def fetch_data(self, **kwargs):
"""this method fetch the segments of the required dump by:
1. read the core dump register from the reg access while more dump bit is
equal to "1" and the sequence number is valid.
2. use SegmentsCreator for converting it to a list of segments.
3. iterate stage 1 and 2 according the depth parameter and in case reference
segments found.
"""
# read the inline data from the resource dump register and split it to segments list
self._start_seq_number = 0
inline_data = self._retrieve_resource_dump_inline_data(kwargs[cs.UI_ARG_SEGMENT], **kwargs)
segments_list = self._create_segments(inline_data)
segments_list_last_position = 0
# go over oll the segments from the last position till the and of the segments list
# and repeat it according the depth parameter
if kwargs[cs.UI_ARG_DEPTH] == "inf":
depth = ResourceDumpFetcher.INF_DEPTH
else:
depth = int(kwargs[cs.UI_ARG_DEPTH]) if kwargs[cs.UI_ARG_DEPTH] else 0
for i in range(depth):
inner_inline_data = []
for seg in segments_list[segments_list_last_position:]:
if seg.get_type() == constants.RESOURCE_DUMP_SEGMENT_TYPE_REFERENCE:
inner_inline_data.extend(
self._retrieve_resource_dump_inline_data(seg.reference_type, index1=seg.index1,
index2=seg.index2, numOfObj1=seg.num_of_obj1,
numOfObj2=seg.num_of_obj2, vHCAid=kwargs["vHCAid"]))
segments_list_last_position = len(segments_list)
segments_list.extend(self._create_segments(inner_inline_data))
# relevant for inf mode, nothing to show, we can stop search for ref segments
# because if refs found we expect that the segments list extend to do something
if segments_list_last_position == len(segments_list):
break
return segments_list
def _validate_sequence_number(self, current_seq_number):
"""validate that the sequence number was incremented.
"""
return current_seq_number == next(self._sequence_number)
@staticmethod
def _sequence_incrementor():
cnt = 0
while True:
yield cnt % 16
cnt += 1
def _retrieve_resource_dump_inline_data(self, segment_type, **kwargs):
"""call the resource dump access register and retrieve the inline data
till more dump is '0'
"""
segment = int(segment_type, 16)
seg_number = self._start_seq_number
more_dump = 0
vhca_id_valid = 0
index1 = int(kwargs["index1"]) if kwargs["index1"] else 0
index2 = int(kwargs["index2"]) if kwargs["index2"] else 0
num_of_obj_1 = int(kwargs["numOfObj1"]) if kwargs["numOfObj1"] else 0
num_of_obj_2 = int(kwargs["numOfObj2"]) if kwargs["numOfObj2"] else 0
device_opaque = 0
inline_data = []
call_res_dump = True
if kwargs["vHCAid"] is None:
vhca_id = 0
else:
vhca_id = int(kwargs["vHCAid"])
vhca_id_valid = 1
while call_res_dump:
results = self.reg_access_obj.sendResDump(segment, # "segment_type"
seg_number, # "seq_num" * need check
1, # "inline_dump"
more_dump, # "more_dump" *
vhca_id, # "vHCAid"
vhca_id_valid, # "vHCAid_valid"
index1, # "index_1" *
index2, # "index_2" *
num_of_obj_2, # "num_of_obj_2" *
num_of_obj_1, # "num_of_obj_1" *
device_opaque, # "device_opaque" *
0, # "mkey" 0
0, # "size" 0
0) # "address" 0
more_dump = results["more_dump"]
vhca_id = results["vhca_id"]
index1 = results["index_1"]
index2 = results["index_2"]
num_of_obj_1 = results["num_of_obj_1"]
num_of_obj_2 = results["num_of_obj_2"]
device_opaque = results["device_opaque"]
size = int(math.ceil(results["size"] / 4))
inline_data.extend(results["inline_data"][:size])
if not self._validate_sequence_number(seg_number):
raise Exception("E - wrong sequence number while calling resource dump register with seq num = {0}"
.format(seg_number))
call_res_dump = False
seg_number = results["seq_num"]
self._start_seq_number = seg_number
if more_dump == 0:
call_res_dump = False
return inline_data