aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroot <root@lamia.panaceas.james.local>2017-01-16 12:16:27 +0000
committerroot <root@lamia.panaceas.james.local>2017-01-16 12:16:27 +0000
commit4477c392b87bdaaae6780ccadc9a4f4923f2b344 (patch)
treedaef2ccf9b2b1cc8c79e7bd46b379a24f06ce515
parent8ee35c49abfcc5118b085fe63994b533944b4595 (diff)
downloadtwa_t-4477c392b87bdaaae6780ccadc9a4f4923f2b344.tar.gz
twa_t-4477c392b87bdaaae6780ccadc9a4f4923f2b344.tar.bz2
twa_t-4477c392b87bdaaae6780ccadc9a4f4923f2b344.zip
add source
-rw-r--r--src/Makefile.am53
-rw-r--r--src/hexdump.c87
-rw-r--r--src/project.h76
-rw-r--r--src/prototypes.h12
-rw-r--r--src/twa.c157
-rw-r--r--src/twa.h169
-rw-r--r--src/twa_t.c162
-rw-r--r--src/util.c23
-rw-r--r--src/version.c15
9 files changed, 754 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..85bb6b0
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,53 @@
+#
+#
+# Makefile.am:
+#
+# Copyright (c) 2017 James McKenzie <foss@madingley.org>,
+# All rights reserved.
+#
+#
+#
+
+CPROTO=cproto
+AM_CPPFLAGS =
+
+noinst_HEADERS=project.h prototypes.h
+
+bin_PROGRAMS = twa_t
+
+SRCS=twa_t.c twa.c version.c util.c hexdump.c
+twa_t_SOURCES = ${SRCS}
+twa_t_LDADD =
+
+AM_CFLAGS=-g
+
+twa_t_LDFLAGS =
+
+BUILT_SOURCES = version.h
+
+
+VFD=${srcdir}/..
+VF=${shell cat ${VFD}/version-files}
+VFS=${VF:%=${VFD}/%}
+VCHK=${shell cat ${VFS} | @MD5SUM@ | @AWK@ '{print $$1 }' }
+VNUM=${shell @GREP@ ${VCHK} ${VFD}/version-md5sums | @AWK@ '{ print $$2 }' }
+VDEF=${shell echo `cat ${VFD}/version-major`.`cat ${VFD}/version-minor`.`cat ${VFD}/version-micro` }
+
+protos:
+ echo > prototypes.h
+ ${CPROTO} -v ${INCLUDES} ${SRCS} > prototypes.tmp
+ mv -f prototypes.tmp prototypes.h
+
+
+
+version.h: $(VFD)/version-files $(VFD)/version-major \
+ $(VFD)/version-minor $(VFD)/version-micro \
+ $(VFD)/version-md5sums ${VFS} Makefile
+ if [ .${VNUM} = . ]; then \
+ echo "#define VERSION \"twa_t Version ${VDEF} + Edits\"" > version.h; \
+ echo ${VDEF}-E > version-num; \
+ else \
+ echo "#define VERSION \"twa_t Version ${VNUM}\"" > version.h; \
+ echo ${VNUM} > version-num; \
+ fi
+
diff --git a/src/hexdump.c b/src/hexdump.c
new file mode 100644
index 0000000..1d51d99
--- /dev/null
+++ b/src/hexdump.c
@@ -0,0 +1,87 @@
+/*
+ * hexdump.c:
+ *
+ * Copyright (c) 2017 James McKenzie <foss@madingley.org>,
+ * All rights reserved.
+ *
+ */
+
+#include "project.h"
+
+
+static unsigned char
+printable (unsigned char c)
+{
+
+ if (c < ' ')
+ c = '.';
+ if (c > 126)
+ c = '.';
+
+ return c;
+}
+
+
+
+void
+hexdump (char *prefix, void *_d, size_t os, size_t oe)
+{
+ unsigned char *d = (unsigned char *) _d;
+ static unsigned char zero[0x10];
+
+ size_t s, e;
+ size_t i, j;
+ int gap = 0;
+
+ s = os & ~15;
+ e = (oe - 1) | 15;
+ e++;
+
+ for (i = s; i < e; i += 0x10)
+ {
+
+ if (((i > s) && ((i + 0x10) < oe)) && !memcmp (&d[i], zero, 0x10))
+ {
+ gap = 1;
+ continue;
+ }
+ if (gap)
+ {
+ printf ("%s ...\n", prefix);
+ gap = 0;
+ }
+
+
+ printf ("%s %06lx:", prefix, i);
+
+ for (j = i; j < (i + 0x10); ++j)
+ {
+
+ if (j == 8)
+ printf (" ");
+
+ if ((j < os) || (j >= oe))
+ printf (" ");
+ else
+ printf (" %02x", d[j]);
+ }
+
+ printf (" ");
+
+ for (j = i; j < (i + 0x10); ++j)
+ {
+
+ if (j == 8)
+ printf (" ");
+
+ if ((j < os) || (j >= oe))
+ printf (" ");
+ else
+ printf ("%c", printable (d[j]));
+ }
+
+
+
+ printf ("\n");
+ }
+}
diff --git a/src/project.h b/src/project.h
new file mode 100644
index 0000000..9126217
--- /dev/null
+++ b/src/project.h
@@ -0,0 +1,76 @@
+/*
+ * project.h:
+ *
+ * Copyright (c) 2017 James McKenzie <foss@madingley.org>,
+ * All rights reserved.
+ *
+ */
+
+#ifndef __PROJECT_H__
+#define __PROJECT_H__
+
+
+#include "config.h"
+
+#ifdef TM_IN_SYS_TIME
+#include <sys/time.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+#else
+#ifdef TIME_WITH_SYS_TIME
+#include <sys/time.h>
+#endif
+#include <time.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if defined(HAVE_STDINT_H)
+#include <stdint.h>
+#elif defined(HAVE_SYS_INT_TYPES_H)
+#include <sys/int_types.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/sg.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+
+#include <endian.h>
+
+#define cpu_to_le32(a) htole32(a)
+#define cpu_to_le16(a) htole16(a)
+#define le16_to_cpu(a) le16toh(a)
+#define le32_to_cpu(a) le32toh(a)
+
+#include "twa.h"
+
+
+#include "prototypes.h"
+
+#endif /* __PROJECT_H__ */
diff --git a/src/prototypes.h b/src/prototypes.h
new file mode 100644
index 0000000..2a749a2
--- /dev/null
+++ b/src/prototypes.h
@@ -0,0 +1,12 @@
+/* hexdump.c */
+void hexdump(char *prefix, void *_d, size_t os, size_t oe);
+/* twa.c */
+ssize_t twa_get_parameter(int fd, int table_id, int parameter_id, void *data, size_t data_len);
+int twa_set_parameter(int fd, int table_id, int parameter_id, void *data, size_t data_len);
+/* twa_t.c */
+void tw_dt_to_tm(TW_DateTime *tw_dt, struct tm *tm);
+void tm_to_tw_dt(struct tm *tm, TW_DateTime *tw_dt);
+int main(int argc, char *argv[]);
+/* util.c */
+void *xmalloc(size_t s);
+/* version.c */
diff --git a/src/twa.c b/src/twa.c
new file mode 100644
index 0000000..9cd89b2
--- /dev/null
+++ b/src/twa.c
@@ -0,0 +1,157 @@
+/*
+ * twa.c:
+ *
+ * Copyright (c) 2017 James McKenzie <foss@madingley.org>,
+ * All rights reserved.
+ *
+ */
+
+#include "project.h"
+
+ssize_t
+twa_get_parameter (int fd, int table_id, int parameter_id, void *data,
+ size_t data_len)
+{
+
+ TW_Command *command;
+ TW_Param_Apache *param;
+ TW_Command_Apache_Header *header;
+ TW_Ioctl_Buf_Apache *tw_ioctl_apache;
+ int rc;
+ size_t buffer_len, ret_len;
+ char error[512];
+
+ buffer_len = data_len + sizeof (TW_Param_Apache);
+
+ tw_ioctl_apache = xmalloc (sizeof (TW_Ioctl_Buf_Apache) + buffer_len);
+
+ memset (tw_ioctl_apache, 0, sizeof (TW_Ioctl_Buf_Apache) + buffer_len);
+
+ tw_ioctl_apache->driver_command.control_code =
+ TW_IOCTL_FIRMWARE_PASS_THROUGH;
+ tw_ioctl_apache->driver_command.buffer_length = buffer_len;
+
+ header =
+ (TW_Command_Apache_Header *) & (tw_ioctl_apache->firmware_command.header);
+ header->header_desc.size_header = sizeof (*header);
+
+ command =
+ (TW_Command *) & (tw_ioctl_apache->firmware_command.command.oldcommand);
+
+ command->byte0.opcode = TW_OP_GET_PARAM;
+ command->byte0.sgl_offset = 0x2;
+
+ command->size = TW_COMMAND_SIZE;
+
+ command->byte6.parameter_count = cpu_to_le16 (1);
+
+ param = (TW_Param_Apache *) tw_ioctl_apache->data_buffer;
+
+ param->table_id = cpu_to_le16 (table_id | 0x8000);
+ param->parameter_id = cpu_to_le16 (parameter_id);
+ param->parameter_size_bytes = cpu_to_le16 (data_len);
+
+ rc = ioctl (fd, TW_IOCTL_FIRMWARE_PASS_THROUGH, tw_ioctl_apache);
+
+ if (rc)
+ {
+ fprintf (stderr,
+ "twa_get_parameter: ioctl TW_IOCTL_FIRMWARE_PASS_THROUGH failed: %m\n");
+ return -1;
+ }
+
+ if (header->status_block.error)
+ {
+ memset (error, 0, sizeof (error));
+ memcpy (error, header->err_specific_desc,
+ sizeof (header->err_specific_desc));
+
+ fprintf (stderr,
+ "twa_get_parameter: controller returns error: (0x%x) %s\n",
+ le16_to_cpu (header->status_block.error), error + 1);
+ return -1;
+ }
+
+ ret_len = le16_to_cpu (param->actual_parameter_size_bytes);
+
+ if (ret_len > data_len)
+ {
+ fprintf (stderr,
+ "twa_get_parameter: buffer passed for table 0x%x, parameter 0x%x too short: given %d bytes need %d\n",
+ table_id, parameter_id, data_len, ret_len);
+ return -1;
+ }
+
+ memcpy (data, param->data, ret_len);
+
+ return ret_len;
+}
+
+int
+twa_set_parameter (int fd, int table_id, int parameter_id, void *data,
+ size_t data_len)
+{
+
+ TW_Command *command;
+ TW_Param_Apache *param;
+ TW_Command_Apache_Header *header;
+ TW_Ioctl_Buf_Apache *tw_ioctl_apache;
+ int rc;
+ size_t buffer_len, ret_len;
+ char error[512];
+
+ buffer_len = data_len + sizeof (TW_Param_Apache);
+
+ tw_ioctl_apache = xmalloc (sizeof (TW_Ioctl_Buf_Apache) + buffer_len);
+
+ memset (tw_ioctl_apache, 0, sizeof (TW_Ioctl_Buf_Apache) + buffer_len);
+
+ tw_ioctl_apache->driver_command.control_code =
+ TW_IOCTL_FIRMWARE_PASS_THROUGH;
+ tw_ioctl_apache->driver_command.buffer_length = buffer_len;
+
+ header =
+ (TW_Command_Apache_Header *) & (tw_ioctl_apache->firmware_command.header);
+ header->header_desc.size_header = sizeof (*header);
+
+ command =
+ (TW_Command *) & (tw_ioctl_apache->firmware_command.command.oldcommand);
+
+ command->byte0.opcode = TW_OP_SET_PARAM;
+ command->byte0.sgl_offset = 0x2;
+
+ command->size = TW_COMMAND_SIZE;
+
+ command->byte6.parameter_count = cpu_to_le16 (1);
+
+ param = (TW_Param_Apache *) tw_ioctl_apache->data_buffer;
+
+ param->table_id = cpu_to_le16 (table_id | 0x8000);
+ param->parameter_id = cpu_to_le16 (parameter_id);
+ param->parameter_size_bytes = cpu_to_le16 (data_len);
+
+ memcpy (param->data, data, data_len);
+
+ rc = ioctl (fd, TW_IOCTL_FIRMWARE_PASS_THROUGH, tw_ioctl_apache);
+
+ if (rc)
+ {
+ fprintf (stderr,
+ "twa_get_parameter: ioctl TW_IOCTL_FIRMWARE_PASS_THROUGH failed: %m\n");
+ return -1;
+ }
+
+ if (header->status_block.error)
+ {
+ memset (error, 0, sizeof (error));
+ memcpy (error, header->err_specific_desc,
+ sizeof (header->err_specific_desc));
+
+ fprintf (stderr,
+ "twa_get_parameter: controller returns error: (0x%x) %s\n",
+ le16_to_cpu (header->status_block.error), error + 1);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/twa.h b/src/twa.h
new file mode 100644
index 0000000..413e70b
--- /dev/null
+++ b/src/twa.h
@@ -0,0 +1,169 @@
+/*
+ * twa.h:
+ *
+ * Copyright (c) 2017 James McKenzie <foss@madingley.org>,
+ * All rights reserved.
+ *
+ */
+
+#ifndef _TWA_H_
+#define _TWA_H_
+
+#define TWA_PACKED __attribute__ (( packed ))
+
+typedef uint64_t dma_addr_t;
+
+
+#define TW_SENSE_DATA_LENGTH 18
+
+#define TW_COMMAND_SIZE (sizeof(dma_addr_t) > 4 ? 5 : 4)
+#define TW_APACHE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 72 : 109)
+#define TW_ESCALADE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 41 : 62)
+#define TW_PADDING_LENGTH (sizeof(dma_addr_t) > 4 ? 8 : 0)
+
+typedef struct TWA_PACKED TAG_TW_SG_Entry
+{
+ dma_addr_t address;
+ uint32_t length;
+} TW_SG_Entry;
+
+
+typedef struct TWA_PACKED TAG_TW_Command_Apache_Header
+{
+ unsigned char sense_data[TW_SENSE_DATA_LENGTH];
+ struct TWA_PACKED
+ {
+ char reserved[4];
+ unsigned short error;
+ unsigned char padding;
+ unsigned char severity__reserved;
+ } status_block;
+ unsigned char err_specific_desc[98];
+ struct TWA_PACKED
+ {
+ unsigned char size_header;
+ unsigned short reserved;
+ unsigned char size_sense;
+ } header_desc;
+} TW_Command_Apache_Header;
+
+
+/* Command Packet */
+typedef struct TWA_PACKED TW_Command
+{
+ /* First DWORD */
+ struct TWA_PACKED
+ {
+ unsigned char opcode:5;
+ unsigned char sgl_offset:3;
+ } byte0;
+ unsigned char size;
+ unsigned char request_id;
+ struct TWA_PACKED
+ {
+ unsigned char unit:4;
+ unsigned char host_id:4;
+ } byte3;
+ /* Second DWORD */
+ unsigned char status;
+ unsigned char flags;
+
+ union
+ {
+ unsigned short block_count;
+ unsigned short parameter_count;
+ unsigned short message_credits;
+ } byte6;
+ union
+ {
+ struct TWA_PACKED
+ {
+ uint32_t lba;
+ TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
+ dma_addr_t padding;
+ } io;
+ struct
+ {
+ TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
+ uint32_t padding;
+ dma_addr_t padding2;
+ } param;
+ } byte8_offset;
+} TW_Command;
+
+typedef struct TWA_PACKED TAG_TW_Command_Apache
+{
+ unsigned char opcode__reserved;
+ unsigned char unit;
+ unsigned short request_id__lunl;
+ unsigned char status;
+ unsigned char sgl_offset;
+ unsigned short sgl_entries__lunh;
+ unsigned char cdb[16];
+ TW_SG_Entry sg_list[TW_APACHE_MAX_SGL_LENGTH];
+ unsigned char padding[TW_PADDING_LENGTH];
+} TW_Command_Apache;
+
+
+typedef struct TWA_PACKED TAG_TW_Command_Full
+{
+ TW_Command_Apache_Header header;
+ union
+ {
+ TW_Command oldcommand;
+ TW_Command_Apache newcommand;
+ } command;
+} TW_Command_Full;
+
+
+
+typedef struct TWA_PACKED TAG_TW_Ioctl_Driver_Command
+{
+ unsigned int control_code;
+ unsigned int status;
+ unsigned int unique_id;
+ unsigned int sequence_id;
+ unsigned int os_specific;
+ unsigned int buffer_length;
+} TW_Ioctl_Driver_Command;
+
+
+
+typedef struct TWA_PACKED TAG_TW_Ioctl_Apache
+{
+ TW_Ioctl_Driver_Command driver_command;
+ char padding[488];
+ TW_Command_Full firmware_command;
+ char data_buffer[0];
+} TW_Ioctl_Buf_Apache;
+
+typedef struct TWA_PACKED
+{
+ unsigned short table_id;
+ unsigned short parameter_id;
+ unsigned short parameter_size_bytes;
+ unsigned short actual_parameter_size_bytes;
+ unsigned char data[0];
+} TW_Param_Apache, *PTW_Param_Apache;
+
+typedef struct
+{
+ uint8_t resv;
+ uint8_t tw_sec;
+ uint8_t tw_min;
+ uint8_t tw_hour;
+ uint8_t tw_day;
+ uint8_t tw_month;
+ uint16_t tw_year;
+} TW_DateTime;
+
+#define TW_IOCTL_FIRMWARE_PASS_THROUGH 0x108
+
+#define TW_OP_GET_PARAM 0x12
+#define TW_OP_SET_PARAM 0x13
+
+#define TW_TIMEKEEP_TABLE 0x040A
+#define TW_TIMEKEEP_DATETIME 0x4
+
+
+#endif /* _TWA_H_ */
diff --git a/src/twa_t.c b/src/twa_t.c
new file mode 100644
index 0000000..cfebb96
--- /dev/null
+++ b/src/twa_t.c
@@ -0,0 +1,162 @@
+/*
+ * twa_t.c:
+ *
+ * Copyright (c) 2017 James McKenzie <foss@madingley.org>,
+ * All rights reserved.
+ *
+ */
+
+#include "project.h"
+
+void
+tw_dt_to_tm (TW_DateTime * tw_dt, struct tm *tm)
+{
+ memset (tm, 0, sizeof (*tm));
+
+ tm->tm_sec = tw_dt->tw_sec;
+ tm->tm_min = tw_dt->tw_min;
+ tm->tm_hour = tw_dt->tw_hour;
+ tm->tm_mday = tw_dt->tw_day;
+ tm->tm_mon = tw_dt->tw_month - 1;
+ tm->tm_year = tw_dt->tw_year - 1900;
+}
+
+
+
+void
+tm_to_tw_dt (struct tm *tm, TW_DateTime * tw_dt)
+{
+ memset (tw_dt, 0, sizeof (*tw_dt));
+
+ tw_dt->tw_sec = tm->tm_sec;
+ tw_dt->tw_min = tm->tm_min;
+ tw_dt->tw_hour = tm->tm_hour;
+ tw_dt->tw_day = tm->tm_mday;
+ tw_dt->tw_month = tm->tm_mon + 1;
+ tw_dt->tw_year = tm->tm_year + 1900;
+}
+
+
+static int
+show_ctrl_time (int fd)
+{
+ TW_DateTime dt;
+ ssize_t ret;
+ struct tm tm;
+
+
+ ret =
+ twa_get_parameter (fd, TW_TIMEKEEP_TABLE, TW_TIMEKEEP_DATETIME, &dt,
+ sizeof (dt));
+
+ if (ret != sizeof (dt))
+ {
+ fprintf (stderr, "Failed to get controller time\n");
+ return -1;
+ }
+
+ tw_dt_to_tm (&dt, &tm);
+
+ printf ("Controller time is: %s", asctime (&tm));
+
+ return 0;
+}
+
+
+
+static int
+set_ctrl_time (int fd)
+{
+ TW_DateTime dt;
+ int ret;
+ struct tm tm;
+ time_t t;
+
+
+ time (&t);
+
+ localtime_r (&t, &tm);
+
+ tm_to_tw_dt (&tm, &dt);
+
+ ret =
+ twa_set_parameter (fd, TW_TIMEKEEP_TABLE, TW_TIMEKEEP_DATETIME, &dt,
+ sizeof (dt));
+
+ if (ret)
+ {
+ fprintf (stderr, "Failed to set controller time\n");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int
+check_ctrl_time (int fd)
+{
+ TW_DateTime dt;
+ ssize_t ret;
+ struct tm tm;
+ time_t ctrl_time, local_time;
+ double d;
+ int rc = 0;
+
+ ret =
+ twa_get_parameter (fd, TW_TIMEKEEP_TABLE, TW_TIMEKEEP_DATETIME, &dt,
+ sizeof (dt));
+
+ if (ret != sizeof (dt))
+ {
+ fprintf (stderr, "Failed to get controller time\n");
+ rc |= -1;
+ return rc;
+ }
+
+ tw_dt_to_tm (&dt, &tm);
+
+ printf ("Controller time is: %s", asctime (&tm));
+
+ ctrl_time = mktime (&tm);
+
+ time (&local_time);
+ localtime_r (&local_time, &tm);
+ local_time = mktime (&tm);
+
+ d = difftime (local_time, ctrl_time);
+
+ printf ("Controller time difference is %.1lf seconds\n", d);
+
+ if ((d > 15.0) || (d < -15.0))
+ {
+ printf ("Setting controller time\n");
+ rc |= set_ctrl_time (fd);
+ rc |= show_ctrl_time (fd);
+ }
+
+ return rc;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ char *dev = "/dev/twa0";
+ int fd;
+ int ret = 0;
+
+ if (argc == 2)
+ dev = argv[1];
+
+ fd = open (dev, O_RDWR);
+
+ if (fd < 0)
+ {
+ fprintf (stderr, "Failed to open %s: %m\n", dev);
+ ret |= -1;
+ return ret;
+ }
+
+
+ return check_ctrl_time (fd);
+}
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..022e04b
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,23 @@
+/*
+ * util.c:
+ *
+ * Copyright (c) 2017 James McKenzie <foss@madingley.org>,
+ * All rights reserved.
+ *
+ */
+
+#include "project.h"
+
+void *
+xmalloc (size_t s)
+{
+ void *ret = malloc (s);
+
+ if (!ret)
+ {
+ fprintf (stderr, "malloc(%lu) failed - aborting\n", s);
+ exit (1);
+ }
+
+ return ret;
+}
diff --git a/src/version.c b/src/version.c
new file mode 100644
index 0000000..e13290c
--- /dev/null
+++ b/src/version.c
@@ -0,0 +1,15 @@
+/*
+ * version.c:
+ *
+ * Copyright (c) 2017 James McKenzie <foss@madingley.org>,
+ * All rights reserved.
+ *
+ */
+
+#include "version.h"
+
+static char *
+GetVersion (void)
+{
+ return VERSION;
+}