diff options
Diffstat (limited to 'src/hddtemp_scsi')
-rw-r--r-- | src/hddtemp_scsi/get_scsi_temp.c | 159 | ||||
-rw-r--r-- | src/hddtemp_scsi/hddtemp.h | 91 | ||||
-rw-r--r-- | src/hddtemp_scsi/scsi.c | 125 | ||||
-rw-r--r-- | src/hddtemp_scsi/scsi.h | 24 | ||||
-rw-r--r-- | src/hddtemp_scsi/scsicmds.c | 221 | ||||
-rw-r--r-- | src/hddtemp_scsi/scsicmds.h | 36 |
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 |