Merge patch series "mpi3mr: Few Enhancements and minor fixes"

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

Few Enhancements and minor fixes of mpi3mr driver.

Link: https://patch.msgid.link/20260916082705.44712-1-ranjan.kumar@broadcom.com
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
Martin K. Petersen (Oracle) 2026-09-16 22:16:52 -04:00
commit c3cff7fac0
9 changed files with 486 additions and 149 deletions

View File

@ -72,6 +72,12 @@
#define MPI3_SECURITY_PGAD_SLOT_GROUP_SHIFT (8)
#define MPI3_SECURITY_PGAD_SLOT_MASK (0x000000ff)
#define MPI3_INSTANCE_PGAD_INSTANCE_MASK (0x0000ffff)
#define MPI3_INSTANCE_PGAD_INSTANCE_SHIFT (0)
#define MPI3_INTERFACE_PGAD_INTERFACE_MASK (0x0000000f)
#define MPI3_INTERFACE_PGAD_INTERFACE_SHIFT (0)
#define MPI3_INTERFACE_PGAD_INTERFACE_MPI (0)
#define MPI3_INTERFACE_PGAD_INTERFACE_NVME_VD (1)
#define MPI3_INTERFACE_PGAD_INTERFACE_NVME_PD (2)
struct mpi3_config_request {
__le16 host_tag;
u8 ioc_use_only02;
@ -492,10 +498,31 @@ struct mpi3_man10_istwi_ctrlr_entry {
};
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_MASK (0x000c)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_100K (0x0000)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_400K (0x0004)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_100_KHZ (0x0000)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_400_KHZ (0x0004)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_TARGET_ENABLED (0x0002)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_INITIATOR_ENABLED (0x0001)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLITCH_FLTR_MASK (0xc000)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLITCH_FLTR_SHIFT (14)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLITCH_FLTR_50_NS (0x0000)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLITCH_FLTR_10_NS (0x4000)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLITCH_FLTR_5_NS (0x8000)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I2C_GLITCH_FLTR_0_NS (0xc000)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_MASK (0x3000)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_SHIFT (12)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_I2C (0x0000)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_I3C (0x1000)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_TYPE_AUTO (0x2000)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_MASK (0x0e00)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_SHIFT (9)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_12_5_MHZ (0x0000)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_8_MHZ (0x0200)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_6_MHZ (0x0400)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_4_MHZ (0x0600)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_I3C_MAX_DATA_RATE_2_MHZ (0x0800)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_MASK (0x000c)
#define MPI3_MAN10_ISTWI_CTRLR_FLAGS_BUS_SPEED_SHIFT (0)
#ifndef MPI3_MAN10_ISTWI_CTRLR_MAX
#define MPI3_MAN10_ISTWI_CTRLR_MAX (1)
#endif
@ -1027,6 +1054,16 @@ struct mpi3_io_unit_page5 {
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SWITCH_ATTACHED (0x02)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_DIRECT_AND_EXPANDER (0x03)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_DIRECT_AND_SWITCH (0x03)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_HDD_SPINDOWN_MASK (0xc000)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_HDD_SPINDOWN_NONE (0x0000)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_HDD_SPINDOWN_ALL (0x4000)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_HDD_SPINDOWN_FILTERED (0x8000)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_HDD_SPINDOWN_RESERVED (0xc000)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SYNC_CACHE_MASK (0x3000)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SYNC_CACHE_ALL (0x0000)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SYNC_CACHE_FILTERED (0x1000)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SYNC_CACHE_NONE (0x2000)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SYNC_CACHE_RESERVED (0x3000)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_HDD_MASK (0x0300)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SATA_HDD_SHIFT (8)
#define MPI3_IOUNIT5_DEVICE_SHUTDOWN_SAS_HDD_MASK (0x00c0)
@ -1069,7 +1106,8 @@ struct mpi3_io_unit_page8 {
struct mpi3_config_page_header header;
u8 sb_mode;
u8 sb_state;
__le16 reserved0a;
u8 flags;
u8 reserved0b;
u8 num_slots;
u8 slots_available;
u8 current_key_encryption_algo;
@ -1088,6 +1126,8 @@ struct mpi3_io_unit_page8 {
#define MPI3_IOUNIT8_SBSTATE_SVN_UPDATE_PENDING (0x04)
#define MPI3_IOUNIT8_SBSTATE_KEY_UPDATE_PENDING (0x02)
#define MPI3_IOUNIT8_SBSTATE_SECURE_BOOT_ENABLED (0x01)
#define MPI3_IOUNIT8_FLAGS_FWQR_CAPABLE (0x80)
#define MPI3_IOUNIT8_FLAGS_FWQR_SECURED (0x40)
#define MPI3_IOUNIT8_SBMODE_CURRENT_KEY_IOUNIT17 (0x10)
#define MPI3_IOUNIT8_SBMODE_HARD_SECURE_RECERTIFIED (0x08)
struct mpi3_io_unit_page9 {
@ -1174,10 +1214,16 @@ struct mpi3_io_unit_page12 {
#define MPI3_IOUNIT12_FLAGS_NUMPASSES_32 (0x00000200)
#define MPI3_IOUNIT12_FLAGS_NUMPASSES_64 (0x00000300)
#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_MASK (0x00000003)
#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_SHIFT (0)
#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_DISABLED (0x00000000)
#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_500US (0x00000001)
#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_1MS (0x00000002)
#define MPI3_IOUNIT12_FLAGS_PASSPERIOD_2MS (0x00000003)
#define MPI3_IOUNIT12_FLAGS_INTERFACE_MASK (0x0000000c)
#define MPI3_IOUNIT12_FLAGS_INTERFACE_SHIFT (2)
#define MPI3_IOUNIT12_FLAGS_INTERFACE_MPI (0x00000000)
#define MPI3_IOUNIT12_FLAGS_INTERFACE_NVME_VD (0x00000004)
#define MPI3_IOUNIT12_FLAGS_INTERFACE_NVME_PD (0x00000008)
#ifndef MPI3_IOUNIT13_FUNC_MAX
#define MPI3_IOUNIT13_FUNC_MAX (1)
#endif
@ -1238,6 +1284,7 @@ struct mpi3_io_unit_page15 {
#define MPI3_IOUNIT15_PAGEVERSION (0x00)
#define MPI3_IOUNIT15_FLAGS_EPRINIT_INITREQUIRED (0x04)
#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_MASK (0x03)
#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_SHIFT (0)
#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_NOT_SUPPORTED (0x00)
#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_WITHOUT_POWER_BRAKE_GPIO (0x01)
#define MPI3_IOUNIT15_FLAGS_EPRSUPPORT_WITH_POWER_BRAKE_GPIO (0x02)
@ -1255,6 +1302,9 @@ struct mpi3_io_unit_page17 {
__le32 current_key[];
};
#define MPI3_IOUNIT17_PAGEVERSION (0x00)
#define MPI3_IOUNIT17_FLAGS_KEYROOT_MASK (0x01)
#define MPI3_IOUNIT17_FLAGS_KEYROOT_HW (0x00)
#define MPI3_IOUNIT17_FLAGS_KEYROOT_FW (0x01)
struct mpi3_io_unit_page18 {
struct mpi3_config_page_header header;
u8 flags;
@ -1640,11 +1690,28 @@ struct mpi3_security_page3 {
};
#define MPI3_SECURITY3_PAGEVERSION (0x00)
#define MPI3_SECURITY3_FLAGS_TYPE_MASK (0x0f)
#define MPI3_SECURITY3_FLAGS_TYPE_MASK (0x1f)
#define MPI3_SECURITY3_FLAGS_TYPE_SHIFT (0)
#define MPI3_SECURITY3_FLAGS_TYPE_NOT_VALID (0)
#define MPI3_SECURITY3_FLAGS_TYPE_MLDSA_PRIVATE (1)
#define MPI3_SECURITY3_FLAGS_TYPE_MLDSA_PUBLIC (2)
union mpi3_security_digest {
__le32 dword[16];
__le16 word[32];
u8 byte[64];
};
struct mpi3_security_page4 {
struct mpi3_config_page_header header;
__le32 reserved08[2];
union mpi3_security_mac mac;
union mpi3_security_nonce nonce;
u8 num_digests;
u8 hash_algorithm;
__le16 reserved92;
__le32 reserved94[3];
union mpi3_security_digest digest[];
};
#define MPI3_SECURITY4_PAGEVERSION (0x00)
struct mpi3_security_page10 {
struct mpi3_config_page_header header;
__le32 reserved08[2];
@ -2074,7 +2141,7 @@ struct mpi3_sas_phy3_phy_event_config {
#define MPI3_SASPHY3_EVENT_CODE_LCCONN_TIME (0xd5)
#define MPI3_SASPHY3_EVENT_CODE_SSP_TX_START_TRANSMIT (0xd6)
#define MPI3_SASPHY3_EVENT_CODE_SATA_TX_START (0xd7)
#define MPI3_SASPHY3_EVENT_CODE_SMP_TX_START_TRANSMT (0xd8)
#define MPI3_SASPHY3_EVENT_CODE_SMP_TX_START_TRANSMIT (0xd8)
#define MPI3_SASPHY3_EVENT_CODE_TX_SMP_BREAK_CONN (0xd9)
#define MPI3_SASPHY3_EVENT_CODE_SSP_RX_START_RECEIVE (0xda)
#define MPI3_SASPHY3_EVENT_CODE_SATA_RX_START_RECEIVE (0xdb)

View File

@ -18,7 +18,7 @@ struct mpi3_hash_exclusion_format {
__le32 size;
};
#define MPI3_IMAGE_HASH_EXCUSION_NUM (4)
#define MPI3_IMAGE_HASH_EXCLUSION_NUM (4)
struct mpi3_component_image_header {
__le32 signature0;
__le32 load_address;
@ -42,7 +42,7 @@ struct mpi3_component_image_header {
union mpi3_version_union rmc_interface_version;
union mpi3_version_union etp_interface_version;
struct mpi3_comp_image_version component_image_version;
struct mpi3_hash_exclusion_format hash_exclusion[MPI3_IMAGE_HASH_EXCUSION_NUM];
struct mpi3_hash_exclusion_format hash_exclusion[MPI3_IMAGE_HASH_EXCLUSION_NUM];
__le32 next_image_header_offset;
union mpi3_version_union security_version;
__le32 reserved84[31];
@ -347,7 +347,8 @@ struct mpi3_encrypted_hash_entry {
struct mpi3_encrypted_hash_data {
u8 image_version;
u8 num_hash;
__le16 reserved02;
u8 fw_num_hash;
u8 reserved03;
__le32 reserved04;
struct mpi3_encrypted_hash_entry encrypted_hash_entry[MPI3_ENCRYPTED_HASH_ENTRY_MAX];
};

View File

@ -428,10 +428,10 @@ struct mpi3_event_data_sas_discovery {
#define MPI3_EVENT_SAS_DISC_FLAGS_IN_PROGRESS (0x01)
#define MPI3_EVENT_SAS_DISC_RC_STARTED (0x01)
#define MPI3_EVENT_SAS_DISC_RC_COMPLETED (0x02)
#define MPI3_SAS_DISC_STATUS_MAX_ENCLOSURES_EXCEED (0x80000000)
#define MPI3_SAS_DISC_STATUS_MAX_EXPANDERS_EXCEED (0x40000000)
#define MPI3_SAS_DISC_STATUS_MAX_DEVICES_EXCEED (0x20000000)
#define MPI3_SAS_DISC_STATUS_MAX_TOPO_PHYS_EXCEED (0x10000000)
#define MPI3_SAS_DISC_STATUS_MAX_ENCLOSURES_EXCEEDED (0x80000000)
#define MPI3_SAS_DISC_STATUS_MAX_EXPANDERS_EXCEEDED (0x40000000)
#define MPI3_SAS_DISC_STATUS_MAX_DEVICES_EXCEEDED (0x20000000)
#define MPI3_SAS_DISC_STATUS_MAX_TOPO_PHYS_EXCEEDED (0x10000000)
#define MPI3_SAS_DISC_STATUS_INVALID_CEI (0x00010000)
#define MPI3_SAS_DISC_STATUS_FECEI_MISMATCH (0x00008000)
#define MPI3_SAS_DISC_STATUS_MULTIPLE_DEVICES_IN_SLOT (0x00004000)
@ -965,7 +965,7 @@ struct mpi3_ci_download_reply {
u8 flags;
u8 cache_dirty;
u8 pending_count;
u8 reserved13;
u8 additional_flags;
};
#define MPI3_CI_DOWNLOAD_FLAGS_DOWNLOAD_IN_PROGRESS (0x80)
@ -979,6 +979,11 @@ struct mpi3_ci_download_reply {
#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_ONLINE_PENDING (0x04)
#define MPI3_CI_DOWNLOAD_FLAGS_ACTIVATION_STATUS_OFFLINE_PENDING (0x06)
#define MPI3_CI_DOWNLOAD_FLAGS_COMPATIBLE (0x01)
#define MPI3_CI_DOWNLOAD_ADDITIONALFLAGS_REDUNDANCYRESTORATION_MASK (0x03)
#define MPI3_CI_DOWNLOAD_ADDITIONALFLAGS_REDUNDANCYRESTORATION_SHIFT (0)
#define MPI3_CI_DOWNLOAD_ADDITIONALFLAGS_REDUNDANCYRESTORATION_NONE (0x00)
#define MPI3_CI_DOWNLOAD_ADDITIONALFLAGS_REDUNDANCYRESTORATION_PRIMARY (0x01)
#define MPI3_CI_DOWNLOAD_ADDITIONALFLAGS_REDUNDANCYRESTORATION_SECONDARY (0x02)
struct mpi3_ci_upload_request {
__le16 host_tag;
u8 ioc_use_only02;

View File

@ -18,7 +18,7 @@ union mpi3_version_union {
#define MPI3_VERSION_MAJOR (3)
#define MPI3_VERSION_MINOR (0)
#define MPI3_VERSION_UNIT (39)
#define MPI3_VERSION_UNIT (41)
#define MPI3_VERSION_DEV (0)
#define MPI3_DEVHANDLE_INVALID (0xffff)
struct mpi3_sysif_oper_queue_indexes {

View File

@ -56,8 +56,8 @@ extern struct list_head mrioc_list;
extern int prot_mask;
extern atomic64_t event_counter;
#define MPI3MR_DRIVER_VERSION "8.17.0.3.50"
#define MPI3MR_DRIVER_RELDATE "09-January-2026"
#define MPI3MR_DRIVER_VERSION "8.18.0.8.50"
#define MPI3MR_DRIVER_RELDATE "26-June-2026"
#define MPI3MR_DRIVER_NAME "mpi3mr"
#define MPI3MR_DRIVER_LICENSE "GPL"
@ -125,6 +125,7 @@ extern atomic64_t event_counter;
#define MPI3MR_RESETTM_TIMEOUT 60
#define MPI3MR_RESET_HOST_IOWAIT_TIMEOUT 5
#define MPI3MR_TSUPDATE_INTERVAL 900
#define MPI3MR_EARLY_TSUPDATE_SECONDS 60
#define MPI3MR_DEFAULT_SHUTDOWN_TIME 120
#define MPI3MR_RAID_ERRREC_RESET_TIMEOUT 180
#define MPI3MR_PREPARE_FOR_RESET_TIMEOUT 180
@ -168,6 +169,7 @@ extern atomic64_t event_counter;
#define MPI3MR_DEFAULT_MDTS (128 * 1024)
#define MPI3MR_DEFAULT_PGSZEXP (12)
#define MPI3MR_MAX_PGSZEXP (27)
/* Command retry count definitions */
#define MPI3MR_DEV_RMHS_RETRY_COUNT 3
@ -177,7 +179,7 @@ extern atomic64_t event_counter;
#define MPI3MR_DEFAULT_SDEV_QD 32
/* Definitions for Threaded IRQ poll*/
#define MPI3MR_IRQ_POLL_SLEEP 20
#define MPI3MR_IRQ_POLL_SLEEP 2
#define MPI3MR_IRQ_POLL_TRIGGER_IOCOUNT 8
/* Definitions for the controller security status*/
@ -1118,6 +1120,7 @@ struct scmd_priv {
* @evtack_cmds_bitmap: Event Ack bitmap
* @delayed_evtack_cmds_list: Delayed event acknowledgment list
* @ts_update_counter: Timestamp update counter
* @early_ts_sync_done: Early (1 min) timestamp sync completed after load
* @ts_update_interval: Timestamp update interval
* @reset_in_progress: Reset in progress flag
* @unrecoverable: Controller unrecoverable flag
@ -1318,6 +1321,7 @@ struct mpi3mr_ioc {
struct list_head delayed_evtack_cmds_list;
u16 ts_update_counter;
u8 early_ts_sync_done;
u16 ts_update_interval;
u8 reset_in_progress;
u8 unrecoverable;
@ -1410,6 +1414,9 @@ struct mpi3mr_ioc {
struct dma_pool *trace_buf_pool;
struct segments *trace_buf;
u8 invalid_io_comp;
bool is_unload;
bool skip_dev_shutdown_on_unload;
};

View File

@ -141,25 +141,27 @@ void mpi3mr_alloc_diag_bufs(struct mpi3mr_ioc *mrioc)
trace_min_size = fw_min_size = MPI3MR_DEFAULT_HDB_MIN_SZ;
} else {
trace_size = driver_pg1.host_diag_trace_max_size * 1024;
trace_dec_size = driver_pg1.host_diag_trace_decrement_size
trace_size = le16_to_cpu(driver_pg1.host_diag_trace_max_size) * 1024;
trace_dec_size = le16_to_cpu(driver_pg1.host_diag_trace_decrement_size)
* 1024;
trace_min_size = driver_pg1.host_diag_trace_min_size * 1024;
fw_size = driver_pg1.host_diag_fw_max_size * 1024;
fw_dec_size = driver_pg1.host_diag_fw_decrement_size * 1024;
fw_min_size = driver_pg1.host_diag_fw_min_size * 1024;
trace_min_size = le16_to_cpu(driver_pg1.host_diag_trace_min_size) * 1024;
fw_size = le16_to_cpu(driver_pg1.host_diag_fw_max_size) * 1024;
fw_dec_size = le16_to_cpu(driver_pg1.host_diag_fw_decrement_size) * 1024;
fw_min_size = le16_to_cpu(driver_pg1.host_diag_fw_min_size) * 1024;
dprint_init(mrioc,
"%s:trace diag buffer sizes read from driver\n"
"page1: maximum size = %dKB, decrement size = %dKB\n"
", minimum size = %dKB\n", __func__, driver_pg1.host_diag_trace_max_size,
driver_pg1.host_diag_trace_decrement_size,
driver_pg1.host_diag_trace_min_size);
", minimum size = %dKB\n", __func__,
le16_to_cpu(driver_pg1.host_diag_trace_max_size),
le16_to_cpu(driver_pg1.host_diag_trace_decrement_size),
le16_to_cpu(driver_pg1.host_diag_trace_min_size));
dprint_init(mrioc,
"%s:firmware diag buffer sizes read from driver\n"
"page1: maximum size = %dKB, decrement size = %dKB\n"
", minimum size = %dKB\n", __func__, driver_pg1.host_diag_fw_max_size,
driver_pg1.host_diag_fw_decrement_size,
driver_pg1.host_diag_fw_min_size);
", minimum size = %dKB\n", __func__,
le16_to_cpu(driver_pg1.host_diag_fw_max_size),
le16_to_cpu(driver_pg1.host_diag_fw_decrement_size),
le16_to_cpu(driver_pg1.host_diag_fw_min_size));
if ((trace_size == 0) && (fw_size == 0))
return;
}
@ -179,6 +181,12 @@ void mpi3mr_alloc_diag_bufs(struct mpi3mr_ioc *mrioc)
mpi3mr_alloc_trace_buffer(mrioc, trace_size)) {
retry = true;
if (!trace_dec_size || trace_dec_size > trace_size) {
retry = false;
goto retry_fw;
}
trace_size -= trace_dec_size;
dprint_init(mrioc, "trace diag buffer allocation failed\n"
"retrying smaller size %dKB\n", trace_size / 1024);
@ -211,11 +219,13 @@ void mpi3mr_alloc_diag_bufs(struct mpi3mr_ioc *mrioc)
diag_buffer->size = fw_size;
} else {
retry = true;
fw_size -= fw_dec_size;
dprint_init(mrioc, "%s:trace diag buffer allocation failed,\n"
"retrying smaller size %dKB\n",
__func__, fw_size / 1024);
goto retry_fw;
if (fw_dec_size && fw_dec_size <= fw_size) {
fw_size -= fw_dec_size;
dprint_init(mrioc, "%s:trace diag buffer allocation failed,\n"
"retrying smaller size %dKB\n",
__func__, fw_size / 1024);
goto retry_fw;
}
}
}
}

View File

@ -490,6 +490,12 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
return 0;
}
/*
* Ensure that the descriptor payload is read only after
* the phase bit check is complete.
*/
dma_rmb();
do {
if (mrioc->unrecoverable || mrioc->io_admin_reset_sync)
break;
@ -510,6 +516,13 @@ int mpi3mr_process_admin_reply_q(struct mpi3mr_ioc *mrioc)
if ((le16_to_cpu(reply_desc->reply_flags) &
MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
break;
/*
* Ensure that the descriptor payload is read only after
* the phase bit check is complete.
*/
dma_rmb();
if (threshold_comps == MPI3MR_THRESHOLD_REPLY_COUNT) {
writel(admin_reply_ci,
&mrioc->sysif_regs->admin_reply_queue_ci);
@ -570,6 +583,9 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
struct mpi3_default_reply_descriptor *reply_desc;
u16 req_q_idx = 0, reply_qidx, threshold_comps = 0;
if (!op_reply_q)
return 0;
reply_qidx = op_reply_q->qid - 1;
if (!atomic_add_unless(&op_reply_q->in_use, 1, 1))
@ -581,15 +597,33 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
if ((le16_to_cpu(reply_desc->reply_flags) &
MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
/* Recheck under in_use before releasing, to avoid a reclaim race */
dma_rmb();
if ((le16_to_cpu(reply_desc->reply_flags) &
MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) == exp_phase)
goto process_desc;
atomic_dec(&op_reply_q->in_use);
return 0;
}
process_desc:
/*
* Ensure that the descriptor payload is read only after
* the phase bit check is complete.
*/
dma_rmb();
do {
if (mrioc->unrecoverable || mrioc->io_admin_reset_sync)
break;
req_q_idx = le16_to_cpu(reply_desc->request_queue_id) - 1;
if (unlikely(req_q_idx >= mrioc->num_op_req_q)) {
ioc_err(mrioc, "Invalid request queue id %d, skipping reply\n",
req_q_idx + 1);
goto next_reply;
}
op_req_q = &mrioc->req_qinfo[req_q_idx];
WRITE_ONCE(op_req_q->ci, le16_to_cpu(reply_desc->request_queue_ci));
@ -598,8 +632,9 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
if (reply_dma)
mpi3mr_repost_reply_buf(mrioc, reply_dma);
num_op_reply++;
threshold_comps++;
next_reply:
num_op_reply++;
if (++reply_ci == op_reply_q->num_replies) {
reply_ci = 0;
@ -609,8 +644,19 @@ int mpi3mr_process_op_reply_q(struct mpi3mr_ioc *mrioc,
reply_desc = mpi3mr_get_reply_desc(op_reply_q, reply_ci);
if ((le16_to_cpu(reply_desc->reply_flags) &
MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase)
MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) != exp_phase) {
dma_rmb();
if ((le16_to_cpu(reply_desc->reply_flags) &
MPI3_REPLY_DESCRIPT_FLAGS_PHASE_MASK) == exp_phase)
goto reply_ready;
break;
}
reply_ready:
/*
* Ensure that the descriptor payload is read only after
* the phase bit check is complete.
*/
dma_rmb();
#ifndef CONFIG_PREEMPT_RT
/*
* Exit completion loop to avoid CPU lockup
@ -672,6 +718,7 @@ static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata)
{
struct mpi3mr_intr_info *intr_info = privdata;
struct mpi3mr_ioc *mrioc;
struct op_reply_qinfo *op_reply_q;
u16 midx;
u32 num_admin_replies = 0, num_op_reply = 0;
@ -687,9 +734,9 @@ static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata)
if (!midx)
num_admin_replies = mpi3mr_process_admin_reply_q(mrioc);
if (intr_info->op_reply_q)
num_op_reply = mpi3mr_process_op_reply_q(mrioc,
intr_info->op_reply_q);
op_reply_q = READ_ONCE(intr_info->op_reply_q);
if (op_reply_q)
num_op_reply = mpi3mr_process_op_reply_q(mrioc, op_reply_q);
if (num_admin_replies || num_op_reply)
return IRQ_HANDLED;
@ -702,6 +749,7 @@ static irqreturn_t mpi3mr_isr_primary(int irq, void *privdata)
static irqreturn_t mpi3mr_isr(int irq, void *privdata)
{
struct mpi3mr_intr_info *intr_info = privdata;
struct op_reply_qinfo *op_reply_q;
int ret;
if (!intr_info)
@ -714,11 +762,12 @@ static irqreturn_t mpi3mr_isr(int irq, void *privdata)
* If more IOs are expected, schedule IRQ polling thread.
* Otherwise exit from ISR.
*/
if ((threaded_isr_poll == false) || !intr_info->op_reply_q)
op_reply_q = READ_ONCE(intr_info->op_reply_q);
if ((threaded_isr_poll == false) || !op_reply_q)
return ret;
if (!intr_info->op_reply_q->enable_irq_poll ||
!atomic_read(&intr_info->op_reply_q->pend_ios))
if (!op_reply_q->enable_irq_poll ||
!atomic_read(&op_reply_q->pend_ios))
return ret;
disable_irq_nosync(intr_info->os_irq);
@ -740,12 +789,19 @@ static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
{
struct mpi3mr_intr_info *intr_info = privdata;
struct mpi3mr_ioc *mrioc;
struct op_reply_qinfo *op_reply_q;
u16 midx;
u32 num_op_reply = 0;
if (!intr_info || !intr_info->op_reply_q)
if (!intr_info)
return IRQ_NONE;
op_reply_q = READ_ONCE(intr_info->op_reply_q);
if (!op_reply_q) {
enable_irq(intr_info->os_irq);
return IRQ_HANDLED;
}
mrioc = intr_info->mrioc;
midx = intr_info->msix_index;
@ -754,19 +810,23 @@ static irqreturn_t mpi3mr_isr_poll(int irq, void *privdata)
if (!mrioc->intr_enabled || mrioc->unrecoverable)
break;
op_reply_q = READ_ONCE(intr_info->op_reply_q);
if (!op_reply_q)
break;
if (!midx)
mpi3mr_process_admin_reply_q(mrioc);
if (intr_info->op_reply_q)
num_op_reply +=
mpi3mr_process_op_reply_q(mrioc,
intr_info->op_reply_q);
num_op_reply +=
mpi3mr_process_op_reply_q(mrioc, op_reply_q);
if (!atomic_read(&op_reply_q->pend_ios))
break;
usleep_range(MPI3MR_IRQ_POLL_SLEEP, MPI3MR_IRQ_POLL_SLEEP + 1);
usleep_range(MPI3MR_IRQ_POLL_SLEEP, 10 * MPI3MR_IRQ_POLL_SLEEP);
} while (atomic_read(&intr_info->op_reply_q->pend_ios) &&
(num_op_reply < mrioc->max_host_ios));
} while (num_op_reply < mrioc->max_host_ios);
intr_info->op_reply_q->enable_irq_poll = false;
if (op_reply_q)
op_reply_q->enable_irq_poll = false;
enable_irq(intr_info->os_irq);
return IRQ_HANDLED;
@ -1950,10 +2010,6 @@ static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
int size;
struct segments *segments;
segments = mrioc->req_qinfo[q_idx].q_segments;
if (!segments)
return;
if (mrioc->enable_segqueue) {
size = MPI3MR_OP_REQ_Q_SEG_SIZE;
if (mrioc->req_qinfo[q_idx].q_segment_list) {
@ -1967,6 +2023,10 @@ static void mpi3mr_free_op_req_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
size = mrioc->req_qinfo[q_idx].segment_qd *
mrioc->facts.op_req_sz;
segments = mrioc->req_qinfo[q_idx].q_segments;
if (!segments)
return;
for (j = 0; j < mrioc->req_qinfo[q_idx].num_segments; j++) {
if (!segments[j].segment)
continue;
@ -1993,10 +2053,17 @@ static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
u16 j;
int size;
struct segments *segments;
u16 midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(q_idx, mrioc->op_reply_q_offset);
segments = mrioc->op_reply_qinfo[q_idx].q_segments;
if (!segments)
return;
/*
* Stop the ISR/poll thread from picking up this queue before its
* segments are freed below, and wait for any in-flight handler
* that already has the old pointer to finish using it.
*/
if (midx < mrioc->intr_info_count) {
WRITE_ONCE(mrioc->intr_info[midx].op_reply_q, NULL);
synchronize_irq(pci_irq_vector(mrioc->pdev, midx));
}
if (mrioc->enable_segqueue) {
size = MPI3MR_OP_REP_Q_SEG_SIZE;
@ -2011,6 +2078,10 @@ static void mpi3mr_free_op_reply_q_segments(struct mpi3mr_ioc *mrioc, u16 q_idx)
size = mrioc->op_reply_qinfo[q_idx].segment_qd *
mrioc->op_reply_desc_sz;
segments = mrioc->op_reply_qinfo[q_idx].q_segments;
if (!segments)
return;
for (j = 0; j < mrioc->op_reply_qinfo[q_idx].num_segments; j++) {
if (!segments[j].segment)
continue;
@ -2477,7 +2548,7 @@ static int mpi3mr_create_op_req_q(struct mpi3mr_ioc *mrioc, u16 idx,
static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc)
{
int retval = 0;
u16 num_queues = 0, i = 0, msix_count_op_q = 1;
u16 num_queues = 0, i = 0, j = 0, msix_count_op_q = 1;
u32 ioc_status;
enum mpi3mr_iocstate ioc_state;
@ -2529,6 +2600,13 @@ static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc)
}
}
if (i < num_queues) {
for (j = i; j < num_queues; j++) {
mpi3mr_free_op_req_q_segments(mrioc, j);
mpi3mr_free_op_reply_q_segments(mrioc, j);
}
}
if (i == 0) {
/* Not even one queue is created successfully*/
retval = -1;
@ -2550,11 +2628,19 @@ static int mpi3mr_create_op_queues(struct mpi3mr_ioc *mrioc)
return retval;
out_failed:
kfree(mrioc->req_qinfo);
mrioc->req_qinfo = NULL;
if (mrioc->req_qinfo) {
for (j = 0; j < i; j++) {
mpi3mr_free_op_req_q_segments(mrioc, j);
mpi3mr_free_op_reply_q_segments(mrioc, j);
}
kfree(mrioc->req_qinfo);
mrioc->req_qinfo = NULL;
}
mrioc->num_op_req_q = 0;
kfree(mrioc->op_reply_qinfo);
mrioc->op_reply_qinfo = NULL;
mrioc->num_op_reply_q = 0;
return retval;
}
@ -2598,7 +2684,8 @@ int mpi3mr_op_request_post(struct mpi3mr_ioc *mrioc,
if (mpi3mr_check_req_qfull(op_req_q)) {
midx = REPLY_QUEUE_IDX_TO_MSIX_IDX(
reply_qidx, mrioc->op_reply_q_offset);
mpi3mr_process_op_reply_q(mrioc, mrioc->intr_info[midx].op_reply_q);
mpi3mr_process_op_reply_q(mrioc,
READ_ONCE(mrioc->intr_info[midx].op_reply_q));
if (mpi3mr_check_req_qfull(op_req_q)) {
@ -2891,8 +2978,9 @@ static int mpi3mr_print_pkg_ver(struct mpi3mr_ioc *mrioc)
* @work: work struct
*
* Watch dog work periodically executed (1 second interval) to
* monitor firmware fault and to issue periodic timer sync to
* the firmware.
* monitor firmware fault and perform timestamp synchronization
* to firmware, with an early sync 1 minute after load followed
* by periodic updates at ts_update_interval seconds (default 15 minutes).
*
* Return: Nothing.
*/
@ -2938,11 +3026,23 @@ static void mpi3mr_watchdog_work(struct work_struct *work)
}
if (!(mrioc->facts.ioc_capabilities &
MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_IOC) &&
(mrioc->ts_update_counter++ >= mrioc->ts_update_interval)) {
MPI3_IOCFACTS_CAPABILITY_NON_SUPERVISOR_IOC)) {
if (!mrioc->early_ts_sync_done) {
/*
* Send time sync 1 min after load
*/
if (mrioc->ts_update_counter++ >=
MPI3MR_EARLY_TSUPDATE_SECONDS) {
mrioc->early_ts_sync_done = 1;
mrioc->ts_update_counter = 0;
mpi3mr_sync_timestamp(mrioc);
}
} else if (mrioc->ts_update_counter++ >=
mrioc->ts_update_interval) {
mrioc->ts_update_counter = 0;
mpi3mr_sync_timestamp(mrioc);
}
mrioc->ts_update_counter = 0;
mpi3mr_sync_timestamp(mrioc);
}
if ((mrioc->prepare_for_reset) &&
@ -4128,26 +4228,35 @@ static int mpi3mr_repost_diag_bufs(struct mpi3mr_ioc *mrioc)
}
/**
* mpi3mr_read_tsu_interval - Update time stamp interval
* mpi3mr_read_driver_page1 - Read Driver Page 1 parameters
* @mrioc: Adapter instance reference
*
* Update time stamp interval if its defined in driver page 1,
* otherwise use default value.
* Reads and caches Driver Page 1 parameters such as
* timestamp update interval and driver behavior flags.
*
* Return: Nothing
*/
static void
mpi3mr_read_tsu_interval(struct mpi3mr_ioc *mrioc)
mpi3mr_read_driver_page1(struct mpi3mr_ioc *mrioc)
{
struct mpi3_driver_page1 driver_pg1;
u16 pg_sz = sizeof(driver_pg1);
int retval = 0;
mrioc->ts_update_interval = MPI3MR_TSUPDATE_INTERVAL;
mrioc->skip_dev_shutdown_on_unload = 0;
retval = mpi3mr_cfg_get_driver_pg1(mrioc, &driver_pg1, pg_sz);
if (!retval && driver_pg1.time_stamp_update)
if (retval)
return;
if (driver_pg1.time_stamp_update)
mrioc->ts_update_interval = (driver_pg1.time_stamp_update * 60);
mrioc->skip_dev_shutdown_on_unload =
(le32_to_cpu(driver_pg1.flags) &
MPI3_DRIVER1_FLAGS_DEVICE_SHUTDOWN_ON_UNLOAD_DISABLE) ? 1 : 0;
}
/**
@ -4453,7 +4562,7 @@ int mpi3mr_init_ioc(struct mpi3mr_ioc *mrioc)
goto out_failed_noretry;
}
mpi3mr_read_tsu_interval(mrioc);
mpi3mr_read_driver_page1(mrioc);
mpi3mr_print_ioc_info(mrioc);
dprint_init(mrioc, "allocating host diag buffers\n");
@ -4625,7 +4734,7 @@ int mpi3mr_reinit_ioc(struct mpi3mr_ioc *mrioc, u8 is_resume)
goto out_failed_noretry;
}
mpi3mr_read_tsu_interval(mrioc);
mpi3mr_read_driver_page1(mrioc);
mpi3mr_print_ioc_info(mrioc);
if (is_resume) {
@ -5110,8 +5219,16 @@ static void mpi3mr_issue_ioc_shutdown(struct mpi3mr_ioc *mrioc)
return;
}
shutdown_action = MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL |
MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ;
shutdown_action = MPI3_SYSIF_IOC_CONFIG_SHUTDOWN_NORMAL;
if (!(mrioc->is_unload && mrioc->skip_dev_shutdown_on_unload))
shutdown_action |=
MPI3_SYSIF_IOC_CONFIG_DEVICE_SHUTDOWN_SEND_REQ;
else
ioc_info(mrioc,
"The shutdown request is issued without the device shutdown bit set\n"
"as indicated by the controller configuration\n");
ioc_config = readl(&mrioc->sysif_regs->ioc_configuration);
ioc_config |= shutdown_action;

View File

@ -283,32 +283,6 @@ void mpi3mr_hdb_trigger_data_event(struct mpi3mr_ioc *mrioc,
mpi3mr_fwevt_add_to_list(mrioc, fwevt);
}
/**
* mpi3mr_fwevt_del_from_list - Delete firmware event from list
* @mrioc: Adapter instance reference
* @fwevt: Firmware event reference
*
* Delete the given firmware event from the firmware event list.
*
* Return: Nothing.
*/
static void mpi3mr_fwevt_del_from_list(struct mpi3mr_ioc *mrioc,
struct mpi3mr_fwevt *fwevt)
{
unsigned long flags;
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
if (!list_empty(&fwevt->list)) {
list_del_init(&fwevt->list);
/*
* Put fwevt reference count after
* removing it from fwevt_list
*/
mpi3mr_fwevt_put(fwevt);
}
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
}
/**
* mpi3mr_dequeue_fwevt - Dequeue firmware event from the list
* @mrioc: Adapter instance reference
@ -328,11 +302,7 @@ static struct mpi3mr_fwevt *mpi3mr_dequeue_fwevt(
fwevt = list_first_entry(&mrioc->fwevt_list,
struct mpi3mr_fwevt, list);
list_del_init(&fwevt->list);
/*
* Put fwevt reference count after
* removing it from fwevt_list
*/
mpi3mr_fwevt_put(fwevt);
}
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
@ -366,6 +336,11 @@ static void mpi3mr_cancel_work(struct mpi3mr_fwevt *fwevt)
*/
mpi3mr_fwevt_put(fwevt);
}
/*
* Drop the reference count that was acquired by the caller.
*/
mpi3mr_fwevt_put(fwevt);
}
/**
@ -380,17 +355,44 @@ static void mpi3mr_cancel_work(struct mpi3mr_fwevt *fwevt)
void mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc)
{
struct mpi3mr_fwevt *fwevt = NULL;
unsigned long flags;
/*
* Safely read current_event under lock to prevent TOCTOU race
* with the firmware event worker thread.
*/
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
if ((list_empty(&mrioc->fwevt_list) && !mrioc->current_event) ||
!mrioc->fwevt_worker_thread)
!mrioc->fwevt_worker_thread) {
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
return;
}
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
while ((fwevt = mpi3mr_dequeue_fwevt(mrioc)))
mpi3mr_cancel_work(fwevt);
if (mrioc->current_event) {
fwevt = mrioc->current_event;
/*
* Safely read current_event under lock to prevent TOCTOU race
* with the firmware event worker thread.
*/
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
fwevt = mrioc->current_event;
if (fwevt) {
/*
* Take a reference to ensure the event is not freed by the
* worker thread while we are evaluating or cancelling it.
*/
mpi3mr_fwevt_get(fwevt);
}
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
if (fwevt) {
bool pending_at_sml;
/*
* Read pending_at_sml under lock to avoid a stale value.
*
* Don't call cancel_work_sync() API for the
* fwevt work if the controller reset is
* get called as part of processing the
@ -398,8 +400,13 @@ void mpi3mr_cleanup_fwevt_list(struct mpi3mr_ioc *mrioc)
* waiting for device add/remove APIs to complete.
* Otherwise we will see deadlock.
*/
if (current_work() == &fwevt->work || fwevt->pending_at_sml) {
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
pending_at_sml = fwevt->pending_at_sml;
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
if (current_work() == &fwevt->work || pending_at_sml) {
fwevt->discard = 1;
mpi3mr_fwevt_put(fwevt);
return;
}
@ -913,6 +920,8 @@ void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc,
struct mpi3mr_tgt_dev *tgtdev)
{
struct mpi3mr_stgt_priv_data *tgt_priv;
unsigned long flags;
bool discard = false;
ioc_info(mrioc, "%s :Removing handle(0x%04x), wwid(0x%016llx)\n",
__func__, tgtdev->dev_handle, (unsigned long long)tgtdev->wwid);
@ -925,17 +934,27 @@ void mpi3mr_remove_tgtdev_from_host(struct mpi3mr_ioc *mrioc,
if (!mrioc->sas_transport_enabled || (tgtdev->dev_type !=
MPI3_DEVICE_DEVFORM_SAS_SATA) || tgtdev->non_stl) {
if (tgtdev->starget) {
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
if (mrioc->stop_drv_processing ||
mrioc->reset_in_progress) {
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
return;
}
if (mrioc->current_event)
mrioc->current_event->pending_at_sml = 1;
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
scsi_remove_target(&tgtdev->starget->dev);
tgtdev->host_exposed = 0;
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
if (mrioc->current_event) {
mrioc->current_event->pending_at_sml = 0;
if (mrioc->current_event->discard) {
mpi3mr_print_device_event_notice(mrioc,
false);
return;
}
discard = mrioc->current_event->discard;
}
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
if (discard) {
mpi3mr_print_device_event_notice(mrioc,
false);
return;
}
}
} else
@ -963,6 +982,8 @@ static int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc,
{
int retval = 0;
struct mpi3mr_tgt_dev *tgtdev;
unsigned long flags;
bool discard = false;
if (mrioc->reset_in_progress || mrioc->pci_err_recovery)
return -1;
@ -979,19 +1000,29 @@ static int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc,
if (!mrioc->sas_transport_enabled || (tgtdev->dev_type !=
MPI3_DEVICE_DEVFORM_SAS_SATA) || tgtdev->non_stl){
tgtdev->host_exposed = 1;
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
if (mrioc->stop_drv_processing || mrioc->reset_in_progress) {
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
tgtdev->host_exposed = 0;
goto out;
}
if (mrioc->current_event)
mrioc->current_event->pending_at_sml = 1;
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
scsi_scan_target(&mrioc->shost->shost_gendev,
mrioc->scsi_device_channel, tgtdev->perst_id,
SCAN_WILD_CARD, SCSI_SCAN_INITIAL);
if (!tgtdev->starget)
tgtdev->host_exposed = 0;
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
if (mrioc->current_event) {
mrioc->current_event->pending_at_sml = 0;
if (mrioc->current_event->discard) {
mpi3mr_print_device_event_notice(mrioc, true);
goto out;
}
discard = mrioc->current_event->discard;
}
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
if (discard) {
mpi3mr_print_device_event_notice(mrioc, true);
goto out;
}
dprint_event_bh(mrioc,
"exposed target device with handle(0x%04x), perst_id(%d)\n",
@ -1350,24 +1381,32 @@ static void mpi3mr_update_tgtdev(struct mpi3mr_ioc *mrioc,
struct mpi3_device0_pcie_format *pcieinf =
&dev_pg0->device_specific.pcie_format;
u16 dev_info = le16_to_cpu(pcieinf->device_info);
u8 pgsz = MPI3MR_DEFAULT_PGSZEXP;
u8 reset_to = MPI3MR_INTADMCMD_TIMEOUT;
u8 abort_to = MPI3MR_INTADMCMD_TIMEOUT;
u8 fw_pgsz = READ_ONCE(pcieinf->page_size);
tgtdev->dev_spec.pcie_inf.dev_info = dev_info;
tgtdev->dev_spec.pcie_inf.capb =
le32_to_cpu(pcieinf->capabilities);
tgtdev->dev_spec.pcie_inf.mdts = MPI3MR_DEFAULT_MDTS;
/* 2^12 = 4096 */
tgtdev->dev_spec.pcie_inf.pgsz = 12;
/* Validate firmware page size to prevent undefined shift behavior */
if (fw_pgsz >= MPI3MR_DEFAULT_PGSZEXP && fw_pgsz <= MPI3MR_MAX_PGSZEXP)
pgsz = fw_pgsz;
if (dev_pg0->access_status == MPI3_DEVICE0_ASTATUS_NO_ERRORS) {
tgtdev->dev_spec.pcie_inf.mdts =
le32_to_cpu(pcieinf->maximum_data_transfer_size);
tgtdev->dev_spec.pcie_inf.pgsz = pcieinf->page_size;
tgtdev->dev_spec.pcie_inf.reset_to =
max_t(u8, pcieinf->controller_reset_to,
MPI3MR_INTADMCMD_TIMEOUT);
tgtdev->dev_spec.pcie_inf.abort_to =
max_t(u8, pcieinf->nvme_abort_to,
reset_to = max_t(u8, pcieinf->controller_reset_to,
MPI3MR_INTADMCMD_TIMEOUT);
abort_to = max_t(u8, pcieinf->nvme_abort_to,
MPI3MR_INTADMCMD_TIMEOUT);
}
tgtdev->dev_spec.pcie_inf.pgsz = pgsz;
tgtdev->dev_spec.pcie_inf.reset_to = reset_to;
tgtdev->dev_spec.pcie_inf.abort_to = abort_to;
if (tgtdev->dev_spec.pcie_inf.mdts > (1024 * 1024))
tgtdev->dev_spec.pcie_inf.mdts = (1024 * 1024);
if (((dev_info & MPI3_DEVICE0_PCIE_DEVICE_INFO_TYPE_MASK) !=
@ -2126,9 +2165,19 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
u16 perst_id, handle, dev_info;
struct mpi3_device0_sas_sata_format *sasinf = NULL;
unsigned int timeout;
unsigned long flags;
mpi3mr_fwevt_del_from_list(mrioc, fwevt);
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
if (!list_empty(&fwevt->list)) {
list_del_init(&fwevt->list);
/*
* Put fwevt reference count after
* removing it from fwevt_list
*/
mpi3mr_fwevt_put(fwevt);
}
mrioc->current_event = fwevt;
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
if (mrioc->stop_drv_processing || mrioc->pci_err_recovery) {
dprint_event_bh(mrioc,
@ -2263,9 +2312,12 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
mpi3mr_process_event_ack(mrioc, fwevt->event_id,
fwevt->evt_ctx);
out:
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
mrioc->current_event = NULL;
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
/* Put fwevt reference count to neutralize kref_init increment */
mpi3mr_fwevt_put(fwevt);
mrioc->current_event = NULL;
}
/**
@ -3484,8 +3536,12 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc,
scsi_reply = mpi3mr_get_reply_virt_addr(mrioc,
*reply_dma);
if (!scsi_reply) {
panic("%s: scsi_reply is NULL, this shouldn't happen\n",
mrioc->name);
ioc_err(mrioc, "scsi_reply is NULL, invalid reply_frame_address\n");
/*
* Do not let the caller repost an address that
* failed virt-addr lookup back to the hardware.
*/
*reply_dma = 0;
goto out;
}
host_tag = le16_to_cpu(scsi_reply->host_tag);
@ -3982,7 +4038,7 @@ inline void mpi3mr_poll_pend_io_completions(struct mpi3mr_ioc *mrioc)
for (i = mrioc->op_reply_q_offset; i < num_of_reply_queues; i++)
mpi3mr_process_op_reply_q(mrioc,
mrioc->intr_info[i].op_reply_q);
READ_ONCE(mrioc->intr_info[i].op_reply_q));
}
/**
@ -5730,6 +5786,8 @@ static void mpi3mr_remove(struct pci_dev *pdev)
return;
mrioc = shost_priv(shost);
mrioc->is_unload = true;
while (mrioc->reset_in_progress || mrioc->is_driver_loading)
ssleep(1);
@ -5862,6 +5920,9 @@ mpi3mr_suspend(struct device *dev)
ssleep(1);
mrioc->stop_drv_processing = 1;
mpi3mr_cleanup_fwevt_list(mrioc);
/* Flush any pending discarded event before unmapping PCI resources below. */
if (mrioc->fwevt_worker_thread)
flush_workqueue(mrioc->fwevt_worker_thread);
scsi_block_requests(shost);
mpi3mr_stop_watchdog(mrioc);
mpi3mr_cleanup_ioc(mrioc);

View File

@ -1223,13 +1223,14 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
}
num_phys = sas_io_unit_pg0->num_phys;
kfree(sas_io_unit_pg0);
sas_io_unit_pg0 = NULL;
mrioc->sas_hba.host_node = 1;
INIT_LIST_HEAD(&mrioc->sas_hba.sas_port_list);
mrioc->sas_hba.parent_dev = &mrioc->shost->shost_gendev;
mrioc->sas_hba.phy = kzalloc_objs(struct mpi3mr_sas_phy, num_phys);
if (!mrioc->sas_hba.phy)
return;
goto out;
mrioc->sas_hba.num_phys = num_phys;
@ -1237,12 +1238,12 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
(num_phys * sizeof(struct mpi3_sas_io_unit0_phy_data));
sas_io_unit_pg0 = kzalloc(sz, GFP_KERNEL);
if (!sas_io_unit_pg0)
return;
goto out_free_phy;
if (mpi3mr_cfg_get_sas_io_unit_pg0(mrioc, sas_io_unit_pg0, sz)) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
goto out;
goto out_free_phy;
}
mrioc->sas_hba.handle = 0;
@ -1256,12 +1257,12 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
MPI3_SAS_PHY_PGAD_FORM_PHY_NUMBER, i)) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
goto out;
goto out_free_phy;
}
if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
goto out;
goto out_free_phy;
}
if (!mrioc->sas_hba.handle)
@ -1271,26 +1272,27 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
if (!(mpi3mr_get_hba_port_by_id(mrioc, port_id)))
if (!mpi3mr_alloc_hba_port(mrioc, port_id))
goto out;
goto out_free_phy;
mrioc->sas_hba.phy[i].handle = mrioc->sas_hba.handle;
mrioc->sas_hba.phy[i].phy_id = i;
mrioc->sas_hba.phy[i].hba_port =
mpi3mr_get_hba_port_by_id(mrioc, port_id);
mpi3mr_add_host_phy(mrioc, &mrioc->sas_hba.phy[i],
phy_pg0, mrioc->sas_hba.parent_dev);
if (mpi3mr_add_host_phy(mrioc, &mrioc->sas_hba.phy[i],
phy_pg0, mrioc->sas_hba.parent_dev))
goto out_free_phy;
}
if ((mpi3mr_cfg_get_dev_pg0(mrioc, &ioc_status, &dev_pg0,
sizeof(dev_pg0), MPI3_DEVICE_PGAD_FORM_HANDLE,
mrioc->sas_hba.handle))) {
ioc_err(mrioc, "%s: device page0 read failed\n", __func__);
goto out;
goto out_free_phy;
}
if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
ioc_err(mrioc, "device page read failed for handle(0x%04x), with ioc_status(0x%04x) failure at %s:%d/%s()!\n",
mrioc->sas_hba.handle, ioc_status, __FILE__, __LINE__,
__func__);
goto out;
goto out_free_phy;
}
mrioc->sas_hba.enclosure_handle =
le16_to_cpu(dev_pg0.enclosure_handle);
@ -1313,6 +1315,17 @@ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
le64_to_cpu(encl_pg0.enclosure_logical_id);
}
goto out;
out_free_phy:
for (i = 0; i < mrioc->sas_hba.num_phys; i++) {
if (mrioc->sas_hba.phy[i].phy)
sas_phy_delete(mrioc->sas_hba.phy[i].phy);
}
kfree(mrioc->sas_hba.phy);
mrioc->sas_hba.phy = NULL;
mrioc->sas_hba.num_phys = 0;
out:
kfree(sas_io_unit_pg0);
}
@ -1337,6 +1350,7 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
struct mpi3mr_sas_phy *mr_sas_phy, *next;
struct mpi3mr_sas_port *mr_sas_port;
unsigned long flags;
bool discard = false;
struct mpi3mr_sas_node *mr_sas_node;
struct sas_rphy *rphy;
struct mpi3mr_tgt_dev *tgtdev = NULL;
@ -1435,9 +1449,15 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
}
port = sas_port_alloc_num(mr_sas_node->parent_dev);
if (!port) {
ioc_err(mrioc, "failure at %s:%d/%s() (sas_port_alloc)!\n",
__FILE__, __LINE__, __func__);
goto out_fail;
}
if ((sas_port_add(port))) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
sas_port_free(port);
goto out_fail;
}
@ -1457,19 +1477,51 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
mr_sas_port->port = port;
if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
rphy = sas_end_device_alloc(port);
if (!rphy) {
ioc_err(mrioc, "failure at %s:%d/%s() (sas_end_device_alloc)!\n",
__FILE__, __LINE__, __func__);
sas_port_delete(port);
goto out_fail;
}
tgtdev->dev_spec.sas_sata_inf.rphy = rphy;
} else {
rphy = sas_expander_alloc(port,
mr_sas_port->remote_identify.device_type);
if (!rphy) {
ioc_err(mrioc, "failure at %s:%d/%s() (sas_expander_alloc)!\n",
__FILE__, __LINE__, __func__);
sas_port_delete(port);
goto out_fail;
}
}
rphy->identify = mr_sas_port->remote_identify;
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
if (mrioc->stop_drv_processing || mrioc->reset_in_progress) {
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
sas_rphy_free(rphy);
sas_port_delete(port);
goto out_fail;
}
if (mrioc->current_event)
mrioc->current_event->pending_at_sml = 1;
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
if ((sas_rphy_add(rphy))) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__);
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
if (mrioc->current_event) {
mrioc->current_event->pending_at_sml = 0;
discard = mrioc->current_event->discard;
}
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
if (discard)
mpi3mr_print_device_event_notice(mrioc, true);
sas_rphy_unlink(rphy);
sas_rphy_free(rphy);
sas_port_delete(port);
goto out_fail;
}
if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 0;
@ -1487,11 +1539,14 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
list_add_tail(&mr_sas_port->port_list, &mr_sas_node->sas_port_list);
spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
if (mrioc->current_event) {
mrioc->current_event->pending_at_sml = 0;
if (mrioc->current_event->discard)
mpi3mr_print_device_event_notice(mrioc, true);
discard = mrioc->current_event->discard;
}
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
if (discard)
mpi3mr_print_device_event_notice(mrioc, true);
/* fill in report manufacture */
if (mr_sas_port->remote_identify.device_type ==
@ -1505,9 +1560,17 @@ static struct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
return mr_sas_port;
out_fail:
if (tgtdev) {
tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 0;
tgtdev->dev_spec.sas_sata_inf.rphy = NULL;
mpi3mr_tgtdev_put(tgtdev);
}
list_for_each_entry_safe(mr_sas_phy, next, &mr_sas_port->phy_list,
port_siblings)
port_siblings) {
mr_sas_phy->phy_belongs_to_port = 0;
list_del(&mr_sas_phy->port_siblings);
}
kfree(mr_sas_port);
return NULL;
}
@ -1529,6 +1592,7 @@ static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
{
int i;
unsigned long flags;
bool discard = false;
struct mpi3mr_sas_port *mr_sas_port, *next;
struct mpi3mr_sas_node *mr_sas_node;
u8 found = 0;
@ -1585,8 +1649,10 @@ static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
if (mrioc->current_event)
mrioc->current_event->pending_at_sml = 1;
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
list_for_each_entry_safe(mr_sas_phy, next_phy,
&mr_sas_port->phy_list, port_siblings) {
@ -1608,11 +1674,14 @@ static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
ioc_info(mrioc, "%s: removed sas_address(0x%016llx)\n",
__func__, (unsigned long long)sas_address);
spin_lock_irqsave(&mrioc->fwevt_lock, flags);
if (mrioc->current_event) {
mrioc->current_event->pending_at_sml = 0;
if (mrioc->current_event->discard)
mpi3mr_print_device_event_notice(mrioc, false);
discard = mrioc->current_event->discard;
}
spin_unlock_irqrestore(&mrioc->fwevt_lock, flags);
if (discard)
mpi3mr_print_device_event_notice(mrioc, false);
kfree(mr_sas_port);
}