На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
[!] Как относитесь к модерированию на этом форуме? Выскажите свое мнение здесь
  
> Добраться до SMART накопителя. , Borland C++ Builder v.6.0.
    Возможно ли это на BCB6? Примеры есть? В интернете с этим туго.
      Единственный исходный код, который и был найден, и был переделан под билдер - ембаркадеровский последней версии. Был нерабочий и, как выяснилось, логически багнутый. Допилю за неделю - выложу здесь: до целого модуля разросся. Правда, только читать данные умеет.
      Сообщение отредактировано: Сергей85 -
        Родился в итоге рабочий модуль для разных семейств дисков.

        ExpandedWrap disabled
          /*
          Модуль тестировался на дисках:
          - Seagate: ST380215A, ST500DM002, ST3120213A, ST3320413AS, ST3320418AS, ST3250318AS, ST340014A;
          - Western Digital: WD5000AAKX, WD5000AADS;
          - Hitachi: HDT725032VLAT80;
          - Samsung: SP1203N, SV4012H.
          */
           
          #include "SMART.h" //Для работы со S.M.A.R.T.
          #include "WinInet.h" //Для работы с сетевыми подключениями.
           
          //Индексы атрибута S.M.A.R.T. Hitachi искажает S.M.A.R.T.: смещение Value с 3 на RAW (+2), смещение WORST с 4 на 9.
          #define INDEX_ATTRIBUTE_INDEX       0 //Идентификатор атрибута.
          #define INDEX_ATTRIBUTE_STATUSFLAGS 1 //Тип атрибута.
                                                //Второго индекса, реально, нет.
          #define INDEX_ATTRIBUTE_VALUE       3 //Текущее значение атрибута.
          #define INDEX_ATTRIBUTE_WORST       4 //Наихудшее зафиксированное значение. Погоровое значение - лежит в byteThreshold[1]. Для Hitachi - смещение по Threshold неизвестно.
          #define INDEX_ATTRIBUTE_RAW         5 //Абсолютное значение.
           
          //Типы атрибута S.M.A.R.T.
          #define PRE_FAILURE_WARRANTY        0x1 //Критический (жизненно важный).
          #define ON_LINE_COLLECTION          0x2 //Коллекция реального времени.
          #define PERFORMANCE_ATTRIBUTE       0x4 //Отражает производительность диска.
          #define ERROR_RATE_ATTRIBUTE        0x8 //Отражает частоту появления ошибок.
          #define EVENT_COUNT_ATTRIBUTE       0x10 //Счетчик событий.
          #define SELF_PRESERVING_ATTRIBUTE   0x20 //Самосохраняющийся.
           
          //Ошибки драйвера накопителя.
          #define SMART_NO_ERROR          0 //No error
          #define SMART_IDE_ERROR         1 //Error from IDE controller
          #define SMART_INVALID_FLAG      2 //Invalid command flag
          #define SMART_INVALID_COMMAND   3 //Invalid command byte
          #define SMART_INVALID_BUFFER    4 //Bad buffer (null, invalid addr..)
          #define SMART_INVALID_DRIVE     5 //Drive number not valid
          #define SMART_INVALID_IOCTL     6 //Invalid IOCTL
          #define SMART_ERROR_NO_MEM      7 //Could not lock user's buffer
          #define SMART_INVALID_REGISTER  8 //Some IDE Register not valid
          #define SMART_NOT_SUPPORTED     9 //Invalid cmd flag set
          #define SMART_NO_IDE_DEVICE     10 //Cmd issued to device not present although drive number is valid.
           
          //Для получения информации о производителе накопителя. Возможно получение и типа.
          #define IOCTL_STORAGE_QUERY_PROPERTY   CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS)
           
          DWORD g_dwBytes_Returned = 0; //Заглушка для выполнения функций.
          char g_cErrorText_Title[2] = "32";
          int g_iErrorText_Icons = 32;
           
          bool bSystem_Test(void)
          {
              int iDisk_Number = 0; //Номер накопителя.
              bool bNormal = true; //Флаг нормы теста. Лучше сразу сообщить обо всех ошибках, чтобы 100 раз не разбирать системник.
           
              //Сбор данных.
              AnsiString asDate = DateToStr(Date()); //Критический. Проверка работоспособности батареи BIOS как фактора записи корректной даты съема телеметрии, в т.ч. для печати протоколов.
              float fHDA_Temperature = fGet_SMART_Parameter(iDisk_Number, 194); //Температура железа накопителя.
              float fMechanical_Shock = fGet_SMART_Parameter(iDisk_Number, 191); //Счетчик механических ударов и внешних нагрузок.
              float fDisk_Shift = fGet_SMART_Parameter(iDisk_Number, 220); //Критический. Показатель смещения блока дисков относительно шпинделя.
              float fWrite_Error_Rate = fGet_SMART_Parameter(iDisk_Number, 200); //Количество сбойных секторов, вместо которых используется резервная область диска (программами проверки поверхности НЕ показываются.
              bool bLAN_Online = InternetGetConnectedState(&g_dwBytes_Returned, 0); //Флаг "хоть одно сетевое подключение подключено", т.е. передача данных возможна.
           
              //Параметры, отсутствующие в S.M.A.R.T. моего HDD WDC WD5000AAKX.
              float fAirflow_Temperature = fGet_SMART_Parameter(iDisk_Number, 190);
              float fHDD_Temperature = fGet_SMART_Parameter(iDisk_Number, 231);
           
              float fReallocated_Sectors_Count = fGet_SMART_Parameter(iDisk_Number, 5);
           
              if (asDate.SubString(asDate.Length()-3, 4).ToInt() < 2019)
              {
                  Application->MessageBox("Дата установлена неправильно. Возможно, разряжена батарея BIOS на системной плате (как правило, CR2032). Программа завершает работу.", g_cErrorText_Title, g_iErrorText_Icons);
                  bNormal = false;
              }
           
              if (fHDA_Temperature > 40)
              {
                  Application->MessageBox(("Температура накопителя HDD №" + IntToStr(iDisk_Number) + " выше 40 градусов ("+ FloatToStr(fHDA_Temperature) + "). Почистите пылевые фильтры и вентиляторы ЭВМ, протрите накопитель от пыли и установите температуру помещения в соответствии с ТУ.").c_str(), g_cErrorText_Title, g_iErrorText_Icons);
                  //bNormal = false;
              }
           
              if (fReallocated_Sectors_Count > 200)
              {
                  Application->MessageBox(("Параметр Reallocated Sectors Count накопителя HDD №" + IntToStr(iDisk_Number) + " выше 200 ("+ FloatToStr(fReallocated_Sectors_Count) + "). Рекомендуется неспешный поиск нового носителя под замену.").c_str(), g_cErrorText_Title, g_iErrorText_Icons);
                  //bNormal = false;
              }
           
              if (fMechanical_Shock > 0)
              {
                  Application->MessageBox(("Параметр Mechanical Shock накопителя HDD №" + IntToStr(iDisk_Number) + " выше 0 ("+ FloatToStr(fMechanical_Shock) + "). Проверьте КПА на отсутствие вибраций, не допускайте ударов накопителя и КПА при эксплуатации и перевозке.").c_str(), g_cErrorText_Title, g_iErrorText_Icons);
                  //bNormal = false;
              }
           
              if (fDisk_Shift > 0)
              {
                  Application->MessageBox(("Параметр Disk Shift накопителя HDD №" + IntToStr(iDisk_Number) + " выше 0 ("+ FloatToStr(fDisk_Shift) + "). Это означает, что произошло смещение блока дисков относительно шпинделя. Немедленно обесточьте КПА и приобретите новый носитель с целью переноса информации. С данной ошибкой диск быстро становится неработоспособным.").c_str(), g_cErrorText_Title, g_iErrorText_Icons);
                  bNormal = false;
              }
           
              if (bLAN_Online)
              {
                  Application->MessageBox("Обнаружено сетевое подключение с состоянием \"подключено\". С активным сетевым подключением работа с КПА невозможна из-за вероятности ложноотрицательных результатов.", g_cErrorText_Title, g_iErrorText_Icons);
                  bNormal = false;
              }
           
              return bNormal;
          }
           
          float fGet_SMART_Parameter(int iDisk_Number, int iParameter_Number)
          {
              //Возвращение текущего значения параметра; без порогового значения, т.к. на разных носителях они разные.
              //В случае отсутствия параметра в S.M.A.R.T. данная функция вернет -2147483648, а не -2147483647 (что за глюки в разрядах у Builder - не знаю).
              float fResult = -2147483647;
           
              bool bData_Getted = false; //Флаг успешного получения информации S.M.A.R.T.
           
              //Для получения производителя диска.
              char cQuery[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0};
              char cResult[512] = {0}; //Буфер для получения данных от DeviceIoControl.
              AnsiString asManufacturer_Disk = ""; //Строка с названием диска и его производителя.
           
              bool bWestern_Digital = false; //WDC содержит текущую температуру в RAW, а не в VALUE, - но нет флага отличия WDC от других дисков. В итоге температура на WDC отличается на +2.5 градуса, что критично.
              bool bHitachi = false; //Hitachi имеет другую структуру S.M.A.R.T. по температуре и расширенный ее съем.
              bool bSeagate = false; //Для кучи.
              bool bSamsung = false; //Для кучи.
           
              //Открытие физического диска.
              AnsiString asDrive_Path = "\\\\.\\PhysicalDrive" + IntToStr(iDisk_Number);
              HANDLE hDrive_Physical = CreateFile(asDrive_Path.c_str(),GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
              if (hDrive_Physical == INVALID_HANDLE_VALUE)
              {
                  Application->MessageBox(("Не удалось открыть накопитель HDD №" + IntToStr(iDisk_Number) + " для получения его состояния. Проверьте наличие диска в системе и не занят ли он какой-либо программой (например, Victoria).").c_str(), g_cErrorText_Title, g_iErrorText_Icons);
                  return -1;
              }
           
              //Определение производителя диска.
              bData_Getted = DeviceIoControl(hDrive_Physical, IOCTL_STORAGE_QUERY_PROPERTY, &cQuery, sizeof(cQuery), &cResult, sizeof(cResult), &g_dwBytes_Returned, NULL);
           
              if (!bData_Getted) Application->MessageBox(("Не удалось получить производителя накопителя №" + IntToStr(iDisk_Number) + ". Показания температуры в S.M.A.R.T. могут быть искажены.").c_str(), g_cErrorText_Title, g_iErrorText_Icons);
              else
              {
                  for (unsigned int iTemp=0; iTemp<g_dwBytes_Returned; iTemp++)
                  {
                      if (cResult[iTemp] != 0) asManufacturer_Disk += cResult[iTemp]; //Исключение терминаторов.
                  }
           
                  if (asManufacturer_Disk.Pos("ST") != 0) bSeagate = true; //Лучше первым: вероятность наличия "ST" в других фирмах сохраняется.
                  if (asManufacturer_Disk.Pos("WDC") != 0) bWestern_Digital = true;
                  if (asManufacturer_Disk.Pos("HDT") != 0) bHitachi = true;
                  if (asManufacturer_Disk.Pos("SP")!=0 || asManufacturer_Disk.Pos("SV")!=0) bSamsung = true;
           
                  //ShowMessage(asManufacturer_Disk);
              }
           
              //Получение информации из S.M.A.R.T.
              //Структура, посылаемая для получения данных в DeviceIoControl.
              const int iParams_To_DeviceIoControl_Size_const = sizeof(SENDCMDINPARAMS) - 1; //Количество байт данных при выполнении DeviceIoControl.
              SENDCMDINPARAMS Params_To_DeviceIoControl = {0}; //Структура, посылаемая для получения данных в DeviceIoControl.
           
              Params_To_DeviceIoControl.cBufferSize = READ_ATTRIBUTE_BUFFER_SIZE; //Размер буфера для получения атрибутов.
              Params_To_DeviceIoControl.irDriveRegs.bFeaturesReg = READ_ATTRIBUTES; //Запрос на чтение атрибутов.
              Params_To_DeviceIoControl.irDriveRegs.bSectorCountReg = 1; //Регистр количества секторов.
              Params_To_DeviceIoControl.irDriveRegs.bSectorNumberReg = 1; //Регистр номера сектора.
              Params_To_DeviceIoControl.irDriveRegs.bCylLowReg = SMART_CYL_LOW; //Младший разряд указателя на № цилиндра.
              Params_To_DeviceIoControl.irDriveRegs.bCylHighReg = SMART_CYL_HI; //Старший разряд указателя на № цилиндра.
              Params_To_DeviceIoControl.irDriveRegs.bDriveHeadReg = 0xA0|((static_cast<BYTE>(iDisk_Number)&1)<<4); //Регистр диска/головки IDE.
              Params_To_DeviceIoControl.irDriveRegs.bCommandReg = SMART_CMD; //Команда IDE.
           
              const int iParams_From_DeviceIoControl_Size_const = sizeof(SENDCMDOUTPARAMS)-1 + READ_ATTRIBUTE_BUFFER_SIZE;  //Количество байт данных при выполнении DeviceIoControl.
              SENDCMDOUTPARAMS Params_From_DeviceIoControl[iParams_From_DeviceIoControl_Size_const] = {0}; //Структура, принимающая данные из DeviceIoControl (данные).
           
              bData_Getted = DeviceIoControl(hDrive_Physical,
                                             SMART_RCV_DRIVE_DATA,
                                             &Params_To_DeviceIoControl,
                                             iParams_To_DeviceIoControl_Size_const,
                                             &Params_From_DeviceIoControl,
                                             iParams_From_DeviceIoControl_Size_const,
                                             &g_dwBytes_Returned,
                                             NULL
                                            );
           
              if (!bData_Getted)
              {
                  Application->MessageBox(("Не удалось получить текущие значения параметров S.M.A.R.T. накопителя HDD №" + IntToStr(iDisk_Number) + " для получения его состояния.").c_str(), g_cErrorText_Title, g_iErrorText_Icons);
                  CloseHandle(hDrive_Physical);
                  return -1;
              }
           
              //Получение ошибок драйвера или интерфейса.
              if (Params_From_DeviceIoControl->DriverStatus.bDriverError != 0)
              {
                  Application->MessageBox(("Обнаружена ошибка драйвера накопителя HDD №" + IntToStr(iDisk_Number) + ". Данные S.M.A.R.T. могут быть искажены.").c_str(), g_cErrorText_Title, g_iErrorText_Icons);
                  CloseHandle(hDrive_Physical);
                  return -1;
              }
           
              if (Params_From_DeviceIoControl->DriverStatus.bIDEError != 0)
              {
                  Application->MessageBox(("Обнаружена ошибка интерфейса IDE накопителя HDD №" + IntToStr(iDisk_Number) + ". Данные S.M.A.R.T. могут быть искажены.").c_str(), g_cErrorText_Title, g_iErrorText_Icons);
                  CloseHandle(hDrive_Physical);
                  return -1;
              }
           
              //Данные для получения пороговых значений параметров (подготовка).
              Params_To_DeviceIoControl.cBufferSize = READ_THRESHOLD_BUFFER_SIZE;
              Params_To_DeviceIoControl.irDriveRegs.bFeaturesReg = READ_THRESHOLDS;
           
              SENDCMDOUTPARAMS Thresholds_From_DeviceIoControl[iParams_From_DeviceIoControl_Size_const] = {0}; //Структура, принимающая данные из DeviceIoControl (пороговые значения).
           
              g_dwBytes_Returned = 0;
              bData_Getted = DeviceIoControl(hDrive_Physical,
                                             SMART_RCV_DRIVE_DATA,
                                             &Params_To_DeviceIoControl,
                                             iParams_To_DeviceIoControl_Size_const,
                                             &Thresholds_From_DeviceIoControl,
                                             iParams_From_DeviceIoControl_Size_const,
                                             &g_dwBytes_Returned,
                                             NULL
                                            );
              if (!bData_Getted)
              {
                  Application->MessageBox(("Не удалось получить пороговые значения параметров S.M.A.R.T. накопителя HDD №" + IntToStr(iDisk_Number) + " для получения его состояния.").c_str(), g_cErrorText_Title, g_iErrorText_Icons);
                  CloseHandle(hDrive_Physical);
                  return -1;
              }
           
              CloseHandle(hDrive_Physical);
           
              //Работа с полученной информацией.
              BYTE *byteAttributes = static_cast<BYTE*>(Params_From_DeviceIoControl->bBuffer); //Обычно 0x0A.
              BYTE *byteThresholds = static_cast<BYTE*>(Thresholds_From_DeviceIoControl->bBuffer); //Обычно 0x01.
           
              for (int i=0; i<54; ++i) //Кол-во параметров S.M.A.R.T. - 54.
              {
                  BYTE *byteAttribute = &byteAttributes[2+i*12];
                  BYTE *byteThreshold = &byteThresholds[2+i*12];
                  unsigned __int64 uiData = 0; //Флаг определения накопителя Hitachi, у которой смещен S.M.A.R.T. И Western Digital, у которых температура записывается не в Value, а в RAW.
           
                  if (!byteAttribute[INDEX_ATTRIBUTE_INDEX]) continue; //Пропуск пустых атрибутов.
           
                  CopyMemory(static_cast<void*>(&uiData),static_cast<void*>(&byteAttribute[INDEX_ATTRIBUTE_RAW]),sizeof(&byteAttribute[INDEX_ATTRIBUTE_RAW])); //Определение uiData для флага Hitachi.
                  if (byteAttribute[INDEX_ATTRIBUTE_INDEX] == iParameter_Number)
                  {
                      if (iParameter_Number==194 || iParameter_Number==190 || iParameter_Number==231) //Танцы с бубном с температурой. 194-й - самый приближенный к физической реальности: температура железа.
                      {
                          if (bHitachi) //Преобразование для Hitachi. uiData показывает на Seagate и WDC просто температуру. Для Hitachi предполагается показ 3 температур как сумма минимальной, текущей и максимальной.
                          {
                              fResult = byteAttribute[INDEX_ATTRIBUTE_RAW];
                              //if (iParameter_Number==194) byteAttribute[INDEX_ATTRIBUTE_RAW+2] - минимальная температура, byteAttribute[INDEX_ATTRIBUTE_RAW+4] - максимальная.
                          }
                          else if (bWestern_Digital) fResult = byteAttribute[INDEX_ATTRIBUTE_RAW];
                          else fResult = byteAttribute[INDEX_ATTRIBUTE_VALUE];
           
                          if (fResult > 80) fResult = (fResult-32) * 5/9; //Жесткие диски могут возвращать температуру и в кельвинах, и в цельсиях.
                      }
                      else fResult = byteAttribute[INDEX_ATTRIBUTE_VALUE]; //Обычный параметр с одним значением.
                      //byteAttribute[INDEX_ATTRIBUTE_WORST] - максимальное зафиксированное значение, byteThreshold[1] - пороговое. Пороговому - нет доверия.
           
                      break;
                  }
              }
           
              return fResult;
          }
        0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
        0 пользователей:


        Рейтинг@Mail.ru
        [ Script execution time: 0,0259 ]   [ 16 queries used ]   [ Generated: 20.04.24, 02:57 GMT ]