Sync 3ware time at boot to system rtc diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index cd4129f..28952c6 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -462,6 +464,93 @@ out: return retval; } /* End twa_aen_severity_lookup() */ +static void twa_time(u8 *buf) +{ + struct timeval utc; + u64 local_time; + struct rtc_time tm; + u16 year; + + do_gettimeofday(&utc); + local_time = (u64)(utc.tv_sec - (sys_tz.tz_minuteswest * 60)); + + rtc_time64_to_tm(local_time, &tm); + + + buf[0] = 0x00; /* Unknown always reads 0 */ + buf[1] = tm.tm_sec; + buf[2] = tm.tm_min; + buf[3] = tm.tm_hour; + + buf[4] = tm.tm_mday; + buf[5] = tm.tm_mon + 1; + + year = cpu_to_le16(tm.tm_year + 1900); + memcpy(&buf[6], &year, sizeof(year)); +} + +static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes); + + +static void twa_print_date_time(TW_Device_Extension *tw_dev, int request_id) +{ + u8 *buf=twa_get_param(tw_dev,1,TW_TIMEKEEP_TABLE,0x4,0x8); + u16 year; + + if (!buf) { + printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: Can't read controller date and time\n", + tw_dev->host->host_no); + return; + } + + memcpy(&year, &buf[6], sizeof(year)); + + year = le16_to_cpu(year); + + printk(KERN_WARNING "3w-9xxx: scsi%d: controller time %02d-%02d-%04d %02d:%02d:%02d\n", + tw_dev->host->host_no, + (int) buf[4], + (int) buf[5], + (int) year, + (int) buf[3], + (int) buf[2], + (int) buf[1]); +} + +/* This function will sync firmware time with the host time */ +static void twa_aen_sync_date_time(TW_Device_Extension *tw_dev, int request_id) +{ + TW_Command_Full *full_command_packet; + TW_Command *command_packet; + TW_Param_Apache *param; + /* Fill out the command packet */ + full_command_packet = tw_dev->command_packet_virt[request_id]; + memset(full_command_packet, 0, sizeof(TW_Command_Full)); + command_packet = &full_command_packet->command.oldcommand; + command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM); + command_packet->request_id = request_id; + command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); + command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE); + command_packet->size = TW_COMMAND_SIZE; + command_packet->byte6_offset.parameter_count = cpu_to_le16(1); + + /* Setup the param */ + param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; + memset(param, 0, TW_SECTOR_SIZE); + param->table_id = cpu_to_le16(TW_TIMEKEEP_TABLE | 0x8000); /* Controller time keep table */ + param->parameter_id = cpu_to_le16(0x4); /* SchedulerTime */ + param->parameter_size_bytes = cpu_to_le16(8); + + twa_time(param->data); + + /* Mark internal command */ + tw_dev->srb[request_id] = NULL; + + /* Now post the command */ + twa_post_command_packet(tw_dev, request_id, 1); +} /* End twa_aen_sync_date_time() */ + + /* This function will sync firmware time with the host time */ static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id) { @@ -2121,6 +2210,21 @@ static int twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH))); + twa_print_date_time(tw_dev, 0); + + /* Set clock */ + twa_aen_sync_date_time(tw_dev, 0); + + /* Poll for completion */ + if (twa_poll_response(tw_dev, 0, 30)) + printk(KERN_WARNING "3w-9xxx: scsi%d: no response to set time\n", + host->host_no); + else + printk(KERN_WARNING "3w-9xxx: scsi%d: setting clock\n", + host->host_no); + + twa_print_date_time(tw_dev, 0); + /* Try to enable MSI */ if (use_msi && (pdev->device != PCI_DEVICE_ID_3WARE_9000) && !pci_enable_msi(pdev))