summaryrefslogtreecommitdiff
path: root/drivers/scsi/mpi3mr
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/mpi3mr')
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr.h10
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_app.c10
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_fw.c17
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_os.c95
4 files changed, 99 insertions, 33 deletions
diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h
index 9bbc7cb98ca3..8d4ef49e04d1 100644
--- a/drivers/scsi/mpi3mr/mpi3mr.h
+++ b/drivers/scsi/mpi3mr/mpi3mr.h
@@ -56,8 +56,8 @@ extern struct list_head mrioc_list;
extern int prot_mask;
extern atomic64_t event_counter;
-#define MPI3MR_DRIVER_VERSION "8.13.0.5.50"
-#define MPI3MR_DRIVER_RELDATE "20-February-2025"
+#define MPI3MR_DRIVER_VERSION "8.14.0.5.50"
+#define MPI3MR_DRIVER_RELDATE "27-June-2025"
#define MPI3MR_DRIVER_NAME "mpi3mr"
#define MPI3MR_DRIVER_LICENSE "GPL"
@@ -1137,6 +1137,8 @@ struct scmd_priv {
* @logdata_buf: Circular buffer to store log data entries
* @logdata_buf_idx: Index of entry in buffer to store
* @logdata_entry_sz: log data entry size
+ * @adm_req_q_bar_writeq_lock: Admin request queue lock
+ * @adm_reply_q_bar_writeq_lock: Admin reply queue lock
* @pend_large_data_sz: Counter to track pending large data
* @io_throttle_data_length: I/O size to track in 512b blocks
* @io_throttle_high: I/O size to start throttle in 512b blocks
@@ -1185,7 +1187,7 @@ struct mpi3mr_ioc {
char name[MPI3MR_NAME_LENGTH];
char driver_name[MPI3MR_NAME_LENGTH];
- volatile struct mpi3_sysif_registers __iomem *sysif_regs;
+ struct mpi3_sysif_registers __iomem *sysif_regs;
resource_size_t sysif_regs_phys;
int bars;
u64 dma_mask;
@@ -1339,6 +1341,8 @@ struct mpi3mr_ioc {
u8 *logdata_buf;
u16 logdata_buf_idx;
u16 logdata_entry_sz;
+ spinlock_t adm_req_q_bar_writeq_lock;
+ spinlock_t adm_reply_q_bar_writeq_lock;
atomic_t pend_large_data_sz;
u32 io_throttle_data_length;
diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c
index f36663613950..0e5478d62580 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_app.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_app.c
@@ -795,9 +795,8 @@ void mpi3mr_release_diag_bufs(struct mpi3mr_ioc *mrioc, u8 skip_rel_action)
*
* @hdb: HDB pointer
* @type: Trigger type
- * @data: Trigger data
- * @force: Trigger overwrite flag
* @trigger_data: Pointer to trigger data information
+ * @force: Trigger overwrite flag
*
* Updates trigger type and trigger data based on parameter
* passed to this function
@@ -822,9 +821,8 @@ void mpi3mr_set_trigger_data_in_hdb(struct diag_buffer_desc *hdb,
*
* @mrioc: Adapter instance reference
* @type: Trigger type
- * @data: Trigger data
- * @force: Trigger overwrite flag
* @trigger_data: Pointer to trigger data information
+ * @force: Trigger overwrite flag
*
* Updates trigger type and trigger data based on parameter
* passed to this function
@@ -3388,6 +3386,8 @@ static DEVICE_ATTR_RO(persistent_id);
* @buf: the buffer returned
*
* A sysfs 'read-only' sdev attribute, only works with SATA devices
+ *
+ * Returns: the number of characters written to @buf
*/
static ssize_t
sas_ncq_prio_supported_show(struct device *dev,
@@ -3406,6 +3406,8 @@ static DEVICE_ATTR_RO(sas_ncq_prio_supported);
* @buf: the buffer returned
*
* A sysfs 'read/write' sdev attribute, only works with SATA devices
+ *
+ * Returns: the number of characters written to @buf
*/
static ssize_t
sas_ncq_prio_enable_show(struct device *dev,
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 1d7901a8f0e4..0152d31d430a 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -23,17 +23,22 @@ module_param(poll_queues, int, 0444);
MODULE_PARM_DESC(poll_queues, "Number of queues for io_uring poll mode. (Range 1 - 126)");
#if defined(writeq) && defined(CONFIG_64BIT)
-static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
+static inline void mpi3mr_writeq(__u64 b, void __iomem *addr,
+ spinlock_t *write_queue_lock)
{
writeq(b, addr);
}
#else
-static inline void mpi3mr_writeq(__u64 b, volatile void __iomem *addr)
+static inline void mpi3mr_writeq(__u64 b, void __iomem *addr,
+ spinlock_t *write_queue_lock)
{
__u64 data_out = b;
+ unsigned long flags;
+ spin_lock_irqsave(write_queue_lock, flags);
writel((u32)(data_out), addr);
writel((u32)(data_out >> 32), (addr + 4));
+ spin_unlock_irqrestore(write_queue_lock, flags);
}
#endif
@@ -428,8 +433,8 @@ static void mpi3mr_process_admin_reply_desc(struct mpi3mr_ioc *mrioc,
MPI3MR_SENSE_BUF_SZ);
}
if (cmdptr->is_waiting) {
- complete(&cmdptr->done);
cmdptr->is_waiting = 0;
+ complete(&cmdptr->done);
} else if (cmdptr->callback)
cmdptr->callback(mrioc, cmdptr);
}
@@ -2954,9 +2959,11 @@ static int mpi3mr_setup_admin_qpair(struct mpi3mr_ioc *mrioc)
(mrioc->num_admin_req);
writel(num_admin_entries, &mrioc->sysif_regs->admin_queue_num_entries);
mpi3mr_writeq(mrioc->admin_req_dma,
- &mrioc->sysif_regs->admin_request_queue_address);
+ &mrioc->sysif_regs->admin_request_queue_address,
+ &mrioc->adm_req_q_bar_writeq_lock);
mpi3mr_writeq(mrioc->admin_reply_dma,
- &mrioc->sysif_regs->admin_reply_queue_address);
+ &mrioc->sysif_regs->admin_reply_queue_address,
+ &mrioc->adm_reply_q_bar_writeq_lock);
writel(mrioc->admin_req_pi, &mrioc->sysif_regs->admin_request_queue_pi);
writel(mrioc->admin_reply_ci, &mrioc->sysif_regs->admin_reply_queue_ci);
return retval;
diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c
index c186b892150f..e467b56949e9 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
@@ -49,6 +49,13 @@ static void mpi3mr_send_event_ack(struct mpi3mr_ioc *mrioc, u8 event,
#define MPI3_EVENT_WAIT_FOR_DEVICES_TO_REFRESH (0xFFFE)
+/*
+ * SAS Log info code for a NCQ collateral abort after an NCQ error:
+ * IOC_LOGINFO_PREFIX_PL | PL_LOGINFO_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR
+ * See: drivers/message/fusion/lsi/mpi_log_sas.h
+ */
+#define IOC_LOGINFO_SATA_NCQ_FAIL_AFTER_ERR 0x31080000
+
/**
* mpi3mr_host_tag_for_scmd - Get host tag for a scmd
* @mrioc: Adapter instance reference
@@ -985,6 +992,10 @@ static int mpi3mr_report_tgtdev_to_host(struct mpi3mr_ioc *mrioc,
goto out;
}
}
+ dprint_event_bh(mrioc,
+ "exposed target device with handle(0x%04x), perst_id(%d)\n",
+ tgtdev->dev_handle, perst_id);
+ goto out;
} else
mpi3mr_report_tgtdev_to_sas_transport(mrioc, tgtdev);
out:
@@ -1344,9 +1355,9 @@ static void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_ioc *mrioc,
(struct mpi3_event_data_device_status_change *)fwevt->event_data;
dev_handle = le16_to_cpu(evtdata->dev_handle);
- ioc_info(mrioc,
- "%s :device status change: handle(0x%04x): reason code(0x%x)\n",
- __func__, dev_handle, evtdata->reason_code);
+ dprint_event_bh(mrioc,
+ "processing device status change event bottom half for handle(0x%04x), rc(0x%02x)\n",
+ dev_handle, evtdata->reason_code);
switch (evtdata->reason_code) {
case MPI3_EVENT_DEV_STAT_RC_HIDDEN:
delete = 1;
@@ -1365,8 +1376,13 @@ static void mpi3mr_devstatuschg_evt_bh(struct mpi3mr_ioc *mrioc,
}
tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
- if (!tgtdev)
+ if (!tgtdev) {
+ dprint_event_bh(mrioc,
+ "processing device status change event bottom half,\n"
+ "cannot identify target device for handle(0x%04x), rc(0x%02x)\n",
+ dev_handle, evtdata->reason_code);
goto out;
+ }
if (uhide) {
tgtdev->is_hidden = 0;
if (!tgtdev->host_exposed)
@@ -1406,12 +1422,17 @@ static void mpi3mr_devinfochg_evt_bh(struct mpi3mr_ioc *mrioc,
perst_id = le16_to_cpu(dev_pg0->persistent_id);
dev_handle = le16_to_cpu(dev_pg0->dev_handle);
- ioc_info(mrioc,
- "%s :Device info change: handle(0x%04x): persist_id(0x%x)\n",
- __func__, dev_handle, perst_id);
+ dprint_event_bh(mrioc,
+ "processing device info change event bottom half for handle(0x%04x), perst_id(%d)\n",
+ dev_handle, perst_id);
tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
- if (!tgtdev)
+ if (!tgtdev) {
+ dprint_event_bh(mrioc,
+ "cannot identify target device for device info\n"
+ "change event handle(0x%04x), perst_id(%d)\n",
+ dev_handle, perst_id);
goto out;
+ }
mpi3mr_update_tgtdev(mrioc, tgtdev, dev_pg0, false);
if (!tgtdev->is_hidden && !tgtdev->host_exposed)
mpi3mr_report_tgtdev_to_host(mrioc, perst_id);
@@ -2012,8 +2033,11 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
mpi3mr_fwevt_del_from_list(mrioc, fwevt);
mrioc->current_event = fwevt;
- if (mrioc->stop_drv_processing)
+ if (mrioc->stop_drv_processing) {
+ dprint_event_bh(mrioc, "ignoring event(0x%02x) in the bottom half handler\n"
+ "due to stop_drv_processing\n", fwevt->event_id);
goto out;
+ }
if (mrioc->unrecoverable) {
dprint_event_bh(mrioc,
@@ -2025,6 +2049,9 @@ static void mpi3mr_fwevt_bh(struct mpi3mr_ioc *mrioc,
if (!fwevt->process_evt)
goto evt_ack;
+ dprint_event_bh(mrioc, "processing event(0x%02x) in the bottom half handler\n",
+ fwevt->event_id);
+
switch (fwevt->event_id) {
case MPI3_EVENT_DEVICE_ADDED:
{
@@ -2763,6 +2790,9 @@ static void mpi3mr_devstatuschg_evt_th(struct mpi3mr_ioc *mrioc,
goto out;
dev_handle = le16_to_cpu(evtdata->dev_handle);
+ dprint_event_th(mrioc,
+ "device status change event top half with rc(0x%02x) for handle(0x%04x)\n",
+ evtdata->reason_code, dev_handle);
switch (evtdata->reason_code) {
case MPI3_EVENT_DEV_STAT_RC_INT_DEVICE_RESET_STRT:
@@ -2786,8 +2816,12 @@ static void mpi3mr_devstatuschg_evt_th(struct mpi3mr_ioc *mrioc,
}
tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle);
- if (!tgtdev)
+ if (!tgtdev) {
+ dprint_event_th(mrioc,
+ "processing device status change event could not identify device for handle(0x%04x)\n",
+ dev_handle);
goto out;
+ }
if (hide)
tgtdev->is_hidden = hide;
if (tgtdev->starget && tgtdev->starget->hostdata) {
@@ -2863,13 +2897,13 @@ static void mpi3mr_energypackchg_evt_th(struct mpi3mr_ioc *mrioc,
u16 shutdown_timeout = le16_to_cpu(evtdata->shutdown_timeout);
if (shutdown_timeout <= 0) {
- ioc_warn(mrioc,
+ dprint_event_th(mrioc,
"%s :Invalid Shutdown Timeout received = %d\n",
__func__, shutdown_timeout);
return;
}
- ioc_info(mrioc,
+ dprint_event_th(mrioc,
"%s :Previous Shutdown Timeout Value = %d New Shutdown Timeout Value = %d\n",
__func__, mrioc->facts.shutdown_timeout, shutdown_timeout);
mrioc->facts.shutdown_timeout = shutdown_timeout;
@@ -2945,9 +2979,9 @@ void mpi3mr_add_event_wait_for_device_refresh(struct mpi3mr_ioc *mrioc)
* @mrioc: Adapter instance reference
* @event_reply: event data
*
- * Identify whteher the event has to handled and acknowledged
- * and either process the event in the tophalf and/or schedule a
- * bottom half through mpi3mr_fwevt_worker.
+ * Identifies whether the event has to be handled and acknowledged,
+ * and either processes the event in the top-half and/or schedule a
+ * bottom-half through mpi3mr_fwevt_worker().
*
* Return: Nothing
*/
@@ -2974,9 +3008,11 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
struct mpi3_device_page0 *dev_pg0 =
(struct mpi3_device_page0 *)event_reply->event_data;
if (mpi3mr_create_tgtdev(mrioc, dev_pg0))
- ioc_err(mrioc,
- "%s :Failed to add device in the device add event\n",
- __func__);
+ dprint_event_th(mrioc,
+ "failed to process device added event for handle(0x%04x),\n"
+ "perst_id(%d) in the event top half handler\n",
+ le16_to_cpu(dev_pg0->dev_handle),
+ le16_to_cpu(dev_pg0->persistent_id));
else
process_evt_bh = 1;
break;
@@ -3039,11 +3075,15 @@ void mpi3mr_os_handle_events(struct mpi3mr_ioc *mrioc,
break;
}
if (process_evt_bh || ack_req) {
+ dprint_event_th(mrioc,
+ "scheduling bottom half handler for event(0x%02x),ack_required=%d\n",
+ evt_type, ack_req);
sz = event_reply->event_data_length * 4;
fwevt = mpi3mr_alloc_fwevt(sz);
if (!fwevt) {
- ioc_info(mrioc, "%s :failure at %s:%d/%s()!\n",
- __func__, __FILE__, __LINE__, __func__);
+ dprint_event_th(mrioc,
+ "failed to schedule bottom half handler for\n"
+ "event(0x%02x), ack_required=%d\n", evt_type, ack_req);
return;
}
@@ -3397,7 +3437,18 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc,
scmd->result = DID_NO_CONNECT << 16;
break;
case MPI3_IOCSTATUS_SCSI_IOC_TERMINATED:
- scmd->result = DID_SOFT_ERROR << 16;
+ if (ioc_loginfo == IOC_LOGINFO_SATA_NCQ_FAIL_AFTER_ERR) {
+ /*
+ * This is a ATA NCQ command aborted due to another NCQ
+ * command failure. We must retry this command
+ * immediately but without incrementing its retry
+ * counter.
+ */
+ WARN_ON_ONCE(xfer_count != 0);
+ scmd->result = DID_IMM_RETRY << 16;
+ } else {
+ scmd->result = DID_SOFT_ERROR << 16;
+ }
break;
case MPI3_IOCSTATUS_SCSI_TASK_TERMINATED:
case MPI3_IOCSTATUS_SCSI_EXT_TERMINATED:
@@ -5332,6 +5383,8 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
spin_lock_init(&mrioc->tgtdev_lock);
spin_lock_init(&mrioc->watchdog_lock);
spin_lock_init(&mrioc->chain_buf_lock);
+ spin_lock_init(&mrioc->adm_req_q_bar_writeq_lock);
+ spin_lock_init(&mrioc->adm_reply_q_bar_writeq_lock);
spin_lock_init(&mrioc->sas_node_lock);
spin_lock_init(&mrioc->trigger_lock);