smart.h:
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237. 238. 239. 240. 241.
/****************************************************************************
* *
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY *
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE *
* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR *
* PURPOSE. *
* *
* Copyright 1993-98 Microsoft Corporation. All Rights Reserved. *
* *
****************************************************************************/
/****************************************************************************
*
* PROGRAM: SMART.H
*
* PURPOSE: Structure definitions for an application that calls SMART Ioctls
*
****************************************************************************/
#ifndef SMARTIOCTL_INCLUDED
#define SMARTIOCTL_INCLUDED
// Miscellaneous
#define MAX_IDE_DRIVES 4 // Max number of drives assuming primary/secondary, master/slave topology
#define READ_ATTRIBUTE_BUFFER_SIZE 512
#define IDENTIFY_BUFFER_SIZE 512
#define READ_THRESHOLD_BUFFER_SIZE 512
//
// IOCTL commands
//
#define DFP_GET_VERSION 0x00074080
#define DFP_SEND_DRIVE_COMMAND 0x0007c084
#define DFP_RECEIVE_DRIVE_DATA 0x0007c088
//---------------------------------------------------------------------
// GETVERSIONOUTPARAMS contains the data returned from the
// Get Driver Version function.
//---------------------------------------------------------------------
typedef struct _GETVERSIONOUTPARAMS {
BYTE bVersion; // Binary driver version.
BYTE bRevision; // Binary driver revision.
BYTE bReserved; // Not used.
BYTE bIDEDeviceMap; // Bit map of IDE devices.
DWORD fCapabilities; // Bit mask of driver capabilities.
DWORD dwReserved[ 4 ]; // For future use.
} GETVERSIONOUTPARAMS, *PGETVERSIONOUTPARAMS, *LPGETVERSIONOUTPARAMS;
//
// Bits returned in the fCapabilities member of GETVERSIONOUTPARAMS
//
#define CAP_IDE_ID_FUNCTION 1 // ATA ID command supported
#define CAP_IDE_ATAPI_ID 2 // ATAPI ID command supported
#define CAP_IDE_EXECUTE_SMART_FUNCTION 4 // SMART commannds supported
//---------------------------------------------------------------------
// IDE registers
//---------------------------------------------------------------------
typedef struct _IDEREGS {
BYTE bFeaturesReg; // Used for specifying SMART "commands".
BYTE bSectorCountReg; // IDE sector count register
BYTE bSectorNumberReg; // IDE sector number register
BYTE bCylLowReg; // IDE low order cylinder value
BYTE bCylHighReg; // IDE high order cylinder value
BYTE bDriveHeadReg; // IDE drive/head register
BYTE bCommandReg; // Actual IDE command.
BYTE bReserved; // reserved for future use. Must be zero.
} IDEREGS, *PIDEREGS, *LPIDEREGS;
//---------------------------------------------------------------------
// SENDCMDINPARAMS contains the input parameters for the
// Send Command to Drive function.
//---------------------------------------------------------------------
typedef struct _SENDCMDINPARAMS {
DWORD cBufferSize; // Buffer size in bytes
IDEREGS irDriveRegs; // Structure with drive register values.
BYTE bDriveNumber; // Physical drive number to send
// command to (0,1,2,3).
BYTE bReserved[ 3 ]; // Reserved for future expansion.
DWORD dwReserved[ 4 ]; // For future use.
BYTE bBuffer[ 1 ]; // Input buffer.
} SENDCMDINPARAMS, *PSENDCMDINPARAMS, *LPSENDCMDINPARAMS;
//
// Valid values for the bCommandReg member of IDEREGS.
//
#define IDE_ATAPI_ID 0xA1 // Returns ID sector for ATAPI.
#define IDE_ID_FUNCTION 0xEC // Returns ID sector for ATA.
#define IDE_EXECUTE_SMART_FUNCTION 0xB0 // Performs SMART cmd.
// Requires valid bFeaturesReg,
// bCylLowReg, and bCylHighReg
//
// Cylinder register values required when issuing SMART command
//
#define SMART_CYL_LOW 0x4F
#define SMART_CYL_HI 0xC2
//---------------------------------------------------------------------
// Status returned from driver
//---------------------------------------------------------------------
typedef struct _DRIVERSTATUS {
BYTE bDriverError; // Error code from driver,
// or 0 if no error.
BYTE bIDEStatus; // Contents of IDE Error register.
// Only valid when bDriverError
// is SMART_IDE_ERROR.
BYTE bReserved[ 2 ]; // Reserved for future expansion.
DWORD dwReserved[ 2 ]; // Reserved for future expansion.
} DRIVERSTATUS, *PDRIVERSTATUS, *LPDRIVERSTATUS;
//
// bDriverError values
//
#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
// 11-255 reserved
//---------------------------------------------------------------------
// Structure returned by SMART IOCTL for several commands
//---------------------------------------------------------------------
typedef struct _SENDCMDOUTPARAMS {
DWORD cBufferSize; // Size of bBuffer in bytes
DRIVERSTATUS DriverStatus; // Driver status structure.
BYTE bBuffer[ 1 ]; // Buffer of arbitrary length in which to store the data read from the // drive.
} SENDCMDOUTPARAMS, *PSENDCMDOUTPARAMS, *LPSENDCMDOUTPARAMS;
//---------------------------------------------------------------------
// Feature register defines for SMART "sub commands"
//---------------------------------------------------------------------
#define SMART_READ_ATTRIBUTE_VALUES 0xD0 // ATA4: Renamed
// SMART READ DATA
#define SMART_READ_ATTRIBUTE_THRESHOLDS 0xD1 // Obsoleted in ATA4!
#define SMART_ENABLE_DISABLE_ATTRIBUTE_AUTOSAVE 0xD2
#define SMART_SAVE_ATTRIBUTE_VALUES 0xD3
#define SMART_EXECUTE_OFFLINE_IMMEDIATE 0xD4 // ATA4
// Vendor specific commands:
#define SMART_ENABLE_SMART_OPERATIONS 0xD8
#define SMART_DISABLE_SMART_OPERATIONS 0xD9
#define SMART_RETURN_SMART_STATUS 0xDA
#endif
//---------------------------------------------------------------------
// The following structure defines the structure of a Drive Attribute
//---------------------------------------------------------------------
typedef struct _DRIVEATTRIBUTE {
BYTE bAttrID; // Identifies which attribute
WORD wStatusFlags; // see bit definitions below
BYTE bAttrValue; // Current normalized value
BYTE bWorstValue; // How bad has it ever been?
BYTE bRawValue[ 6 ]; // Un-normalized value
BYTE bReserved; // ...
} DRIVEATTRIBUTE, *PDRIVEATTRIBUTE, *LPDRIVEATTRIBUTE;
//---------------------------------------------------------------------
// The following structure defines the structure of a Warranty Threshold
// Obsoleted in ATA4!
//---------------------------------------------------------------------
typedef struct _ATTRTHRESHOLD {
BYTE bAttrID; // Identifies which attribute
BYTE bWarrantyThreshold; // Triggering value
BYTE bReserved[ 10 ]; // ...
} ATTRTHRESHOLD, *PATTRTHRESHOLD, *LPATTRTHRESHOLD;
//---------------------------------------------------------------------
// The following struct defines the interesting part of the IDENTIFY
// buffer:
//---------------------------------------------------------------------
typedef struct _IDSECTOR {
USHORT wGenConfig;
USHORT wNumCyls;
USHORT wReserved;
USHORT wNumHeads;
USHORT wBytesPerTrack;
USHORT wBytesPerSector;
USHORT wSectorsPerTrack;
USHORT wVendorUnique[ 3 ];
CHAR sSerialNumber[ 20 ];
USHORT wBufferType;
USHORT wBufferSize;
USHORT wECCSize;
CHAR sFirmwareRev[ 8 ];
CHAR sModelNumber[ 40 ];
USHORT wMoreVendorUnique;
USHORT wDoubleWordIO;
USHORT wCapabilities;
USHORT wReserved1;
USHORT wPIOTiming;
USHORT wDMATiming;
USHORT wBS;
USHORT wNumCurrentCyls;
USHORT wNumCurrentHeads;
USHORT wNumCurrentSectorsPerTrack;
ULONG ulCurrentSectorCapacity;
USHORT wMultSectorStuff;
ULONG ulTotalAddressableSectors;
USHORT wSingleWordDMA;
USHORT wMultiWordDMA;
BYTE bReserved[ 128 ];
} IDSECTOR, *PIDSECTOR;
//---------------------------------------------------------------------
// Valid Attribute IDs
//---------------------------------------------------------------------
#define ATTR_INVALID 0
#define ATTR_READ_ERROR_RATE 1
#define ATTR_THROUGHPUT_PERF 2
#define ATTR_SPIN_UP_TIME 3
#define ATTR_START_STOP_COUNT 4
#define ATTR_REALLOC_SECTOR_COUNT 5
#define ATTR_READ_CHANNEL_MARGIN 6
#define ATTR_SEEK_ERROR_RATE 7
#define ATTR_SEEK_TIME_PERF 8
#define ATTR_POWER_ON_HRS_COUNT 9
#define ATTR_SPIN_RETRY_COUNT 10
#define ATTR_CALIBRATION_RETRY_COUNT 11
#define ATTR_POWER_CYCLE_COUNT 12
//---------------------------------------------------------------------
// Status Flags Values
//---------------------------------------------------------------------
#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 NUM_ATTRIBUTE_STRUCTS 30
smartapp.h:
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31.
/****************************************************************************
* *
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY *
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE *
* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR *
* PURPOSE. *
* *
* Copyright 1993-98 Microsoft Corporation. All Rights Reserved. *
* *
****************************************************************************/
/****************************************************************************
*
* PROGRAM: SMARTAPP.H
*
* PURPOSE: Simple console application for calling SMART IOCTL's
*
****************************************************************************/
//
// FUNCTION DEFINITIONS
//
BOOL DoIDENTIFY(HANDLE, PSENDCMDINPARAMS, PSENDCMDOUTPARAMS, BYTE, BYTE, PDWORD);
BOOL DoEnableSMART(HANDLE, PSENDCMDINPARAMS, PSENDCMDOUTPARAMS, BYTE, PDWORD);
BOOL DoReadAttributesCmd(HANDLE, PSENDCMDINPARAMS, PSENDCMDOUTPARAMS, BYTE );
BOOL DoReadThresholdsCmd(HANDLE, PSENDCMDINPARAMS, PSENDCMDOUTPARAMS, BYTE );
VOID DoPrintData(PCHAR, PCHAR, BYTE);
VOID ChangeByteOrder(PCHAR, USHORT);
VOID PrintIDERegs(PSENDCMDINPARAMS);
HANDLE OpenSMART(VOID);
VOID DisplayIdInfo(PIDSECTOR, PSENDCMDINPARAMS, BYTE, BYTE, BYTE);
smartapp.c:
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. 105. 106. 107. 108. 109. 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. 122. 123. 124. 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. 165. 166. 167. 168. 169. 170. 171. 172. 173. 174. 175. 176. 177. 178. 179. 180. 181. 182. 183. 184. 185. 186. 187. 188. 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. 229. 230. 231. 232. 233. 234. 235. 236. 237. 238. 239. 240. 241. 242. 243. 244. 245. 246. 247. 248. 249. 250. 251. 252. 253. 254. 255. 256. 257. 258. 259. 260. 261. 262. 263. 264. 265. 266. 267. 268. 269. 270. 271. 272. 273. 274. 275. 276. 277. 278. 279. 280. 281. 282. 283. 284. 285. 286. 287. 288. 289. 290. 291. 292. 293. 294. 295. 296. 297. 298. 299. 300. 301. 302. 303. 304. 305. 306. 307. 308. 309. 310. 311. 312. 313. 314. 315. 316. 317. 318. 319. 320. 321. 322. 323. 324. 325. 326. 327. 328. 329. 330. 331. 332. 333. 334. 335. 336. 337. 338. 339. 340. 341. 342. 343. 344. 345. 346. 347. 348. 349. 350. 351. 352. 353. 354. 355. 356. 357. 358. 359. 360. 361. 362. 363. 364. 365. 366. 367. 368. 369. 370. 371. 372. 373. 374. 375. 376.
/****************************************************************************
* *
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY *
* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE *
* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR *
* PURPOSE. *
* *
* Copyright 1993-98 Microsoft Corporation. All Rights Reserved. *
* *
****************************************************************************/
/****************************************************************************
*
* PROGRAM: SMARTAPP.C
*
* PURPOSE: Simple console application that calls SMART IOCTL
*
* FUNCTIONS:
* main() - Console application opens SMART IOCTL which supports DeviceIoControl.
* SMART IOCTL will return values to this application through this
* same DeviceIoControl interface.
*
****************************************************************************/
// #define WINDOWS9X Define this to compile for Windows 9x
#include <stdio.h>
#include <conio.h>
#include <windows.h>
#pragma pack( 1 ) // Required to ensure correct SMART IOCTL structure setup
#include "smart.h"
#include "smartapp.h"
//
// Define global buffers.
//
BYTE AttrOutCmd[sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1 ];
BYTE ThreshOutCmd[sizeof(SENDCMDOUTPARAMS) + READ_THRESHOLD_BUFFER_SIZE - 1 ];
BYTE IdOutCmd[sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1 ];
int main()
{
HANDLE hSMARTIOCTL = 0 ;
DWORD cbBytesReturned;
GETVERSIONOUTPARAMS VersionParams;
SENDCMDINPARAMS scip;
SENDCMDOUTPARAMS OutCmd;
BYTE bDfpDriveMap = 0 ;
BYTE i;
BYTE bSuccess = 1 ;
BYTE bIDCmd; // IDE or ATAPI IDENTIFY cmd
if ((hSMARTIOCTL = OpenSMART()) != INVALID_HANDLE_VALUE) // Try to get a handle to SMART IOCTL, report failure and exit if can't.
{
memset((void*)&VersionParams, 0, sizeof(VersionParams)); // Get the version, etc of SMART IOCTL
if ( DeviceIoControl(hSMARTIOCTL, DFP_GET_VERSION,NULL,0,&VersionParams,sizeof(VersionParams),
&cbBytesReturned, NULL) )
{
printf("DFP_GET_VERSION returned:\n");
printf("\tbVersion = %d\n", VersionParams.bVersion);
printf("\tbRevision = %d\n", VersionParams.bRevision);
printf("\tfCapabilities = 0x%lx\n", VersionParams.fCapabilities);
printf("\tbReserved = 0x%x\n", VersionParams.bReserved);
printf("\tbIDEDeviceMap = 0x%x\n", VersionParams.bIDEDeviceMap);
printf("\tcbBytesReturned = %d\n\n", cbBytesReturned);
}
else
printf("DFP_GET_VERSION failed.\n");
for (i = 0; i < MAX_IDE_DRIVES; i++)
{
if (VersionParams.bIDEDeviceMap >> i & 1) // If there is a IDE device at number "i" issue commands to the device.
{
if (!(VersionParams.bIDEDeviceMap >> i & 0x10)) // Try to enable SMART so we can tell if a drive supports it. Ignore ATAPI devices.
{
memset(&scip, 0, sizeof(scip));
memset(&OutCmd, 0, sizeof(OutCmd));
if (DoEnableSMART(hSMARTIOCTL,&scip,&OutCmd,i,&cbBytesReturned))
{
printf("SMART Enabled on Drive: %d\n", i);
bDfpDriveMap |= (1 << i); // Mark the drive as SMART enabled
}
else
{
printf("SMART Enable Command Failed, Drive: %d.\n",i);
printf(" DriverStatus: bDriverError=0x%X, bIDEStatus=0x%X\n\n",
OutCmd.DriverStatus.bDriverError, OutCmd.DriverStatus.bIDEStatus);
}
printf("\tcbBytesReturned: %d\n\n", cbBytesReturned);
}
// Now, get the ID sector for all IDE devices in the system. If the device is ATAPI
// use the IDE_ATAPI_ID command, otherwise use the IDE_ID_FUNCTION command.
bIDCmd = (VersionParams.bIDEDeviceMap >> i & 0x10) ? IDE_ATAPI_ID : IDE_ID_FUNCTION;
memset(&scip, 0, sizeof(scip));
memset(IdOutCmd, 0, sizeof(IdOutCmd));
if ( DoIDENTIFY(hSMARTIOCTL, &scip, (PSENDCMDOUTPARAMS)&IdOutCmd,
bIDCmd, i, &cbBytesReturned))
DisplayIdInfo((PIDSECTOR) ((PSENDCMDOUTPARAMS)IdOutCmd)->bBuffer, &scip,
bIDCmd, bDfpDriveMap, i);
else
{
printf("Identify Command Failed on Drive: %d\n", i);
printf(" DriverStatus: bDriverError=0x%X, bIDEStatus=0x%X\n\n",
((PSENDCMDOUTPARAMS)IdOutCmd)->DriverStatus.bDriverError,
((PSENDCMDOUTPARAMS)IdOutCmd)->DriverStatus.bIDEStatus);
}
printf("\tcbBytesReturned: %d\n\n", cbBytesReturned);
}
}
// Loop through all possible IDE drives and send commands to the ones that support SMART.
for (i = 0; i < MAX_IDE_DRIVES; i++)
{
if (bDfpDriveMap >> i & 1)
{
memset(AttrOutCmd, 0, sizeof(AttrOutCmd));
memset(ThreshOutCmd, 0, sizeof(ThreshOutCmd));
if ( !(bSuccess = DoReadAttributesCmd(hSMARTIOCTL, &scip, (PSENDCMDOUTPARAMS)&AttrOutCmd, i)))
{
printf("\nSMART Read Attr Command Failed on Drive: %d.\n", i);
printf(" DriverStatus: bDriverError=0x%X, bIDEStatus=0x%X\n\n",
((PSENDCMDOUTPARAMS)AttrOutCmd)->DriverStatus.bDriverError,
((PSENDCMDOUTPARAMS)AttrOutCmd)->DriverStatus.bIDEStatus);
}
// ReadAttributes worked. Try ReadThresholds.
else if ( !(DoReadThresholdsCmd(hSMARTIOCTL, &scip, (PSENDCMDOUTPARAMS)&ThreshOutCmd, i)))
{
printf("\nSMART Read Thrsh Command Failed on Drive: %d.\n", i);
printf(" DriverStatus: bDriverError=0x%X, bIDEStatus=0x%X\n\n",
((PSENDCMDOUTPARAMS)ThreshOutCmd)->DriverStatus.bDriverError,
((PSENDCMDOUTPARAMS)ThreshOutCmd)->DriverStatus.bIDEStatus);
}
// The following report will print if ReadAttributes works. If ReadThresholds works,
// the report will also show values for Threshold values.
if (bSuccess)
DoPrintData(((PSENDCMDOUTPARAMS)AttrOutCmd)->bBuffer,
((PSENDCMDOUTPARAMS)ThreshOutCmd)->bBuffer, i);
}
}
// Close SMART.
CloseHandle(hSMARTIOCTL);
}
return(0);
}
/****************************************************************************
* DoIDENTIFY
* FUNCTION: Send an IDENTIFY command to the drive
* bDriveNum = 0-3
* bIDCmd = IDE_ID_FUNCTION or IDE_ATAPI_ID
****************************************************************************/
BOOL DoIDENTIFY(HANDLE hSMARTIOCTL, PSENDCMDINPARAMS pSCIP,
PSENDCMDOUTPARAMS pSCOP, BYTE bIDCmd, BYTE bDriveNum, PDWORD lpcbBytesReturned)
{
// Set up data structures for IDENTIFY command.
pSCIP->cBufferSize = IDENTIFY_BUFFER_SIZE;
pSCIP->irDriveRegs.bFeaturesReg = 0;
pSCIP->irDriveRegs.bSectorCountReg = 1;
pSCIP->irDriveRegs.bSectorNumberReg = 1;
pSCIP->irDriveRegs.bCylLowReg = 0;
pSCIP->irDriveRegs.bCylHighReg = 0;
pSCIP->irDriveRegs.bDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4); // Compute the drive number.
pSCIP->irDriveRegs.bCommandReg = bIDCmd; // The command can either be IDE identify or ATAPI identify.
pSCIP->bDriveNumber = bDriveNum;
pSCIP->cBufferSize = IDENTIFY_BUFFER_SIZE;
return ( DeviceIoControl(hSMARTIOCTL, DFP_RECEIVE_DRIVE_DATA,
(LPVOID)pSCIP, sizeof(SENDCMDINPARAMS) - 1,
(LPVOID)pSCOP, sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1,
lpcbBytesReturned, NULL) );
}
/****************************************************************************
* DisplayIdInfo
* Display the contents of the ID buffer
****************************************************************************/
VOID DisplayIdInfo(PIDSECTOR pids, PSENDCMDINPARAMS pSCIP, BYTE bIDCmd, BYTE bDfpDriveMap, BYTE bDriveNum)
{
BYTE szOutBuffer[41];
if (bIDCmd == IDE_ID_FUNCTION)
{
printf("Drive %d is an IDE Hard drive", bDriveNum);
printf("%s\n", ( bDfpDriveMap >> bDriveNum & 1) ? " that supports SMART" : "");
printf("\t#Cylinders: %d, #Heads: %d, #Sectors per Track: %d\n", pids->wNumCyls,
pids->wNumHeads, pids->wSectorsPerTrack);
PrintIDERegs(pSCIP);
}
else
printf("Drive %d is an ATAPI device.\n", bDriveNum);
ChangeByteOrder(pids->sModelNumber, sizeof pids->sModelNumber); // Change the WORD array to a BYTE array
memset(szOutBuffer,0, sizeof(szOutBuffer));
strncpy(szOutBuffer, pids->sModelNumber, sizeof(pids->sModelNumber));
printf("\tModel number: %s\n", szOutBuffer);
ChangeByteOrder(pids->sFirmwareRev, sizeof pids->sFirmwareRev); // Change the WORD array to a BYTE array
memset(szOutBuffer,0, sizeof(szOutBuffer));
strncpy(szOutBuffer, pids->sFirmwareRev, sizeof(pids->sFirmwareRev));
printf("\tFirmware rev: %s\n", szOutBuffer);
ChangeByteOrder(pids->sSerialNumber, sizeof pids->sSerialNumber); // Change the WORD array to a BYTE array
memset(szOutBuffer,0, sizeof(szOutBuffer));
strncpy(szOutBuffer, pids->sSerialNumber, sizeof(pids->sSerialNumber));
printf("\tSerial number: %s\n",szOutBuffer );
}
/****************************************************************************
* DoEnableSMART
* FUNCTION: Send a SMART_ENABLE_SMART_OPERATIONS command to the drive
* bDriveNum = 0-3
****************************************************************************/
BOOL DoEnableSMART(HANDLE hSMARTIOCTL, PSENDCMDINPARAMS pSCIP, PSENDCMDOUTPARAMS pSCOP, BYTE bDriveNum, PDWORD lpcbBytesReturned)
{
// Set up data structures for Enable SMART Command.
pSCIP->cBufferSize = 0;
pSCIP->irDriveRegs.bFeaturesReg = SMART_ENABLE_SMART_OPERATIONS;
pSCIP->irDriveRegs.bSectorCountReg = 1;
pSCIP->irDriveRegs.bSectorNumberReg = 1;
pSCIP->irDriveRegs.bCylLowReg = SMART_CYL_LOW;
pSCIP->irDriveRegs.bCylHighReg = SMART_CYL_HI;
pSCIP->irDriveRegs.bDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4); // Compute the drive number.
pSCIP->irDriveRegs.bCommandReg = IDE_EXECUTE_SMART_FUNCTION;
pSCIP->bDriveNumber = bDriveNum;
return ( DeviceIoControl(hSMARTIOCTL, DFP_SEND_DRIVE_COMMAND,
(LPVOID)pSCIP, sizeof(SENDCMDINPARAMS) - 1,
(LPVOID)pSCOP, sizeof(SENDCMDOUTPARAMS) - 1,
lpcbBytesReturned, NULL) );
}
/****************************************************************************
* DoReadAttributesCmd
* FUNCTION: Send a SMART_READ_ATTRIBUTE_VALUES command to the drive
* bDriveNum = 0-3
****************************************************************************/
BOOL DoReadAttributesCmd(HANDLE hSMARTIOCTL, PSENDCMDINPARAMS pSCIP, PSENDCMDOUTPARAMS pSCOP, BYTE bDriveNum)
{
DWORD cbBytesReturned;
// Set up data structures for Read Attributes SMART Command.
pSCIP->cBufferSize = READ_ATTRIBUTE_BUFFER_SIZE;
pSCIP->irDriveRegs.bFeaturesReg = SMART_READ_ATTRIBUTE_VALUES;
pSCIP->irDriveRegs.bSectorCountReg = 1;
pSCIP->irDriveRegs.bSectorNumberReg = 1;
pSCIP->irDriveRegs.bCylLowReg = SMART_CYL_LOW;
pSCIP->irDriveRegs.bCylHighReg = SMART_CYL_HI;
pSCIP->irDriveRegs.bDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4); // Compute the drive number.
pSCIP->irDriveRegs.bCommandReg = IDE_EXECUTE_SMART_FUNCTION;
pSCIP->bDriveNumber = bDriveNum;
return ( DeviceIoControl(hSMARTIOCTL, DFP_RECEIVE_DRIVE_DATA,
(LPVOID)pSCIP, sizeof(SENDCMDINPARAMS) - 1,
(LPVOID)pSCOP, sizeof(SENDCMDOUTPARAMS) + READ_ATTRIBUTE_BUFFER_SIZE - 1,
&cbBytesReturned, NULL) );
}
/****************************************************************************
* DoReadThresholdsCmd
* FUNCTION: Send a SMART_READ_ATTRIBUTE_THRESHOLDS command to the drive
* bDriveNum = 0-3
****************************************************************************/
BOOL DoReadThresholdsCmd(HANDLE hSMARTIOCTL, PSENDCMDINPARAMS pSCIP, PSENDCMDOUTPARAMS pSCOP, BYTE bDriveNum)
{
DWORD cbBytesReturned;
// Set up data structures for Read Thresholds SMART Command.
pSCIP->cBufferSize = READ_THRESHOLD_BUFFER_SIZE;
pSCIP->irDriveRegs.bFeaturesReg = SMART_READ_ATTRIBUTE_THRESHOLDS;
pSCIP->irDriveRegs.bSectorCountReg = 1;
pSCIP->irDriveRegs.bSectorNumberReg = 1;
pSCIP->irDriveRegs.bCylLowReg = SMART_CYL_LOW;
pSCIP->irDriveRegs.bCylHighReg = SMART_CYL_HI;
pSCIP->irDriveRegs.bDriveHeadReg = 0xA0 | ((bDriveNum & 1) << 4); // Compute the drive number.
pSCIP->irDriveRegs.bCommandReg = IDE_EXECUTE_SMART_FUNCTION;
pSCIP->bDriveNumber = bDriveNum;
return ( DeviceIoControl(hSMARTIOCTL, DFP_RECEIVE_DRIVE_DATA,
(LPVOID)pSCIP, sizeof(SENDCMDINPARAMS) - 1,
(LPVOID)pSCOP, sizeof(SENDCMDOUTPARAMS) + READ_THRESHOLD_BUFFER_SIZE - 1,
&cbBytesReturned, NULL) );
}
// Declare a global structure to help print the data.
// NOTE: Per ATA3 and ATA4 specs, these attribute definitions are defined by the drive vendor
// and hence their attributes may vary between vendors.
PCHAR pAttrNames[] = {
"No Attribute Here ", //0
"Raw Read Error Rate ", //1
"Throughput Performance ", //2
"Spin Up Time ", //3
"Start/Stop Count ", //4
"Reallocated Sector Count", //5
"Read Channel Margin ", //6
"Seek Error Rate ", //7
"Seek Time Performance ", //8
"Power On Hours Count ", //9
"Spin Retry Count ", //10
"Calibration Retry Count ", //11
"Power Cycle Count ", //12
"(Unknown attribute) "
};
#define MAX_KNOWN_ATTRIBUTES 12
/****************************************************************************
* DoPrintData
* FUNCTION: Display the SMART Attributes and Thresholds
****************************************************************************/
VOID DoPrintData(PCHAR pAttrBuffer, PCHAR pThrsBuffer, BYTE bDriveNum)
{
int i;
PDRIVEATTRIBUTE pDA;
PATTRTHRESHOLD pAT;
BYTE Attr;
printf("\nData for Drive Number %d\n", bDriveNum); // Print the drive number
// Print the revisions of the data structures
printf("Attribute Structure Revision Threshold Structure Revision\n");
printf(" %d %d\n\n",
(WORD)pAttrBuffer[0], (WORD)pThrsBuffer[0]);
// Print the header and loop through the structures, printing
// the structures when the attribute ID is known.
printf(" -Attribute Name- -Attribute Value- -Threshold Value-\n");
pDA = (PDRIVEATTRIBUTE)&pAttrBuffer[2];
pAT = (PATTRTHRESHOLD)&pThrsBuffer[2];
for (i = 0; i < NUM_ATTRIBUTE_STRUCTS; i++)
{
Attr = pDA->bAttrID;
if (Attr)
{
if (Attr > MAX_KNOWN_ATTRIBUTES)
Attr = MAX_KNOWN_ATTRIBUTES+1;
printf("%2X %-29s%d%20c%d\n", pDA->bAttrID, pAttrNames[Attr],
pDA->bAttrValue, ' ', pAT->bWarrantyThreshold );
}
pDA++;
pAT++;
}
}
//---------------------------------------------------------------------
VOID ChangeByteOrder(PCHAR szString, USHORT uscStrSize)
{
USHORT i;
CHAR temp;
for (i = 0 ; i < uscStrSize; i+= 2 )
{
temp = szString[i];
szString[i] = szString[i+ 1 ];
szString[i+ 1 ] = temp;
}
}
//---------------------------------------------------------------------
// Display contents of IDE hardware registers reported by SMART
//---------------------------------------------------------------------
VOID PrintIDERegs(PSENDCMDINPARAMS pscip)
{
printf("\tIDE TASK FILE REGISTERS:\n");
printf("\t\tbFeaturesReg = 0x%X\n", pscip->irDriveRegs.bFeaturesReg);
printf("\t\tbSectorCountReg = 0x%X\n", pscip->irDriveRegs.bSectorCountReg);
printf("\t\tbSectorNumberReg = 0x%X\n", pscip->irDriveRegs.bSectorNumberReg);
printf("\t\tbCylLowReg = 0x%X\n", pscip->irDriveRegs.bCylLowReg);
printf("\t\tbCylHighReg = 0x%X\n", pscip->irDriveRegs.bCylHighReg);
printf("\t\tbDriveHeadReg = 0x%X\n", pscip->irDriveRegs.bDriveHeadReg);
printf("\t\tStatus = 0x%X\n", pscip->irDriveRegs.bCommandReg);
}
//---------------------------------------------------------------------
// Open SMART to allow DeviceIoControl communications.
//---------------------------------------------------------------------
HANDLE OpenSMART(VOID)
{
HANDLE hSMARTIOCTL = 0 ;
#ifdef WINDOWS9X
// Version Windows 95 OSR2, Windows 98
if ((hSMARTIOCTL = CreateFile("\\\\.\\SMARTVSD", 0 , 0 , 0 ,CREATE_NEW, 0 , 0 )) == INVALID_HANDLE_VALUE)
printf("Unable to open SMARTVSD, error code: 0x%lX\n", GetLastError());
else
printf("SMARTVSD opened successfully\n");
#else
// Windows NT, Windows 2000
if ((hSMARTIOCTL = CreateFile("\\\\.\\PhysicalDrive0",GENERIC_READ | GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,
OPEN_EXISTING, 0 ,NULL)) == INVALID_HANDLE_VALUE)
printf("Unable to open physical drive, error code: 0x%lX\n", GetLastError());
else
printf("Physical drive opened successfully\n");
#endif
return hSMARTIOCTL;
}
|