Merge patch series "mpi3mr: Host diag buffer support"

Ranjan Kumar <ranjan.kumar@broadcom.com> says:

The controllers managed by mpi3mr driver requires system memory to
save hardware and firmware diagnostic information, this patch set
enhances the drivers to provide host memory to the controller for
diagnostic information.  This patch set also provides driver changes
to push kernel messages into the diagnostic buffers reserved for the
driver, so that the information will be available as part of debug
data fetched from the controller.  In addition, support for
configuring automatic diagnostic information is added in the driver.

Link: https://lore.kernel.org/r/20240626102646.14298-1-ranjan.kumar@broadcom.com
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Martin K. Petersen
2024-06-26 23:30:54 -04:00
6 changed files with 1634 additions and 11 deletions

View File

@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright 2016-2024 Broadcom Inc. All rights reserved.
*/
#ifndef MPI30_TOOL_H
#define MPI30_TOOL_H 1
#define MPI3_DIAG_BUFFER_TYPE_TRACE (0x01)
#define MPI3_DIAG_BUFFER_TYPE_FW (0x02)
#define MPI3_DIAG_BUFFER_ACTION_RELEASE (0x01)
struct mpi3_diag_buffer_post_request {
__le16 host_tag;
u8 ioc_use_only02;
u8 function;
__le16 ioc_use_only04;
u8 ioc_use_only06;
u8 msg_flags;
__le16 change_count;
__le16 reserved0a;
u8 type;
u8 reserved0d;
__le16 reserved0e;
__le64 address;
__le32 length;
__le32 reserved1c;
};
struct mpi3_diag_buffer_manage_request {
__le16 host_tag;
u8 ioc_use_only02;
u8 function;
__le16 ioc_use_only04;
u8 ioc_use_only06;
u8 msg_flags;
__le16 change_count;
__le16 reserved0a;
u8 type;
u8 action;
__le16 reserved0e;
};
#endif

View File

@@ -47,6 +47,7 @@
#include "mpi/mpi30_ioc.h"
#include "mpi/mpi30_sas.h"
#include "mpi/mpi30_pci.h"
#include "mpi/mpi30_tool.h"
#include "mpi3mr_debug.h"
/* Global list and lock for storing multiple adapters managed by the driver */
@@ -55,8 +56,8 @@ extern struct list_head mrioc_list;
extern int prot_mask;
extern atomic64_t event_counter;
#define MPI3MR_DRIVER_VERSION "8.8.1.0.50"
#define MPI3MR_DRIVER_RELDATE "5-March-2024"
#define MPI3MR_DRIVER_VERSION "8.9.1.0.50"
#define MPI3MR_DRIVER_RELDATE "14-May-2024"
#define MPI3MR_DRIVER_NAME "mpi3mr"
#define MPI3MR_DRIVER_LICENSE "GPL"
@@ -187,6 +188,30 @@ extern atomic64_t event_counter;
#define MPI3MR_HARD_SECURE_DEVICE 0x08
#define MPI3MR_TAMPERED_DEVICE 0x0C
#define MPI3MR_DEFAULT_HDB_MAX_SZ (4 * 1024 * 1024)
#define MPI3MR_DEFAULT_HDB_DEC_SZ (1 * 1024 * 1024)
#define MPI3MR_DEFAULT_HDB_MIN_SZ (2 * 1024 * 1024)
#define MPI3MR_MAX_NUM_HDB 2
#define MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN 0
#define MPI3MR_HDB_TRIGGER_TYPE_FAULT 1
#define MPI3MR_HDB_TRIGGER_TYPE_ELEMENT 2
#define MPI3MR_HDB_TRIGGER_TYPE_GLOBAL 3
#define MPI3MR_HDB_TRIGGER_TYPE_SOFT_RESET 4
#define MPI3MR_HDB_TRIGGER_TYPE_FW_RELEASED 5
#define MPI3MR_HDB_REFRESH_TYPE_RESERVED 0
#define MPI3MR_HDB_REFRESH_TYPE_CURRENT 1
#define MPI3MR_HDB_REFRESH_TYPE_DEFAULT 2
#define MPI3MR_HDB_HDB_REFRESH_TYPE_PERSISTENT 3
#define MPI3MR_DEFAULT_HDB_SZ (4 * 1024 * 1024)
#define MPI3MR_MAX_NUM_HDB 2
#define MPI3MR_HDB_QUERY_ELEMENT_TRIGGER_FORMAT_INDEX 0
#define MPI3MR_HDB_QUERY_ELEMENT_TRIGGER_FORMAT_DATA 1
/* SGE Flag definition */
#define MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST \
(MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | MPI3_SGE_FLAGS_DLAS_SYSTEM | \
@@ -210,6 +235,8 @@ extern atomic64_t event_counter;
#define MPI3MR_WRITE_SAME_MAX_LEN_256_BLKS 256
#define MPI3MR_WRITE_SAME_MAX_LEN_2048_BLKS 2048
#define MPI3MR_DRIVER_EVENT_PROCESS_TRIGGER (0xFFFD)
/**
* struct mpi3mr_nvme_pt_sge - Structure to store SGEs for NVMe
* Encapsulated commands.
@@ -289,9 +316,12 @@ enum mpi3mr_reset_reason {
MPI3MR_RESET_FROM_PELABORT_TIMEOUT = 22,
MPI3MR_RESET_FROM_SYSFS = 23,
MPI3MR_RESET_FROM_SYSFS_TIMEOUT = 24,
MPI3MR_RESET_FROM_DIAG_BUFFER_POST_TIMEOUT = 25,
MPI3MR_RESET_FROM_DIAG_BUFFER_RELEASE_TIMEOUT = 26,
MPI3MR_RESET_FROM_FIRMWARE = 27,
MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT = 29,
MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT = 30,
MPI3MR_RESET_FROM_TRIGGER = 31,
};
#define MPI3MR_RESET_REASON_OSTYPE_LINUX 1
@@ -327,6 +357,9 @@ struct mpi3mr_ioc_facts {
u32 ioc_capabilities;
struct mpi3mr_compimg_ver fw_ver;
u32 mpi_version;
u32 diag_trace_sz;
u32 diag_fw_sz;
u32 diag_drvr_sz;
u16 max_reqs;
u16 product_id;
u16 op_req_sz;
@@ -852,6 +885,59 @@ struct mpi3mr_drv_cmd {
struct mpi3mr_drv_cmd *drv_cmd);
};
/**
* union mpi3mr_trigger_data - Trigger data information
* @fault: Fault code
* @global: Global trigger data
* @element: element trigger data
*/
union mpi3mr_trigger_data {
u16 fault;
u64 global;
union mpi3_driver2_trigger_element element;
};
/**
* struct trigger_event_data - store trigger related
* information.
*
* @trace_hdb: Trace diag buffer descriptor reference
* @fw_hdb: FW diag buffer descriptor reference
* @trigger_type: Trigger type
* @trigger_specific_data: Trigger specific data
* @snapdump: Snapdump enable or disable flag
*/
struct trigger_event_data {
struct diag_buffer_desc *trace_hdb;
struct diag_buffer_desc *fw_hdb;
u8 trigger_type;
union mpi3mr_trigger_data trigger_specific_data;
bool snapdump;
};
/**
* struct diag_buffer_desc - memory descriptor structure to
* store virtual, dma addresses, size, buffer status for host
* diagnostic buffers.
*
* @type: Buffer type
* @trigger_data: Trigger data
* @trigger_type: Trigger type
* @status: Buffer status
* @size: Buffer size
* @addr: Virtual address
* @dma_addr: Buffer DMA address
*/
struct diag_buffer_desc {
u8 type;
union mpi3mr_trigger_data trigger_data;
u8 trigger_type;
u8 status;
u32 size;
void *addr;
dma_addr_t dma_addr;
};
/**
* struct dma_memory_desc - memory descriptor structure to store
* virtual address, dma address and size for any generic dma
@@ -1054,11 +1140,19 @@ struct scmd_priv {
* @sas_node_lock: Lock to protect SAS node list
* @hba_port_table_list: List of HBA Ports
* @enclosure_list: List of Enclosure objects
* @diag_buffers: Host diagnostic buffers
* @driver_pg2: Driver page 2 pointer
* @reply_trigger_present: Reply trigger present flag
* @event_trigger_present: Event trigger present flag
* @scsisense_trigger_present: Scsi sense trigger present flag
* @ioctl_dma_pool: DMA pool for IOCTL data buffers
* @ioctl_sge: DMA buffer descriptors for IOCTL data
* @ioctl_chain_sge: DMA buffer descriptor for IOCTL chain
* @ioctl_resp_sge: DMA buffer descriptor for Mgmt cmd response
* @ioctl_sges_allocated: Flag for IOCTL SGEs allocated or not
* @trace_release_trigger_active: Trace trigger active flag
* @fw_release_trigger_active: Fw release trigger active flag
* @snapdump_trigger_active: Snapdump trigger active flag
*/
struct mpi3mr_ioc {
struct list_head list;
@@ -1250,6 +1344,15 @@ struct mpi3mr_ioc {
struct dma_memory_desc ioctl_chain_sge;
struct dma_memory_desc ioctl_resp_sge;
bool ioctl_sges_allocated;
bool reply_trigger_present;
bool event_trigger_present;
bool scsisense_trigger_present;
struct diag_buffer_desc diag_buffers[MPI3MR_MAX_NUM_HDB];
struct mpi3_driver_page2 *driver_pg2;
spinlock_t trigger_lock;
bool snapdump_trigger_active;
bool trace_release_trigger_active;
bool fw_release_trigger_active;
};
/**
@@ -1406,6 +1509,8 @@ int mpi3mr_cfg_set_sas_io_unit_pg1(struct mpi3mr_ioc *mrioc,
struct mpi3_sas_io_unit_page1 *sas_io_unit_pg1, u16 pg_sz);
int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc,
struct mpi3_driver_page1 *driver_pg1, u16 pg_sz);
int mpi3mr_cfg_get_driver_pg2(struct mpi3mr_ioc *mrioc,
struct mpi3_driver_page2 *driver_pg2, u16 pg_sz, u8 page_type);
u8 mpi3mr_is_expander_device(u16 device_info);
int mpi3mr_expander_add(struct mpi3mr_ioc *mrioc, u16 handle);
@@ -1439,4 +1544,28 @@ void mpi3mr_free_enclosure_list(struct mpi3mr_ioc *mrioc);
int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc);
void mpi3mr_expander_node_remove(struct mpi3mr_ioc *mrioc,
struct mpi3mr_sas_node *sas_expander);
void mpi3mr_alloc_diag_bufs(struct mpi3mr_ioc *mrioc);
int mpi3mr_post_diag_bufs(struct mpi3mr_ioc *mrioc);
int mpi3mr_issue_diag_buf_release(struct mpi3mr_ioc *mrioc,
struct diag_buffer_desc *diag_buffer);
void mpi3mr_release_diag_bufs(struct mpi3mr_ioc *mrioc, u8 skip_rel_action);
void mpi3mr_set_trigger_data_in_hdb(struct diag_buffer_desc *hdb,
u8 type, union mpi3mr_trigger_data *trigger_data, bool force);
int mpi3mr_refresh_trigger(struct mpi3mr_ioc *mrioc, u8 page_type);
struct diag_buffer_desc *mpi3mr_diag_buffer_for_type(struct mpi3mr_ioc *mrioc,
u8 buf_type);
int mpi3mr_issue_diag_buf_post(struct mpi3mr_ioc *mrioc,
struct diag_buffer_desc *diag_buffer);
void mpi3mr_set_trigger_data_in_all_hdb(struct mpi3mr_ioc *mrioc,
u8 type, union mpi3mr_trigger_data *trigger_data, bool force);
void mpi3mr_reply_trigger(struct mpi3mr_ioc *mrioc, u16 iocstatus,
u32 iocloginfo);
void mpi3mr_hdb_trigger_data_event(struct mpi3mr_ioc *mrioc,
struct trigger_event_data *event_data);
void mpi3mr_scsisense_trigger(struct mpi3mr_ioc *mrioc, u8 senseky, u8 asc,
u8 ascq);
void mpi3mr_event_trigger(struct mpi3mr_ioc *mrioc, u8 event);
void mpi3mr_global_trigger(struct mpi3mr_ioc *mrioc, u64 trigger_data);
void mpi3mr_hdbstatuschg_evt_th(struct mpi3mr_ioc *mrioc,
struct mpi3_event_notification_reply *event_reply);
#endif /*MPI3MR_H_INCLUDED*/

File diff suppressed because it is too large Load Diff

View File

@@ -274,6 +274,9 @@ static void mpi3mr_print_event_data(struct mpi3mr_ioc *mrioc,
case MPI3_EVENT_PREPARE_FOR_RESET:
desc = "Prepare For Reset";
break;
case MPI3_EVENT_DIAGNOSTIC_BUFFER_STATUS_CHANGE:
desc = "Diagnostic Buffer Status Change";
break;
}
if (!desc)
@@ -342,13 +345,14 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
{
u16 reply_desc_type, host_tag = 0;
u16 ioc_status = MPI3_IOCSTATUS_SUCCESS;
u32 ioc_loginfo = 0;
u32 ioc_loginfo = 0, sense_count = 0;
struct mpi3_status_reply_descriptor *status_desc;
struct mpi3_address_reply_descriptor *addr_desc;
struct mpi3_success_reply_descriptor *success_desc;
struct mpi3_default_reply *def_reply = NULL;
struct mpi3mr_drv_cmd *cmdptr = NULL;
struct mpi3_scsi_io_reply *scsi_reply;
struct scsi_sense_hdr sshdr;
u8 *sense_buf = NULL;
*reply_dma = 0;
@@ -363,6 +367,7 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
mpi3mr_reply_trigger(mrioc, ioc_status, ioc_loginfo);
break;
case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
@@ -380,7 +385,15 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
scsi_reply = (struct mpi3_scsi_io_reply *)def_reply;
sense_buf = mpi3mr_get_sensebuf_virt_addr(mrioc,
le64_to_cpu(scsi_reply->sense_data_buffer_address));
sense_count = le32_to_cpu(scsi_reply->sense_count);
if (sense_buf) {
scsi_normalize_sense(sense_buf, sense_count,
&sshdr);
mpi3mr_scsisense_trigger(mrioc, sshdr.sense_key,
sshdr.asc, sshdr.ascq);
}
}
mpi3mr_reply_trigger(mrioc, ioc_status, ioc_loginfo);
break;
case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
@@ -938,6 +951,14 @@ static const struct {
},
{ MPI3MR_RESET_FROM_SYSFS, "sysfs invocation" },
{ MPI3MR_RESET_FROM_SYSFS_TIMEOUT, "sysfs TM timeout" },
{
MPI3MR_RESET_FROM_DIAG_BUFFER_POST_TIMEOUT,
"diagnostic buffer post timeout"
},
{
MPI3MR_RESET_FROM_DIAG_BUFFER_RELEASE_TIMEOUT,
"diagnostic buffer release timeout"
},
{ MPI3MR_RESET_FROM_FIRMWARE, "firmware asynchronous reset" },
{ MPI3MR_RESET_FROM_CFG_REQ_TIMEOUT, "configuration request timeout"},
{ MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT, "timeout of a SAS transport layer request" },
@@ -2387,6 +2408,7 @@ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code)
{
u32 ioc_status, host_diagnostic, timeout;
union mpi3mr_trigger_data trigger_data;
if (mrioc->unrecoverable) {
ioc_err(mrioc, "controller is unrecoverable\n");
@@ -2398,16 +2420,30 @@ void mpi3mr_check_rh_fault_ioc(struct mpi3mr_ioc *mrioc, u32 reason_code)
ioc_err(mrioc, "controller is not present\n");
return;
}
memset(&trigger_data, 0, sizeof(trigger_data));
ioc_status = readl(&mrioc->sysif_regs->ioc_status);
if ((ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) ||
(ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT)) {
if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
mpi3mr_set_trigger_data_in_all_hdb(mrioc,
MPI3MR_HDB_TRIGGER_TYPE_FW_RELEASED, NULL, 0);
return;
} else if (ioc_status & MPI3_SYSIF_IOC_STATUS_FAULT) {
trigger_data.fault = (readl(&mrioc->sysif_regs->fault) &
MPI3_SYSIF_FAULT_CODE_MASK);
mpi3mr_set_trigger_data_in_all_hdb(mrioc,
MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0);
mpi3mr_print_fault_info(mrioc);
return;
}
mpi3mr_set_diagsave(mrioc);
mpi3mr_issue_reset(mrioc, MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT,
reason_code);
trigger_data.fault = (readl(&mrioc->sysif_regs->fault) &
MPI3_SYSIF_FAULT_CODE_MASK);
mpi3mr_set_trigger_data_in_all_hdb(mrioc, MPI3MR_HDB_TRIGGER_TYPE_FAULT,
&trigger_data, 0);
timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
do {
host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
@@ -2587,7 +2623,8 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
container_of(work, struct mpi3mr_ioc, watchdog_work.work);
unsigned long flags;
enum mpi3mr_iocstate ioc_state;
u32 fault, host_diagnostic, ioc_status;
u32 host_diagnostic, ioc_status;
union mpi3mr_trigger_data trigger_data;
u16 reset_reason = MPI3MR_RESET_FROM_FAULT_WATCH;
if (mrioc->reset_in_progress)
@@ -2618,8 +2655,11 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
return;
}
memset(&trigger_data, 0, sizeof(trigger_data));
ioc_status = readl(&mrioc->sysif_regs->ioc_status);
if (ioc_status & MPI3_SYSIF_IOC_STATUS_RESET_HISTORY) {
mpi3mr_set_trigger_data_in_all_hdb(mrioc,
MPI3MR_HDB_TRIGGER_TYPE_FW_RELEASED, NULL, 0);
mpi3mr_soft_reset_handler(mrioc, MPI3MR_RESET_FROM_FIRMWARE, 0);
return;
}
@@ -2629,7 +2669,9 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
if (ioc_state != MRIOC_STATE_FAULT)
goto schedule_work;
fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
trigger_data.fault = readl(&mrioc->sysif_regs->fault) & MPI3_SYSIF_FAULT_CODE_MASK;
mpi3mr_set_trigger_data_in_all_hdb(mrioc,
MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0);
host_diagnostic = readl(&mrioc->sysif_regs->host_diagnostic);
if (host_diagnostic & MPI3_SYSIF_HOST_DIAG_SAVE_IN_PROGRESS) {
if (!mrioc->diagsave_timeout) {
@@ -2643,7 +2685,7 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
mpi3mr_print_fault_info(mrioc);
mrioc->diagsave_timeout = 0;
switch (fault) {
switch (trigger_data.fault) {
case MPI3_SYSIF_FAULT_CODE_COMPLETE_RESET_NEEDED:
case MPI3_SYSIF_FAULT_CODE_POWER_CYCLE_REQUIRED:
ioc_warn(mrioc,
@@ -3003,7 +3045,11 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc,
mrioc->facts.sge_mod_shift = facts_data->sge_modifier_shift;
mrioc->facts.shutdown_timeout =
le16_to_cpu(facts_data->shutdown_timeout);
mrioc->facts.diag_trace_sz =
le32_to_cpu(facts_data->diag_trace_size);
mrioc->facts.diag_fw_sz =
le32_to_cpu(facts_data->diag_fw_size);
mrioc->facts.diag_drvr_sz = le32_to_cpu(facts_data->diag_driver_size);
mrioc->facts.max_dev_per_tg =
facts_data->max_devices_per_throttle_group;
mrioc->facts.io_throttle_data_length =
@@ -3681,6 +3727,94 @@ static const struct {
{ MPI3_IOCFACTS_CAPABILITY_MULTIPATH_SUPPORTED, "MultiPath" },
};
/**
* mpi3mr_repost_diag_bufs - repost host diag buffers
* @mrioc: Adapter instance reference
*
* repost firmware and trace diag buffers based on global
* trigger flag from driver page 2
*
* Return: 0 on success, non-zero on failures.
*/
static int mpi3mr_repost_diag_bufs(struct mpi3mr_ioc *mrioc)
{
u64 global_trigger;
union mpi3mr_trigger_data prev_trigger_data;
struct diag_buffer_desc *trace_hdb = NULL;
struct diag_buffer_desc *fw_hdb = NULL;
int retval = 0;
bool trace_repost_needed = false;
bool fw_repost_needed = false;
u8 prev_trigger_type;
retval = mpi3mr_refresh_trigger(mrioc, MPI3_CONFIG_ACTION_READ_CURRENT);
if (retval)
return -1;
trace_hdb = mpi3mr_diag_buffer_for_type(mrioc,
MPI3_DIAG_BUFFER_TYPE_TRACE);
if (trace_hdb &&
trace_hdb->status != MPI3MR_HDB_BUFSTATUS_NOT_ALLOCATED &&
trace_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_GLOBAL &&
trace_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_ELEMENT)
trace_repost_needed = true;
fw_hdb = mpi3mr_diag_buffer_for_type(mrioc, MPI3_DIAG_BUFFER_TYPE_FW);
if (fw_hdb && fw_hdb->status != MPI3MR_HDB_BUFSTATUS_NOT_ALLOCATED &&
fw_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_GLOBAL &&
fw_hdb->trigger_type != MPI3MR_HDB_TRIGGER_TYPE_ELEMENT)
fw_repost_needed = true;
if (trace_repost_needed || fw_repost_needed) {
global_trigger = le64_to_cpu(mrioc->driver_pg2->global_trigger);
if (global_trigger &
MPI3_DRIVER2_GLOBALTRIGGER_POST_DIAG_TRACE_DISABLED)
trace_repost_needed = false;
if (global_trigger &
MPI3_DRIVER2_GLOBALTRIGGER_POST_DIAG_FW_DISABLED)
fw_repost_needed = false;
}
if (trace_repost_needed) {
prev_trigger_type = trace_hdb->trigger_type;
memcpy(&prev_trigger_data, &trace_hdb->trigger_data,
sizeof(trace_hdb->trigger_data));
retval = mpi3mr_issue_diag_buf_post(mrioc, trace_hdb);
if (!retval) {
dprint_init(mrioc, "trace diag buffer reposted");
mpi3mr_set_trigger_data_in_hdb(trace_hdb,
MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1);
} else {
trace_hdb->trigger_type = prev_trigger_type;
memcpy(&trace_hdb->trigger_data, &prev_trigger_data,
sizeof(prev_trigger_data));
ioc_err(mrioc, "trace diag buffer repost failed");
return -1;
}
}
if (fw_repost_needed) {
prev_trigger_type = fw_hdb->trigger_type;
memcpy(&prev_trigger_data, &fw_hdb->trigger_data,
sizeof(fw_hdb->trigger_data));
retval = mpi3mr_issue_diag_buf_post(mrioc, fw_hdb);
if (!retval) {
dprint_init(mrioc, "firmware diag buffer reposted");
mpi3mr_set_trigger_data_in_hdb(fw_hdb,
MPI3MR_HDB_TRIGGER_TYPE_UNKNOWN, NULL, 1);
} else {
fw_hdb->trigger_type = prev_trigger_type;
memcpy(&fw_hdb->trigger_data, &prev_trigger_data,
sizeof(prev_trigger_data));
ioc_err(mrioc, "firmware diag buffer repost failed");
return -1;
}
}
return retval;
}
/**
* mpi3mr_print_ioc_info - Display controller information
* @mrioc: Adapter instance reference
@@ -3898,6 +4032,7 @@ static int mpi3mr_enable_events(struct mpi3mr_ioc *mrioc)
mpi3mr_unmask_events(mrioc, MPI3_EVENT_PREPARE_FOR_RESET);
mpi3mr_unmask_events(mrioc, MPI3_EVENT_CABLE_MGMT);
mpi3mr_unmask_events(mrioc, MPI3_EVENT_ENERGY_PACK_CHANGE);
mpi3mr_unmask_events(mrioc, MPI3_EVENT_DIAGNOSTIC_BUFFER_STATUS_CHANGE);
retval = mpi3mr_issue_event_notification(mrioc);
if (retval)
@@ -3989,9 +4124,18 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
}
}
dprint_init(mrioc, "allocating host diag buffers\n");
mpi3mr_alloc_diag_bufs(mrioc);
dprint_init(mrioc, "allocating ioctl dma buffers\n");
mpi3mr_alloc_ioctl_dma_memory(mrioc);
dprint_init(mrioc, "posting host diag buffers\n");
retval = mpi3mr_post_diag_bufs(mrioc);
if (retval)
ioc_warn(mrioc, "failed to post host diag buffers\n");
if (!mrioc->init_cmds.reply) {
retval = mpi3mr_alloc_reply_sense_bufs(mrioc);
if (retval) {
@@ -4067,6 +4211,12 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
goto out_failed;
}
retval = mpi3mr_refresh_trigger(mrioc, MPI3_CONFIG_ACTION_READ_CURRENT);
if (retval) {
ioc_err(mrioc, "failed to refresh triggers\n");
goto out_failed;
}
ioc_info(mrioc, "controller initialization completed successfully\n");
return retval;
out_failed:
@@ -4144,6 +4294,17 @@ int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume)
mpi3mr_print_ioc_info(mrioc);
if (is_resume) {
dprint_reset(mrioc, "posting host diag buffers\n");
retval = mpi3mr_post_diag_bufs(mrioc);
if (retval)
ioc_warn(mrioc, "failed to post host diag buffers\n");
} else {
retval = mpi3mr_repost_diag_bufs(mrioc);
if (retval)
ioc_warn(mrioc, "failed to re post host diag buffers\n");
}
dprint_reset(mrioc, "sending ioc_init\n");
retval = mpi3mr_issue_iocinit(mrioc);
if (retval) {
@@ -4409,6 +4570,7 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
{
u16 i;
struct mpi3mr_intr_info *intr_info;
struct diag_buffer_desc *diag_buffer;
mpi3mr_free_enclosure_list(mrioc);
mpi3mr_free_ioctl_dma_memory(mrioc);
@@ -4543,6 +4705,19 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc)
mrioc->pel_seqnum_virt = NULL;
}
for (i = 0; i < MPI3MR_MAX_NUM_HDB; i++) {
diag_buffer = &mrioc->diag_buffers[i];
if (diag_buffer->addr) {
dma_free_coherent(&mrioc->pdev->dev,
diag_buffer->size, diag_buffer->addr,
diag_buffer->dma_addr);
diag_buffer->addr = NULL;
diag_buffer->size = 0;
diag_buffer->type = 0;
diag_buffer->status = 0;
}
}
kfree(mrioc->throttle_groups);
mrioc->throttle_groups = NULL;
@@ -4980,6 +5155,7 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
int retval = 0, i;
unsigned long flags;
u32 host_diagnostic, timeout = MPI3_SYSIF_DIAG_SAVE_TIMEOUT * 10;
union mpi3mr_trigger_data trigger_data;
/* Block the reset handler until diag save in progress*/
dprint_reset(mrioc,
@@ -5012,10 +5188,16 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
mrioc->reset_in_progress = 1;
mrioc->stop_bsgs = 1;
mrioc->prev_reset_result = -1;
memset(&trigger_data, 0, sizeof(trigger_data));
if ((!snapdump) && (reset_reason != MPI3MR_RESET_FROM_FAULT_WATCH) &&
(reset_reason != MPI3MR_RESET_FROM_FIRMWARE) &&
(reset_reason != MPI3MR_RESET_FROM_CIACTIV_FAULT)) {
mpi3mr_set_trigger_data_in_all_hdb(mrioc,
MPI3MR_HDB_TRIGGER_TYPE_SOFT_RESET, NULL, 0);
dprint_reset(mrioc,
"soft_reset_handler: releasing host diagnostic buffers\n");
mpi3mr_release_diag_bufs(mrioc, 0);
for (i = 0; i < MPI3_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
mrioc->event_masks[i] = -1;
@@ -5032,6 +5214,8 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
retval = mpi3mr_issue_reset(mrioc,
MPI3_SYSIF_HOST_DIAG_RESET_ACTION_DIAG_FAULT, reset_reason);
if (!retval) {
trigger_data.fault = (readl(&mrioc->sysif_regs->fault) &
MPI3_SYSIF_FAULT_CODE_MASK);
do {
host_diagnostic =
readl(&mrioc->sysif_regs->host_diagnostic);
@@ -5040,6 +5224,8 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
break;
msleep(100);
} while (--timeout);
mpi3mr_set_trigger_data_in_all_hdb(mrioc,
MPI3MR_HDB_TRIGGER_TYPE_FAULT, &trigger_data, 0);
}
}
@@ -5075,6 +5261,15 @@ int mpi3mr_soft_reset_handler(struct mpi3mr_ioc *mrioc,
mrioc->prepare_for_reset_timeout_counter = 0;
}
mpi3mr_memset_buffers(mrioc);
mpi3mr_release_diag_bufs(mrioc, 1);
mrioc->fw_release_trigger_active = false;
mrioc->trace_release_trigger_active = false;
mrioc->snapdump_trigger_active = false;
mpi3mr_set_trigger_data_in_all_hdb(mrioc,
MPI3MR_HDB_TRIGGER_TYPE_SOFT_RESET, NULL, 0);
dprint_reset(mrioc,
"soft_reset_handler: reinitializing the controller\n");
retval = mpi3mr_reinit_ioc(mrioc, 0);
if (retval) {
pr_err(IOCNAME "reinit after soft reset failed: reason %d\n",
@@ -5954,3 +6149,64 @@ int mpi3mr_cfg_get_driver_pg1(struct mpi3mr_ioc *mrioc,
out_failed:
return -1;
}
/**
* mpi3mr_cfg_get_driver_pg2 - Read current driver page2
* @mrioc: Adapter instance reference
* @driver_pg2: Pointer to return driver page 2
* @pg_sz: Size of the memory allocated to the page pointer
* @page_action: Page action
*
* This is handler for config page read for the driver page2.
* This routine checks ioc_status to decide whether the page
* read is success or not.
*
* Return: 0 on success, non-zero on failure.
*/
int mpi3mr_cfg_get_driver_pg2(struct mpi3mr_ioc *mrioc,
struct mpi3_driver_page2 *driver_pg2, u16 pg_sz, u8 page_action)
{
struct mpi3_config_page_header cfg_hdr;
struct mpi3_config_request cfg_req;
u16 ioc_status = 0;
memset(driver_pg2, 0, pg_sz);
memset(&cfg_hdr, 0, sizeof(cfg_hdr));
memset(&cfg_req, 0, sizeof(cfg_req));
cfg_req.function = MPI3_FUNCTION_CONFIG;
cfg_req.action = MPI3_CONFIG_ACTION_PAGE_HEADER;
cfg_req.page_type = MPI3_CONFIG_PAGETYPE_DRIVER;
cfg_req.page_number = 2;
cfg_req.page_address = 0;
cfg_req.page_version = MPI3_DRIVER2_PAGEVERSION;
if (mpi3mr_process_cfg_req(mrioc, &cfg_req, NULL,
MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, &cfg_hdr, sizeof(cfg_hdr))) {
ioc_err(mrioc, "driver page2 header read failed\n");
goto out_failed;
}
if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
ioc_err(mrioc, "driver page2 header read failed with\n"
"ioc_status(0x%04x)\n",
ioc_status);
goto out_failed;
}
cfg_req.action = page_action;
if (mpi3mr_process_cfg_req(mrioc, &cfg_req, &cfg_hdr,
MPI3MR_INTADMCMD_TIMEOUT, &ioc_status, driver_pg2, pg_sz)) {
ioc_err(mrioc, "driver page2 read failed\n");
goto out_failed;
}
if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
ioc_err(mrioc, "driver page2 read failed with\n"
"ioc_status(0x%04x)\n",
ioc_status);
goto out_failed;
}
return 0;
out_failed:
return -1;
}

View File

@@ -241,6 +241,40 @@ static void mpi3mr_fwevt_add_to_list(struct mpi3mr_ioc *mrioc,
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
}
/**
* mpi3mr_hdb_trigger_data_event - Add hdb trigger data event to
* the list
* @mrioc: Adapter instance reference
* @event_data: Event data
*
* Add the given hdb trigger data event to the firmware event
* list.
*
* Return: Nothing.
*/
void mpi3mr_hdb_trigger_data_event(struct mpi3mr_ioc *mrioc,
struct trigger_event_data *event_data)
{
struct mpi3mr_fwevt *fwevt;
u16 sz = sizeof(*event_data);
fwevt = mpi3mr_alloc_fwevt(sz);
if (!fwevt) {
ioc_warn(mrioc, "failed to queue hdb trigger data event\n");
return;
}
fwevt->mrioc = mrioc;
fwevt->event_id = MPI3MR_DRIVER_EVENT_PROCESS_TRIGGER;
fwevt->send_ack = 0;
fwevt->process_evt = 1;
fwevt->evt_ctx = 0;
fwevt->event_data_size = sz;
memcpy(fwevt->event_data, event_data, sz);
mpi3mr_fwevt_add_to_list(mrioc, fwevt);
}
/**
* mpi3mr_fwevt_del_from_list - Delete firmware event from list
* @mrioc: Adapter instance reference
@@ -898,6 +932,8 @@ void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc,
}
} else
mpi3mr_remove_tgtdev_from_sas_transport(mrioc, tgtdev);
mpi3mr_global_trigger(mrioc,
MPI3_DRIVER2_GLOBALTRIGGER_DEVICE_REMOVAL_ENABLED);
ioc_info(mrioc, "%s :Removed handle(0x%04x), wwid(0x%016llx)\n",
__func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid);
@@ -1433,6 +1469,62 @@ struct mpi3mr_enclosure_node *mpi3mr_enclosure_find_by_handle(
return r;
}
/**
* mpi3mr_process_trigger_data_event_bh - Process trigger event
* data
* @mrioc: Adapter instance reference
* @event_data: Event data
*
* This function releases diage buffers or issues diag fault
* based on trigger conditions
*
* Return: Nothing
*/
static void mpi3mr_process_trigger_data_event_bh(struct mpi3mr_ioc *mrioc,
struct trigger_event_data *event_data)
{
struct diag_buffer_desc *trace_hdb = event_data->trace_hdb;
struct diag_buffer_desc *fw_hdb = event_data->fw_hdb;
unsigned long flags;
int retval = 0;
u8 trigger_type = event_data->trigger_type;
union mpi3mr_trigger_data *trigger_data =
&event_data->trigger_specific_data;
if (event_data->snapdump) {
if (trace_hdb)
mpi3mr_set_trigger_data_in_hdb(trace_hdb, trigger_type,
trigger_data, 1);
if (fw_hdb)
mpi3mr_set_trigger_data_in_hdb(fw_hdb, trigger_type,
trigger_data, 1);
mpi3mr_soft_reset_handler(mrioc,
MPI3MR_RESET_FROM_TRIGGER, 1);
return;
}
if (trace_hdb) {
retval = mpi3mr_issue_diag_buf_release(mrioc, trace_hdb);
if (!retval) {
mpi3mr_set_trigger_data_in_hdb(trace_hdb, trigger_type,
trigger_data, 1);
}
spin_lock_irqsave(&mrioc->trigger_lock, flags);
mrioc->trace_release_trigger_active = false;
spin_unlock_irqrestore(&mrioc->trigger_lock, flags);
}
if (fw_hdb) {
retval = mpi3mr_issue_diag_buf_release(mrioc, fw_hdb);
if (!retval) {
mpi3mr_set_trigger_data_in_hdb(fw_hdb, trigger_type,
trigger_data, 1);
}
spin_lock_irqsave(&mrioc->trigger_lock, flags);
mrioc->fw_release_trigger_active = false;
spin_unlock_irqrestore(&mrioc->trigger_lock, flags);
}
}
/**
* mpi3mr_encldev_add_chg_evt_debug - debug for enclosure event
* @mrioc: Adapter instance reference
@@ -2019,6 +2111,12 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
"scan for non responding and newly added devices after soft reset completed\n");
break;
}
case MPI3MR_DRIVER_EVENT_PROCESS_TRIGGER:
{
mpi3mr_process_trigger_data_event_bh(mrioc,
(struct trigger_event_data *)fwevt->event_data);
break;
}
default:
break;
}
@@ -2857,6 +2955,7 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
ack_req = 1;
evt_type = event_reply->event;
mpi3mr_event_trigger(mrioc, event_reply->event);
switch (evt_type) {
case MPI3_EVENT_DEVICE_ADDED:
@@ -2895,6 +2994,11 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
ack_req = 0;
break;
}
case MPI3_EVENT_DIAGNOSTIC_BUFFER_STATUS_CHANGE:
{
mpi3mr_hdbstatuschg_evt_th(mrioc, event_reply);
break;
}
case MPI3_EVENT_DEVICE_INFO_CHANGED:
case MPI3_EVENT_LOG_DATA:
case MPI3_EVENT_ENCL_DEVICE_STATUS_CHANGE:
@@ -3158,6 +3262,7 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc,
MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_LOGINFOAVAIL)
ioc_loginfo = le32_to_cpu(status_desc->ioc_log_info);
ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
mpi3mr_reply_trigger(mrioc, ioc_status, ioc_loginfo);
break;
case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_ADDRESS_REPLY:
addr_desc = (struct mpi3_address_reply_descriptor *)reply_desc;
@@ -3186,6 +3291,12 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc,
ioc_status &= MPI3_REPLY_DESCRIPT_STATUS_IOCSTATUS_STATUS_MASK;
if (sense_state == MPI3_SCSI_STATE_SENSE_BUFF_Q_EMPTY)
panic("%s: Ran out of sense buffers\n", mrioc->name);
if (sense_buf) {
scsi_normalize_sense(sense_buf, sense_count, &sshdr);
mpi3mr_scsisense_trigger(mrioc, sshdr.sense_key,
sshdr.asc, sshdr.ascq);
}
mpi3mr_reply_trigger(mrioc, ioc_status, ioc_loginfo);
break;
case MPI3_REPLY_DESCRIPT_FLAGS_TYPE_SUCCESS:
success_desc = (struct mpi3_success_reply_descriptor *)reply_desc;
@@ -3811,6 +3922,8 @@ int mpi3mr_issue_tm(struct mpi3mr_ioc *mrioc, u8 tm_type,
default:
break;
}
mpi3mr_global_trigger(mrioc,
MPI3_DRIVER2_GLOBALTRIGGER_TASK_MANAGEMENT_ENABLED);
out_unlock:
drv_cmd->state = MPI3MR_CMD_NOTUSED;

View File

@@ -296,6 +296,7 @@ struct mpi3mr_hdb_entry {
* multiple hdb entries.
*
* @num_hdb_types: Number of host diag buffer types supported
* @element_trigger_format: Element trigger format
* @rsvd1: Reserved
* @rsvd2: Reserved
* @rsvd3: Reserved
@@ -303,7 +304,7 @@ struct mpi3mr_hdb_entry {
*/
struct mpi3mr_bsg_in_hdb_status {
__u8 num_hdb_types;
__u8 rsvd1;
__u8 element_trigger_format;
__u16 rsvd2;
__u32 rsvd3;
struct mpi3mr_hdb_entry entry[1];