diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG index bafb547074ef53dc4f13c2ed3af3b84080b99eed..70654a144188188f2bcf932530c5f42a765d0cff 100644 --- a/sm5/CHANGELOG +++ b/sm5/CHANGELOG @@ -1,6 +1,6 @@ CHANGELOG for smartmontools -$Id: CHANGELOG,v 1.658 2008/03/03 22:38:48 shattered Exp $ +$Id: CHANGELOG,v 1.659 2008/03/04 21:24:58 ballen4705 Exp $ The most recent version of this file is: http://smartmontools.cvs.sourceforge.net/smartmontools/sm5/CHANGELOG?view=markup @@ -36,7 +36,19 @@ NOTES FOR FUTURE RELEASES: see TODO file. -SMARTMONTOOLS STABLE RELEASE 5.38 2008/02/24 +SMARTMONTOOLS STABLE RELEASE 5.38 2008/03/04 + + [BA] smartd.initd.in addition from Erwan Velu <erwan@seanodes.com> + + [BA] smartd fixes: + + - On Linux, DEVICESCAN now automatically recognizes SATA devices + behind libata, and SATA devices behind the Marvell driver, and + treats them correctly. + + - On Linux, a '-d sat' or '-d marvell' is automatically added + if libata or the marvell driver are recognized behind a SCSI + device type [SS] (Maybe) fix attribute autosave in FreeBSD. diff --git a/sm5/NEWS b/sm5/NEWS index 059fc6a7310be59070ad1b04b7f2a5c5724cf071..0df7b1ee7545d92c12efe1b7b6fed19259e4310c 100644 --- a/sm5/NEWS +++ b/sm5/NEWS @@ -1,17 +1,19 @@ smartmontools NEWS ------------------ -CVS ID: $Id: NEWS,v 1.33 2008/02/24 20:16:31 ballen4705 Exp $ +CVS ID: $Id: NEWS,v 1.34 2008/03/04 21:24:58 ballen4705 Exp $ The most up-to-date version of this file is: http://smartmontools.cvs.sourceforge.net/smartmontools/sm5/NEWS?view=markup -Date 2008-02-24 +Date 2008-03-04 Summary: smartmontools release 5.38 (STABLE) -------------------------------------------- This is a stable release of smartmontools. In addition to changes below, it includes: - - Fixed auto-offline support in FreeBSD + - Libata/Marvell driver devices no longer need explicit '-d' switch + - DEVICESCAN automatically detects libata/marvell driver SATA devices + - Fixed auto-offline/autosave support in FreeBSD - SAT device type + SCSI generic devices work properly with smartd under Linux - Many additions to drive database - More portable autogen/autoconf/automake script set diff --git a/sm5/smartd.cpp b/sm5/smartd.cpp index fa809c8532733efd4a2147a55e1f404fecbbc846..48d748eacd09801a7b4c2c960e0f5d171d6c93fa 100644 --- a/sm5/smartd.cpp +++ b/sm5/smartd.cpp @@ -119,14 +119,14 @@ extern "C" int getdomainname(char *, int); // no declaration in header files! extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *escalade_c_cvsid, *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *utility_c_cvsid; -static const char *filenameandversion="$Id: smartd.cpp,v 1.395 2007/11/26 18:11:32 guidog Exp $"; +static const char *filenameandversion="$Id: smartd.cpp,v 1.396 2008/03/04 21:24:58 ballen4705 Exp $"; #ifdef NEED_SOLARIS_ATA_CODE extern const char *os_solaris_ata_s_cvsid; #endif #ifdef _WIN32 extern const char *daemon_win32_c_cvsid, *hostname_win32_c_cvsid, *syslog_win32_c_cvsid; #endif -const char *smartd_c_cvsid="$Id: smartd.cpp,v 1.395 2007/11/26 18:11:32 guidog Exp $" +const char *smartd_c_cvsid="$Id: smartd.cpp,v 1.396 2008/03/04 21:24:58 ballen4705 Exp $" ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID #ifdef DAEMON_WIN32_H_CVSID DAEMON_WIN32_H_CVSID @@ -189,8 +189,8 @@ int cfgentries_max=0; // pointers to ATA and SCSI devices being monitored, maximum and // actual numbers -cfgfile **atadevlist=NULL, **scsidevlist=NULL; -int atadevlist_max=0, scsidevlist_max=0; +cfgfile **ATAandSCSIdevlist=NULL; +int ATAandSCSIdevlist_max=0; int numdevata=0, numdevscsi=0; // track memory usage @@ -392,17 +392,11 @@ void RmAllConfigEntries(){ void RmAllDevEntries(){ int i; - for (i=0; i<atadevlist_max; i++) - RmConfigEntry(atadevlist+i, __LINE__); - - atadevlist=FreeNonZero(atadevlist, sizeof(cfgfile *)*atadevlist_max, __LINE__, filenameandversion); - atadevlist_max=0; - - for (i=0; i<scsidevlist_max; i++) - RmConfigEntry(scsidevlist+i, __LINE__); + for (i=0; i<ATAandSCSIdevlist_max; i++) + RmConfigEntry(ATAandSCSIdevlist+i, __LINE__); - scsidevlist=FreeNonZero(scsidevlist, sizeof(cfgfile *)*scsidevlist_max, __LINE__, filenameandversion); - scsidevlist_max=0; + ATAandSCSIdevlist=FreeNonZero(ATAandSCSIdevlist, sizeof(cfgfile *)*ATAandSCSIdevlist_max, __LINE__, filenameandversion); + ATAandSCSIdevlist_max=0; return; } @@ -1609,8 +1603,8 @@ int ATADeviceScan(cfgfile *cfg, int scanning){ } // Do we still have entries available? - while (numdevata>=atadevlist_max) - atadevlist=AllocateMoreSpace(atadevlist, &atadevlist_max, "ATA device"); + while (numdevata+numdevscsi>=ATAandSCSIdevlist_max) + ATAandSCSIdevlist=AllocateMoreSpace(ATAandSCSIdevlist, &ATAandSCSIdevlist_max, "ATA and SCSI devices"); // register device PrintOut(LOG_INFO,"Device: %s, is SMART capable. Adding to \"monitor\" list.\n",name); @@ -1624,10 +1618,12 @@ int ATADeviceScan(cfgfile *cfg, int scanning){ return 0; } -// Returns 0 if normal SCSI device. Returns -1 if INQUIRY fails. +// Returns 0 if normal SCSI device. +// Returns -1 if INQUIRY fails. // Returns 2 if ATA device detected behind SAT layer. +// Returns 3 if ATA device detected behind Marvell controller. // Returns 1 if other device detected that we don't want to treat -// as a normal SCSI device. +// as a normal SCSI device. static int SCSIFilterKnown(int fd, char * device) { char req_buff[256]; @@ -1642,7 +1638,7 @@ static int SCSIFilterKnown(int fd, char * device) if (scsiStdInquiry(fd, (unsigned char *)req_buff, req_len)) { PrintOut(LOG_INFO, "Device: %s, failed on INQUIRY; skip device\n", device); // device doesn't like INQUIRY commands - return -1; + return SCSIFK_FAILED; } } avail_len = req_buff[4] + 5; @@ -1651,29 +1647,25 @@ static int SCSIFilterKnown(int fd, char * device) if (0 == strncmp(req_buff + 8, "3ware", 5) || 0 == strncmp(req_buff + 8, "AMCC", 4) ) { PrintOut(LOG_INFO, "Device %s, please try adding '-d 3ware,N'\n", device); PrintOut(LOG_INFO, "Device %s, you may need to replace %s with /dev/twaN or /dev/tweN\n", device, device); - return 1; + return SCSIFK_3WARE; } else if ((len >= 42) && (0 == strncmp(req_buff + 36, "MVSATA", 6))) { - PrintOut(LOG_INFO, "Device %s, please try '-d marvell'\n", device); - return 1; + PrintOut(LOG_INFO, "Device %s: using '-d marvell' for ATA disk with Marvell driver\n", device); + return SCSIFK_MARVELL; } else if ((avail_len >= 36) && (0 == strncmp(req_buff + 8, "ATA ", 8)) && has_sat_pass_through(fd, 0 /* non-packet dev */)) { - - PrintOut(LOG_INFO, "Device %s: ATA disk detected behind SAT layer\n", + PrintOut(LOG_INFO, "Device %s: using '-d sat' for ATA disk behind SAT layer.\n", device); - PrintOut(LOG_INFO, " Try adding '-d sat' to the device line in the " - "smartd.conf file.\n"); - PrintOut(LOG_INFO, " For example: '%s -a -d sat'\n", device); - return 2; + return SCSIFK_SAT; } } - return 0; + return SCSIFK_NORMAL; } // on success, return 0. On failure, return >0. Never return <0, // please. static int SCSIDeviceScan(cfgfile *cfg, int scanning) { - int k, fd, err; + int k, fd, err, retval; char *device = cfg->name; struct scsi_iec_mode_page iec; UINT8 tBuf[64]; @@ -1702,9 +1694,18 @@ static int SCSIDeviceScan(cfgfile *cfg, int scanning) { // early skip if device known and needs to be handled by some other // device type (e.g. '-d 3ware,<n>') - if (SCSIFilterKnown(fd, device)) { + if ((retval = SCSIFilterKnown(fd, device))) { CloseDevice(fd, device); - return 2; + + if (retval==SCSIFK_SAT) + // SATA Device behind SAT layer + return SCSIFK_SAT; + + if (retval==SCSIFK_MARVELL) + // ATA/SATA device behind Marvell driver + return SCSIFK_MARVELL; + + return 2; } // check that device is ready for commands. IE stores its stuff on @@ -1751,8 +1752,8 @@ static int SCSIDeviceScan(cfgfile *cfg, int scanning) { } // Device exists, and does SMART. Add to list (allocating more space if needed) - while (numdevscsi >= scsidevlist_max) - scsidevlist=AllocateMoreSpace(scsidevlist, &scsidevlist_max, "SCSI device"); + while (numdevscsi+numdevata >= ATAandSCSIdevlist_max) + ATAandSCSIdevlist=AllocateMoreSpace(ATAandSCSIdevlist, &ATAandSCSIdevlist_max, "ATA and SCSI devices"); // Flag that certain log pages are supported (information may be // available from other sources). @@ -1842,6 +1843,29 @@ static int SCSIDeviceScan(cfgfile *cfg, int scanning) { return 0; } +// modified treatment of SCSI device behind SAT layer +static int SCSIandSATDeviceScan(cfgfile *cfg, int scanning) { + int retval = SCSIDeviceScan(cfg, scanning); + cfg->WhichCheckDevice=1; // default SCSI device + + if (retval==SCSIFK_SAT) { + // found SATA device behind SAT translation layer + cfg->controller_type=CONTROLLER_SAT; + cfg->WhichCheckDevice=0; // actually SATA device! + return ATADeviceScan(cfg, scanning); + } + + if (retval==SCSIFK_MARVELL) { + // found SATA device behind Marvell controller + cfg->controller_type=CONTROLLER_MARVELL_SATA; + cfg->WhichCheckDevice=0; // actually SATA device! + return ATADeviceScan(cfg, scanning); + } + + return retval; +} + + // We compare old and new values of the n'th attribute. Note that n // is NOT the attribute ID number.. If (Normalized & Raw) equal, // then return 0, else nonzero. @@ -2050,7 +2074,7 @@ int DoTestNow(cfgfile *cfg, char testtype, time_t testtime) { } // Print a list of future tests. -void PrintTestSchedule(cfgfile **atadevices, cfgfile **scsidevices){ +void PrintTestSchedule(cfgfile **ATAandSCSIdevices){ int i, t; cfgfile * cfg; char datenow[DATEANDEPOCHLEN], date[DATEANDEPOCHLEN]; @@ -2073,8 +2097,8 @@ void PrintTestSchedule(cfgfile **atadevices, cfgfile **scsidevices){ // Check for each device whether a test will be run time_t testtime = now + seconds; for (i=0; i<numdev; i++) { - cfg = (i<numdevata? atadevices[i] : scsidevices[i-numdevata]); - for (t=0; t<(i<numdevata?4:2); t++) { + cfg = ATAandSCSIdevices[i]; + for (t=0; t<(cfg->WhichCheckDevice==0?4:2); t++) { char testtype = "LSCO"[t]; if (DoTestNow(cfg, testtype, testtime)) { // Report at most 5 tests of each type @@ -2092,8 +2116,8 @@ void PrintTestSchedule(cfgfile **atadevices, cfgfile **scsidevices){ dateandtimezoneepoch(date, now+seconds); PrintOut(LOG_INFO, "\nTotals [%s - %s]:\n", datenow, date); for (i=0; i<numdev; i++) { - cfg = (i<numdevata? atadevices[i] : scsidevices[i-numdevata]); - for (t=0; t<(i<numdevata?4:2); t++) { + cfg = ATAandSCSIdevices[i]; + for (t=0; t<(cfg->WhichCheckDevice==0?4:2); t++) { PrintOut(LOG_INFO, "Device: %s, will do %3d test%s of type %c\n", cfg->name, testcnts[i][t], (testcnts[i][t]==1?"":"s"), "LSCO"[t]); } @@ -2657,14 +2681,15 @@ int SCSICheckDevice(cfgfile *cfg, bool allow_selftests) } // Checks the SMART status of all ATA and SCSI devices -void CheckDevicesOnce(cfgfile **atadevices, cfgfile **scsidevices, bool allow_selftests){ +void CheckDevicesOnce(cfgfile **ATAandSCSIdevices, bool allow_selftests){ int i; - for (i=0; i<numdevata; i++) - ATACheckDevice(atadevices[i], allow_selftests); - - for (i=0; i<numdevscsi; i++) - SCSICheckDevice(scsidevices[i], allow_selftests); + for (i=0; i<numdevata+numdevscsi; i++) { + if (ATAandSCSIdevices[i]->WhichCheckDevice==1) + SCSICheckDevice(ATAandSCSIdevices[i], allow_selftests); + else + ATACheckDevice(ATAandSCSIdevices[i], allow_selftests); + } return; } @@ -4253,9 +4278,11 @@ void RegisterDevices(int scanning){ else { // move onto the list of ata devices cfgentries[i]=NULL; - while (numdevata>=atadevlist_max) - atadevlist=AllocateMoreSpace(atadevlist, &atadevlist_max, "ATA device"); - atadevlist[numdevata++]=ent; + while (numdevata+numdevscsi>=ATAandSCSIdevlist_max) + ATAandSCSIdevlist=AllocateMoreSpace(ATAandSCSIdevlist, &ATAandSCSIdevlist_max, "ATA and SCSI devices"); + ent->WhichCheckDevice=0; + ATAandSCSIdevlist[numdevscsi+numdevata]=ent; + numdevata++; } } @@ -4274,7 +4301,7 @@ void RegisterDevices(int scanning){ if (sigaction(SIGALRM, &alarmAction, &defaultaction)) { // if we can't set timeout, just scan device PrintOut(LOG_CRIT, "Unable to initialize SCSI timeout mechanism.\n"); - retscsi=SCSIDeviceScan(ent, scanning); + retscsi=SCSIandSATDeviceScan(ent, scanning); } else { // prepare return point in case of bad SCSI device @@ -4284,7 +4311,7 @@ void RegisterDevices(int scanning){ else { // Set alarm, make SCSI call, reset alarm alarm(SCSITIMEOUT); - retscsi=SCSIDeviceScan(ent, scanning); + retscsi=SCSIandSATDeviceScan(ent, scanning); alarm(0); } if (sigaction(SIGALRM, &defaultaction, NULL)){ @@ -4292,7 +4319,7 @@ void RegisterDevices(int scanning){ } } #else - retscsi=SCSIDeviceScan(ent, scanning); + retscsi=SCSIandSATDeviceScan(ent, scanning); #endif // Now scan SCSI device... @@ -4304,9 +4331,10 @@ void RegisterDevices(int scanning){ else { // move onto the list of scsi devices cfgentries[i]=NULL; - while (numdevscsi>=scsidevlist_max) - scsidevlist=AllocateMoreSpace(scsidevlist, &scsidevlist_max, "SCSI device"); - scsidevlist[numdevscsi++]=ent; + while (numdevscsi+numdevata>=ATAandSCSIdevlist_max) + ATAandSCSIdevlist=AllocateMoreSpace(ATAandSCSIdevlist, &ATAandSCSIdevlist_max, "ATA and SCSI devices"); + ATAandSCSIdevlist[numdevata+numdevscsi]=ent; + numdevscsi++; } } @@ -4430,7 +4458,7 @@ static int smartd_main(int argc, char **argv) if (quit==4) { // user has asked to print test schedule - PrintTestSchedule(atadevlist, scsidevlist); + PrintTestSchedule(ATAandSCSIdevlist); EXIT(0); } @@ -4440,7 +4468,7 @@ static int smartd_main(int argc, char **argv) // check all devices once, // self tests are not started in first pass unless '-q onecheck' is specified - CheckDevicesOnce(atadevlist, scsidevlist, (!firstpass || quit==3)); + CheckDevicesOnce(ATAandSCSIdevlist, (!firstpass || quit==3)); // user has asked us to exit after first check if (quit==3) { diff --git a/sm5/smartd.h b/sm5/smartd.h index 1ac23e396fc44b093935a5ca290f7ffaba27327b..2518c066427ce8075e8b2727a86f534ef97a3c9a 100644 --- a/sm5/smartd.h +++ b/sm5/smartd.h @@ -32,7 +32,7 @@ #ifndef SMARTD_H_CVSID -#define SMARTD_H_CVSID "$Id: smartd.h,v 1.84 2006/11/11 17:50:50 ballen4705 Exp $\n" +#define SMARTD_H_CVSID "$Id: smartd.h,v 1.85 2008/03/04 21:24:58 ballen4705 Exp $\n" #endif // Configuration file @@ -233,6 +233,9 @@ typedef struct configfile_s { struct ata_smart_values *smartval; // Pointer to SMART data struct ata_smart_thresholds_pvt *smartthres; // Pointer to SMART thresholds + // Added to distinguish ATA and SCSI entries on list + int WhichCheckDevice; + } cfgfile; @@ -278,7 +281,6 @@ export NJAMD_TRACE_LIBS=1 #define SIGNALFN signal #endif -#endif #define SELFTEST_ERRORCOUNT(x) (x & 0xff) #define SELFTEST_ERRORHOURS(x) ((x >> 8) & 0xffff) @@ -297,3 +299,16 @@ export NJAMD_TRACE_LIBS=1 // if cfg->pending has this value, dont' monitor #define DONT_MONITOR_UNC (256*OFF_UNC_DEFAULT+CUR_UNC_DEFAULT) + +// Some return values from SCSIFilterKnown(), used to detect known +// device types hidden behind SCSI devices. + +#define SCSIFK_FAILED -1 +#define SCSIFK_NORMAL 0 +#define SCSIFK_3WARE 11 +#define SCSIFK_SAT 12 +#define SCSIFK_MARVELL 13 + +// Make additions BEFORE this line. The line is the end of +// double-inclusion protection and should remain the final line. +#endif // #ifndef SMARTD_H_ diff --git a/sm5/smartd.initd.in b/sm5/smartd.initd.in index 9b2ca48533efafe76cc8e67102bedf84593cbf02..aefb5aa7c011a607aafe759a2ff53f4bf887327e 100755 --- a/sm5/smartd.initd.in +++ b/sm5/smartd.initd.in @@ -2,7 +2,7 @@ # smartmontools init file for smartd # Copyright (C) 2002-7 Bruce Allen <smartmontools-support@lists.sourceforge.net> -# $Id: smartd.initd.in,v 1.36 2007/11/01 20:53:30 chrfranke Exp $ +# $Id: smartd.initd.in,v 1.37 2008/03/04 21:24:58 ballen4705 Exp $ # For RedHat and cousins: # chkconfig: 2345 40 40 @@ -11,15 +11,16 @@ # For SuSE and cousins ### BEGIN INIT INFO -# Provides: smartd -# Required-Start: $syslog +# Provides: smartd +# Required-Start: $syslog # X-UnitedLinux-Should-Start: $sendmail -# Required-Stop: $syslog +# Should-Start: $sendmail +# Required-Stop: $syslog # X-UnitedLinux-Should-Stop: -# Default-Start: 2 3 5 +# Default-Start: 2 3 5 # Default-Stop: -# Short-Description: Monitors disk and tape health via S.M.A.R.T. -# Description: Start S.M.A.R.T. disk and tape monitor. +# Short-Description: Monitors disk and tape health via S.M.A.R.T. +# Description: Start S.M.A.R.T. disk and tape monitor. ### END INIT INFO # This program is free software; you can redistribute it and/or modify it