local common_def = require('common_def')
local method_misc = require('method_misc')
local queue = require('skynet.queue')
local ctrl_commu_loss_monitor = require('ctrl_commu_loss_monitor')
local c_storageconfig = require('storageconfig.storageconfig_object')
local STORAGE_MGNT_STATE = common_def.STORAGE_MGNT_STATE
local log = require('mc.logging')
local debounce = require('mc.debounce.debounce')
local mctp_service = require('mctp.mctp_service')
local mdb = require('mc.mdb')
local skynet = require('skynet')
local storage_bus = require('storage_bus')
local controller_dump = require('controller.controller_dump')
local sml = require('sml')
local cjson = require('cjson')
local phy_err
local signal = require('mc.signal')
local c_object = require('mc.orm.object')
local pd_object = require('pd.pd_object')
local volume_obj_info = require('volume.volume_obj_info')
local volume_collection = require('volume.volume_collection')
local battery_collection = require('battery.battery_collection')
local operation_code = require('controller.ctrl_operation_cmd')
local ctrl_config_backup = require('controller.ctrl_config_backup')
local drive_collection = require('drive.drive_collection')
local array_collection = require('array.array_collection')
local custom_msg = require('messages.custom')
local upgrade_defs = require('upgrade.upgrade_defs')
local CTRL_OPTION = common_def.CTRL_OPTION
local MAX_RETRY_TIMES = 30
local PCIE_CARD_PATH <const> = '/bmc/kepler/Systems/1/PCIeDevices/PCIeCards'
local PCIE_CARD_INTERFACE <const> = 'bmc.kepler.Systems.PCIeDevices.PCIeCard'
local QUAD_RETRY_TIMES <const> = 3
local QUAD_RETRY_INTERVAL <const> = 500
local TASK_UPDATE <const> = 'update'
local TASK_UPDATE_PD_LIST <const> = 'update_pd_list'
local TASK_UPDATE_LD_LIST <const> = 'update_ld_list'
local VOLUME_TYPE_PHYSICAL_DRIVE_BIT <const> = 0x10000000
local VOLUME_TYPE_LOGICAL_DRIVE_BIT <const> = 0x20000000
local CONTROLLER_ID = 1
local rate_array = { 'Low', 'Medium', 'High' }
local running_state = { 'Off', 'On' }
local work_mode = { 'RAID', 'HBA', 'JBOD', 'Mixed' }
local c_controller = c_object('Controller', { 'position' })
local CONTROLLER_TYPE = {
[0] = 'SAS3108',
[1] = 'SAS3108',
[2] = 'SAS3108',
[3] = 'SAS3008',
[4] = 'SAS3008',
[5] = 'SAS3008',
[6] = 'SAS3508',
[7] = 'SAS3516',
[8] = 'SAS3408',
[9] = 'SAS3416',
[10] = 'SAS3408',
[11] = 'SAS3416',
[12] = 'SAS3004',
[13] = 'SAS3908',
[14] = 'SAS3908',
[15] = 'SAS3916',
[16] = 'SAS3808',
[17] = 'SAS3816',
[18] = 'SAS3808',
[19] = 'SAS3808',
[20] = 'SAS3816',
[64] = 'PM3152',
[65] = 'PM2100',
[66] = 'PM8204',
[67] = 'PM8254',
[68] = 'PM8222',
[96] = 'B80121',
[97] = 'B80121',
[98] = 'B80121',
[99] = 'B80121',
[100] = 'B80121',
[101] = 'B80121',
[102] = 'B80121',
[103] = 'B80121',
[113] = 'B80121',
[200] = 'JZ9234',
}
local SLOW_DISK_MODES = common_def.SLOW_DISK_DETECTION_MODE
local SLOW_DISK_TYPES = common_def.SLOW_DISK_TYPE
local MODE_TRANSITIONS = {
[SLOW_DISK_MODES.DISABLE] = {
[SLOW_DISK_MODES.ENABLE_RAW_AND_MEMBER_DRIVE] = {
{ type = SLOW_DISK_TYPES.MEMBER, sw = 1 },
{ type = SLOW_DISK_TYPES.RAW, sw = 1 },
},
[SLOW_DISK_MODES.ENABLE_RAW_DRIVE] = {
{ type = SLOW_DISK_TYPES.RAW, sw = 1 },
},
[SLOW_DISK_MODES.ENABLE_MEMBER_DRIVE] = {
{ type = SLOW_DISK_TYPES.MEMBER, sw = 1 },
},
},
[SLOW_DISK_MODES.ENABLE_RAW_AND_MEMBER_DRIVE] = {
[SLOW_DISK_MODES.DISABLE] = {
{ type = SLOW_DISK_TYPES.MEMBER, sw = 0 },
{ type = SLOW_DISK_TYPES.RAW, sw = 0 },
},
[SLOW_DISK_MODES.ENABLE_RAW_DRIVE] = {
{ type = SLOW_DISK_TYPES.MEMBER, sw = 0 },
},
[SLOW_DISK_MODES.ENABLE_MEMBER_DRIVE] = {
{ type = SLOW_DISK_TYPES.RAW, sw = 0 },
},
},
[SLOW_DISK_MODES.ENABLE_RAW_DRIVE] = {
[SLOW_DISK_MODES.DISABLE] = {
{ type = SLOW_DISK_TYPES.RAW, sw = 0 },
},
[SLOW_DISK_MODES.ENABLE_RAW_AND_MEMBER_DRIVE] = {
{ type = SLOW_DISK_TYPES.MEMBER, sw = 1 },
},
[SLOW_DISK_MODES.ENABLE_MEMBER_DRIVE] = {
{ type = SLOW_DISK_TYPES.RAW, sw = 0 },
{ type = SLOW_DISK_TYPES.MEMBER, sw = 1 },
},
},
[SLOW_DISK_MODES.ENABLE_MEMBER_DRIVE] = {
[SLOW_DISK_MODES.DISABLE] = {
{ type = SLOW_DISK_TYPES.MEMBER, sw = 0 },
},
[SLOW_DISK_MODES.ENABLE_RAW_AND_MEMBER_DRIVE] = {
{ type = SLOW_DISK_TYPES.RAW, sw = 1 },
},
[SLOW_DISK_MODES.ENABLE_RAW_DRIVE] = {
{ type = SLOW_DISK_TYPES.RAW, sw = 1 },
{ type = SLOW_DISK_TYPES.MEMBER, sw = 0 },
},
},
}
local SLOW_DESK_TYPE_TO_DISK = {
[SLOW_DISK_TYPES.RAW] = 'raw',
[SLOW_DISK_TYPES.MEMBER] = 'RAID member',
}
local SLOW_DESK_TYPE_TO_SW = {
[0] = 'Disable',
[1] = 'Enable',
}
local function handle_slow_disk_mode_setting(ctrl_obj, mode, new_mode)
if ctrl_obj.OOBSupport ~= 1 or ctrl_obj.is_working then
log:error(
'[Storage]Controller%s no support set operation. is_suport:%s, is_working:%s',
ctrl_obj.Id,
ctrl_obj.OOBSupport,
ctrl_obj.is_working
)
return false
end
local operations = MODE_TRANSITIONS[mode] and MODE_TRANSITIONS[mode][new_mode] or {}
if #operations == 0 and mode ~= new_mode then
log:error('[Storage]No transition defined from %s to %s', mode, new_mode)
return false
end
for _, op in ipairs(operations) do
ctrl_obj.is_working = true
local ok, ret = pcall(function()
return sml.ctrl_operation(
ctrl_obj.Id,
operation_code.CTRL_OPERATION_SET_SLOW_DISK_DETECTION,
CTRL_OPTION.drive_detection:pack({ type = op.type, sw = op.sw })
)
end)
ctrl_obj.is_working = false
if not ok or ret ~= common_def.RET_OK then
log:error('[Storage]Failed to set SlowDriveDetectionMode: %s', ret)
log:operation(
method_misc:get_op_initiator(),
'storage',
'%s %s drives detection failed',
SLOW_DESK_TYPE_TO_SW[op.sw],
SLOW_DESK_TYPE_TO_DISK[op.type]
)
return false
else
log:notice('[Storage]Successfully set SlowDriveDetectionMode for Controller%s.', ctrl_obj.Id)
log:operation(
method_misc:get_op_initiator(),
'storage',
'%s %s drives detection successfully',
SLOW_DESK_TYPE_TO_SW[op.sw],
SLOW_DESK_TYPE_TO_DISK[op.type]
)
end
end
return true
end
function c_controller:ctor(obj)
self.bus = storage_bus.get_instance().bus
self.obj = obj
obj.Eid = 0
obj.Phyaddr = 0
self.NodeId = ''
self.controller_path = string.match(obj.path, 'Controller_%d+_%x+')
self.pd_list = {}
self.on_add_pd = signal.new()
self.on_add_pd_complete = signal.new()
self.on_del_pd = signal.new()
self.volume_list = {}
self.array_list = {}
self.on_update = signal.new()
self.on_update_volume_array = signal.new()
self.is_working = false
self.registered_state = false
self.registering = false
self.temp_debounce = debounce[debounce.DEBOUNCED_CONT].new(5, 0)
self.presence_debounce = false
self.tasks_pause = false
self.first_register_task = false
self.timeout_times = 0
self.update_queue = queue()
self.firmware_register_status = false
self.config_backed_up = false
end
function c_controller:dtor()
c_storageconfig.get_instance().controller_mask = c_storageconfig.get_instance().controller_mask ~ (1 << self.Id)
if self.firmware_register_status then
method_misc:retry_unregister_firmware_info(self.NodeId, function()
self.firmware_register_status = false
end)
end
self:stop()
end
function c_controller:init()
log:info('controller init obj.Id = %s, object_id = %s, key = %s', self.obj.Id, CONTROLLER_ID, self.DeviceName)
self.obj.Id = (self.obj.Id == common_def.INVALID_U8) and CONTROLLER_ID - 1 or self.obj.Id
CONTROLLER_ID = CONTROLLER_ID + 1
self.super.init(self)
self.presence_debounce = debounce[debounce.DEBOUNCED_CONT].new(9, self.BatteryPresence)
if not method_misc:test_controller_oob_support(self.TypeId) then
self.Type = CONTROLLER_TYPE[self.TypeId]
end
self.NodeId = string.gsub(self.DeviceName, '[^%a%d]', '')
self.ComponentName = self.DeviceName
self.ComponentType = 'Controller'
self:set_default_values()
if not self.CreatedByDeviceObject then
self:set_default_volume_manage_values()
end
self:set_default_health_status()
self.on_update_volume_array:on(function()
self.update_queue(function()
self:update_volume_list()
self:update_array_list()
end)
end)
if c_storageconfig.get_instance().power_on == 1 then
self:register()
end
end
local function prefix_equal(str, prefix)
return string.sub(str, 1, string.len(prefix)) == prefix
end
function c_controller.before_add_object(object)
while true do
skynet.sleep(10)
if
not prefix_equal(object.DeviceName, 'PCIe Card')
or prefix_equal(object.DeviceName, 'PCIe Card $')
or prefix_equal(object.DeviceName, 'PCIe Card 0')
or prefix_equal(object.DeviceName, 'PCIe Card 255')
then
skynet.sleep(500)
else
break
end
end
end
function c_controller:fill_supported_raid_levels()
local supported_raid_levels = {}
if not self.CtrlOption3 then
return supported_raid_levels
end
local level_array = { '0', '1', '5', '6', '10', '50', '60', '1(ADM)', '10(ADM)', '1Triple', '10Triple' }
local bit_val = 1 << 8
for i = 1, #level_array do
if bit_val & self.CtrlOption3 ~= 0 then
table.insert(supported_raid_levels, 'RAID' .. level_array[i])
end
bit_val = bit_val << 1
end
return supported_raid_levels
end
function c_controller:start_related_tasks()
log:notice('controller%s start_related_tasks, registered_state = %s', self.Id, self.registered_state)
if self.registered_state then
self:start()
else
if not self.registering then
self:register()
end
end
end
function c_controller:stop_related_tasks()
log:notice('controller%s stop_related_tasks', self.Id)
if self.registering then
self.registering = false
end
if self.TypeId == 20 then
self.registered_state = false
local ok, ret = pcall(self.unregister_controller_to_sml, self)
if not ok then
log:error('controller:%s unregister failed, ret:%s', self.Id, ret)
end
end
self:stop()
log:notice('controller%s set_default_values', self.Id)
self:set_default_values()
if method_misc:get_oob_interface_type(self.TypeId) == sml.OOB_TYPE_OVER_PCIE then
log:notice('controller%s set_default_consistency_values', self.Id)
self:set_default_consistency_values()
end
if not self.CreatedByDeviceObject then
log:notice('controller%s set_default_volume_manage_values', self.Id)
self:set_default_volume_manage_values()
end
log:notice('controller%s set_default_health_status', self.Id)
self:set_default_health_status()
log:notice('controller%s set_default_battery_info', self.Id)
self:set_default_battery_info()
log:notice('controller%s set_default_phy_err', self.Id)
self:set_default_phy_err()
self:clear_asset_data_info()
end
function c_controller:change_tasks_state(os_state)
log:notice('controller%s change task state to %s', self.Id, os_state and 'start' or 'stop')
if os_state then
self:start_related_tasks()
else
self:stop_related_tasks()
end
end
local function record_commu_loss(ret, ctrl_index)
local ctrl_obj
local ok = pcall(function()
ctrl_obj = c_controller.collection:find({ Id = ctrl_index })
end)
if ok and ctrl_obj and ctrl_obj.CreatedByDeviceObject then
return
end
if c_storageconfig.get_instance().power_on ~= 1 then
return
end
if ret ~= common_def.SML_ERR_I2C_READ_WRITE_FAILED then
c_storageconfig.get_instance().configuration_ready_mask = c_storageconfig.get_instance().configuration_ready_mask
~ (1 << ctrl_index)
c_storageconfig.get_instance().on_update_flag:emit(STORAGE_MGNT_STATE.STORAGE_MGNT_CTRL_ABNOMAL)
end
if type(ret) == 'table' and ret.name == 'kepler.hwproxy.RequestTimeout' then
return
end
if ret ~= common_def.SML_ERR_CTRL_STATUS_INVALID and ret ~= common_def.SML_ERR_NULL_INFTERFACE then
ctrl_commu_loss_monitor.get_instance():update(true, ctrl_index)
end
end
function c_controller:is_directly_manage_physical_drive()
return self.TypeId == common_def.HRDT_B261s
end
function c_controller:register()
log:notice('controller%s begin register', self.Id)
self:new_task({ 'register_controller', self.Id })
:loop(function(task)
self.registering = true
log:info(
'controller%s register task loop, CreatedByDeviceObject=%s, power_on=%s',
self.Id,
tostring(self.CreatedByDeviceObject),
c_storageconfig.get_instance().power_on
)
if not self.CreatedByDeviceObject then
if c_storageconfig.get_instance().power_on == 0 then
self.registering = false
task:stop()
return
end
if self.OOBSupport ~= 1 then
c_storageconfig.get_instance().on_update_flag:emit(STORAGE_MGNT_STATE.STORAGE_MGNT_OOB_NOT_SUPPORT)
self.registering = false
task:stop()
return
end
if method_misc:get_oob_interface_type(self.TypeId) == common_def.INVALID_U8 then
log:error('[Storage]Invalid TypeId, controller_id = %d', self.Id)
self.registering = false
task:stop()
return
end
if method_misc:get_oob_interface_type(self.TypeId) == common_def.OOB_TYPE_OVER_PCIE then
if not mctp_service.get_instance().mctp_state then
return
end
if self.DevBus == 0 and self.DevDevice == 0 and self.DevFunction == 0 then
return
end
end
self:add_controller_to_link_topo()
log:notice('ctrl%s add_controller_to_link_topo successfully', self.Id)
self:add_controller_to_sml()
log:notice('ctrl%s add_controller_to_sml successfully', self.Id)
end
self:register_controller_to_sml()
log:notice('ctrl%s register_controller_to_sml successfully', self.Id)
self.registering = false
self.registered_state = true
self:start()
log:notice('controller_collection:add_object success, controller_id = %d', self.Id)
self:trans_pd_vendor_data()
self:property_change_listen_func()
self:register_controller_firmware_info()
task:stop()
end)
:set_timeout_ms(5000)
end
function c_controller:property_change_listen_func()
if not method_misc:test_controller_vendor(self.TypeId, common_def.VENDER_HUAWEI) then
return
end
self:get_mdb_object('bmc.kepler.Systems.Storage.Controller').property_before_change
:on(function(prop_name, prop_value, sender)
if prop_name ~= 'SlowDriveDetectionMode' or prop_value == common_def.INVALID_U8 then
return true
end
if prop_name == 'SlowDriveDetectionMode' and self.SlowDriveDetectionMode == common_def.INVALID_U8 then
log:notice(
'controller %s SlowDriveDetectionMode changed, %s -> %s',
self.Id,
self.SlowDriveDetectionMode,
prop_value
)
return true
end
if prop_value < SLOW_DISK_MODES.DISABLE or prop_value > SLOW_DISK_MODES.ENABLE_MEMBER_DRIVE then
log:error('[Storage]Invalid SlowDriveDetectionMode: %s', prop_value)
return false
end
local success = handle_slow_disk_mode_setting(self, self.SlowDriveDetectionMode, prop_value)
if not success then
log:error(
'[Storage]Failed to set SlowDriveDetectionMode from %s to %s',
self.SlowDriveDetectionMode,
prop_value
)
error(custom_msg.CurrentStatusNotSupportOperation(prop_value, '%SlowDriveDetectionMode'))
end
return true
end)
self.on_property_changed:on(function(prop_name, prop_value)
if prop_name ~= 'FirmwareVersion' or prop_value == '' or prop_value == common_def.INVALID_STRING then
return
end
if not self.firmware_register_status then
self:register_controller_firmware_info()
end
if self.firmware_register_status then
method_misc:update_firmware_info(self, prop_value)
end
end)
end
function c_controller:update_temp_abnormal(ret)
pcall(function()
if
c_storageconfig.get_instance().obj
and c_storageconfig.get_instance().obj.StorageConfigReady
== common_def.STORAGE_MGNT_STATE.STORAGE_MGNT_READY
then
self.TemperatureAbnormal = self.temp_debounce:get_debounced_val(ret and 0 or 1)
end
end)
end
function c_controller:fetch_controller_init_state()
local ok, ret = pcall(sml.update_ctrl_init_state, self.Id)
if not ok then
record_commu_loss(ret, self.Id)
return false
end
ctrl_commu_loss_monitor.get_instance():update(false, self.Id)
return ret == 2
end
function c_controller:fetch_controller_info(priority)
local err_count = 0
::continue::
log:debug('controller%s start s.ctl_info %s times, typeid is %d', self.Id, err_count, self.TypeId)
local ok, ret = pcall(sml.get_ctrl_info, { Priority = priority or 'Secondary' }, self.Id)
self:update_temp_abnormal(ok)
if not ok then
if (self.TypeId == 19 or self.TypeId == 20) and err_count < 5 then
err_count = err_count + 1
goto continue
end
record_commu_loss(ret, self.Id)
else
ctrl_commu_loss_monitor.get_instance():update(false, self.Id)
pcall(function()
self:update_ctrl_info_from_sml(ret)
end)
end
pcall(function()
self:update_controller_info_via_bma()
end)
pcall(function()
self:update_sas_addr()
end)
pcall(function()
self:update_boot_devices()
end)
pcall(function()
self:update_fault_code()
end)
pcall(function()
self:update_asset_data_info()
end)
if not self.CreatedByDeviceObject then
self.CommunicationLoss = ctrl_commu_loss_monitor.get_instance():get_ctrl_commu_loss(self.Id)
end
self.RefDrives = drive_collection.get_instance():get_drives_by_controller_id(self.Id)
pcall(function()
self:update_controller_battery_info()
end)
if ok then
c_storageconfig.get_instance().configuration_ready_mask = c_storageconfig.get_instance().configuration_ready_mask
| (1 << self.Id)
c_storageconfig.get_instance().on_update_flag:emit(STORAGE_MGNT_STATE.STORAGE_MGNT_READY)
end
end
function c_controller:start_update_task()
local id = tostring(self.Id)
log:notice('controller%s start TASK_UPDATE', self.Id)
self:new_task({ TASK_UPDATE, id })
:loop(function(task)
if self.tasks_pause or c_storageconfig.get_instance().power_on == 0 then
return
end
if not self:fetch_controller_init_state() then
return
end
if self.tasks_pause or c_storageconfig.get_instance().power_on == 0 then
return
end
self:fetch_controller_info()
end)
:set_timeout_ms(20000)
end
function c_controller:start_update_pd_list_task()
local id = tostring(self.Id)
log:notice('controller%s start TASK_UPDATE_PD_LIST', self.Id)
self:new_task({ TASK_UPDATE_PD_LIST, id })
:loop(function(task)
if self.tasks_pause or c_storageconfig.get_instance().power_on == 0 then
return
end
self:update_pd_list()
end)
:set_timeout_ms(10000)
end
function c_controller:start_update_ld_list_task()
local id = tostring(self.Id)
if self.TypeId == 19 or self.TypeId == 20 then
return
end
log:notice('controller%s start TASK_UPDATE_LD_LIST', self.Id)
self:new_task({ TASK_UPDATE_LD_LIST, id })
:loop(function(task)
if self.tasks_pause or c_storageconfig.get_instance().power_on == 0 then
return
end
self.update_queue(function()
self:update_volume_list()
self:update_array_list()
end)
self:update_phy_info()
end)
:set_timeout_ms(60000)
end
function c_controller:start()
log:notice('controller%s start update tasks', self.Id)
self.tasks_pause = false
if not self.first_register_task then
log:notice('[Storage] first register task!!')
self:start_update_task()
self:start_update_pd_list_task()
self:start_update_ld_list_task()
self.first_register_task = true
end
self:update_supported_boot_devices_count()
drive_collection.get_instance().on_controller_commu_changed:emit(true, self.Id)
battery_collection.get_instance().on_controller_commu_changed:emit(true, self.Id)
if not phy_err then
phy_err = require('diagnose.phy_biterr')
end
phy_err.get_instance().on_controller_commu_changed:emit(true)
end
function c_controller:stop()
log:notice('controller%s stop tasks', self.Id)
self.tasks_pause = true
drive_collection.get_instance().on_controller_commu_changed:emit(false, self.Id)
battery_collection.get_instance().on_controller_commu_changed:emit(false, self.Id)
self:remove_array_list()
self:remove_volume_list()
end
function c_controller:set_default_values()
if method_misc:test_controller_oob_support(self.TypeId) then
self.ControllerName = common_def.INVALID_STRING
self.Type = common_def.INVALID_STRING
end
self.FirmwareVersion = common_def.INVALID_STRING
self.DeviceInterface = common_def.INVALID_STRING
self.SASAddr = common_def.INVALID_STRING
if not method_misc:test_controller_vendor(self.TypeId, common_def.VENDER_HUAWEI) then
self.SerialNumber = common_def.INVALID_STRING
end
self.MinStripSizeBytes, self.MaxStripSizeBytes = common_def.INVALID_U32, common_def.INVALID_U32
self.MemorySizeMiB = common_def.INVALID_U16
self.NVDataVersion = common_def.INVALID_STRING
self.HardwareRevision = common_def.INVALID_STRING
self.PCIeLinkWidth = common_def.INVALID_STRING
self.TemperatureCelsius = common_def.INVALID_U8
self.TemperatureAbnormal = 0
self.SupportedMode = { common_def.INVALID_STRING }
self.SupportedRAIDTypes = self:fill_supported_raid_levels()
self.DDREccCount = common_def.INVALID_U16
self.UncorrectableParityErrorCount = common_def.INVALID_U32
self.CachePinnedState = common_def.INVALID_U8
self.MaintainPDFailHistrory = common_def.INVALID_U8
self.WorkMode = common_def.INVALID_STRING
self.JBODState = common_def.INVALID_U8
self.CopyBackState = common_def.INVALID_U8
self.SmarterCopyBackState = common_def.INVALID_U8
self.BootDevices = { common_def.INVALID_STRING, common_def.INVALID_STRING }
self.SupportedBootDeviceCount = common_def.BOOT_DEVICE_COUNT_DEFAULT
self.RefDrives = {}
self.NoBatteryWriteCacheEnabled = common_def.INVALID_BOOLEAN
self.ReadCachePercent = common_def.INVALID_U8
self.DriverName = common_def.INVALID_STRING
self.DriverVersion = common_def.INVALID_STRING
self.SlowDriveDetectionMode = common_def.INVALID_U8
end
function c_controller:set_default_ctrl1_values()
local string_pack = string.pack('I4', self.CtrlOption1)
local opt1 = CTRL_OPTION.option1_format:unpack(string_pack)
local prop_value = {}
if opt1.no_read_ahead_opt == 1 then
table.insert(prop_value, common_def.READ_POLICY_LIST[0])
end
if opt1.read_ahead_opt == 1 then
table.insert(prop_value, common_def.READ_POLICY_LIST[1])
end
self.SupportedReadPolicyList = prop_value
self.DefaultReadPolicy = common_def.READ_POLICY_LIST[opt1.read_policy_default]
self.ReadPolicyWritable = opt1.read_policy_support ~= 0
prop_value = {}
if opt1.write_through_opt == 1 then
table.insert(prop_value, common_def.WRITE_PLOICY_LIST[0])
end
if opt1.write_back_opt == 1 then
table.insert(prop_value, common_def.WRITE_PLOICY_LIST[1])
end
if opt1.write_back_if_bad_bbu_opt == 1 then
table.insert(prop_value, common_def.WRITE_PLOICY_LIST[2])
end
self.SupportedWritePolicyList = prop_value
self.DefaultWritePolicy = common_def.WRITE_PLOICY_LIST[opt1.write_policy_default]
self.WritePolicyWritable = opt1.write_policy_support ~= 0
prop_value = {}
if opt1.cached_io_opt == 1 then
table.insert(prop_value, common_def.IO_PLOICY_LIST[0])
end
if opt1.direct_io_opt == 1 then
table.insert(prop_value, common_def.IO_PLOICY_LIST[1])
end
self.SupportedIOPolicyList = prop_value
self.DefaultIOPolicy = common_def.IO_PLOICY_LIST[opt1.io_policy_default]
self.IOPolicyWritable = opt1.io_policy_support ~= 0
prop_value = {}
if opt1.access_rw_opt == 1 then
table.insert(prop_value, common_def.ACCESS_POLICY_LIST[0])
end
if opt1.access_read_only_opt == 1 then
table.insert(prop_value, common_def.ACCESS_POLICY_LIST[1])
end
if opt1.access_blocked_opt == 1 then
table.insert(prop_value, common_def.ACCESS_POLICY_LIST[2])
end
self.SupportedAccessPolicyList = prop_value
self.DefaultAccessPolicy = common_def.ACCESS_POLICY_LIST[opt1.access_policy_default]
self.AccessPolicyWritable = opt1.access_policy_support ~= 0
end
function c_controller:set_default_ctrl2_values()
local string_pack = string.pack('I4', self.CtrlOption2)
local opt2 = CTRL_OPTION.option2_format:unpack(string_pack)
local prop_value = {}
if opt2.pd_cache_unchanged_opt == 1 then
table.insert(prop_value, common_def.DRIVE_CACHE_POLICY_LIST[0])
end
if opt2.pd_cache_enable_opt == 1 then
table.insert(prop_value, common_def.DRIVE_CACHE_POLICY_LIST[1])
end
if opt2.pd_cache_disable_opt == 1 then
table.insert(prop_value, common_def.DRIVE_CACHE_POLICY_LIST[2])
end
self.SupportedDriveCachePolicyList = prop_value
self.DefaultDriveCachePolicy = common_def.DRIVE_CACHE_POLICY_LIST[opt2.pd_cache_policy_default]
self.DriveCachePolicyWritable = opt2.pd_cache_policy_support ~= 0
self.EpdSupported = opt2.ctrl_support_epd ~= 0 and true or false
self.JbodSupported = opt2.ctrl_support_jbod_state ~= 0 and true or false
end
function c_controller:set_default_ctrl3_values()
local string_pack = string.pack('I4', self.CtrlOption3)
local opt3 = CTRL_OPTION.option3_format:unpack(string_pack)
self.ConfiguredDriveWriteCachePolicy = common_def.RAID_CTRL_WCP_NAME[opt3.configured_drive_wcp] or ''
self.UnconfiguredDriveWriteCachePolicy = common_def.RAID_CTRL_WCP_NAME[opt3.unconfigured_drive_wcp] or ''
self.HBADriveWriteCachePolicy = common_def.RAID_CTRL_WCP_NAME[opt3.hba_drive_wcp] or ''
end
function c_controller:set_default_volume_manage_values()
self.CreateVolumeSupported = false
self:set_default_ctrl1_values()
self:set_default_ctrl2_values()
self:set_default_ctrl3_values()
end
function c_controller:update_supported_boot_devices_count()
if not method_misc:test_controller_vendor(self.TypeId, common_def.VENDER_HUAWEI) then
self.SupportedBootDeviceCount = common_def.BOOT_DEVICE_COUNT_DEFAULT
return
end
local ok, ret = pcall(sml.get_ctrl_fw_type, self.Id)
if ok then
local cfg = self.BootDeviceCountMappings
if not cfg or #cfg ~= 2 then
self.SupportedBootDeviceCount = common_def.BOOT_DEVICE_COUNT_DEFAULT
return
end
local fw_list = cfg.ControllerFwType or cfg[1]
local count_list = cfg.BootDeviceCount or cfg[2]
if not fw_list or not count_list or #fw_list ~= #count_list or #fw_list == 0 then
self.SupportedBootDeviceCount = common_def.BOOT_DEVICE_COUNT_DEFAULT
return
end
for i, v in ipairs(fw_list) do
if v == ret then
self.SupportedBootDeviceCount = count_list[i]
log:notice('update supported boot devices count to %d', self.SupportedBootDeviceCount)
if self.SupportedBootDeviceCount ~= common_def.BOOT_DEVICE_COUNT_DEFAULT then
self.BootDevices = {}
for j = 1, self.SupportedBootDeviceCount do
table.insert(self.BootDevices, common_def.INVALID_STRING)
end
end
return
end
end
end
self.SupportedBootDeviceCount = common_def.BOOT_DEVICE_COUNT_DEFAULT
return
end
function c_controller:set_default_consistency_values()
self.ConsistencyCheckState = common_def.INVALID_BOOLEAN
self.Rate = common_def.INVALID_STRING
self.PeriodOfHours = common_def.INVALID_U16
self.AutoRepairEnabled = common_def.INVALID_BOOLEAN
self.RunningStatus = common_def.INVALID_STRING
self.TotalVolumeCounts = common_def.INVALID_U16
self.CompletedVolumeCounts = common_def.INVALID_U16
end
function c_controller:set_default_health_status()
ctrl_commu_loss_monitor.get_instance():update(false, self.Id)
self.FaultCode = common_def.INVALID_U16
self.CommunicationLoss = 0
end
function c_controller:set_default_battery_info()
self.BatteryFault = 0
end
function c_controller:set_default_phy_err()
local phy_children = self:get_phy_children()
for _, v in pairs(phy_children) do
v.PhyId = common_def.INVALID_U8
v.InvalidDwordCount = 0
v.LossDwordSyncCount = 0
v.PhyResetProblemCount = 0
v.RunningDisparityErrorCount = 0
end
end
local function generate_controller_health_maintain_log(controller, ret)
local last_fault_code = controller.FaultCode == common_def.INVALID_U16 and 0 or controller.FaultCode
local cur_fault_code = ret.health_status_code
local tmp = last_fault_code ~ cur_fault_code
if tmp == 0 and ret.err_change == 0 then
return
end
if tmp & 1 ~= 0 then
log:maintenance(
log.MLOG_ERROR,
common_def.FC_STORAGE_RAID_CE,
'RAID controller (%s) detected memory correctable errors - %s.',
controller.DeviceName,
cur_fault_code & 1 ~= 0 and 'Asserted' or 'Deasserted'
)
end
if tmp & 1 << common_def.BIT_OFFSET_MEMORY_CORRECTABLE_ERROR ~= 0 then
log:maintenance(
log.MLOG_ERROR,
common_def.FC_STORAGE_RAID_UCE,
'RAID controller (%s) detected memory uncorrectable errors - %s.',
controller.DeviceName,
cur_fault_code & 1 << common_def.BIT_OFFSET_MEMORY_CORRECTABLE_ERROR ~= 0 and 'Asserted' or 'Deasserted'
)
end
if tmp & 1 << common_def.BIT_OFFSET_MEMORY_UNCORRECTABLE_ERROR ~= 0 then
log:maintenance(
log.MLOG_ERROR,
common_def.FC_STORAGE_RAID_ECC,
'RAID controller (%s) detected memory ECC errors reaching limit - %s.',
controller.DeviceName,
cur_fault_code & 1 << common_def.BIT_OFFSET_MEMORY_UNCORRECTABLE_ERROR ~= 0 and 'Asserted' or 'Deasserted'
)
end
if tmp & 1 << common_def.BIT_OFFSET_ECC_ERROR ~= 0 then
log:maintenance(
log.MLOG_ERROR,
common_def.FC_STORAGE_RAID_NVRAM,
'RAID controller (%s) detected NVRAM errors - %s.',
controller.DeviceName,
cur_fault_code & 1 << common_def.BIT_OFFSET_ECC_ERROR ~= 0 and 'Asserted' or 'Deasserted'
)
end
if tmp & 1 << common_def.BIT_OFFSET_RAID_HW_ERROR ~= 0 or ret.err_change & 2 ~= 0 then
log:maintenance(
log.MLOG_ERROR,
common_def.FC_STORAGE_RAID_BOARD_HARDWARE,
'RAID controller (%s) detected BOARD_HW errors, err_code: 0x%s - %s.',
controller.DeviceName,
string.format('%x', ret.hw_err),
cur_fault_code & 1 << common_def.BIT_OFFSET_RAID_HW_ERROR ~= 0 and 'Asserted' or 'Deasserted'
)
end
if tmp & 1 << common_def.BIT_OFFSET_RAID_CLK_ERROR ~= 0 or ret.err_change & 4 ~= 0 then
log:maintenance(
log.MLOG_ERROR,
common_def.FC_STORAGE_RAID_BOARD_CLOCK,
'RAID controller (%s) detected BOARD_CLK errors, err_code: 0x%s - %s.',
controller.DeviceName,
string.format('%x', ret.clk_err),
cur_fault_code & 1 << common_def.BIT_OFFSET_RAID_CLK_ERROR ~= 0 and 'Asserted' or 'Deasserted'
)
end
if tmp & 1 << common_def.BIT_OFFSET_RAID_POWER_ERROR ~= 0 or ret.err_change & 8 ~= 0 then
log:maintenance(
log.MLOG_ERROR,
common_def.FC_STORAGE_RAID_BOARD_POWER,
'RAID controller (%s) detected BOARD_POWER errors, err_code: 0x%s - %s.',
controller.DeviceName,
string.format('%x', ret.power_err),
cur_fault_code & 1 << common_def.BIT_OFFSET_RAID_POWER_ERROR ~= 0 and 'Asserted' or 'Deasserted'
)
end
if tmp & 1 << common_def.BIT_OFFSET_RAID_CAPACITY_ERROR ~= 0 or ret.err_change & 16 ~= 0 then
log:maintenance(
log.MLOG_ERROR,
common_def.FC_STORAGE_RAID_BOARD_CAPACITY,
'RAID controller (%s) detected BOARD_CAPACITY errors, err_code: 0x%s - %s.',
controller.DeviceName,
string.format('%x', ret.capacity_err),
cur_fault_code & 1 << common_def.BIT_OFFSET_RAID_CAPACITY_ERROR ~= 0 and 'Asserted' or 'Deasserted'
)
end
if tmp & 1 << common_def.BIT_OFFSET_RAID_FLASH_ERROR ~= 0 or ret.err_change & 32 ~= 0 then
log:maintenance(
log.MLOG_ERROR,
common_def.FC_STORAGE_RAID_BOARD_FLASH,
'RAID controller (%s) detected FLASH errors, err_code: 0x%s - %s.',
controller.DeviceName,
string.format('%x', ret.flash_err),
cur_fault_code & 1 << common_def.BIT_OFFSET_RAID_FLASH_ERROR ~= 0 and 'Asserted' or 'Deasserted'
)
end
end
function c_controller:add_controller_to_link_topo()
if method_misc:get_oob_interface_type(self.TypeId) == sml.OOB_TYPE_OVER_I2C then
local ok, _ = sml.set_i2c_chip(self.Id, self.RefChip)
if not ok then
error('[Storage]Failed to set i2c chip, controller_id = %d', self.Id)
end
log:notice('Controller_%d, RefChip.Path:%s', self.Id, self.RefChip.path)
elseif method_misc:get_oob_interface_type(self.TypeId) == sml.OOB_TYPE_OVER_PCIE then
local ok, ret = pcall(mctp_service.get_instance().register_mctp_object, mctp_service.get_instance(), self)
if not ok then
error(string.format('[Storage]Failed to register mctp object, ret = %s', ret))
end
log:notice('Register Controller_%d to mctp successfully', self.Id)
end
end
function c_controller:add_controller_to_sml()
local data = {}
if method_misc:get_oob_interface_type(self.TypeId) == sml.OOB_TYPE_OVER_PCIE then
data = {
Eid = self.Eid,
Phyaddr = self.Phyaddr,
}
end
local ret = sml.register_controller(self.Id, self.TypeId, sml.SML_ADD_CTRL, data)
if ret ~= 0 then
if ret ~= common_def.SML_ERR_CTRL_DUPLICATE_REGISTERED then
ctrl_commu_loss_monitor.get_instance():update(true, self.Id)
end
error(string.format('[Storage] Failed to add controller %d, ret: %s', self.Id, ret))
end
ctrl_commu_loss_monitor.get_instance():update(false, self.Id)
end
function c_controller:register_controller_to_sml()
local data = {}
local type_id_param = self:get_mapping_type_id()
local ret
log:notice(
'ctrl%s register_controller_to_sml, CreatedByDeviceObject=%s, DevicePath=%s',
self.Id,
tostring(self.CreatedByDeviceObject),
self.DevicePath
)
if self.CreatedByDeviceObject then
ret = sml.register_dev_controller(self.Id, type_id_param, sml.SML_REGISTER_CTRL, data, self.DevicePath)
else
ret = sml.register_controller(self.Id, type_id_param, sml.SML_REGISTER_CTRL, data)
end
log:info('ctrl%s register_controller_to_sml ret=%s', self.Id, tostring(ret))
if ret ~= 0 then
if ret ~= common_def.SML_ERR_CTRL_DUPLICATE_REGISTERED then
ctrl_commu_loss_monitor.get_instance():update(true, self.Id)
end
error(string.format('[Storage] Failed to register controller %d, ret: %s', self.Id, ret))
end
ctrl_commu_loss_monitor.get_instance():update(false, self.Id)
end
function c_controller:unregister_controller_to_sml()
local data = {}
local type_id_param = self:get_mapping_type_id()
local ret = sml.unregister_controller(self.Id, type_id_param, sml.SML_UNREGISTER_CTRL, data)
if ret ~= 0 then
error(string.format('[Storage] Failed to unregister controller %d, ret: %s', self.Id, ret))
end
end
local function get_state(v)
return (v == 0 or v == 1) and v or 2
end
local function set_suitable_state(v)
return (v == 0 or v == 1) and v or common_def.INVALID_U8
end
local function str_or_na(v)
if not v or #v == 0 then
return common_def.INVALID_STRING
end
return v
end
local function update_slow_drive_dection_mode(type_id, support_properties)
if not method_misc:test_controller_vendor(type_id, common_def.VENDER_HUAWEI) then
return common_def.INVALID_U8
end
local res
if support_properties.o_raw_drive_sw ~= support_properties.o_member_drive_sw then
res = support_properties.o_raw_drive_sw == 0 and common_def.SLOW_DISK_DETECTION_MODE.ENABLE_MEMBER_DRIVE
or common_def.SLOW_DISK_DETECTION_MODE.ENABLE_RAW_DRIVE
else
res = support_properties.o_raw_drive_sw == 0 and common_def.SLOW_DISK_DETECTION_MODE.DISABLE
or common_def.SLOW_DISK_DETECTION_MODE.ENABLE_RAW_AND_MEMBER_DRIVE
end
return res
end
function c_controller:update_sas_addr()
local ok, ret = pcall(sml.get_ctrl_sas_addr, self.Id)
if ok then
ctrl_commu_loss_monitor.get_instance():update(false, self.Id)
self.SASAddr = ret
else
record_commu_loss(ret, self.Id)
end
end
function c_controller:update_boot_devices()
local ok, ret = pcall(sml.get_ctrl_boot_devices, self.Id)
if ok then
ctrl_commu_loss_monitor.get_instance():update(false, self.Id)
local device_names = {}
for _, volume_id in ipairs(ret) do
local device_name = self:generate_boot_device_desc(volume_id)
table.insert(device_names, device_name)
end
local valid_device_names = {}
for i = 1, self.SupportedBootDeviceCount do
if device_names[i] then
table.insert(valid_device_names, device_names[i])
else
table.insert(valid_device_names, 'None')
end
end
self.BootDevices = valid_device_names
else
record_commu_loss(ret, self.Id)
end
end
function c_controller:update_fault_code()
local ok, ret = pcall(sml.get_ctrl_faultcode, self.Id)
if ok then
ctrl_commu_loss_monitor.get_instance():update(false, self.Id)
generate_controller_health_maintain_log(self, ret)
self.FaultCode = ret.health_status_code
else
record_commu_loss(ret, self.Id)
end
end
function c_controller:update_ctrl_info_from_sml(info)
self.ControllerName = info.ctrl_name
self.Type = CONTROLLER_TYPE[self.TypeId]
self.FirmwareVersion = info.fw_version
self.DeviceInterface = info:get_ctrl_device_interface()
if not method_misc:test_controller_vendor(self.TypeId, common_def.VENDER_HUAWEI) then
self.SerialNumber = info.ctrl_sn
end
self.MinStripSizeBytes, self.MaxStripSizeBytes = info:get_ctrl_strip_szie_options()
self.MemorySizeMiB = method_misc:update_if_valid(0, info.memory_size, common_def.INVALID_U16)
self.NVDataVersion = str_or_na(info.nvdata_version)
self.HardwareRevision = str_or_na(info.hardware_revision)
self.PCIeLinkWidth = (info.pcie_link_width and info.pcie_link_width ~= common_def.INVALID_U8)
and string.format('x%d', info.pcie_link_width)
or common_def.INVALID_STRING
self.SupportedMode = info.work_mode
self.HotSpareActivationMode = common_def.ACTIVATION_MODE[info.spare_activation_mode] or ''
self.SupportedRAIDTypes = info:get_raid_types()
self.NoBatteryWriteCacheEnabled = get_state(info.nobattery_write_cache)
self.ReadCachePercent = info.read_cache_percent
local two_bytes_width = info.ctrl_temp & common_def.U16_MAX
local trans_temperature = two_bytes_width >= common_def.SIGNED_BIT and -(common_def.U16_MAX - two_bytes_width + 1)
or two_bytes_width
self.TemperatureCelsius = (trans_temperature >= 255) and 255 or trans_temperature
self.DDREccCount = info.memory_ecc_count
self.UncorrectableParityErrorCount = info.memory_uce_count
self.CachePinnedState = set_suitable_state(info.cache_pinned)
self.MaintainPDFailHistrory = set_suitable_state(info.maint_pd_fail_history)
self.WorkMode = (info.mode and info.mode < #work_mode) and work_mode[info.mode + 1] or common_def.INVALID_STRING
local operations = info:get_support_operations()
local ld_operations = operations.ld_operations
self.WritePolicyWritable = ld_operations.o_support_write_policy == 1
self.IOPolicyWritable = ld_operations.o_support_io_policy == 1
self.AccessPolicyWritable = ld_operations.o_support_access_policy == 1
self.ReadPolicyWritable = ld_operations.o_support_read_policy == 1
self.DriveCachePolicyWritable = ld_operations.o_support_disk_cache_policy == 1
local ctrl_operations = operations.ctrl_operations
self.HBADriveWriteCachePolicy = common_def.RAID_CTRL_WCP_NAME[ctrl_operations.o_hba_drive_wcp] or ''
self.ConfiguredDriveWriteCachePolicy = common_def.RAID_CTRL_WCP_NAME[ctrl_operations.o_configured_drive_wcp] or ''
self.UnconfiguredDriveWriteCachePolicy = common_def.RAID_CTRL_WCP_NAME[ctrl_operations.o_unconfigured_drive_wcp]
or ''
self.EpdSupported = ctrl_operations.o_support_epd ~= 0 and true or false
self.JbodSupported = ctrl_operations.o_support_jbod_state ~= 0 and true or false
local support_properties = info:get_support_properties(self.TypeId)
self.JBODState = set_suitable_state(support_properties.o_jbod_enabled)
self.CopyBackState = set_suitable_state(support_properties.o_copyback_enabled)
self.SmarterCopyBackState = set_suitable_state(support_properties.o_smarter_copyback_enabled)
self.CryptoEraseSupported = get_state(support_properties.o_support_crypto_erase) ~= 0
self.CreateVolumeSupported = c_storageconfig.get_instance():get_set_configuration_ready_flag(self.Id)
self.SlowDriveDetectionMode = update_slow_drive_dection_mode(self.TypeId, support_properties)
if method_misc:get_oob_interface_type(self.TypeId) == sml.OOB_TYPE_OVER_PCIE then
self:update_consistency_check(support_properties)
end
if not self.config_backed_up then
skynet.fork(function()
ctrl_config_backup.get_instance():on_first_config_loaded(self)
end)
else
skynet.fork(function()
ctrl_config_backup.get_instance():sync_inband_config(self)
end)
end
end
function c_controller:generate_boot_device_desc(volume_id)
if not volume_id or volume_id == 0 then
return 'None'
end
if volume_id & VOLUME_TYPE_PHYSICAL_DRIVE_BIT ~= 0 then
local drive_obj =
drive_collection:get_drive_by_physic_id(self.Id, volume_id & 0xFF, (volume_id & 0xFFFF00) >> 8)
if drive_obj then
return drive_obj.Name
end
end
if volume_id & VOLUME_TYPE_LOGICAL_DRIVE_BIT ~= 0 then
local ret = 'Volume' .. (volume_id & 0xFFFF)
return ret
end
end
function c_controller:update_consistency_check(consis_check_table)
self.ConsistencyCheckState = get_state(consis_check_table.o_consis_check_enabled)
self.PeriodOfHours = consis_check_table.o_consis_check_period
self.Rate = rate_array[consis_check_table.o_consis_check_rate]
self.AutoRepairEnabled = get_state(consis_check_table.o_consis_check_repair)
self.RunningStatus = running_state[consis_check_table.o_consis_check_status + 1]
self.TotalVolumeCounts = consis_check_table.o_consis_check_totalvd
self.CompletedVolumeCounts = consis_check_table.o_consis_check_completedvd
end
function c_controller:update_controller_battery_info()
local ref_battery = battery_collection.get_instance():get_capcacitance_by_controller_id(self.Id)
if not ref_battery then
return
end
self.BatteryPresence =
self.presence_debounce:get_debounced_val(ref_battery.State and ref_battery.State or common_def.INVALID_U8)
if ref_battery.Fault ~= common_def.INVALID_U8 then
self.BatteryFault = (ref_battery.Fault == 0 and 0 or 1)
end
ref_battery.Health = self.BatteryHealth
end
function c_controller:compare_pd_list(pd_list)
local new_pd_list = {}
local del_pd_list = {}
local pd_count = 0
for _, pd in ipairs(pd_list) do
if not self.pd_list[pd.key] then
new_pd_list[#new_pd_list + 1] = pd
end
new_pd_list[pd.key] = true
end
for key in pairs(self.pd_list) do
pd_count = pd_count + 1
if not new_pd_list[key] then
del_pd_list[#del_pd_list + 1] = key
end
end
return new_pd_list, del_pd_list
end
function c_controller:get_ctrl_pd_list()
local pd_list = {}
local controller_id = self.Id
if self.tasks_pause or c_storageconfig.get_instance().power_on == 0 then
return
end
local ok, ret = pcall(sml.get_ctrl_pd_list, controller_id)
if not ok then
log:error('get_ctrl_pd_list failed and return %s', ret)
if
ret == common_def.SML_ERR_MCTP_TIME_OUT
and method_misc:test_controller_vendor(self.TypeId, common_def.VENDER_HUAWEI)
then
self.timeout_times = self.timeout_times + 1
if self.timeout_times == MAX_RETRY_TIMES then
self:register()
self.timeout_times = 0
end
end
record_commu_loss(ret, self.Id)
return nil
end
self.timeout_times = 0
ctrl_commu_loss_monitor.get_instance():update(false, self.Id)
for _, pd in ipairs(ret) do
pd_list[#pd_list + 1] = pd_object.new(controller_id, pd, self.TypeId)
end
table.sort(pd_list, function(a, b)
return a.slot_num < b.slot_num
end)
log:debug(pd_list)
return pd_list
end
function c_controller:check_pd_missing(pd_list)
local drive_list = drive_collection:get_all_drives()
for _, drive_obj in pairs(drive_list) do
if
drive_obj.Presence == 1
and drive_obj.RefControllerId == self.Id
and drive_obj.RefControllerTypeId ~= common_def.INVALID_U8
then
drive_obj:check_missing(pd_list)
end
end
end
function c_controller:update_pd_list()
local ok, ret = pcall(sml.get_ctrl_init_state, self.Id)
if not ok or ret ~= 2 then
return
end
local pd_list = self:get_ctrl_pd_list()
if pd_list == nil then
return
end
self:check_pd_missing(pd_list)
local new_pd_list, del_pd_list = self:compare_pd_list(pd_list)
for _, key in ipairs(del_pd_list) do
local deleted_pd = self.pd_list[key]
self.pd_list[key] = nil
if self:is_directly_manage_physical_drive() then
local drive = drive_collection
.get_instance()
:get_drive_by_physic_id(self.Id, deleted_pd.slot_num, deleted_pd.enclosure_id)
if drive then
drive:set_presence(0)
end
end
deleted_pd:invalid()
self.on_del_pd:emit(deleted_pd)
end
for _, pd in ipairs(new_pd_list) do
self.pd_list[pd.key] = pd
if self:is_directly_manage_physical_drive() then
local start_drive_id = common_def.HRDT_B261_START_DRIVE_ID
local drive_id = start_drive_id + pd.slot_num - 1
local drive_name = string.format('Disk%d', drive_id)
local drive = drive_collection.get_instance():get_drive(drive_name)
if drive then
drive:set_presence(1)
end
end
self.on_add_pd:emit(pd)
end
self.on_add_pd_complete:emit(true)
end
function c_controller:get_sub_objs(path)
local service = 'bmc.kepler.host_agent'
local bus_resource = self.bus
for _ = 1, 3 do
local err, objects =
bus_resource:pcall(service, path, 'org.freedesktop.DBus.ObjectManager', 'GetManagedObjects', '')
if not err and objects then
return objects
end
skynet.sleep(100)
end
end
function c_controller:update_controller_info_via_bma()
local ok_sms_status, sms_status_obj =
pcall(mdb.get_object, self.bus, '/bmc/kepler/Systems/1/Sms', 'bmc.kepler.Systems.Sms.SmsStatus')
local ok_sms, sms_obj = pcall(mdb.get_object, self.bus, '/bmc/kepler/Systems/1/Sms', 'bmc.kepler.Systems.Sms')
if not ok_sms_status or not ok_sms then
return
end
if sms_status_obj.State == 0 and sms_obj.Registered == true then
self:update_info_via_bma()
else
self.DriverName = common_def.INVALID_STRING
self.DriverVersion = common_def.INVALID_STRING
end
end
local CONTROLLER_PATH = '/bmc/kepler/Systems/1/Sms/1/ComputerSystem/Systems/1/Storage/1/StorageControllers'
local function convert_bdf(bdf)
if not bdf then
error('no bdf')
end
return string.match(bdf, '(.+):(.+):(.+).(.+)')
end
local BDF_PATH = 'bmc.kepler.sms.redfish.Oem.Huawei.BDFNumber'
function c_controller:bdf_match(bma_resource)
if not bma_resource[BDF_PATH] or not bma_resource[BDF_PATH].BDF then
log:error('bma_resource bdf path:%s or BDF property not exist', BDF_PATH)
return false
end
local ok, _, dev_bus, dev_device, dev_func = pcall(convert_bdf, bma_resource[BDF_PATH].BDF:value():value())
if not ok or not dev_bus or not dev_device or not dev_func then
log:error(
'[controller_object] Failed to convert BDF, ctrl_id=%s, BDF=%s:%s:%s',
self.Id,
dev_bus,
dev_device,
dev_func
)
return false
end
if
self.DevBus == tonumber(dev_bus, 16)
and self.DevDevice == tonumber(dev_device, 16)
and self.DevFunction == tonumber(dev_func, 16)
then
return true
end
return false
end
local function update_drive_info_from_bma(driveinfo)
local driveinfo_str = common_def.INVALID_STRING
if driveinfo ~= 'null' then
driveinfo_str = driveinfo
end
return driveinfo_str
end
function c_controller:update_info_via_bma()
local info_interface = 'bmc.kepler.sms.redfish.Oem.Huawei.DriverInfo'
local objects = self:get_sub_objs(CONTROLLER_PATH)
if not objects or not next(objects) then
return
end
for _, object in pairs(objects) do
if self:bdf_match(object) then
self.DriverName = update_drive_info_from_bma(object[info_interface].DriverName:value():value())
self.DriverVersion = update_drive_info_from_bma(object[info_interface].DriverVersion:value():value())
return
end
end
log:info('Controller %s update DriverName and DriverVersion failed!', self.Id)
end
function c_controller:compare_volume_list(volume_list)
local new_volume_list = {}
local del_volume_list = {}
for _, volume in ipairs(volume_list) do
if not self.volume_list[volume.key] then
new_volume_list[#new_volume_list + 1] = volume
end
new_volume_list[volume.key] = true
end
for key in pairs(self.volume_list) do
if not new_volume_list[key] then
del_volume_list[#del_volume_list + 1] = key
end
end
if log:getLevel() >= log.INFO then
log:info(
'Controller %s add new volume list:%s, del volume list:%s',
self.Id,
cjson.encode(new_volume_list),
cjson.encode(del_volume_list)
)
end
return new_volume_list, del_volume_list
end
function c_controller:get_ctrl_volume_list()
local volume_list = {}
local controller_id = self.Id
if self.tasks_pause or c_storageconfig.get_instance().power_on == 0 then
return
end
local ok, ret = pcall(sml.get_ctrl_ld_list, controller_id)
if not ok then
log:debug('get_ctrl_ld_list failed and return %s', ret)
record_commu_loss(ret, self.Id)
return nil
end
ctrl_commu_loss_monitor.get_instance():update(false, self.Id)
for _, volume_id in ipairs(ret) do
volume_list[#volume_list + 1] =
volume_obj_info.new(self.position, controller_id, volume_id, self.CreatedByDeviceObject)
end
return volume_list
end
function c_controller:update_volume_list()
local ok, ret = pcall(sml.get_ctrl_init_state, self.Id)
if not ok or ret ~= 2 then
return
end
local volume_list = self:get_ctrl_volume_list()
if volume_list == nil then
return
end
local new_volume_list, del_volume_list = self:compare_volume_list(volume_list)
for _, key in ipairs(del_volume_list) do
local deleted_volume = self.volume_list[key]
self.volume_list[key] = nil
volume_collection.get_instance().on_del_volume:emit(deleted_volume)
end
for _, volume in ipairs(new_volume_list) do
self.volume_list[volume.key] = volume
volume_collection.get_instance().on_add_volume:emit(volume)
end
end
function c_controller:remove_volume_list()
local old_volume_list = self.volume_list
self.volume_list = {}
for _, volume_obj in pairs(old_volume_list) do
volume_collection.get_instance().on_del_volume:emit(volume_obj)
end
end
function c_controller:compare_array_list(sml_array_list)
local add_array_list = {}
local del_array_list = {}
local new_array_list = {}
for _, array_id in ipairs(sml_array_list) do
if not self.array_list[array_id] then
add_array_list[#add_array_list + 1] = array_id
end
new_array_list[array_id] = true
end
for array_id, _ in pairs(self.array_list) do
if not new_array_list[array_id] then
del_array_list[#del_array_list + 1] = array_id
end
end
return add_array_list, del_array_list
end
function c_controller:update_array_list()
local controller_id = self.Id
local ok, ret = pcall(sml.get_ctrl_init_state, self.Id)
if not ok or ret ~= 2 then
return
end
if self.tasks_pause or c_storageconfig.get_instance().power_on == 0 then
return
end
ok, ret = pcall(sml.get_ctrl_array_list, controller_id)
if not ok then
record_commu_loss(ret, self.Id)
return
end
ctrl_commu_loss_monitor.get_instance():update(false, self.Id)
self.array_list = array_collection.get_instance():get_ctrl_array_list_by_ctrl_id(self.Id)
local add_array_list, del_array_list = self:compare_array_list(ret)
for _, array_id in ipairs(del_array_list) do
self.array_list[array_id] = nil
array_collection.get_instance().on_del_array:emit(self.Id, array_id)
end
for _, array_id in ipairs(add_array_list) do
self.array_list[array_id] = true
array_collection.get_instance().on_add_array:emit(self.Id, self.controller_path, array_id)
end
end
function c_controller:remove_array_list()
local old_array_list = self.array_list
self.array_list = {}
for array_id, _ in pairs(old_array_list) do
array_collection.get_instance().on_del_array:emit(self.Id, array_id)
end
end
function c_controller:get_phy_children()
local phy_children = {}
if self.CreatedByDeviceObject and self.DevicePath then
local controller_mgmt = require('controller.controller_mgmt')
local mgmt = controller_mgmt.get_instance()
if mgmt and mgmt.sasphys then
local prefix = self.DevicePath .. '/'
for device_path, obj in pairs(mgmt.sasphys) do
if type(obj) == 'table' and string.sub(device_path, 1, #prefix) == prefix then
table.insert(phy_children, obj)
end
end
end
if next(phy_children) then
table.sort(phy_children, function(a, b)
return a.PhyId < b.PhyId
end)
end
return phy_children
end
local children = self:get_children()
for _, v in pairs(children) do
if v['PhyId'] then
table.insert(phy_children, v)
end
end
if next(phy_children) then
table.sort(phy_children, function(a, b)
return a.path < b.path
end)
end
return phy_children
end
function c_controller:update_phy_info()
local ok, phy_addr = pcall(function()
return sml.get_ctrl_sas_phy_err(self.Id, 0)
end)
if not ok or not phy_addr then
return
end
local phy_children = self:get_phy_children()
if #phy_addr + 1 ~= #phy_children then
return
end
local phy_id
for k, v in pairs(phy_children) do
phy_id = k - 1
v.PhyId = phy_id
v.InvalidDwordCount = phy_addr[phy_id].invalid_dword_count
v.LossDwordSyncCount = phy_addr[phy_id].loss_dword_sync_count
v.PhyResetProblemCount = phy_addr[phy_id].phy_reset_problem_count
v.RunningDisparityErrorCount = phy_addr[phy_id].running_disparity_error_count
end
end
function c_controller:dump_info(fp_w)
controller_dump:dump_info(fp_w, self)
end
function c_controller:clear_asset_data_info()
self.AssetType = ''
self.AssetName = ''
self.InventorySerialNumber = ''
self.InventoryFirmwareVersion = ''
self.Manufacturer = ''
self.AssetTag = ''
self.PartNumber = ''
self.ManufactureDate = ''
self.Slot = ''
self.UUID = ''
self.InventoryModel = ''
end
function c_controller:update_asset_data_info()
self.AssetType = 'PCIe RAID Card'
self.AssetName = self.ControllerName
self.InventorySerialNumber = self.SerialNumber
self.InventoryFirmwareVersion = self.FirmwareVersion
self.Manufacturer = self.ChipManufacturer
self.InventoryModel = self.Model
self.AssetTag = 'N/A'
self.PartNumber = self.BOMNumber
self.ManufactureDate = 'N/A'
self.Slot = tostring(self.Id)
self.UUID = 'N/A'
end
function c_controller:trans_pd_vendor_data()
local data_str = cjson.encode(common_def.DRIVE_VENDOR_TABLE)
local ok, ret = pcall(sml.trans_drive_data, self.Id, data_str)
if not ok then
log:error('trans pd_vendor_data failed ,ret is %s', ret)
end
end
function c_controller:get_mapping_type_id()
return common_def.TYPEID_MAPPING[self.TypeId] and common_def.TYPEID_MAPPING[self.TypeId] or self.TypeId
end
function c_controller:get_pcie_card_quad()
local software_id = 'RAID-NA'
local retries = 0
while retries < QUAD_RETRY_TIMES do
retries = retries + 1
local ok, card_list = pcall(mdb.get_sub_objects, self.bus, PCIE_CARD_PATH, PCIE_CARD_INTERFACE)
if ok and card_list then
for _, card in pairs(card_list) do
if card.DeviceName == self.DeviceName then
software_id = string.format(
'RAID-%04x.%04x.%04x.%04x',
card.VendorID,
card.DeviceID,
card.SubVendorID,
card.SubDeviceID
)
log:notice(
'[Controller] get PCIeCard quad success, attempt %s/%s, DeviceName=%s, SoftwareId=%s',
retries,
QUAD_RETRY_TIMES,
tostring(self.DeviceName),
software_id
)
return software_id
end
end
end
if retries < QUAD_RETRY_TIMES then
skynet.sleep(QUAD_RETRY_INTERVAL)
else
log:error(
'[Controller] get PCIeCard quad failed after %s times, DeviceName=%s, SlotId=%s',
QUAD_RETRY_TIMES,
tostring(self.DeviceName),
tostring(self.SlotId)
)
end
end
return software_id
end
function c_controller:register_controller_firmware_info()
if not method_misc:check_is_suport_upgrade(self.TypeId) then
return
end
local data = {
Id = self.NodeId,
Name = self.DeviceName,
Version = self.FirmwareVersion,
Manufacturer = self.ChipManufacturer,
State = 'Enabled',
Severity = 'Informational',
EstimatedDuration = '30',
Location = tostring(self.Id),
SoftwareId = self:get_pcie_card_quad(),
ActiveCondition = 'None',
StageSupported = 'false',
ComponentID = tostring(upgrade_defs.RAID_COMPONENT_ID),
SubComponentID = tostring(upgrade_defs.RAID_COMPONENT_IDEX),
FirmwareType = upgrade_defs.FIRMWARE_TYPE_RAID,
TargetUIDs = '',
RelatedItem = upgrade_defs.REDFISH_RAID_URI_PREFIX .. self.Id,
}
method_misc:retry_register_firmware_info(data, true, 4, 10, function()
self.firmware_register_status = true
end)
end
c_controller.record_commu_loss = record_commu_loss
return c_controller