scsi: ips: fix firmware timestamps for 32-bit
authorArnd Bergmann <arnd@arndb.de>
Fri, 20 Apr 2018 16:04:40 +0000 (18:04 +0200)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 20 Apr 2018 23:40:17 +0000 (19:40 -0400)
do_gettimeofday() is deprecated since it will stop working in 2038 on
32-bit platforms, leading to incorrect times passed to the firmware.
On 64-bit platforms the current code appears to be fine, as the
calculation passes an 8-bit century number into the firmware that can
represent times long in the future (possibly until 25599).

Using ktime_get_real_seconds() to get a 64-bit seconds value and
time64_to_tm() to convert it into the firmware format greatly simplifies
the ips timekeeping code, makes 32-bit and 64-bit behave the same way
here, and gets us closer to removing the deprecated interfaces.

Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/ips.c
drivers/scsi/ips.h

index e3c8857..bd6ac6b 100644 (file)
@@ -291,7 +291,7 @@ static void ips_freescb(ips_ha_t *, ips_scb_t *);
 static void ips_setup_funclist(ips_ha_t *);
 static void ips_statinit(ips_ha_t *);
 static void ips_statinit_memio(ips_ha_t *);
-static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t);
+static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time64_t);
 static void ips_ffdc_reset(ips_ha_t *, int);
 static void ips_ffdc_time(ips_ha_t *);
 static uint32_t ips_statupd_copperhead(ips_ha_t *);
@@ -985,10 +985,7 @@ static int __ips_eh_reset(struct scsi_cmnd *SC)
 
        /* FFDC */
        if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) {
-               struct timeval tv;
-
-               do_gettimeofday(&tv);
-               ha->last_ffdc = tv.tv_sec;
+               ha->last_ffdc = ktime_get_real_seconds();
                ha->reset_count++;
                ips_ffdc_reset(ha, IPS_INTR_IORL);
        }
@@ -2392,7 +2389,6 @@ static int
 ips_hainit(ips_ha_t * ha)
 {
        int i;
-       struct timeval tv;
 
        METHOD_TRACE("ips_hainit", 1);
 
@@ -2407,8 +2403,7 @@ ips_hainit(ips_ha_t * ha)
 
        /* Send FFDC */
        ha->reset_count = 1;
-       do_gettimeofday(&tv);
-       ha->last_ffdc = tv.tv_sec;
+       ha->last_ffdc = ktime_get_real_seconds();
        ips_ffdc_reset(ha, IPS_INTR_IORL);
 
        if (!ips_read_config(ha, IPS_INTR_IORL)) {
@@ -2548,12 +2543,9 @@ ips_next(ips_ha_t * ha, int intr)
 
        if ((ha->subsys->param[3] & 0x300000)
            && (ha->scb_activelist.count == 0)) {
-               struct timeval tv;
-
-               do_gettimeofday(&tv);
-
-               if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) {
-                       ha->last_ffdc = tv.tv_sec;
+               time64_t now = ktime_get_real_seconds();
+               if (now - ha->last_ffdc > IPS_SECS_8HOURS) {
+                       ha->last_ffdc = now;
                        ips_ffdc_time(ha);
                }
        }
@@ -5988,59 +5980,21 @@ ips_ffdc_time(ips_ha_t * ha)
 /*                                                                          */
 /****************************************************************************/
 static void
-ips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time_t current_time)
+ips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time64_t current_time)
 {
-       long days;
-       long rem;
-       int i;
-       int year;
-       int yleap;
-       int year_lengths[2] = { IPS_DAYS_NORMAL_YEAR, IPS_DAYS_LEAP_YEAR };
-       int month_lengths[12][2] = { {31, 31},
-       {28, 29},
-       {31, 31},
-       {30, 30},
-       {31, 31},
-       {30, 30},
-       {31, 31},
-       {31, 31},
-       {30, 30},
-       {31, 31},
-       {30, 30},
-       {31, 31}
-       };
+       struct tm tm;
 
        METHOD_TRACE("ips_fix_ffdc_time", 1);
 
-       days = current_time / IPS_SECS_DAY;
-       rem = current_time % IPS_SECS_DAY;
-
-       scb->cmd.ffdc.hour = (rem / IPS_SECS_HOUR);
-       rem = rem % IPS_SECS_HOUR;
-       scb->cmd.ffdc.minute = (rem / IPS_SECS_MIN);
-       scb->cmd.ffdc.second = (rem % IPS_SECS_MIN);
-
-       year = IPS_EPOCH_YEAR;
-       while (days < 0 || days >= year_lengths[yleap = IPS_IS_LEAP_YEAR(year)]) {
-               int newy;
-
-               newy = year + (days / IPS_DAYS_NORMAL_YEAR);
-               if (days < 0)
-                       --newy;
-               days -= (newy - year) * IPS_DAYS_NORMAL_YEAR +
-                   IPS_NUM_LEAP_YEARS_THROUGH(newy - 1) -
-                   IPS_NUM_LEAP_YEARS_THROUGH(year - 1);
-               year = newy;
-       }
-
-       scb->cmd.ffdc.yearH = year / 100;
-       scb->cmd.ffdc.yearL = year % 100;
-
-       for (i = 0; days >= month_lengths[i][yleap]; ++i)
-               days -= month_lengths[i][yleap];
+       time64_to_tm(current_time, 0, &tm);
 
-       scb->cmd.ffdc.month = i + 1;
-       scb->cmd.ffdc.day = days + 1;
+       scb->cmd.ffdc.hour   = tm.tm_hour;
+       scb->cmd.ffdc.minute = tm.tm_min;
+       scb->cmd.ffdc.second = tm.tm_sec;
+       scb->cmd.ffdc.yearH  = (tm.tm_year + 1900) / 100;
+       scb->cmd.ffdc.yearL  = tm.tm_year % 100;
+       scb->cmd.ffdc.month  = tm.tm_mon + 1;
+       scb->cmd.ffdc.day    = tm.tm_mday;
 }
 
 /****************************************************************************
index 366be3b..db54617 100644 (file)
    #define IPS_BIOS_HEADER             0xC0
 
    /* time oriented stuff */
-   #define IPS_IS_LEAP_YEAR(y)           (((y % 4 == 0) && ((y % 100 != 0) || (y % 400 == 0))) ? 1 : 0)
-   #define IPS_NUM_LEAP_YEARS_THROUGH(y) ((y) / 4 - (y) / 100 + (y) / 400)
-
-   #define IPS_SECS_MIN                 60
-   #define IPS_SECS_HOUR                3600
    #define IPS_SECS_8HOURS              28800
-   #define IPS_SECS_DAY                 86400
-   #define IPS_DAYS_NORMAL_YEAR         365
-   #define IPS_DAYS_LEAP_YEAR           366
-   #define IPS_EPOCH_YEAR               1970
 
    /*
     * Scsi_Host Template
@@ -1054,7 +1045,7 @@ typedef struct ips_ha {
    uint8_t            active;
    int                ioctl_reset;        /* IOCTL Requested Reset Flag */
    uint16_t           reset_count;        /* number of resets           */
-   time_t             last_ffdc;          /* last time we sent ffdc info*/
+   time64_t           last_ffdc;          /* last time we sent ffdc info*/
    uint8_t            slot_num;           /* PCI Slot Number            */
    int                ioctl_len;          /* size of ioctl buffer       */
    dma_addr_t         ioctl_busaddr;      /* dma address of ioctl buffer*/