summaryrefslogtreecommitdiffstats
path: root/src/hddtemp_scsi
diff options
context:
space:
mode:
Diffstat (limited to 'src/hddtemp_scsi')
-rw-r--r--src/hddtemp_scsi/get_scsi_temp.c159
-rw-r--r--src/hddtemp_scsi/hddtemp.h91
-rw-r--r--src/hddtemp_scsi/scsi.c125
-rw-r--r--src/hddtemp_scsi/scsi.h24
-rw-r--r--src/hddtemp_scsi/scsicmds.c221
-rw-r--r--src/hddtemp_scsi/scsicmds.h36
6 files changed, 656 insertions, 0 deletions
diff --git a/src/hddtemp_scsi/get_scsi_temp.c b/src/hddtemp_scsi/get_scsi_temp.c
new file mode 100644
index 0000000..e36d357
--- /dev/null
+++ b/src/hddtemp_scsi/get_scsi_temp.c
@@ -0,0 +1,159 @@
+/*
+ * get_scsi_temp.c: functions that populate the drive temperature variables
+ * in SCSI/SAS drives context structure.
+ * Routines from hddtemp are used here.
+ *
+ * Author: Gerold Gruber <Gerold.Gruber@edv2g.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+//#define _LARGEFILE64_SOURCE
+//#define _FILE_OFFSET_BITS 64
+#define _BSD_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <dirent.h>
+#include <assert.h>
+
+#include "nwipe.h"
+#include "context.h"
+#include "method.h"
+#include "device.h"
+#include "prng.h"
+#include "options.h"
+#include "device.h"
+#include "logging.h"
+#include "temperature.h"
+#include "miscellaneous.h"
+#include "hddtemp.h"
+#include "scsi.h"
+
+int scsi_get_temperature( struct disk * );
+
+int nwipe_init_scsi_temperature( nwipe_context_t* c )
+{
+
+/* dsk anlegen, malloc */
+ struct disk *dsk = (struct disk *) malloc(sizeof(struct disk));
+
+ /* Check the allocation. */
+ if( !dsk )
+ {
+ nwipe_perror( errno, __FUNCTION__, "malloc" );
+ nwipe_log( NWIPE_LOG_FATAL, "Unable to get memory for disk struct for %s",
+ c->device_name );
+ exit( 1 ) ;
+ }
+
+ assert(dsk);
+
+ memset(dsk, 0, sizeof(*dsk));
+
+ /* save the dsk pointer for later use */
+ c->templ_disk = dsk;
+
+ /* initialize */
+ dsk->drive = c->device_name;
+ dsk->type = BUS_SCSI; /* we know this as we are only called in this case */
+
+ errno = 0;
+ dsk->errormsg[0] = '\0';
+ if( (dsk->fd = open(dsk->drive, O_RDONLY | O_NONBLOCK)) < 0) {
+ snprintf(dsk->errormsg, MAX_ERRORMSG_SIZE, "open: %s\n", strerror(errno));
+ dsk->type = ERROR;
+ return 1;
+ }
+
+ // sg_logs -t <device>
+ if( scsi_get_temperature( dsk ) == GETTEMP_SUCCESS )
+ {
+ c->temp1_input = dsk->value;
+ c->temp1_crit = dsk->refvalue;
+ c->temp1_lcrit = -40; /* just to give it a value with some kind of sense */
+ c->temp1_highest = dsk->value;
+ c->temp1_lowest = dsk->value;
+ c->temp1_max = dsk->refvalue - 5; /* seems to be kind of useful */
+ }
+ else
+ {
+ nwipe_log( NWIPE_LOG_ERROR, "Can not read SCSI temperature for %s, %s",
+ dsk->drive, dsk->errormsg );
+ close( dsk->fd );
+ free( dsk );
+ c->templ_disk = NULL;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+int nwipe_get_scsi_temperature( nwipe_context_t* c )
+{
+ struct disk *dsk;
+
+ dsk = c->templ_disk;
+
+ if( c->templ_disk != NULL && c->templ_disk->fd != -1 )
+ {
+ if( scsi_get_temperature( dsk ) == GETTEMP_SUCCESS )
+ {
+ c->temp1_input = dsk->value;
+
+/* not at all of interest */
+ if( c->temp1_input > c->temp1_highest )
+ {
+ c->temp1_highest = c->temp1_input;
+ }
+ if( c->temp1_input < c->temp1_lowest )
+ {
+ c->temp1_lowest = c->temp1_input;
+ }
+
+/* end not at all of interest ;-) */
+
+ }
+ else
+ {
+ nwipe_log( NWIPE_LOG_ERROR, "Could not read SCSI temperature for %s, %s",
+ dsk->drive, dsk->errormsg );
+ return 2;
+ }
+ }
+ else
+ {
+ nwipe_log( NWIPE_LOG_INFO, "no SCSI temperature reading for %s", dsk->drive );
+ return 1;
+ }
+ return 0;
+}
+
+void nwipe_shut_scsi_temperature( nwipe_context_t* c )
+{
+ if( c->templ_disk->fd != -1 )
+ {
+ close( c->templ_disk->fd );
+ }
+ if( c->templ_disk != NULL )
+ {
+ free( c->templ_disk );
+ }
+
+ return;
+}
diff --git a/src/hddtemp_scsi/hddtemp.h b/src/hddtemp_scsi/hddtemp.h
new file mode 100644
index 0000000..6565991
--- /dev/null
+++ b/src/hddtemp_scsi/hddtemp.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2002 Emmanuel VARAGNAT <hddtemp@guzu.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __HDDTEMP_H__
+#define __HDDTEMP_H__
+
+#include <time.h>
+// #include "db.h"
+
+//#ifdef ARCH_I386
+//typedef unsigned short u16;
+//#endif
+#include <linux/types.h>
+typedef __u16 u16;
+
+#define MAX_ERRORMSG_SIZE 128
+#define DEFAULT_ATTRIBUTE_ID 194
+
+#define F_to_C(val) (int)(((double)(val)-32.0)/1.8)
+#define C_to_F(val) (int)(((double)(val)*(double)1.8) + (double)32.0)
+
+enum e_bustype { ERROR = 0, BUS_UNKNOWN, BUS_SATA, BUS_ATA, BUS_SCSI, BUS_TYPE_MAX };
+
+#define GETTEMP_SUCCESS 0
+#define GETTEMP_ERROR 1
+#define GETTEMP_NOT_APPLICABLE 2
+#define GETTEMP_UNKNOWN 3
+#define GETTEMP_GUESS 4
+#define GETTEMP_KNOWN 5
+#define GETTEMP_NOSENSOR 6
+#define GETTEMP_DRIVE_SLEEP 7
+
+enum e_powermode {
+ PWM_UNKNOWN,
+ PWM_ACTIVE,
+ PWM_SLEEPING,
+ PWM_STANDBY
+};
+
+
+struct disk {
+ struct disk * next;
+
+ int fd;
+ const char * drive;
+ const char * model;
+ enum e_bustype type;
+ int value; /* the drive's temperature */
+ int refvalue; /* aka trip temperature */
+ struct harddrive_entry * db_entry;
+
+ char errormsg[MAX_ERRORMSG_SIZE];
+// enum e_gettemp ret;
+ int ret;
+ time_t last_time;
+};
+
+struct bustype {
+ char *name;
+ int (*probe)(int);
+ const char *(*model)(int);
+ enum e_gettemp (*get_temperature)(struct disk *);
+};
+
+
+extern struct bustype * bus[BUS_TYPE_MAX];
+extern char errormsg[MAX_ERRORMSG_SIZE];
+extern int tcp_daemon, debug, quiet, wakeup, af_hint;
+extern char separator;
+extern long portnum, syslog_interval;
+extern char * listen_addr;
+
+int value_to_unit(struct disk *dsk);
+char get_unit(struct disk *dsk);
+
+#endif
diff --git a/src/hddtemp_scsi/scsi.c b/src/hddtemp_scsi/scsi.c
new file mode 100644
index 0000000..ab00ad6
--- /dev/null
+++ b/src/hddtemp_scsi/scsi.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2002 Emmanuel VARAGNAT <hddtemp@guzu.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/*
+ * Adapted from a patch sended by : Frederic LOCHON <lochon@roulaise.net>
+ */
+/*
+ * Adapted for use with nwipe by : Gerold Gruber <Gerold.Gruber@edv2g.de>
+ */
+
+// Include file generated by ./configure
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// Gettext includes
+#if ENABLE_NLS
+#include <libintl.h>
+#define _(String) gettext (String)
+#else
+#define _(String) (String)
+#endif
+
+// Standard includes
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <scsi/scsi.h>
+
+// Application specific includes
+#include "scsicmds.h"
+#include "hddtemp.h"
+
+int scsi_get_temperature(struct disk *dsk) {
+ int i;
+ int tempPage = 0;
+ unsigned char buffer[1024];
+
+ /*
+ on triche un peu
+ we cheat a little and do not really read form drivedb as SCSI disks are not included there
+ original code omitted as there is no need for it in the context of nwipe
+ */
+
+ /*
+ Enable SMART
+ */
+ if (scsi_smartDEXCPTdisable(dsk->fd) != 0) {
+ snprintf(dsk->errormsg, MAX_ERRORMSG_SIZE, "%s", strerror(errno));
+ close(dsk->fd);
+ dsk->fd = -1;
+ return GETTEMP_ERROR;
+ }
+
+ /*
+ Temp. capable
+ */
+ if (scsi_logsense(dsk->fd , SUPPORT_LOG_PAGES, buffer, sizeof(buffer)) != 0) {
+ snprintf(dsk->errormsg, MAX_ERRORMSG_SIZE, _("log sense failed : %s"), strerror(errno));
+ close(dsk->fd);
+ dsk->fd = -1;
+ return GETTEMP_ERROR;
+ }
+
+ for ( i = 4; i < buffer[3] + LOGPAGEHDRSIZE ; i++) {
+ if (buffer[i] == TEMPERATURE_PAGE) {
+ tempPage = 1;
+ break;
+ }
+ }
+
+ if(tempPage) {
+ /*
+ get temperature (from scsiGetTemp (scsicmd.c))
+ */
+ if (scsi_logsense(dsk->fd , TEMPERATURE_PAGE, buffer, sizeof(buffer)) != 0) {
+ snprintf(dsk->errormsg, MAX_ERRORMSG_SIZE, _("log sense failed : %s"), strerror(errno));
+ close(dsk->fd);
+ dsk->fd = -1;
+ return GETTEMP_ERROR;
+ }
+
+ if( (int)buffer[7] == 2 ) /* PARAMETER LENGTH */
+ {
+ dsk->value = buffer[9];
+ }
+ else
+ {
+ snprintf(dsk->errormsg, MAX_ERRORMSG_SIZE, _("parameter length unexpected: %d"), (int)buffer[7] );
+ return GETTEMP_UNKNOWN;
+ }
+ dsk->refvalue = buffer[15];
+ if( (int)buffer[13] == 2 ) /* PARAMETER LENGTH */
+ {
+ dsk->refvalue = buffer[15];
+ }
+ else
+ {
+ snprintf(dsk->errormsg, MAX_ERRORMSG_SIZE, _("parameter ref length unexpected: %d"), (int)buffer[13] );
+ return GETTEMP_UNKNOWN;
+ }
+ return GETTEMP_SUCCESS;
+ } else {
+ return GETTEMP_NOSENSOR;
+ }
+}
diff --git a/src/hddtemp_scsi/scsi.h b/src/hddtemp_scsi/scsi.h
new file mode 100644
index 0000000..c349e37
--- /dev/null
+++ b/src/hddtemp_scsi/scsi.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2002 Emmanuel VARAGNAT <hddtemp@guzu.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SCSIC_H_
+#define SCSIC_H_
+
+extern struct bustype scsi_bus;
+
+#endif
diff --git a/src/hddtemp_scsi/scsicmds.c b/src/hddtemp_scsi/scsicmds.c
new file mode 100644
index 0000000..3449203
--- /dev/null
+++ b/src/hddtemp_scsi/scsicmds.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2002 Emmanuel VARAGNAT <hddtemp@guzu.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+// Include file generated by ./configure
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// Gettext includes
+#if ENABLE_NLS
+#include <libintl.h>
+#define _(String) gettext (String)
+#else
+#define _(String) (String)
+#endif
+
+// Standard includes
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <scsi/scsi.h>
+#include <scsi/sg.h>
+#include <scsi/scsi_ioctl.h>
+
+// Application specific includes
+#include "scsicmds.h"
+
+static void scsi_fixstring(unsigned char *s, int bytecount)
+{
+ unsigned char *p;
+ unsigned char *end;
+
+ p = s;
+ end = s + bytecount;
+
+ /* strip leading blanks */
+ while (s != end && *s == ' ')
+ ++s;
+ /* compress internal blanks and strip trailing blanks */
+ while (s != end && *s) {
+ if (*s++ != ' ' || (s != end && *s && *s != ' '))
+ *p++ = *(s-1);
+ }
+ /* wipe out trailing garbage */
+ while (p != end)
+ *p++ = '\0';
+}
+
+int scsi_SG_IO(int device, unsigned char *cdb, int cdb_len, unsigned char *buffer, int buffer_len, unsigned char *sense, unsigned char sense_len, int dxfer_direction) {
+ struct sg_io_hdr io_hdr;
+
+ memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
+ io_hdr.interface_id = 'S';
+ io_hdr.cmdp = cdb;
+ io_hdr.cmd_len = cdb_len;
+ io_hdr.dxfer_len = buffer_len;
+ io_hdr.dxferp = buffer;
+ io_hdr.mx_sb_len = sense_len;
+ io_hdr.sbp = sense;
+ io_hdr.dxfer_direction = dxfer_direction;
+ io_hdr.timeout = 3000; /* 3 seconds should be ample */
+
+ return ioctl(device, SG_IO, &io_hdr);
+}
+
+int scsi_SEND_COMMAND(int device, unsigned char *cdb, int cdb_len, unsigned char *buffer, int buffer_len, int dxfer_direction)
+{
+ unsigned char buf[2048];
+ unsigned int inbufsize, outbufsize, ret;
+
+ switch(dxfer_direction) {
+ case SG_DXFER_FROM_DEV:
+ inbufsize = 0;
+ outbufsize = buffer_len;
+ break;
+ case SG_DXFER_TO_DEV:
+ inbufsize = buffer_len;
+ outbufsize = 0;
+ break;
+ default:
+ inbufsize = 0;
+ outbufsize = 0;
+ break;
+ }
+ memcpy(buf, &inbufsize , sizeof(inbufsize));
+ memcpy(buf + sizeof(inbufsize), &outbufsize , sizeof(outbufsize));
+ memcpy(buf + sizeof(inbufsize) + sizeof(outbufsize), cdb, cdb_len);
+ memcpy(buf + sizeof(inbufsize) + sizeof(outbufsize) + cdb_len, buffer, buffer_len);
+
+ ret = ioctl(device, SCSI_IOCTL_SEND_COMMAND, buf);
+
+ memcpy(buffer, buf + sizeof(inbufsize) + sizeof(outbufsize), buffer_len);
+
+ return ret;
+}
+
+int scsi_command(int device, unsigned char *cdb, int cdb_len, unsigned char *buffer, int buffer_len, int dxfer_direction)
+{
+ static int SG_IO_supported = -1;
+ int ret;
+
+ if (SG_IO_supported == 1)
+ return scsi_SG_IO(device, cdb, cdb_len, buffer, buffer_len, NULL, 0, dxfer_direction);
+ else if (SG_IO_supported == 0)
+ return scsi_SEND_COMMAND(device, cdb, cdb_len, buffer, buffer_len, dxfer_direction);
+ else {
+ ret = scsi_SG_IO(device, cdb, cdb_len, buffer, buffer_len, NULL, 0, dxfer_direction);
+ if (ret == 0) {
+ SG_IO_supported = 1;
+ return ret;
+ } else {
+ SG_IO_supported = 0;
+ return scsi_SEND_COMMAND(device, cdb, cdb_len, buffer, buffer_len, dxfer_direction);
+ }
+ }
+}
+
+int scsi_inquiry(int device, unsigned char *buffer)
+{
+ unsigned char cdb[6];
+
+ memset(cdb, 0, sizeof(cdb));
+ cdb[0] = INQUIRY;
+ cdb[4] = 36; /* should be 36 for unsafe devices (like USB mass storage stuff)
+ * otherwise they can lock up! SPC sections 7.4 and 8.6 */
+
+ if (scsi_command(device, cdb, sizeof(cdb), buffer, cdb[4], SG_DXFER_FROM_DEV) != 0)
+ return 1;
+ else {
+ scsi_fixstring(buffer + 8, 24);
+ return 0;
+ }
+}
+
+int scsi_modesense(int device, unsigned char pagenum, unsigned char *buffer, int buffer_len) {
+ unsigned char cdb[6];
+ int ret;
+
+ memset(cdb, 0, sizeof(cdb));
+ cdb[0] = MODE_SENSE;
+ cdb[2] = pagenum;
+ cdb[4] = 0xff;
+
+ ret = scsi_command(device, cdb, sizeof(cdb), buffer, buffer_len, SG_DXFER_FROM_DEV);
+ if (ret == 0) {
+ if ((buffer[3] + 5) > buffer[0]) /* response length too short */
+ return -1;
+ }
+ return ret;
+}
+
+int scsi_modeselect(int device, char *buffer) {
+ unsigned char cdb[6];
+
+ memset(cdb, 0, sizeof(cdb));
+ cdb[0] = MODE_SELECT;
+ cdb[1] = 0x11;
+ cdb[4] = buffer[0] + 1;
+
+ memset(buffer, 0, 12);
+ buffer[3] = 0x08;
+ buffer[10] = 0x02;
+ buffer[12] &= 0x3f;
+
+ return scsi_command(device, cdb, sizeof(cdb), buffer, cdb[4], SG_DXFER_TO_DEV);
+}
+
+int scsi_logsense(int device, int pagenum, unsigned char *buffer, int buffer_len) {
+ unsigned char cdb[10];
+
+ memset(cdb, 0, sizeof(cdb));
+ cdb[0] = LOG_SENSE;
+ cdb[2] = 0x40 | pagenum;
+ cdb[7] = 0x04;
+
+ return scsi_command(device, cdb, sizeof(cdb), buffer, buffer_len, SG_DXFER_FROM_DEV);
+}
+
+int scsi_smartsupport(int device) {
+ unsigned char buf[255];
+
+ if (scsi_modesense (device, EXCEPTIONS_CONTROL_PAGE, buf, sizeof(buf)) != 0)
+ return 0;
+ else
+ return (buf[14] & 0x08) == 0;
+}
+
+int scsi_smartDEXCPTdisable(int device) {
+ unsigned char buf[255];
+
+ if (scsi_modesense (device, EXCEPTIONS_CONTROL_PAGE, buf, sizeof(buf)) != 0)
+ return 1;
+
+ if (buf[14] & 0x08) {
+ buf[14] &= 0xf7;
+ buf[15] = 0x04;
+ return scsi_modeselect (device, buf);
+ }
+ else
+ return 0;
+}
+
diff --git a/src/hddtemp_scsi/scsicmds.h b/src/hddtemp_scsi/scsicmds.h
new file mode 100644
index 0000000..46cd268
--- /dev/null
+++ b/src/hddtemp_scsi/scsicmds.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2002 Emmanuel VARAGNAT <hddtemp@guzu.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#ifndef SCSICMDS_H_
+#define SCSICMDS_H_
+
+#define SUPPORT_LOG_PAGES 0x00
+#define TEMPERATURE_PAGE 0x0d
+#define EXCEPTIONS_CONTROL_PAGE 0x1c
+#define LOGPAGEHDRSIZE 4
+
+int scsi_SG_IO(int device, unsigned char *cdb, int cdb_len, unsigned char *buffer, int buffer_len, unsigned char *sense, unsigned char sense_len, int dxfer_direction);
+int scsi_inquiry(int device, unsigned char *buffer);
+int scsi_modesense(int device, unsigned char pagenum, unsigned char *buffer, int buffer_len);
+int scsi_modeselect(int device, char *buffer);
+int scsi_logsense(int device, int pagenum, unsigned char *buffer, int buffer_len);
+int scsi_smartsupport(int device);
+int scsi_smartDEXCPTdisable(int device);
+
+#endif