Skip to content

Commit c076756

Browse files
Ranjan Kumarmartinkpetersen
authored andcommitted
scsi: mpt3sas: Reload SBR without rebooting HBA
Add a new IOCTL command MPT3ENABLEDIAGSBRRELOAD. As a part of firmware update operation, applications use this IOCTL command to set the SBR reload bit in the Host Diagnostic register. This permits HBA firmware to be updated without powercycling the system. Reported-by: kernel test robot <lkp@intel.com> Closes: https://lore.kernel.org/oe-kbuild-all/202312280909.MZyhxwBL-lkp@intel.com/ Closes: https://lore.kernel.org/oe-kbuild-all/202312281141.jDyPezRn-lkp@intel.com/ Signed-off-by: Ranjan Kumar <ranjan.kumar@broadcom.com> Link: https://lore.kernel.org/r/20231228114810.11923-2-ranjan.kumar@broadcom.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 10a3966 commit c076756

File tree

5 files changed

+136
-32
lines changed

5 files changed

+136
-32
lines changed

drivers/scsi/mpt3sas/mpt3sas_base.c

Lines changed: 67 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -5481,7 +5481,7 @@ mpt3sas_atto_validate_nvram(struct MPT3SAS_ADAPTER *ioc,
54815481
* mpt3sas_atto_get_sas_addr - get the ATTO SAS address from mfg page 1
54825482
*
54835483
* @ioc : per adapter object
5484-
* @*sas_addr : return sas address
5484+
* @sas_addr : return sas address
54855485
* Return: 0 for success, non-zero for failure.
54865486
*/
54875487
static int
@@ -7914,26 +7914,22 @@ mpt3sas_base_validate_event_type(struct MPT3SAS_ADAPTER *ioc, u32 *event_type)
79147914
}
79157915

79167916
/**
7917-
* _base_diag_reset - the "big hammer" start of day reset
7918-
* @ioc: per adapter object
7919-
*
7920-
* Return: 0 for success, non-zero for failure.
7921-
*/
7922-
static int
7923-
_base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
7924-
{
7925-
u32 host_diagnostic;
7926-
u32 ioc_state;
7927-
u32 count;
7928-
u32 hcb_size;
7929-
7930-
ioc_info(ioc, "sending diag reset !!\n");
7931-
7932-
pci_cfg_access_lock(ioc->pdev);
7917+
* mpt3sas_base_unlock_and_get_host_diagnostic- enable Host Diagnostic Register writes
7918+
* @ioc: per adapter object
7919+
* @host_diagnostic: host diagnostic register content
7920+
*
7921+
* Return: 0 for success, non-zero for failure.
7922+
*/
79337923

7934-
drsprintk(ioc, ioc_info(ioc, "clear interrupts\n"));
7924+
int
7925+
mpt3sas_base_unlock_and_get_host_diagnostic(struct MPT3SAS_ADAPTER *ioc,
7926+
u32 *host_diagnostic)
7927+
{
79357928

7929+
u32 count;
7930+
*host_diagnostic = 0;
79367931
count = 0;
7932+
79377933
do {
79387934
/* Write magic sequence to WriteSequence register
79397935
* Loop until in diagnostic mode
@@ -7952,30 +7948,67 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
79527948

79537949
if (count++ > 20) {
79547950
ioc_info(ioc,
7955-
"Stop writing magic sequence after 20 retries\n");
7951+
"Stop writing magic sequence after 20 retries\n");
79567952
_base_dump_reg_set(ioc);
7957-
goto out;
7953+
return -EFAULT;
79587954
}
79597955

7960-
host_diagnostic = ioc->base_readl_ext_retry(&ioc->chip->HostDiagnostic);
7956+
*host_diagnostic = ioc->base_readl_ext_retry(&ioc->chip->HostDiagnostic);
79617957
drsprintk(ioc,
7962-
ioc_info(ioc, "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n",
7963-
count, host_diagnostic));
7958+
ioc_info(ioc, "wrote magic sequence: count(%d), host_diagnostic(0x%08x)\n",
7959+
count, *host_diagnostic));
79647960

7965-
} while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0);
7961+
} while ((*host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0);
7962+
return 0;
7963+
}
79667964

7967-
hcb_size = ioc->base_readl(&ioc->chip->HCBSize);
7965+
/**
7966+
* mpt3sas_base_lock_host_diagnostic: Disable Host Diagnostic Register writes
7967+
* @ioc: per adapter object
7968+
*/
79687969

7970+
void
7971+
mpt3sas_base_lock_host_diagnostic(struct MPT3SAS_ADAPTER *ioc)
7972+
{
7973+
drsprintk(ioc, ioc_info(ioc, "disable writes to the diagnostic register\n"));
7974+
writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
7975+
}
7976+
7977+
/**
7978+
* _base_diag_reset - the "big hammer" start of day reset
7979+
* @ioc: per adapter object
7980+
*
7981+
* Return: 0 for success, non-zero for failure.
7982+
*/
7983+
static int
7984+
_base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
7985+
{
7986+
u32 host_diagnostic;
7987+
u32 ioc_state;
7988+
u32 count;
7989+
u32 hcb_size;
7990+
7991+
ioc_info(ioc, "sending diag reset !!\n");
7992+
7993+
pci_cfg_access_lock(ioc->pdev);
7994+
7995+
drsprintk(ioc, ioc_info(ioc, "clear interrupts\n"));
7996+
7997+
mutex_lock(&ioc->hostdiag_unlock_mutex);
7998+
if (mpt3sas_base_unlock_and_get_host_diagnostic(ioc, &host_diagnostic))
7999+
goto out;
8000+
8001+
hcb_size = ioc->base_readl(&ioc->chip->HCBSize);
79698002
drsprintk(ioc, ioc_info(ioc, "diag reset: issued\n"));
79708003
writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,
79718004
&ioc->chip->HostDiagnostic);
79728005

7973-
/*This delay allows the chip PCIe hardware time to finish reset tasks*/
8006+
/* This delay allows the chip PCIe hardware time to finish reset tasks */
79748007
msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000);
79758008

79768009
/* Approximately 300 second max wait */
79778010
for (count = 0; count < (300000000 /
7978-
MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) {
8011+
MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) {
79798012

79808013
host_diagnostic = ioc->base_readl_ext_retry(&ioc->chip->HostDiagnostic);
79818014

@@ -7988,13 +8021,15 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
79888021
if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))
79898022
break;
79908023

7991-
msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC / 1000);
8024+
/* Wait to pass the second read delay window */
8025+
msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC/1000);
79928026
}
79938027

79948028
if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
79958029

79968030
drsprintk(ioc,
7997-
ioc_info(ioc, "restart the adapter assuming the HCB Address points to good F/W\n"));
8031+
ioc_info(ioc, "restart the adapter assuming the\n"
8032+
"HCB Address points to good F/W\n"));
79988033
host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
79998034
host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
80008035
writel(host_diagnostic, &ioc->chip->HostDiagnostic);
@@ -8008,9 +8043,8 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
80088043
writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET,
80098044
&ioc->chip->HostDiagnostic);
80108045

8011-
drsprintk(ioc,
8012-
ioc_info(ioc, "disable writes to the diagnostic register\n"));
8013-
writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
8046+
mpt3sas_base_lock_host_diagnostic(ioc);
8047+
mutex_unlock(&ioc->hostdiag_unlock_mutex);
80148048

80158049
drsprintk(ioc, ioc_info(ioc, "Wait for FW to go to the READY state\n"));
80168050
ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20);
@@ -8028,6 +8062,7 @@ _base_diag_reset(struct MPT3SAS_ADAPTER *ioc)
80288062
out:
80298063
pci_cfg_access_unlock(ioc->pdev);
80308064
ioc_err(ioc, "diag reset: FAILED\n");
8065+
mutex_unlock(&ioc->hostdiag_unlock_mutex);
80318066
return -EFAULT;
80328067
}
80338068

drivers/scsi/mpt3sas/mpt3sas_base.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,7 @@ struct MPT3SAS_ADAPTER {
13661366
u8 got_task_abort_from_ioctl;
13671367

13681368
struct mutex reset_in_progress_mutex;
1369+
struct mutex hostdiag_unlock_mutex;
13691370
spinlock_t ioc_reset_in_progress_lock;
13701371
u8 ioc_link_reset_in_progress;
13711372

@@ -1790,6 +1791,9 @@ void mpt3sas_base_disable_msix(struct MPT3SAS_ADAPTER *ioc);
17901791
int mpt3sas_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num);
17911792
void mpt3sas_base_pause_mq_polling(struct MPT3SAS_ADAPTER *ioc);
17921793
void mpt3sas_base_resume_mq_polling(struct MPT3SAS_ADAPTER *ioc);
1794+
int mpt3sas_base_unlock_and_get_host_diagnostic(struct MPT3SAS_ADAPTER *ioc,
1795+
u32 *host_diagnostic);
1796+
void mpt3sas_base_lock_host_diagnostic(struct MPT3SAS_ADAPTER *ioc);
17931797

17941798
/* scsih shared API */
17951799
struct scsi_cmnd *mpt3sas_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc,

drivers/scsi/mpt3sas/mpt3sas_ctl.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2543,6 +2543,56 @@ _ctl_addnl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
25432543
return 0;
25442544
}
25452545

2546+
/**
2547+
* _ctl_enable_diag_sbr_reload - enable sbr reload bit
2548+
* @ioc: per adapter object
2549+
* @arg: user space buffer containing ioctl content
2550+
*
2551+
* Enable the SBR reload bit
2552+
*/
2553+
static int
2554+
_ctl_enable_diag_sbr_reload(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
2555+
{
2556+
u32 ioc_state, host_diagnostic;
2557+
2558+
if (ioc->shost_recovery ||
2559+
ioc->pci_error_recovery || ioc->is_driver_loading ||
2560+
ioc->remove_host)
2561+
return -EAGAIN;
2562+
2563+
ioc_state = mpt3sas_base_get_iocstate(ioc, 1);
2564+
2565+
if (ioc_state != MPI2_IOC_STATE_OPERATIONAL)
2566+
return -EFAULT;
2567+
2568+
host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic);
2569+
2570+
if (host_diagnostic & MPI2_DIAG_SBR_RELOAD)
2571+
return 0;
2572+
2573+
if (mutex_trylock(&ioc->hostdiag_unlock_mutex)) {
2574+
if (mpt3sas_base_unlock_and_get_host_diagnostic(ioc, &host_diagnostic)) {
2575+
mutex_unlock(&ioc->hostdiag_unlock_mutex);
2576+
return -EFAULT;
2577+
}
2578+
} else
2579+
return -EAGAIN;
2580+
2581+
host_diagnostic |= MPI2_DIAG_SBR_RELOAD;
2582+
writel(host_diagnostic, &ioc->chip->HostDiagnostic);
2583+
host_diagnostic = ioc->base_readl(&ioc->chip->HostDiagnostic);
2584+
mpt3sas_base_lock_host_diagnostic(ioc);
2585+
mutex_unlock(&ioc->hostdiag_unlock_mutex);
2586+
2587+
if (!(host_diagnostic & MPI2_DIAG_SBR_RELOAD)) {
2588+
ioc_err(ioc, "%s: Failed to set Diag SBR Reload Bit\n", __func__);
2589+
return -EFAULT;
2590+
}
2591+
2592+
ioc_info(ioc, "%s: Successfully set the Diag SBR Reload Bit\n", __func__);
2593+
return 0;
2594+
}
2595+
25462596
#ifdef CONFIG_COMPAT
25472597
/**
25482598
* _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,
27192769
if (_IOC_SIZE(cmd) == sizeof(struct mpt3_addnl_diag_query))
27202770
ret = _ctl_addnl_diag_query(ioc, arg);
27212771
break;
2772+
case MPT3ENABLEDIAGSBRRELOAD:
2773+
if (_IOC_SIZE(cmd) == sizeof(struct mpt3_enable_diag_sbr_reload))
2774+
ret = _ctl_enable_diag_sbr_reload(ioc, arg);
2775+
break;
27222776
default:
27232777
dctlprintk(ioc,
27242778
ioc_info(ioc, "unsupported ioctl opcode(0x%08x)\n",

drivers/scsi/mpt3sas/mpt3sas_ctl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@
9898
struct mpt3_diag_read_buffer)
9999
#define MPT3ADDNLDIAGQUERY _IOWR(MPT3_MAGIC_NUMBER, 32, \
100100
struct mpt3_addnl_diag_query)
101+
#define MPT3ENABLEDIAGSBRRELOAD _IOWR(MPT3_MAGIC_NUMBER, 33, \
102+
struct mpt3_enable_diag_sbr_reload)
101103

102104
/* Trace Buffer default UniqueId */
103105
#define MPT2DIAGBUFFUNIQUEID (0x07075900)
@@ -448,4 +450,12 @@ struct mpt3_addnl_diag_query {
448450
uint32_t reserved2[2];
449451
};
450452

453+
/**
454+
* struct mpt3_enable_diag_sbr_reload - enable sbr reload
455+
* @hdr - generic header
456+
*/
457+
struct mpt3_enable_diag_sbr_reload {
458+
struct mpt3_ioctl_header hdr;
459+
};
460+
451461
#endif /* MPT3SAS_CTL_H_INCLUDED */

drivers/scsi/mpt3sas/mpt3sas_scsih.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12240,6 +12240,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
1224012240

1224112241
/* misc semaphores and spin locks */
1224212242
mutex_init(&ioc->reset_in_progress_mutex);
12243+
mutex_init(&ioc->hostdiag_unlock_mutex);
1224312244
/* initializing pci_access_mutex lock */
1224412245
mutex_init(&ioc->pci_access_mutex);
1224512246
spin_lock_init(&ioc->ioc_reset_in_progress_lock);

0 commit comments

Comments
 (0)