Skip to content

Commit f98790c

Browse files
suganathprabu0512martinkpetersen
authored andcommitted
scsi: mpt3sas: Sync time periodically between driver and firmware
The controller time currently gets updated with host time during driver load or when a controller reset is issued. I.e. when host issues the IOCInit request message to the HBA firmware. This IOCInit message has a field named 'TimeStamp' with which the host updates the controller time. Sometimes controller time drifts with respect to the host and it is difficult to correlate host logs with controller logs. Issuing a controller reset to sync the time would impact in-flight I/O and is not a viable option. Instead the driver now sends an IO_UNIT_CONTROL Request to sync the time periodically. This is done from the watchdog thread which gets invoked every second. The time synchronization interval is specified in the 'TimeSyncInterval' field in Manufacturing Page11 by the controller: TimeSyncInterval - 8 bits bits 0-6: Time stamp Synchronization interval value bit 7: Time stamp Synchronization interval unit, (if this bit is one then Timestamp Synchronization interval value is specified in terms of hours else Timestamp Synchronization interval value is specified in terms of minutes). The driver keeps track of the timer using IOC's timestamp_update_count field. This field value gets incremented whenever the watchdog thread gets invoked. And whenever this field value is greater than or equal to the Time Stamp Synchronization interval value, the driver sends the IO_UNIT_CONTROL Request message to controller to update the time and then it resets the timestamp_update_count field to zero. Link: https://lore.kernel.org/r/[email protected] Reported-by: kernel test robot <[email protected]> Signed-off-by: Suganath Prabu S <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent afc516d commit f98790c

File tree

2 files changed

+104
-3
lines changed

2 files changed

+104
-3
lines changed

drivers/scsi/mpt3sas/mpt3sas_base.c

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,71 @@ static int mpt3sas_remove_dead_ioc_func(void *arg)
596596
return 0;
597597
}
598598

599+
/**
600+
* _base_sync_drv_fw_timestamp - Sync Drive-Fw TimeStamp.
601+
* @ioc: Per Adapter Object
602+
*
603+
* Return nothing.
604+
*/
605+
static void _base_sync_drv_fw_timestamp(struct MPT3SAS_ADAPTER *ioc)
606+
{
607+
Mpi26IoUnitControlRequest_t *mpi_request;
608+
Mpi26IoUnitControlReply_t *mpi_reply;
609+
u16 smid;
610+
ktime_t current_time;
611+
u64 TimeStamp = 0;
612+
u8 issue_reset = 0;
613+
614+
mutex_lock(&ioc->scsih_cmds.mutex);
615+
if (ioc->scsih_cmds.status != MPT3_CMD_NOT_USED) {
616+
ioc_err(ioc, "scsih_cmd in use %s\n", __func__);
617+
goto out;
618+
}
619+
ioc->scsih_cmds.status = MPT3_CMD_PENDING;
620+
smid = mpt3sas_base_get_smid(ioc, ioc->scsih_cb_idx);
621+
if (!smid) {
622+
ioc_err(ioc, "Failed obtaining a smid %s\n", __func__);
623+
ioc->scsih_cmds.status = MPT3_CMD_NOT_USED;
624+
goto out;
625+
}
626+
mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
627+
ioc->scsih_cmds.smid = smid;
628+
memset(mpi_request, 0, sizeof(Mpi26IoUnitControlRequest_t));
629+
mpi_request->Function = MPI2_FUNCTION_IO_UNIT_CONTROL;
630+
mpi_request->Operation = MPI26_CTRL_OP_SET_IOC_PARAMETER;
631+
mpi_request->IOCParameter = MPI26_SET_IOC_PARAMETER_SYNC_TIMESTAMP;
632+
current_time = ktime_get_real();
633+
TimeStamp = ktime_to_ms(current_time);
634+
mpi_request->Reserved7 = cpu_to_le32(TimeStamp & 0xFFFFFFFF);
635+
mpi_request->IOCParameterValue = cpu_to_le32(TimeStamp >> 32);
636+
init_completion(&ioc->scsih_cmds.done);
637+
ioc->put_smid_default(ioc, smid);
638+
dinitprintk(ioc, ioc_info(ioc,
639+
"Io Unit Control Sync TimeStamp (sending), @time %lld ms\n",
640+
TimeStamp));
641+
wait_for_completion_timeout(&ioc->scsih_cmds.done,
642+
MPT3SAS_TIMESYNC_TIMEOUT_SECONDS*HZ);
643+
if (!(ioc->scsih_cmds.status & MPT3_CMD_COMPLETE)) {
644+
mpt3sas_check_cmd_timeout(ioc,
645+
ioc->scsih_cmds.status, mpi_request,
646+
sizeof(Mpi2SasIoUnitControlRequest_t)/4, issue_reset);
647+
goto issue_host_reset;
648+
}
649+
if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) {
650+
mpi_reply = ioc->scsih_cmds.reply;
651+
dinitprintk(ioc, ioc_info(ioc,
652+
"Io Unit Control sync timestamp (complete): ioc_status(0x%04x), loginfo(0x%08x)\n",
653+
le16_to_cpu(mpi_reply->IOCStatus),
654+
le32_to_cpu(mpi_reply->IOCLogInfo)));
655+
}
656+
issue_host_reset:
657+
if (issue_reset)
658+
mpt3sas_base_hard_reset_handler(ioc, FORCE_BIG_HAMMER);
659+
ioc->scsih_cmds.status = MPT3_CMD_NOT_USED;
660+
out:
661+
mutex_unlock(&ioc->scsih_cmds.mutex);
662+
}
663+
599664
/**
600665
* _base_fault_reset_work - workq handling ioc fault conditions
601666
* @work: input argument, used to derive ioc
@@ -720,7 +785,11 @@ _base_fault_reset_work(struct work_struct *work)
720785
return; /* don't rearm timer */
721786
}
722787
ioc->ioc_coredump_loop = 0;
723-
788+
if (ioc->time_sync_interval &&
789+
++ioc->timestamp_update_count >= ioc->time_sync_interval) {
790+
ioc->timestamp_update_count = 0;
791+
_base_sync_drv_fw_timestamp(ioc);
792+
}
724793
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
725794
rearm_timer:
726795
if (ioc->fault_reset_work_q)
@@ -744,6 +813,7 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc)
744813
if (ioc->fault_reset_work_q)
745814
return;
746815

816+
ioc->timestamp_update_count = 0;
747817
/* initialize fault polling */
748818

749819
INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work);
@@ -4754,7 +4824,24 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
47544824
else
47554825
ioc->nvme_abort_timeout = ioc->manu_pg11.NVMeAbortTO;
47564826
}
4757-
4827+
ioc->time_sync_interval =
4828+
ioc->manu_pg11.TimeSyncInterval & MPT3SAS_TIMESYNC_MASK;
4829+
if (ioc->time_sync_interval) {
4830+
if (ioc->manu_pg11.TimeSyncInterval & MPT3SAS_TIMESYNC_UNIT_MASK)
4831+
ioc->time_sync_interval =
4832+
ioc->time_sync_interval * SECONDS_PER_HOUR;
4833+
else
4834+
ioc->time_sync_interval =
4835+
ioc->time_sync_interval * SECONDS_PER_MIN;
4836+
dinitprintk(ioc, ioc_info(ioc,
4837+
"Driver-FW TimeSync interval is %d seconds. ManuPg11 TimeSync Unit is in %s\n",
4838+
ioc->time_sync_interval, (ioc->manu_pg11.TimeSyncInterval &
4839+
MPT3SAS_TIMESYNC_UNIT_MASK) ? "Hour" : "Minute"));
4840+
} else {
4841+
if (ioc->is_gen35_ioc)
4842+
ioc_warn(ioc,
4843+
"TimeSync Interval in Manuf page-11 is not enabled. Periodic Time-Sync will be disabled\n");
4844+
}
47584845
mpt3sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
47594846
mpt3sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
47604847
mpt3sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
@@ -6466,6 +6553,8 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc)
64666553
r = -EIO;
64676554
}
64686555

6556+
/* Reset TimeSync Counter*/
6557+
ioc->timestamp_update_count = 0;
64696558
return r;
64706559
}
64716560

drivers/scsi/mpt3sas/mpt3sas_base.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,14 @@
9393
/* CoreDump: Default timeout */
9494
#define MPT3SAS_DEFAULT_COREDUMP_TIMEOUT_SECONDS (15) /*15 seconds*/
9595
#define MPT3SAS_COREDUMP_LOOP_DONE (0xFF)
96+
#define MPT3SAS_TIMESYNC_TIMEOUT_SECONDS (10) /* 10 seconds */
97+
#define MPT3SAS_TIMESYNC_UPDATE_INTERVAL (900) /* 15 minutes */
98+
#define MPT3SAS_TIMESYNC_UNIT_MASK (0x80) /* bit 7 */
99+
#define MPT3SAS_TIMESYNC_MASK (0x7F) /* 0 - 6 bits */
100+
#define SECONDS_PER_MIN (60)
101+
#define SECONDS_PER_HOUR (3600)
102+
#define MPT3SAS_COREDUMP_LOOP_DONE (0xFF)
103+
#define MPI26_SET_IOC_PARAMETER_SYNC_TIMESTAMP (0x81)
96104

97105
/*
98106
* Set MPT3SAS_SG_DEPTH value based on user input.
@@ -405,7 +413,7 @@ struct Mpi2ManufacturingPage11_t {
405413
u16 HostTraceBufferMaxSizeKB; /* 50h */
406414
u16 HostTraceBufferMinSizeKB; /* 52h */
407415
u8 CoreDumpTOSec; /* 54h */
408-
u8 Reserved8; /* 55h */
416+
u8 TimeSyncInterval; /* 55h */
409417
u16 Reserved9; /* 56h */
410418
__le32 Reserved10; /* 58h */
411419
};
@@ -1113,6 +1121,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
11131121
* @cpu_msix_table_sz: table size
11141122
* @total_io_cnt: Gives total IO count, used to load balance the interrupts
11151123
* @ioc_coredump_loop: will have non-zero value when FW is in CoreDump state
1124+
* @timestamp_update_count: Counter to fire timeSync command
1125+
* time_sync_interval: Time sync interval read from man page 11
11161126
* @high_iops_outstanding: used to load balance the interrupts
11171127
* within high iops reply queues
11181128
* @msix_load_balance: Enables load balancing of interrupts across
@@ -1308,6 +1318,8 @@ struct MPT3SAS_ADAPTER {
13081318
MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds;
13091319
u32 non_operational_loop;
13101320
u8 ioc_coredump_loop;
1321+
u32 timestamp_update_count;
1322+
u32 time_sync_interval;
13111323
atomic64_t total_io_cnt;
13121324
atomic64_t high_iops_outstanding;
13131325
bool msix_load_balance;

0 commit comments

Comments
 (0)