@@ -7920,26 +7920,20 @@ mpt3sas_base_validate_event_type(struct MPT3SAS_ADAPTER *ioc, u32 *event_type)
}
/**
- * _base_diag_reset - the "big hammer" start of day reset
+ * mpt3sas_base_unlock_and_get_host_diagnostic- enable Host Diagnostic Register writes
* @ioc: per adapter object
+ * @host_diagnostic: host diagnostic register content
*
* Return: 0 for success, non-zero for failure.
*/
-static int
-_base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
+int
+mpt3sas_base_unlock_and_get_host_diagnostic(struct MPT3SAS_ADAPTER *ioc,
+ u32 *host_diagnostic)
{
- u32 host_diagnostic;
- u32 ioc_state;
u32 count;
- u32 hcb_size;
-
- ioc_info(ioc, "sending diag reset !!\n");
-
- pci_cfg_access_lock(ioc->pdev);
-
- drsprintk(ioc, ioc_info(ioc, "clear interrupts\n"));
-
+ *host_diagnostic = 0;
count = 0;
+
do {
/* Write magic sequence to WriteSequence register
* Loop until in diagnostic mode
@@ -7960,15 +7954,55 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
ioc_info(ioc,
"Stop writing magic sequence after 20 retries\n");
_base_dump_reg_set(ioc);
- goto out;
+ return -EFAULT;
}
- host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic);
+ *host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic);
drsprintk(ioc,
ioc_info(ioc, "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n",
- count, host_diagnostic));
+ count, *host_diagnostic));
+
+ } while ((*host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0);
+ return 0;
+}
+
+/**
+ * mpt3sas_base_lock_host_diagnostic - Disable Host Diagnostic Register writes
+ * @ioc: per adapter object
+ *
+ */
+void
+mpt3sas_base_lock_host_diagnostic(struct MPT3SAS_ADAPTER *ioc)
+{
+ drsprintk(ioc, ioc_info(ioc, "disable writes to the diagnostic register\n"));
+ writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
+}
- } while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0);
+/**
+ * _base_diag_reset - the "big hammer" start of day reset
+ * @ioc: per adapter object
+ *
+ * Return: 0 for success, non-zero for failure.
+ */
+static int
+_base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
+{
+ u32 host_diagnostic;
+ u32 ioc_state;
+ u32 count;
+ u32 hcb_size;
+
+ ioc_info(ioc, "sending diag reset !!\n");
+
+ pci_cfg_access_lock(ioc->pdev);
+
+ drsprintk(ioc, ioc_info(ioc, "clear interrupts\n"));
+
+ mutex_lock(&ioc->hostdiag_unlock_mutex);
+ if (mpt3sas_base_unlock_and_get_host_diagnostic(ioc, &host_diagnostic)) {
+ mutex_unlock(&ioc->hostdiag_unlock_mutex);
+ goto out;
+ }
hcb_size = ioc->base_readl(&ioc->chip->HCBSize);
@@ -8013,10 +8047,8 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
drsprintk(ioc, ioc_info(ioc, "restart the adapter\n"));
writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET,
&ioc->chip->HostDiagnostic);
-
- drsprintk(ioc,
- ioc_info(ioc, "disable writes to the diagnostic register\n"));
- writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
+ mpt3sas_base_lock_host_diagnostic(ioc);
+ mutex_unlock(&ioc->hostdiag_unlock_mutex);
drsprintk(ioc, ioc_info(ioc, "Wait for FW to go to the READY state\n"));
ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20);
@@ -8034,6 +8066,7 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
out:
pci_cfg_access_unlock(ioc->pdev);
ioc_err(ioc, "diag reset: FAILED\n");
+ mutex_unlock(&ioc->hostdiag_unlock_mutex);
return -EFAULT;
}
@@ -1367,6 +1367,7 @@ struct MPT3SAS_ADAPTER {
u8 got_task_abort_from_ioctl;
struct mutex reset_in_progress_mutex;
+ struct mutex hostdiag_unlock_mutex;
spinlock_t ioc_reset_in_progress_lock;
u8 ioc_link_reset_in_progress;
@@ -1791,6 +1792,9 @@ void mpt3sas_base_disable_msix(struct MPT3SAS_ADAPTER *ioc);
int mpt3sas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num);
void mpt3sas_base_pause_mq_polling(struct MPT3SAS_ADAPTER *ioc);
void mpt3sas_base_resume_mq_polling(struct MPT3SAS_ADAPTER *ioc);
+int mpt3sas_base_unlock_and_get_host_diagnostic(struct MPT3SAS_ADAPTER *ioc,
+ u32 *host_diagnostic);
+void mpt3sas_base_lock_host_diagnostic(struct MPT3SAS_ADAPTER *ioc);
/* scsih shared API */
struct scsi_cmnd *mpt3sas_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc,
@@ -2543,6 +2543,56 @@ _ctl_addnl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
return 0;
}
+/**
+ * _ctl_enable_diag_sbr_reload - enable sbr reload bit
+ * @ioc: per adapter object
+ * @arg - user space buffer containing ioctl content
+ *
+ * Enable the SBR reload bit
+ */
+static int
+_ctl_enable_diag_sbr_reload(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
+{
+ u32 ioc_state, host_diagnostic;
+
+ if (ioc->shost_recovery ||
+ ioc->pci_error_recovery || ioc->is_driver_loading ||
+ ioc->remove_host)
+ return -EAGAIN;
+
+ ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
+
+ if (ioc_state != MPI2_IOC_STATE_OPERATIONAL)
+ return -EFAULT;
+
+ host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic);
+
+ if (host_diagnostic & MPI2_DIAG_SBR_RELOAD)
+ return 0;
+
+ if (mutex_trylock(&ioc->hostdiag_unlock_mutex)) {
+ if (mpt3sas_base_unlock_and_get_host_diagnostic(ioc, &host_diagnostic)) {
+ mutex_unlock(&ioc->hostdiag_unlock_mutex);
+ return -EFAULT;
+ }
+ } else
+ return -EAGAIN;
+
+ host_diagnostic |= MPI2_DIAG_SBR_RELOAD;
+ writel(host_diagnostic, &ioc->chip->HostDiagnostic);
+ host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic);
+ mpt3sas_base_lock_host_diagnostic(ioc);
+ mutex_unlock(&ioc->hostdiag_unlock_mutex);
+
+ if (!(host_diagnostic & MPI2_DIAG_SBR_RELOAD)) {
+ ioc_err(ioc, "%s: Failed to set Diag SBR Reload Bit\n", __func__);
+ return -EFAULT;
+ }
+
+ ioc_info(ioc, "%s: Successfully set the Diag SBR Reload Bit\n", __func__);
+ return 0;
+}
+
#ifdef CONFIG_COMPAT
/**
* _ctl_compat_mpt_command - convert 32bit pointers to 64bit.
@@ -2719,6 +2769,10 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
if (_IOC_SIZE(cmd) == sizeof(struct mpt3_addnl_diag_query))
ret = _ctl_addnl_diag_query(ioc, arg);
break;
+ case MPT3ENABLEDIAGSBRRELOAD:
+ if (_IOC_SIZE(cmd) == sizeof(struct mpt3_enable_diag_sbr_reload))
+ ret = _ctl_enable_diag_sbr_reload(ioc, arg);
+ break;
default:
dctlprintk(ioc,
ioc_info(ioc, "unsupported ioctl opcode(0x%08x)\n",
@@ -98,6 +98,8 @@
struct mpt3_diag_read_buffer)
#define MPT3ADDNLDIAGQUERY _IOWR(MPT3_MAGIC_NUMBER, 32, \
struct mpt3_addnl_diag_query)
+#define MPT3ENABLEDIAGSBRRELOAD _IOWR(MPT3_MAGIC_NUMBER, 33, \
+ struct mpt3_enable_diag_sbr_reload)
/* Trace Buffer default UniqueId */
#define MPT2DIAGBUFFUNIQUEID (0x07075900)
@@ -448,4 +450,12 @@ struct mpt3_addnl_diag_query {
uint32_t reserved2[2];
};
+/**
+ * struct mpt3_enable_diag_sbr_reload - enable sbr reload
+ * @hdr - generic header
+ */
+struct mpt3_enable_diag_sbr_reload {
+ struct mpt3_ioctl_header hdr;
+};
+
#endif /* MPT3SAS_CTL_H_INCLUDED */
@@ -12259,6 +12259,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* misc semaphores and spin locks */
mutex_init(&ioc->reset_in_progress_mutex);
+ mutex_init(&ioc->hostdiag_unlock_mutex);
/* initializing pci_access_mutex lock */
mutex_init(&ioc->pci_access_mutex);
spin_lock_init(&ioc->ioc_reset_in_progress_lock);