summaryrefslogtreecommitdiffstats
path: root/sys/dev/ips/ips_commands.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ips/ips_commands.c')
-rw-r--r--sys/dev/ips/ips_commands.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/sys/dev/ips/ips_commands.c b/sys/dev/ips/ips_commands.c
index 67f1655..cb0dd76 100644
--- a/sys/dev/ips/ips_commands.c
+++ b/sys/dev/ips/ips_commands.c
@@ -434,6 +434,93 @@ int ips_flush_cache(ips_softc_t *sc)
return 0;
}
+/* Simplified localtime to provide timevalues for ffdc.
+ * Taken from libc/stdtime/localtime.c
+ */
+void static ips_ffdc_settime(ips_adapter_ffdc_cmd *command, time_t sctime)
+{
+ long days, rem, y;
+ int yleap, *ip, month;
+ int year_lengths[2] = { IPS_DAYSPERNYEAR, IPS_DAYSPERLYEAR };
+ int mon_lengths[2][IPS_MONSPERYEAR] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+ };
+
+ days = sctime / IPS_SECSPERDAY;
+ rem = sctime % IPS_SECSPERDAY;
+
+ command->hour = rem / IPS_SECSPERHOUR;
+ rem = rem % IPS_SECSPERHOUR;
+
+ command->minute = rem / IPS_SECSPERMIN;
+ command->second = rem % IPS_SECSPERMIN;
+
+ y = IPS_EPOCH_YEAR;
+ while (days < 0 || days >= (long) year_lengths[yleap = ips_isleap(y)]) {
+ long newy;
+
+ newy = y + days / IPS_DAYSPERNYEAR;
+ if (days < 0)
+ --newy;
+ days -= (newy - y) * IPS_DAYSPERNYEAR +
+ IPS_LEAPS_THRU_END_OF(newy - 1) -
+ IPS_LEAPS_THRU_END_OF(y - 1);
+ y = newy;
+ }
+ command->yearH = y / 100;
+ command->yearL = y % 100;
+ ip = mon_lengths[yleap];
+ for(month = 0; days >= (long) ip[month]; ++month)
+ days = days - (long) ip[month];
+ command->month = month + 1;
+ command->day = days + 1;
+}
+
+static int ips_send_ffdc_reset_cmd(ips_command_t *command)
+{
+ ips_softc_t *sc = command->sc;
+ ips_cmd_status_t *status = command->arg;
+ ips_adapter_ffdc_cmd *command_struct;
+
+ PRINTF(10,"ips test: got a command, building ffdc reset command\n");
+ command->callback = ips_wakeup_callback;
+ command_struct = (ips_adapter_ffdc_cmd *)command->command_buffer;
+ command_struct->command = IPS_FFDC_CMD;
+ command_struct->id = command->id;
+ command_struct->reset_count = sc->ffdc_resetcount;
+ command_struct->reset_type = 0x80;
+ ips_ffdc_settime(command_struct, sc->ffdc_resettime.tv_sec);
+
+ bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
+ BUS_DMASYNC_PREWRITE);
+ mtx_lock(&sc->cmd_mtx);
+ sc->ips_issue_cmd(command);
+ if (status->value != IPS_ERROR_STATUS)
+ msleep(status, &sc->cmd_mtx, 0, "ffdc", 0);
+ mtx_unlock(&sc->cmd_mtx);
+ ips_insert_free_cmd(sc, command);
+ return 0;
+}
+
+int ips_ffdc_reset(ips_softc_t *sc)
+{
+ ips_cmd_status_t *status;
+ status = malloc(sizeof(ips_cmd_status_t), M_DEVBUF, M_NOWAIT|M_ZERO);
+ if(!status)
+ return ENOMEM;
+ if(ips_get_free_cmd(sc, ips_send_ffdc_reset_cmd, status,
+ IPS_NOWAIT_FLAG)){
+ free(status, M_DEVBUF);
+ device_printf(sc->dev, "ERROR: unable to get a command! can't send ffdc reset!\n");
+ }
+ if(COMMAND_ERROR(status)){
+ device_printf(sc->dev, "ERROR: ffdc reset command failed!\n");
+ }
+ free(status, M_DEVBUF);
+ return 0;
+}
+
static void ips_write_nvram(ips_command_t *command){
ips_softc_t *sc = command->sc;
ips_rw_nvram_cmd *command_struct;
@@ -449,6 +536,9 @@ static void ips_write_nvram(ips_command_t *command){
bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
BUS_DMASYNC_POSTREAD);
nvram = command->data_buffer;
+ /* retrieve adapter info and save in sc */
+ sc->adapter_type = nvram->adapter_type;
+
strncpy(nvram->driver_high, IPS_VERSION_MAJOR, 4);
strncpy(nvram->driver_low, IPS_VERSION_MINOR, 4);
nvram->operating_system = IPS_OS_FREEBSD;
OpenPOWER on IntegriCloud