📄 smartd.cpp
字号:
// capability check: ATA error log if (cfg->errorlog){ int val; // start with service disabled, and re-enable it if all works OK cfg->errorlog=0; cfg->ataerrorcount=0; if (!cfg->smartval) PrintOut(LOG_INFO, "Device: %s, no SMART Error log (SMART READ DATA failed); disabling -l error\n", name); else if (!cfg->permissive && !isSmartErrorLogCapable(cfg->smartval, &drive)) PrintOut(LOG_INFO, "Device: %s, appears to lack SMART Error log; disabling -l error (override with -T permissive Directive)\n", name); else if ((val=ATAErrorCount(fd, name))<0) PrintOut(LOG_INFO, "Device: %s, no SMART Error log; remove -l error Directive from smartd.conf\n", name); else { cfg->errorlog=1; cfg->ataerrorcount=val; } } // If we don't need to save SMART data, get rid of it now if (!retainsmartdata) { if (cfg->smartval) { cfg->smartval=CheckFree(cfg->smartval, __LINE__,filenameandversion); bytes-=sizeof(struct ata_smart_values); } if (cfg->smartthres) { cfg->smartthres=CheckFree(cfg->smartthres, __LINE__,filenameandversion); bytes-=sizeof(struct ata_smart_thresholds_pvt); } } // capabilities check -- does it support powermode? if (cfg->powermode) { int powermode=ataCheckPowerMode(fd); if (-1 == powermode) { PrintOut(LOG_CRIT, "Device: %s, no ATA CHECK POWER STATUS support, ignoring -n Directive\n", name); cfg->powermode=0; } else if (powermode!=0 && powermode!=0x80 && powermode!=0xff) { PrintOut(LOG_CRIT, "Device: %s, CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Directive\n", name, powermode); cfg->powermode=0; } } // If no tests available or selected, return if (!(cfg->errorlog || cfg->selftest || cfg->smartcheck || cfg->usagefailed || cfg->prefail || cfg->usage || cfg->tempdiff || cfg->tempinfo || cfg->tempcrit )) { CloseDevice(fd, name); return 3; } // Do we still have entries available? 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); // record number of device, type of device, increment device count if (cfg->controller_type == CONTROLLER_UNKNOWN) cfg->controller_type=CONTROLLER_ATA; // close file descriptor CloseDevice(fd, name); return 0;}// 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.static int SCSIFilterKnown(int fd, char * device){ char req_buff[256]; int req_len, avail_len, len; memset(req_buff, 0, 96); req_len = 36; if (scsiStdInquiry(fd, (unsigned char *)req_buff, req_len)) { /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */ /* watch this spot ... other devices could lock up here */ req_len = 64; 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 SCSIFK_FAILED; } } avail_len = req_buff[4] + 5; len = (avail_len < req_len) ? avail_len : req_len; if (len >= 36) { 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 SCSIFK_3WARE; } else if ((len >= 42) && (0 == strncmp(req_buff + 36, "MVSATA", 6))) { 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: using '-d sat' for ATA disk behind SAT layer.\n", device); return SCSIFK_SAT; } } 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, retval; char *device = cfg->name; struct scsi_iec_mode_page iec; UINT8 tBuf[64]; char *mode=NULL; // should we try to register this as a SCSI device? switch (cfg->controller_type) { case CONTROLLER_SCSI: case CONTROLLER_UNKNOWN: mode="SCSI"; break; case CONTROLLER_CCISS: mode="CCISS"; break; default: return 1; } // pass user settings on to low-level SCSI commands con->controller_port=cfg->controller_port; con->controller_type=cfg->controller_type; // open the device if ((fd = OpenDevice(device, mode, scanning)) < 0) return 1; PrintOut(LOG_INFO,"Device: %s, opened\n", device); // early skip if device known and needs to be handled by some other // device type (e.g. '-d 3ware,<n>') if ((retval = SCSIFilterKnown(fd, device))) { CloseDevice(fd, device); 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 // the media. if ((err = scsiTestUnitReady(fd))) { if (SIMPLE_ERR_NOT_READY == err) PrintOut(LOG_INFO, "Device: %s, NOT READY (e.g. spun down); skip device\n", device); else if (SIMPLE_ERR_NO_MEDIUM == err) PrintOut(LOG_INFO, "Device: %s, NO MEDIUM present; skip device\n", device); else if (SIMPLE_ERR_BECOMING_READY == err) PrintOut(LOG_INFO, "Device: %s, BECOMING (but not yet) READY; skip device\n", device); else PrintOut(LOG_CRIT, "Device: %s, failed Test Unit Ready [err=%d]\n", device, err); CloseDevice(fd, device); return 2; } // Badly-conforming USB storage devices may fail this check. // The response to the following IE mode page fetch (current and // changeable values) is carefully examined. It has been found // that various USB devices that malform the response will lock up // if asked for a log page (e.g. temperature) so it is best to // bail out now. if (!(err = scsiFetchIECmpage(fd, &iec, cfg->modese_len))) cfg->modese_len = iec.modese_len; else if (SIMPLE_ERR_BAD_FIELD == err) ; /* continue since it is reasonable not to support IE mpage */ else { /* any other error (including malformed response) unreasonable */ PrintOut(LOG_INFO, "Device: %s, Bad IEC (SMART) mode page, err=%d, skip device\n", device, err); CloseDevice(fd, device); return 3; } // N.B. The following is passive (i.e. it doesn't attempt to turn on // smart if it is off). This may change to be the same as the ATA side. if (!scsi_IsExceptionControlEnabled(&iec)) { PrintOut(LOG_INFO, "Device: %s, IE (SMART) not enabled, skip device\n" "Try 'smartctl -s on %s' to turn on SMART features\n", device, device); CloseDevice(fd, device); return 3; } // Device exists, and does SMART. Add to list (allocating more space if needed) 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). if (0 == scsiLogSense(fd, SUPPORTED_LPAGES, 0, tBuf, sizeof(tBuf), 0)) { for (k = 4; k < tBuf[3] + LOGPAGEHDRSIZE; ++k) { switch (tBuf[k]) { case TEMPERATURE_LPAGE: cfg->TempPageSupported = 1; break; case IE_LPAGE: cfg->SmartPageSupported = 1; break; default: break; } } } // record type of device if (cfg->controller_type == CONTROLLER_UNKNOWN) cfg->controller_type = CONTROLLER_SCSI; // get rid of allocated memory only needed for ATA devices. These // might have been allocated if the user specified Ignore options or // other ATA-only Attribute-specific options on the DEVICESCAN line. cfg->monitorattflags = FreeNonZero(cfg->monitorattflags, NMONITOR*32,__LINE__,filenameandversion); cfg->attributedefs = FreeNonZero(cfg->attributedefs, MAX_ATTRIBUTE_NUM,__LINE__,filenameandversion); cfg->smartval = FreeNonZero(cfg->smartval, sizeof(struct ata_smart_values),__LINE__,filenameandversion); cfg->smartthres = FreeNonZero(cfg->smartthres, sizeof(struct ata_smart_thresholds_pvt),__LINE__,filenameandversion); // Check if scsiCheckIE() is going to work { UINT8 asc = 0; UINT8 ascq = 0; UINT8 currenttemp = 0; UINT8 triptemp = 0; if (scsiCheckIE(fd, cfg->SmartPageSupported, cfg->TempPageSupported, &asc, &ascq, ¤ttemp, &triptemp)) { PrintOut(LOG_INFO, "Device: %s, unexpectedly failed to read SMART values\n", device); cfg->SuppressReport = 1; if (cfg->tempdiff || cfg->tempinfo || cfg->tempcrit) { PrintOut(LOG_CRIT, "Device: %s, can't monitor Temperature, ignoring -W Directive\n", device); cfg->tempdiff = cfg->tempinfo = cfg->tempcrit = 0; } } } // capability check: self-test-log if (cfg->selftest){ int retval=scsiCountFailedSelfTests(fd, 0); if (retval<0) { // no self-test log, turn off monitoring PrintOut(LOG_INFO, "Device: %s, does not support SMART Self-Test Log.\n", device); cfg->selftest=0; cfg->selflogcount=0; cfg->selfloghour=0; } else { // register starting values to watch for changes cfg->selflogcount=SELFTEST_ERRORCOUNT(retval); cfg->selfloghour =SELFTEST_ERRORHOURS(retval); } } // disable autosave (set GLTSD bit) if (cfg->autosave==1){ if (scsiSetControlGLTSD(fd, 1, cfg->modese_len)) PrintOut(LOG_INFO,"Device: %s, could not disable autosave (set GLTSD bit).\n",device); else PrintOut(LOG_INFO,"Device: %s, disabled autosave (set GLTSD bit).\n",device); } // or enable autosave (clear GLTSD bit) if (cfg->autosave==2){ if (scsiSetControlGLTSD(fd, 0, cfg->modese_len)) PrintOut(LOG_INFO,"Device: %s, could not enable autosave (clear GLTSD bit).\n",device); else PrintOut(LOG_INFO,"Device: %s, enabled autosave (cleared GLTSD bit).\n",device); } // tell user we are registering device PrintOut(LOG_INFO, "Device: %s, is SMART capable. Adding to \"monitor\" list.\n", device); // close file descriptor CloseDevice(fd, device); return 0;}// modified treatment of SCSI device behind SAT layerstatic 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.int ATACompareValues(changedattribute_t *delta, struct ata_smart_values *newv, struct ata_smart_values *oldv, struct ata_smart_thresholds_pvt *thresholds, int n, char *name){ struct ata_smart_attribute *now,*was; struct ata_smart_threshold_entry *thre; unsigned char oldval,newval; int sameraw; // check that attribute number in range, and no null pointers if (n<0 || n>=NUMBER_ATA_SMART_ATTRIBUTES || !newv || !oldv || !thresholds) return 0; // pointers to disk's values and vendor's thresholds now=newv->vendor_attributes+n; was=oldv->vendor_attributes+n; thre=thresholds->thres_entries+n; // consider only valid attributes if (!now->id || !was->id || !thre->id) return 0; // issue warning if they don't have the same ID in all structures: if ( (now->id != was->id) || (now->id != thre->id) ){ PrintOut(LOG_INFO,"Device: %s, same Attribute has different ID numbers: %d = %d = %d\n", name, (int)now->id, (int)was->id, (int)thre->id); return 0; } // new and old values of Normalized Attributes newval=now->current; oldval=was->current; // See if the RAW values are unchanged (ie, the same) if (memcmp(now->raw, was->raw, 6)) sameraw=0; else sameraw=1; // if any values out of the allowed range, or if the values haven't // changed, return 0 if (!newval || !oldval || newval>0xfe || oldval>0xfe || (oldval==newval && sameraw)) return 0; // values have changed. Construct output and return delta->newval=newval; delta->oldval=oldval; delta->id=now->id; delta->prefail=ATTRIBUTE_FLAGS_PREFAILURE(now->flags); delta->sameraw=sameraw; return 1;}// This looks to see if the corresponding bit of the 32 bytes is set.// This wastes a few bytes of storage but eliminates all searching and// sorting functions! Entry is ZERO <==> the attribute ON. Calling// with set=0 tells you if the attrib
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -