PageRenderTime 71ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 1ms

/drivers/storage/class/disk_new/diskwmi.c

https://bitbucket.org/arty/arty-newcc-reactos
C | 3434 lines | 2062 code | 487 blank | 885 comment | 198 complexity | 2ac7dbd89e493f284519f6b87e97edd3 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-3.0, CC-BY-SA-3.0, AGPL-3.0, GPL-3.0, CPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. diskwmi.c
  5. Abstract:
  6. SCSI disk class driver - WMI support routines
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. --*/
  12. #include "disk.h"
  13. NTSTATUS
  14. DiskSendFailurePredictIoctl(
  15. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  16. PSTORAGE_PREDICT_FAILURE checkFailure
  17. );
  18. NTSTATUS
  19. DiskGetIdentifyInfo(
  20. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  21. PBOOLEAN SupportSmart
  22. );
  23. NTSTATUS
  24. DiskDetectFailurePrediction(
  25. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  26. PFAILURE_PREDICTION_METHOD FailurePredictCapability
  27. );
  28. NTSTATUS
  29. DiskReadFailurePredictThresholds(
  30. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  31. PSTORAGE_FAILURE_PREDICT_THRESHOLDS DiskSmartThresholds
  32. );
  33. NTSTATUS
  34. DiskReadSmartLog(
  35. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  36. IN UCHAR SectorCount,
  37. IN UCHAR LogAddress,
  38. OUT PUCHAR Buffer
  39. );
  40. NTSTATUS
  41. DiskWriteSmartLog(
  42. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  43. IN UCHAR SectorCount,
  44. IN UCHAR LogAddress,
  45. IN PUCHAR Buffer
  46. );
  47. void DiskReregWorker(
  48. IN PVOID Context
  49. );
  50. //
  51. // WMI reregistration globals
  52. //
  53. // Since it will take too long to do a mode sense on some drive, we
  54. // need a good way to effect the mode sense for the info exceptions
  55. // mode page so that we can determine if SMART is supported and enabled
  56. // for the drive. So the strategy is to do an asynchronous mode sense
  57. // when the device starts and then look at the info exceptions mode
  58. // page within the completion routine. Now within the completion
  59. // routine we cannot call IoWMIRegistrationControl since we are at DPC
  60. // level, so we create a stack of device objects that will be processed
  61. // by a single work item that is fired off only when the stack
  62. // transitions from empty to non empty.
  63. //
  64. WORK_QUEUE_ITEM DiskReregWorkItem;
  65. SINGLE_LIST_ENTRY DiskReregHead;
  66. KSPIN_LOCK DiskReregSpinlock;
  67. LONG DiskReregWorkItems;
  68. GUIDREGINFO DiskWmiFdoGuidList[] =
  69. {
  70. {
  71. WMI_DISK_GEOMETRY_GUID,
  72. 1,
  73. 0
  74. },
  75. {
  76. WMI_STORAGE_FAILURE_PREDICT_STATUS_GUID,
  77. 1,
  78. WMIREG_FLAG_EXPENSIVE
  79. },
  80. {
  81. WMI_STORAGE_FAILURE_PREDICT_DATA_GUID,
  82. 1,
  83. WMIREG_FLAG_EXPENSIVE
  84. },
  85. {
  86. WMI_STORAGE_FAILURE_PREDICT_FUNCTION_GUID,
  87. 1,
  88. WMIREG_FLAG_EXPENSIVE
  89. },
  90. {
  91. WMI_STORAGE_PREDICT_FAILURE_EVENT_GUID,
  92. 1,
  93. WMIREG_FLAG_EVENT_ONLY_GUID
  94. },
  95. {
  96. WMI_STORAGE_FAILURE_PREDICT_THRESHOLDS_GUID,
  97. 1,
  98. WMIREG_FLAG_EXPENSIVE
  99. },
  100. {
  101. WMI_STORAGE_SCSI_INFO_EXCEPTIONS_GUID,
  102. 1,
  103. 0
  104. },
  105. };
  106. GUID DiskPredictFailureEventGuid = WMI_STORAGE_PREDICT_FAILURE_EVENT_GUID;
  107. #define DiskGeometryGuid 0
  108. #define SmartStatusGuid 1
  109. #define SmartDataGuid 2
  110. #define SmartPerformFunction 3
  111. #define AllowDisallowPerformanceHit 1
  112. #define EnableDisableHardwareFailurePrediction 2
  113. #define EnableDisableFailurePredictionPolling 3
  114. #define GetFailurePredictionCapability 4
  115. #define EnableOfflineDiags 5
  116. #define SmartEventGuid 4
  117. #define SmartThresholdsGuid 5
  118. #define ScsiInfoExceptionsGuid 6
  119. #if 0
  120. //
  121. // Enable this to add WMI support for PDOs
  122. GUIDREGINFO DiskWmiPdoGuidList[] =
  123. {
  124. {
  125. // {25007F51-57C2-11d1-A528-00A0C9062910}
  126. { 0x25007f52, 0x57c2, 0x11d1,
  127. { 0xa5, 0x28, 0x0, 0xa0, 0xc9, 0x6, 0x29, 0x10 } },
  128. 0
  129. },
  130. };
  131. ULONG DiskDummyData[4] = { 1, 2, 3, 4};
  132. #endif
  133. #ifdef ALLOC_PRAGMA
  134. #pragma alloc_text(PAGE, DiskWmiFunctionControl)
  135. #pragma alloc_text(PAGE, DiskFdoQueryWmiRegInfo)
  136. #pragma alloc_text(PAGE, DiskFdoQueryWmiDataBlock)
  137. #pragma alloc_text(PAGE, DiskFdoSetWmiDataBlock)
  138. #pragma alloc_text(PAGE, DiskFdoSetWmiDataItem)
  139. #pragma alloc_text(PAGE, DiskFdoExecuteWmiMethod)
  140. #pragma alloc_text(PAGE, DiskDetectFailurePrediction)
  141. #pragma alloc_text(PAGE, DiskEnableDisableFailurePrediction)
  142. #pragma alloc_text(PAGE, DiskEnableDisableFailurePredictPolling)
  143. #pragma alloc_text(PAGE, DiskReadFailurePredictStatus)
  144. #pragma alloc_text(PAGE, DiskReadFailurePredictData)
  145. #pragma alloc_text(PAGE, DiskReadFailurePredictThresholds)
  146. #pragma alloc_text(PAGE, DiskGetIdentifyInfo)
  147. #pragma alloc_text(PAGE, DiskReadSmartLog)
  148. #pragma alloc_text(PAGE, DiskWriteSmartLog)
  149. #pragma alloc_text(PAGE, DiskPerformSmartCommand)
  150. #pragma alloc_text(PAGE, DiskSendFailurePredictIoctl)
  151. #pragma alloc_text(PAGE, DiskReregWorker)
  152. #pragma alloc_text(PAGE, DiskInitializeReregistration)
  153. #endif
  154. //
  155. // SMART/IDE specific routines
  156. //
  157. // Read SMART data attributes.
  158. // SrbControl should be sizeof(SRB_IO_CONTROL) +
  159. // (sizeof(SENDCMDINPARAMS)-1) +
  160. // READ_ATTRIBUTE_BUFFER_SIZE
  161. // Attribute data returned at &SendCmdOutParams->bBuffer[0]
  162. //
  163. #define DiskReadSmartData(FdoExtension, \
  164. SrbControl, \
  165. BufferSize) \
  166. DiskPerformSmartCommand(FdoExtension, \
  167. IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS, \
  168. SMART_CMD, \
  169. READ_ATTRIBUTES, \
  170. 0, \
  171. 0, \
  172. (SrbControl), \
  173. (BufferSize))
  174. //
  175. // Read SMART data thresholds.
  176. // SrbControl should be sizeof(SRB_IO_CONTROL) +
  177. // (sizeof(SENDCMDINPARAMS)-1) +
  178. // READ_THRESHOLD_BUFFER_SIZE
  179. // Attribute data returned at &SendCmdOutParams->bBuffer[0]
  180. //
  181. #define DiskReadSmartThresholds(FdoExtension, \
  182. SrbControl, \
  183. BufferSize) \
  184. DiskPerformSmartCommand(FdoExtension, \
  185. IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS, \
  186. SMART_CMD, \
  187. READ_THRESHOLDS, \
  188. 0, \
  189. 0, \
  190. (SrbControl), \
  191. (BufferSize))
  192. //
  193. // Read SMART status
  194. // SrbControl should be sizeof(SRB_IO_CONTROL) +
  195. // (sizeof(SENDCMDINPARAMS)-1) +
  196. // sizeof(IDEREGS)
  197. // Failure predicted if cmdOutParameters[3] == 0xf4 and [4] == 0x2c
  198. //
  199. #define DiskReadSmartStatus(FdoExtension, \
  200. SrbControl, \
  201. BufferSize) \
  202. DiskPerformSmartCommand(FdoExtension, \
  203. IOCTL_SCSI_MINIPORT_RETURN_STATUS, \
  204. SMART_CMD, \
  205. RETURN_SMART_STATUS, \
  206. 0, \
  207. 0, \
  208. (SrbControl), \
  209. (BufferSize))
  210. //
  211. // Read disks IDENTIFY data
  212. // SrbControl should be sizeof(SRB_IO_CONTROL) +
  213. // (sizeof(SENDCMDINPARAMS)-1) +
  214. // sizeof(IDENTIFY_BUFFER_SIZE)
  215. // Identify data returned at &cmdOutParams.bBuffer[0]
  216. //
  217. #define DiskGetIdentifyData(FdoExtension, \
  218. SrbControl, \
  219. BufferSize) \
  220. DiskPerformSmartCommand(FdoExtension, \
  221. IOCTL_SCSI_MINIPORT_IDENTIFY, \
  222. ID_CMD, \
  223. 0, \
  224. 0, \
  225. 0, \
  226. (SrbControl), \
  227. (BufferSize))
  228. //
  229. // Enable SMART
  230. //
  231. __inline NTSTATUS
  232. DiskEnableSmart(
  233. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  234. )
  235. {
  236. UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)];
  237. ULONG bufferSize = sizeof(srbControl);
  238. return DiskPerformSmartCommand(FdoExtension,
  239. IOCTL_SCSI_MINIPORT_ENABLE_SMART,
  240. SMART_CMD,
  241. ENABLE_SMART,
  242. 0,
  243. 0,
  244. (PSRB_IO_CONTROL)srbControl,
  245. &bufferSize);
  246. }
  247. //
  248. // Disable SMART
  249. //
  250. __inline NTSTATUS
  251. DiskDisableSmart(
  252. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  253. )
  254. {
  255. UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)];
  256. ULONG bufferSize = sizeof(srbControl);
  257. return DiskPerformSmartCommand(FdoExtension,
  258. IOCTL_SCSI_MINIPORT_DISABLE_SMART,
  259. SMART_CMD,
  260. DISABLE_SMART,
  261. 0,
  262. 0,
  263. (PSRB_IO_CONTROL)srbControl,
  264. &bufferSize);
  265. }
  266. //
  267. // Enable Attribute Autosave
  268. //
  269. __inline NTSTATUS
  270. DiskEnableSmartAttributeAutosave(
  271. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  272. )
  273. {
  274. UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)];
  275. ULONG bufferSize = sizeof(srbControl);
  276. return DiskPerformSmartCommand(FdoExtension,
  277. IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE,
  278. SMART_CMD,
  279. ENABLE_DISABLE_AUTOSAVE,
  280. 0xf1,
  281. 0,
  282. (PSRB_IO_CONTROL)srbControl,
  283. &bufferSize);
  284. }
  285. //
  286. // Disable Attribute Autosave
  287. //
  288. __inline NTSTATUS
  289. DiskDisableSmartAttributeAutosave(
  290. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  291. )
  292. {
  293. UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)];
  294. ULONG bufferSize = sizeof(srbControl);
  295. return DiskPerformSmartCommand(FdoExtension,
  296. IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE,
  297. SMART_CMD,
  298. ENABLE_DISABLE_AUTOSAVE,
  299. 0x00,
  300. 0,
  301. (PSRB_IO_CONTROL)srbControl,
  302. &bufferSize);
  303. }
  304. //
  305. // Initialize execution of SMART online diagnostics
  306. //
  307. __inline NTSTATUS
  308. DiskExecuteSmartDiagnostics(
  309. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  310. UCHAR Subcommand
  311. )
  312. {
  313. UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)];
  314. ULONG bufferSize = sizeof(srbControl);
  315. return DiskPerformSmartCommand(FdoExtension,
  316. IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS,
  317. SMART_CMD,
  318. EXECUTE_OFFLINE_DIAGS,
  319. 0,
  320. Subcommand,
  321. (PSRB_IO_CONTROL)srbControl,
  322. &bufferSize);
  323. }
  324. NTSTATUS
  325. DiskReadSmartLog(
  326. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  327. IN UCHAR SectorCount,
  328. IN UCHAR LogAddress,
  329. OUT PUCHAR Buffer
  330. )
  331. {
  332. PSRB_IO_CONTROL srbControl;
  333. NTSTATUS status;
  334. PSENDCMDOUTPARAMS sendCmdOutParams;
  335. ULONG logSize, bufferSize;
  336. PAGED_CODE();
  337. logSize = SectorCount * SMART_LOG_SECTOR_SIZE;
  338. bufferSize = sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1 +
  339. logSize;
  340. srbControl = ExAllocatePoolWithTag(NonPagedPool,
  341. bufferSize,
  342. DISK_TAG_SMART);
  343. if (srbControl != NULL)
  344. {
  345. status = DiskPerformSmartCommand(FdoExtension,
  346. IOCTL_SCSI_MINIPORT_READ_SMART_LOG,
  347. SMART_CMD,
  348. SMART_READ_LOG,
  349. SectorCount,
  350. LogAddress,
  351. srbControl,
  352. &bufferSize);
  353. if (NT_SUCCESS(status))
  354. {
  355. sendCmdOutParams = (PSENDCMDOUTPARAMS)((PUCHAR)srbControl +
  356. sizeof(SRB_IO_CONTROL));
  357. RtlCopyMemory(Buffer,
  358. &sendCmdOutParams->bBuffer[0],
  359. logSize);
  360. }
  361. ExFreePool(srbControl);
  362. } else {
  363. status = STATUS_INSUFFICIENT_RESOURCES;
  364. }
  365. return(status);
  366. }
  367. NTSTATUS
  368. DiskWriteSmartLog(
  369. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  370. IN UCHAR SectorCount,
  371. IN UCHAR LogAddress,
  372. IN PUCHAR Buffer
  373. )
  374. {
  375. PSRB_IO_CONTROL srbControl;
  376. NTSTATUS status;
  377. PSENDCMDINPARAMS sendCmdInParams;
  378. ULONG logSize, bufferSize;
  379. PAGED_CODE();
  380. logSize = SectorCount * SMART_LOG_SECTOR_SIZE;
  381. bufferSize = sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1 +
  382. logSize;
  383. srbControl = ExAllocatePoolWithTag(NonPagedPool,
  384. bufferSize,
  385. DISK_TAG_SMART);
  386. if (srbControl != NULL)
  387. {
  388. sendCmdInParams = (PSENDCMDINPARAMS)((PUCHAR)srbControl +
  389. sizeof(SRB_IO_CONTROL));
  390. RtlCopyMemory(&sendCmdInParams->bBuffer[0],
  391. Buffer,
  392. logSize);
  393. status = DiskPerformSmartCommand(FdoExtension,
  394. IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG,
  395. SMART_CMD,
  396. SMART_WRITE_LOG,
  397. SectorCount,
  398. LogAddress,
  399. srbControl,
  400. &bufferSize);
  401. ExFreePool(srbControl);
  402. } else {
  403. status = STATUS_INSUFFICIENT_RESOURCES;
  404. }
  405. return(status);
  406. }
  407. NTSTATUS
  408. DiskPerformSmartCommand(
  409. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  410. IN ULONG SrbControlCode,
  411. IN UCHAR Command,
  412. IN UCHAR Feature,
  413. IN UCHAR SectorCount,
  414. IN UCHAR SectorNumber,
  415. IN OUT PSRB_IO_CONTROL SrbControl,
  416. OUT PULONG BufferSize
  417. )
  418. /*++
  419. Routine Description:
  420. This routine will perform some SMART command
  421. Arguments:
  422. FdoExtension is the FDO device extension
  423. SrbControlCode is the SRB control code to use for the request
  424. Command is the SMART command to be executed. It may be SMART_CMD or
  425. ID_CMD.
  426. Feature is the value to place in the IDE feature register.
  427. SectorCount is the value to place in the IDE SectorCount register
  428. SrbControl is the buffer used to build the SRB_IO_CONTROL and pass
  429. any input parameters. It also returns the output parameters.
  430. *BufferSize on entry has total size of SrbControl and on return has
  431. the size used in SrbControl.
  432. Return Value:
  433. status
  434. --*/
  435. {
  436. PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
  437. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  438. PUCHAR buffer;
  439. PSENDCMDINPARAMS cmdInParameters;
  440. PSENDCMDOUTPARAMS cmdOutParameters;
  441. ULONG outBufferSize;
  442. NTSTATUS status;
  443. ULONG availableBufferSize;
  444. KEVENT event;
  445. PIRP irp;
  446. IO_STATUS_BLOCK ioStatus;
  447. SCSI_REQUEST_BLOCK srb;
  448. LARGE_INTEGER startingOffset;
  449. ULONG length;
  450. PIO_STACK_LOCATION irpStack;
  451. PAGED_CODE();
  452. //
  453. // Point to the 'buffer' portion of the SRB_CONTROL and compute how
  454. // much room we have left in the srb control
  455. //
  456. buffer = (PUCHAR)SrbControl;
  457. buffer += sizeof(SRB_IO_CONTROL);
  458. cmdInParameters = (PSENDCMDINPARAMS)buffer;
  459. cmdOutParameters = (PSENDCMDOUTPARAMS)buffer;
  460. availableBufferSize = *BufferSize - sizeof(SRB_IO_CONTROL);
  461. #if DBG
  462. //
  463. // Ensure control codes and buffer lengths passed are correct
  464. //
  465. {
  466. ULONG controlCode;
  467. ULONG lengthNeeded = sizeof(SENDCMDINPARAMS) - 1;
  468. if (Command == SMART_CMD)
  469. {
  470. switch (Feature)
  471. {
  472. case ENABLE_SMART:
  473. {
  474. controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
  475. break;
  476. }
  477. case DISABLE_SMART:
  478. {
  479. controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
  480. break;
  481. }
  482. case RETURN_SMART_STATUS:
  483. {
  484. //
  485. // Ensure bBuffer is at least 2 bytes (to hold the values of
  486. // cylinderLow and cylinderHigh).
  487. //
  488. lengthNeeded = sizeof(SENDCMDINPARAMS) - 1 + sizeof(IDEREGS);
  489. controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
  490. break;
  491. }
  492. case ENABLE_DISABLE_AUTOSAVE:
  493. {
  494. controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
  495. break;
  496. }
  497. case SAVE_ATTRIBUTE_VALUES:
  498. {
  499. controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
  500. break;
  501. }
  502. case EXECUTE_OFFLINE_DIAGS:
  503. {
  504. controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
  505. break;
  506. }
  507. case READ_ATTRIBUTES:
  508. {
  509. controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
  510. lengthNeeded = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS) - 1;
  511. break;
  512. }
  513. case READ_THRESHOLDS:
  514. {
  515. controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
  516. lengthNeeded = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS) - 1;
  517. break;
  518. }
  519. case SMART_READ_LOG:
  520. {
  521. controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_LOG;
  522. lengthNeeded = (SectorCount * SMART_LOG_SECTOR_SIZE) +
  523. sizeof(SENDCMDINPARAMS) - 1;
  524. break;
  525. }
  526. case SMART_WRITE_LOG:
  527. {
  528. controlCode = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG;
  529. lengthNeeded = (SectorCount * SMART_LOG_SECTOR_SIZE) +
  530. sizeof(SENDCMDINPARAMS) - 1;
  531. break;
  532. }
  533. default:
  534. controlCode = 0;
  535. break;
  536. }
  537. } else if (Command == ID_CMD) {
  538. controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
  539. lengthNeeded = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS) -1;
  540. } else {
  541. controlCode = 0;
  542. ASSERT(FALSE);
  543. }
  544. ASSERT(controlCode == SrbControlCode);
  545. ASSERT(availableBufferSize >= lengthNeeded);
  546. }
  547. #endif
  548. //
  549. // Build SrbControl and input to SMART command
  550. //
  551. SrbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
  552. RtlMoveMemory (SrbControl->Signature, "SCSIDISK", 8);
  553. SrbControl->Timeout = FdoExtension->TimeOutValue;
  554. SrbControl->Length = availableBufferSize;
  555. SrbControl->ControlCode = SrbControlCode;
  556. cmdInParameters->cBufferSize = sizeof(SENDCMDINPARAMS);
  557. cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
  558. cmdInParameters->irDriveRegs.bFeaturesReg = Feature;
  559. cmdInParameters->irDriveRegs.bSectorCountReg = SectorCount;
  560. cmdInParameters->irDriveRegs.bSectorNumberReg = SectorNumber;
  561. cmdInParameters->irDriveRegs.bCylLowReg = SMART_CYL_LOW;
  562. cmdInParameters->irDriveRegs.bCylHighReg = SMART_CYL_HI;
  563. cmdInParameters->irDriveRegs.bCommandReg = Command;
  564. //
  565. // Create and send irp
  566. //
  567. KeInitializeEvent(&event, NotificationEvent, FALSE);
  568. startingOffset.QuadPart = (LONGLONG) 1;
  569. length = SrbControl->HeaderLength + SrbControl->Length;
  570. irp = IoBuildSynchronousFsdRequest(
  571. IRP_MJ_SCSI,
  572. commonExtension->LowerDeviceObject,
  573. SrbControl,
  574. length,
  575. &startingOffset,
  576. &event,
  577. &ioStatus);
  578. if (irp == NULL) {
  579. return STATUS_INSUFFICIENT_RESOURCES;
  580. }
  581. irpStack = IoGetNextIrpStackLocation(irp);
  582. //
  583. // Set major and minor codes.
  584. //
  585. irpStack->MajorFunction = IRP_MJ_SCSI;
  586. irpStack->MinorFunction = 1;
  587. //
  588. // Fill in SRB fields.
  589. //
  590. irpStack->Parameters.Others.Argument1 = &srb;
  591. //
  592. // Zero out the srb.
  593. //
  594. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  595. srb.PathId = diskData->ScsiAddress.PathId;
  596. srb.TargetId = diskData->ScsiAddress.TargetId;
  597. srb.Lun = diskData->ScsiAddress.Lun;
  598. srb.Function = SRB_FUNCTION_IO_CONTROL;
  599. srb.Length = sizeof(SCSI_REQUEST_BLOCK);
  600. srb.SrbFlags = FdoExtension->SrbFlags;
  601. SET_FLAG(srb.SrbFlags, SRB_FLAGS_DATA_IN);
  602. SET_FLAG(srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
  603. SET_FLAG(srb.SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE);
  604. srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;
  605. srb.QueueTag = SP_UNTAGGED;
  606. srb.OriginalRequest = irp;
  607. //
  608. // Set timeout to requested value.
  609. //
  610. srb.TimeOutValue = SrbControl->Timeout;
  611. //
  612. // Set the data buffer.
  613. //
  614. srb.DataBuffer = SrbControl;
  615. srb.DataTransferLength = length;
  616. //
  617. // Flush the data buffer for output. This will insure that the data is
  618. // written back to memory. Since the data-in flag is the the port driver
  619. // will flush the data again for input which will ensure the data is not
  620. // in the cache.
  621. //
  622. KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
  623. //
  624. // Call port driver to handle this request.
  625. //
  626. status = IoCallDriver(commonExtension->LowerDeviceObject, irp);
  627. if (status == STATUS_PENDING) {
  628. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  629. status = ioStatus.Status;
  630. }
  631. return status;
  632. }
  633. NTSTATUS
  634. DiskGetIdentifyInfo(
  635. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  636. PBOOLEAN SupportSmart
  637. )
  638. {
  639. UCHAR outBuffer[sizeof(SRB_IO_CONTROL) + (sizeof(SENDCMDINPARAMS)-1) + IDENTIFY_BUFFER_SIZE];
  640. ULONG outBufferSize = sizeof(outBuffer);
  641. NTSTATUS status;
  642. PAGED_CODE();
  643. status = DiskGetIdentifyData(FdoExtension,
  644. (PSRB_IO_CONTROL)outBuffer,
  645. &outBufferSize);
  646. if (NT_SUCCESS(status))
  647. {
  648. PUSHORT identifyData = (PUSHORT)&(outBuffer[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS)-1]);
  649. USHORT commandSetSupported = identifyData[82];
  650. *SupportSmart = ((commandSetSupported != 0xffff) &&
  651. (commandSetSupported != 0) &&
  652. ((commandSetSupported & 1) == 1));
  653. } else {
  654. *SupportSmart = FALSE;
  655. }
  656. DebugPrint((3, "DiskGetIdentifyInfo: SMART %s supported for device %p, status %lx\n",
  657. *SupportSmart ? "is" : "is not",
  658. FdoExtension->DeviceObject,
  659. status));
  660. return status;
  661. }
  662. //
  663. // FP Ioctl specific routines
  664. //
  665. NTSTATUS
  666. DiskSendFailurePredictIoctl(
  667. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  668. PSTORAGE_PREDICT_FAILURE checkFailure
  669. )
  670. {
  671. KEVENT event;
  672. PDEVICE_OBJECT deviceObject;
  673. IO_STATUS_BLOCK ioStatus;
  674. PIRP irp;
  675. NTSTATUS status;
  676. PAGED_CODE();
  677. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  678. deviceObject = IoGetAttachedDeviceReference(FdoExtension->DeviceObject);
  679. irp = IoBuildDeviceIoControlRequest(
  680. IOCTL_STORAGE_PREDICT_FAILURE,
  681. deviceObject,
  682. NULL,
  683. 0,
  684. checkFailure,
  685. sizeof(STORAGE_PREDICT_FAILURE),
  686. FALSE,
  687. &event,
  688. &ioStatus);
  689. if (irp != NULL)
  690. {
  691. status = IoCallDriver(deviceObject, irp);
  692. if (status == STATUS_PENDING)
  693. {
  694. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  695. status = ioStatus.Status;
  696. }
  697. } else {
  698. status = STATUS_INSUFFICIENT_RESOURCES;
  699. }
  700. ObDereferenceObject(deviceObject);
  701. return status;
  702. }
  703. //
  704. // FP type independent routines
  705. //
  706. NTSTATUS
  707. DiskEnableDisableFailurePrediction(
  708. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  709. BOOLEAN Enable
  710. )
  711. /*++
  712. Routine Description:
  713. Enable or disable failure prediction at the hardware level
  714. Arguments:
  715. FdoExtension
  716. Enable
  717. Return Value:
  718. NT Status
  719. --*/
  720. {
  721. NTSTATUS status;
  722. PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension);
  723. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  724. PAGED_CODE();
  725. switch(diskData->FailurePredictionCapability)
  726. {
  727. case FailurePredictionSmart:
  728. {
  729. if (Enable)
  730. {
  731. status = DiskEnableSmart(FdoExtension);
  732. } else {
  733. status = DiskDisableSmart(FdoExtension);
  734. }
  735. break;
  736. }
  737. case FailurePredictionSense:
  738. case FailurePredictionIoctl:
  739. {
  740. //
  741. // We assume that the drive is already setup properly for
  742. // failure prediction
  743. //
  744. status = STATUS_SUCCESS;
  745. break;
  746. }
  747. default:
  748. {
  749. status = STATUS_INVALID_DEVICE_REQUEST;
  750. }
  751. }
  752. return status;
  753. }
  754. NTSTATUS
  755. DiskEnableDisableFailurePredictPolling(
  756. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  757. BOOLEAN Enable,
  758. ULONG PollTimeInSeconds
  759. )
  760. /*++
  761. Routine Description:
  762. Enable or disable polling for hardware failure detection
  763. Arguments:
  764. FdoExtension
  765. Enable
  766. PollTimeInSeconds - if 0 then no change to current polling timer
  767. Return Value:
  768. NT Status
  769. --*/
  770. {
  771. NTSTATUS status;
  772. PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
  773. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  774. PAGED_CODE();
  775. if (Enable)
  776. {
  777. status = DiskEnableDisableFailurePrediction(FdoExtension,
  778. Enable);
  779. } else {
  780. status = STATUS_SUCCESS;
  781. }
  782. if (NT_SUCCESS(status))
  783. {
  784. status = ClassSetFailurePredictionPoll(FdoExtension,
  785. Enable ? diskData->FailurePredictionCapability :
  786. FailurePredictionNone,
  787. PollTimeInSeconds);
  788. //
  789. // Even if this failed we do not want to disable FP on the
  790. // hardware. FP is only ever disabled on the hardware by
  791. // specific command of the user.
  792. //
  793. }
  794. return status;
  795. }
  796. NTSTATUS
  797. DiskReadFailurePredictStatus(
  798. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  799. PSTORAGE_FAILURE_PREDICT_STATUS DiskSmartStatus
  800. )
  801. /*++
  802. Routine Description:
  803. Obtains current failure prediction status
  804. Arguments:
  805. FdoExtension
  806. DiskSmartStatus
  807. Return Value:
  808. NT Status
  809. --*/
  810. {
  811. PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
  812. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  813. NTSTATUS status;
  814. PAGED_CODE();
  815. DiskSmartStatus->PredictFailure = FALSE;
  816. switch(diskData->FailurePredictionCapability)
  817. {
  818. case FailurePredictionSmart:
  819. {
  820. UCHAR outBuffer[sizeof(SRB_IO_CONTROL) + (sizeof(SENDCMDINPARAMS) - 1 + sizeof(IDEREGS))];
  821. ULONG outBufferSize = sizeof(outBuffer);
  822. PSENDCMDOUTPARAMS cmdOutParameters;
  823. status = DiskReadSmartStatus(FdoExtension,
  824. (PSRB_IO_CONTROL)outBuffer,
  825. &outBufferSize);
  826. if (NT_SUCCESS(status))
  827. {
  828. cmdOutParameters = (PSENDCMDOUTPARAMS)(outBuffer +
  829. sizeof(SRB_IO_CONTROL));
  830. DiskSmartStatus->Reason = 0; // Unknown;
  831. DiskSmartStatus->PredictFailure = ((cmdOutParameters->bBuffer[3] == 0xf4) &&
  832. (cmdOutParameters->bBuffer[4] == 0x2c));
  833. }
  834. break;
  835. }
  836. case FailurePredictionSense:
  837. {
  838. DiskSmartStatus->Reason = FdoExtension->FailureReason;
  839. DiskSmartStatus->PredictFailure = FdoExtension->FailurePredicted;
  840. status = STATUS_SUCCESS;
  841. break;
  842. }
  843. case FailurePredictionIoctl:
  844. case FailurePredictionNone:
  845. default:
  846. {
  847. status = STATUS_INVALID_DEVICE_REQUEST;
  848. break;
  849. }
  850. }
  851. return status;
  852. }
  853. NTSTATUS
  854. DiskReadFailurePredictData(
  855. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  856. PSTORAGE_FAILURE_PREDICT_DATA DiskSmartData
  857. )
  858. /*++
  859. Routine Description:
  860. Obtains current failure prediction data. Not available for
  861. FAILURE_PREDICT_SENSE types.
  862. Arguments:
  863. FdoExtension
  864. DiskSmartData
  865. Return Value:
  866. NT Status
  867. --*/
  868. {
  869. PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
  870. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  871. NTSTATUS status;
  872. PAGED_CODE();
  873. switch(diskData->FailurePredictionCapability)
  874. {
  875. case FailurePredictionSmart:
  876. {
  877. PUCHAR outBuffer;
  878. ULONG outBufferSize;
  879. PSENDCMDOUTPARAMS cmdOutParameters;
  880. outBufferSize = sizeof(SRB_IO_CONTROL) +
  881. (sizeof(SENDCMDOUTPARAMS)-1) +
  882. READ_ATTRIBUTE_BUFFER_SIZE;
  883. outBuffer = ExAllocatePoolWithTag(NonPagedPool,
  884. outBufferSize,
  885. DISK_TAG_SMART);
  886. if (outBuffer != NULL)
  887. {
  888. status = DiskReadSmartData(FdoExtension,
  889. (PSRB_IO_CONTROL)outBuffer,
  890. &outBufferSize);
  891. if (NT_SUCCESS(status))
  892. {
  893. cmdOutParameters = (PSENDCMDOUTPARAMS)(outBuffer +
  894. sizeof(SRB_IO_CONTROL));
  895. DiskSmartData->Length = READ_ATTRIBUTE_BUFFER_SIZE;
  896. RtlCopyMemory(DiskSmartData->VendorSpecific,
  897. cmdOutParameters->bBuffer,
  898. READ_ATTRIBUTE_BUFFER_SIZE);
  899. }
  900. ExFreePool(outBuffer);
  901. } else {
  902. status = STATUS_INSUFFICIENT_RESOURCES;
  903. }
  904. break;
  905. }
  906. case FailurePredictionSense:
  907. {
  908. DiskSmartData->Length = sizeof(ULONG);
  909. *((PULONG)DiskSmartData->VendorSpecific) = FdoExtension->FailureReason;
  910. status = STATUS_SUCCESS;
  911. break;
  912. }
  913. case FailurePredictionIoctl:
  914. case FailurePredictionNone:
  915. default:
  916. {
  917. status = STATUS_INVALID_DEVICE_REQUEST;
  918. break;
  919. }
  920. }
  921. return status;
  922. }
  923. NTSTATUS
  924. DiskReadFailurePredictThresholds(
  925. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  926. PSTORAGE_FAILURE_PREDICT_THRESHOLDS DiskSmartThresholds
  927. )
  928. /*++
  929. Routine Description:
  930. Obtains current failure prediction thresholds. Not available for
  931. FAILURE_PREDICT_SENSE types.
  932. Arguments:
  933. FdoExtension
  934. DiskSmartData
  935. Return Value:
  936. NT Status
  937. --*/
  938. {
  939. PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
  940. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  941. NTSTATUS status;
  942. PAGED_CODE();
  943. switch(diskData->FailurePredictionCapability)
  944. {
  945. case FailurePredictionSmart:
  946. {
  947. PUCHAR outBuffer;
  948. PSENDCMDOUTPARAMS cmdOutParameters;
  949. ULONG outBufferSize;
  950. outBufferSize = sizeof(SRB_IO_CONTROL) +
  951. (sizeof(SENDCMDOUTPARAMS)-1) +
  952. READ_THRESHOLD_BUFFER_SIZE;
  953. outBuffer = ExAllocatePoolWithTag(NonPagedPool,
  954. outBufferSize,
  955. DISK_TAG_SMART);
  956. if (outBuffer != NULL)
  957. {
  958. status = DiskReadSmartThresholds(FdoExtension,
  959. (PSRB_IO_CONTROL)outBuffer,
  960. &outBufferSize);
  961. if (NT_SUCCESS(status))
  962. {
  963. cmdOutParameters = (PSENDCMDOUTPARAMS)(outBuffer +
  964. sizeof(SRB_IO_CONTROL));
  965. RtlCopyMemory(DiskSmartThresholds->VendorSpecific,
  966. cmdOutParameters->bBuffer,
  967. READ_THRESHOLD_BUFFER_SIZE);
  968. }
  969. ExFreePool(outBuffer);
  970. } else {
  971. status = STATUS_INSUFFICIENT_RESOURCES;
  972. }
  973. break;
  974. }
  975. case FailurePredictionSense:
  976. case FailurePredictionIoctl:
  977. case FailurePredictionNone:
  978. default:
  979. {
  980. status = STATUS_INVALID_DEVICE_REQUEST;
  981. break;
  982. }
  983. }
  984. return status;
  985. }
  986. void DiskReregWorker(
  987. IN PVOID Context
  988. )
  989. {
  990. PDISKREREGREQUEST reregRequest;
  991. NTSTATUS status;
  992. PDEVICE_OBJECT deviceObject;
  993. PIRP irp;
  994. PAGED_CODE();
  995. do
  996. {
  997. reregRequest = (PDISKREREGREQUEST)ExInterlockedPopEntryList(
  998. &DiskReregHead,
  999. &DiskReregSpinlock);
  1000. deviceObject = reregRequest->DeviceObject;
  1001. irp = reregRequest->Irp;
  1002. status = IoWMIRegistrationControl(deviceObject,
  1003. WMIREG_ACTION_UPDATE_GUIDS);
  1004. if (! NT_SUCCESS(status))
  1005. {
  1006. DebugPrint((1, "DiskReregWorker: Reregistration failed %x\n",
  1007. status));
  1008. }
  1009. //
  1010. // Release remove lock and free irp, now that we are done
  1011. // processing this
  1012. //
  1013. ClassReleaseRemoveLock(deviceObject, irp);
  1014. IoFreeMdl(irp->MdlAddress);
  1015. IoFreeIrp(irp);
  1016. ExFreePool(reregRequest);
  1017. } while (InterlockedDecrement(&DiskReregWorkItems));
  1018. }
  1019. NTSTATUS DiskInitializeReregistration(
  1020. void
  1021. )
  1022. {
  1023. PAGED_CODE();
  1024. //
  1025. // Initialize the global work item and spinlock used to manage the
  1026. // list of disks reregistering their guids
  1027. //
  1028. ExInitializeWorkItem( &DiskReregWorkItem,
  1029. DiskReregWorker,
  1030. NULL );
  1031. KeInitializeSpinLock(&DiskReregSpinlock);
  1032. return(STATUS_SUCCESS);
  1033. }
  1034. NTSTATUS DiskPostReregisterRequest(
  1035. PDEVICE_OBJECT DeviceObject,
  1036. PIRP Irp
  1037. )
  1038. {
  1039. PDISKREREGREQUEST reregRequest;
  1040. NTSTATUS status;
  1041. reregRequest = ExAllocatePoolWithTag(NonPagedPool,
  1042. sizeof(DISKREREGREQUEST),
  1043. DISK_TAG_SMART);
  1044. if (reregRequest != NULL)
  1045. {
  1046. //
  1047. // add the disk that needs reregistration to the stack of disks
  1048. // to reregister. If the list is transitioning from empty to
  1049. // non empty then also kick off the work item so that the
  1050. // reregistration worker can do the reregister.
  1051. //
  1052. reregRequest->DeviceObject = DeviceObject;
  1053. reregRequest->Irp = Irp;
  1054. ExInterlockedPushEntryList(
  1055. &DiskReregHead,
  1056. &reregRequest->Next,
  1057. &DiskReregSpinlock);
  1058. if (InterlockedIncrement(&DiskReregWorkItems) == 1)
  1059. {
  1060. ExQueueWorkItem( &DiskReregWorkItem, DelayedWorkQueue );
  1061. }
  1062. status = STATUS_SUCCESS;
  1063. } else {
  1064. DebugPrint((1, "DiskPostReregisterRequest: could not allocate reregRequest for %p\n",
  1065. DeviceObject));
  1066. status = STATUS_INSUFFICIENT_RESOURCES;
  1067. }
  1068. return(status);
  1069. }
  1070. NTSTATUS DiskInfoExceptionComplete(
  1071. PDEVICE_OBJECT DeviceObject,
  1072. PIRP Irp,
  1073. PVOID Context
  1074. )
  1075. {
  1076. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  1077. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  1078. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  1079. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1080. PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
  1081. PSCSI_REQUEST_BLOCK srb = Context;
  1082. NTSTATUS status;
  1083. BOOLEAN retry;
  1084. ULONG retryInterval;
  1085. ULONG srbStatus;
  1086. BOOLEAN freeLockAndIrp = TRUE;
  1087. KIRQL oldIrql;
  1088. ASSERT(fdoExtension->CommonExtension.IsFdo);
  1089. srbStatus = SRB_STATUS(srb->SrbStatus);
  1090. //
  1091. // Check SRB status for success of completing request.
  1092. // SRB_STATUS_DATA_OVERRUN also indicates success.
  1093. //
  1094. if ((srbStatus != SRB_STATUS_SUCCESS) &&
  1095. (srbStatus != SRB_STATUS_DATA_OVERRUN))
  1096. {
  1097. DebugPrint((2, "DiskInfoExceptionComplete: IRP %p, SRB %p\n", Irp, srb));
  1098. retry = ClassInterpretSenseInfo(
  1099. DeviceObject,
  1100. srb,
  1101. irpStack->MajorFunction,
  1102. 0,
  1103. MAXIMUM_RETRIES -
  1104. ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
  1105. &status,
  1106. &retryInterval);
  1107. //
  1108. // If the status is verified required and the this request
  1109. // should bypass verify required then retry the request.
  1110. //
  1111. if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
  1112. status == STATUS_VERIFY_REQUIRED)
  1113. {
  1114. status = STATUS_IO_DEVICE_ERROR;
  1115. retry = TRUE;
  1116. }
  1117. if (retry && irpStack->Parameters.Others.Argument4)
  1118. {
  1119. irpStack->Parameters.Others.Argument4 =
  1120. (PVOID)((ULONG_PTR)irpStack->Parameters.Others.Argument4 - 1);
  1121. //
  1122. // Retry request.
  1123. //
  1124. DebugPrint((1, "DiskInfoExceptionComplete: Retry request %p\n", Irp));
  1125. ASSERT(srb->DataBuffer == MmGetMdlVirtualAddress(Irp->MdlAddress));
  1126. //
  1127. // Reset byte count of transfer in SRB Extension.
  1128. //
  1129. srb->DataTransferLength = Irp->MdlAddress->ByteCount;
  1130. //
  1131. // Zero SRB statuses.
  1132. //
  1133. srb->SrbStatus = srb->ScsiStatus = 0;
  1134. //
  1135. // Set the no disconnect flag, disable synchronous data transfers and
  1136. // disable tagged queuing. This fixes some errors.
  1137. //
  1138. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT);
  1139. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  1140. CLEAR_FLAG(srb->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
  1141. srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
  1142. srb->QueueTag = SP_UNTAGGED;
  1143. //
  1144. // Set up major SCSI function.
  1145. //
  1146. nextIrpStack->MajorFunction = IRP_MJ_SCSI;
  1147. //
  1148. // Save SRB address in next stack for port driver.
  1149. //
  1150. nextIrpStack->Parameters.Scsi.Srb = srb;
  1151. IoSetCompletionRoutine(Irp,
  1152. DiskInfoExceptionComplete,
  1153. srb,
  1154. TRUE, TRUE, TRUE);
  1155. (VOID)IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  1156. return STATUS_MORE_PROCESSING_REQUIRED;
  1157. }
  1158. } else {
  1159. //
  1160. // Get the results from the mode sense
  1161. //
  1162. PMODE_INFO_EXCEPTIONS pageData;
  1163. PMODE_PARAMETER_HEADER modeData;
  1164. ULONG modeDataLength;
  1165. modeData = srb->DataBuffer;
  1166. modeDataLength = srb->DataTransferLength;
  1167. pageData = ClassFindModePage((PUCHAR) modeData,
  1168. modeDataLength,
  1169. MODE_PAGE_FAULT_REPORTING,
  1170. TRUE);
  1171. if (pageData != NULL)
  1172. {
  1173. DebugPrint((1, "DiskInfoExceptionComplete: %p supports SMART\n",
  1174. DeviceObject));
  1175. if (pageData->Dexcpt == 0)
  1176. {
  1177. diskData->FailurePredictionCapability = FailurePredictionSense;
  1178. status = DiskPostReregisterRequest(DeviceObject, Irp);
  1179. if (NT_SUCCESS(status))
  1180. {
  1181. //
  1182. // Make sure we won't free the remove lock and the irp
  1183. // since we need to keep these until after the work
  1184. // item has completed running
  1185. //
  1186. freeLockAndIrp = FALSE;
  1187. }
  1188. } else {
  1189. DebugPrint((1, "DiskInfoExceptionComplete: %p is not enabled for SMART\n",
  1190. DeviceObject));
  1191. }
  1192. } else {
  1193. DebugPrint((1, "DiskInfoExceptionComplete: %p does not supports SMART\n",
  1194. DeviceObject));
  1195. }
  1196. //
  1197. // Set status for successful request
  1198. //
  1199. status = STATUS_SUCCESS;
  1200. } // end if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)
  1201. //
  1202. // Free the srb
  1203. //
  1204. ExFreePool(srb->SenseInfoBuffer);
  1205. ExFreePool(srb->DataBuffer);
  1206. ExFreePool(srb);
  1207. if (freeLockAndIrp)
  1208. {
  1209. //
  1210. // Set status in completing IRP.
  1211. //
  1212. Irp->IoStatus.Status = status;
  1213. //
  1214. // If pending has be returned for this irp then mark the current stack as
  1215. // pending.
  1216. //
  1217. if (Irp->PendingReturned) {
  1218. IoMarkIrpPending(Irp);
  1219. }
  1220. ClassReleaseRemoveLock(DeviceObject, Irp);
  1221. IoFreeMdl(Irp->MdlAddress);
  1222. IoFreeIrp(Irp);
  1223. }
  1224. return(STATUS_MORE_PROCESSING_REQUIRED);
  1225. }
  1226. NTSTATUS DiskInfoExceptionCheck(
  1227. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  1228. )
  1229. {
  1230. PUCHAR modeData;
  1231. PSCSI_REQUEST_BLOCK srb;
  1232. PCDB cdb;
  1233. PIRP irp;
  1234. PIO_STACK_LOCATION irpStack;
  1235. PVOID senseInfoBuffer;
  1236. ULONG isRemoved;
  1237. modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1238. MODE_DATA_SIZE,
  1239. DISK_TAG_INFO_EXCEPTION);
  1240. if (modeData == NULL)
  1241. {
  1242. DebugPrint((1, "DiskInfoExceptionCheck: Can't allocate mode data "
  1243. "buffer\n"));
  1244. return(STATUS_INSUFFICIENT_RESOURCES);
  1245. }
  1246. srb = ExAllocatePoolWithTag(NonPagedPool,
  1247. SCSI_REQUEST_BLOCK_SIZE,
  1248. DISK_TAG_SRB);
  1249. if (srb == NULL)
  1250. {
  1251. ExFreePool(modeData);
  1252. DebugPrint((1, "DiskInfoExceptionCheck: Can't allocate srb "
  1253. "buffer\n"));
  1254. return(STATUS_INSUFFICIENT_RESOURCES);
  1255. }
  1256. //
  1257. // Build the MODE SENSE CDB.
  1258. //
  1259. RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
  1260. cdb = (PCDB)srb->Cdb;
  1261. srb->CdbLength = 6;
  1262. cdb = (PCDB)srb->Cdb;
  1263. //
  1264. // Set timeout value from device extension.
  1265. //
  1266. srb->TimeOutValue = FdoExtension->TimeOutValue;
  1267. cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
  1268. cdb->MODE_SENSE.PageCode = MODE_PAGE_FAULT_REPORTING;
  1269. cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
  1270. //
  1271. // Write length to SRB.
  1272. //
  1273. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  1274. //
  1275. // Set SCSI bus address.
  1276. //
  1277. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  1278. //
  1279. // Enable auto request sense.
  1280. //
  1281. srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  1282. //
  1283. // Sense buffer is in aligned nonpaged pool.
  1284. //
  1285. senseInfoBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1286. SENSE_BUFFER_SIZE,
  1287. '7CcS');
  1288. if (senseInfoBuffer == NULL)
  1289. {
  1290. ExFreePool(srb);
  1291. ExFreePool(modeData);
  1292. DebugPrint((1, "DiskInfoExceptionCheck: Can't allocate request sense "
  1293. "buffer\n"));
  1294. return(STATUS_INSUFFICIENT_RESOURCES);
  1295. }
  1296. srb->SenseInfoBuffer = senseInfoBuffer;
  1297. srb->DataBuffer = modeData;
  1298. srb->SrbFlags = FdoExtension->SrbFlags;
  1299. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  1300. //
  1301. // Disable synchronous transfer for these requests.
  1302. //
  1303. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  1304. //
  1305. // Don't freeze the queue on an error
  1306. //
  1307. SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
  1308. srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
  1309. srb->QueueTag = SP_UNTAGGED;
  1310. //
  1311. // Build device I/O control request with METHOD_NEITHER data transfer.
  1312. // We'll queue a completion routine to cleanup the MDL's and such ourself.
  1313. //
  1314. irp = IoAllocateIrp(
  1315. (CCHAR) (FdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1),
  1316. FALSE);
  1317. if (irp == NULL)
  1318. {
  1319. ExFreePool(senseInfoBuffer);
  1320. ExFreePool(srb);
  1321. ExFreePool(modeData);
  1322. DebugPrint((1, "DiskInfoExceptionCheck: Can't allocate Irp\n"));
  1323. return(STATUS_INSUFFICIENT_RESOURCES);
  1324. }
  1325. isRemoved = ClassAcquireRemoveLock(FdoExtension->DeviceObject, irp);
  1326. if (isRemoved)
  1327. {
  1328. ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp);
  1329. IoFreeIrp(irp);
  1330. ExFreePool(senseInfoBuffer);
  1331. ExFreePool(srb);
  1332. ExFreePool(modeData);
  1333. DebugPrint((1, "DiskInfoExceptionCheck: RemoveLock says isRemoved\n"));
  1334. return(STATUS_DEVICE_DOES_NOT_EXIST);
  1335. }
  1336. //
  1337. // Get next stack location.
  1338. //
  1339. IoSetNextIrpStackLocation(irp);
  1340. irpStack = IoGetCurrentIrpStackLocation(irp);
  1341. irpStack->DeviceObject = FdoExtension->DeviceObject;
  1342. //
  1343. // Save retry count in current Irp stack.
  1344. //
  1345. irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
  1346. irpStack = IoGetNextIrpStackLocation(irp);
  1347. //
  1348. // Set up SRB for execute scsi request. Save SRB address in next stack
  1349. // for the port driver.
  1350. //
  1351. irpStack->MajorFunction = IRP_MJ_SCSI;
  1352. irpStack->Parameters.Scsi.Srb = srb;
  1353. IoSetCompletionRoutine(irp,
  1354. DiskInfoExceptionComplete,
  1355. srb,
  1356. TRUE,
  1357. TRUE,
  1358. TRUE);
  1359. irp->MdlAddress = IoAllocateMdl( modeData,
  1360. MODE_DATA_SIZE,
  1361. FALSE,
  1362. FALSE,
  1363. irp );
  1364. if (irp->MdlAddress == NULL)
  1365. {
  1366. ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp);
  1367. ExFreePool(srb);
  1368. ExFreePool(modeData);
  1369. ExFreePool(senseInfoBuffer);
  1370. IoFreeIrp( irp );
  1371. DebugPrint((1, "DiskINfoExceptionCheck: Can't allocate MDL\n"));
  1372. return STATUS_INSUFFICIENT_RESOURCES;
  1373. }
  1374. MmBuildMdlForNonPagedPool(irp->MdlAddress);
  1375. //
  1376. // Set the transfer length.
  1377. //
  1378. srb->DataTransferLength = MODE_DATA_SIZE;
  1379. //
  1380. // Zero out status.
  1381. //
  1382. srb->ScsiStatus = srb->SrbStatus = 0;
  1383. srb->NextSrb = 0;
  1384. //
  1385. // Set up IRP Address.
  1386. //
  1387. srb->OriginalRequest = irp;
  1388. //
  1389. // Call the port driver with the request and wait for it to complete.
  1390. //
  1391. IoMarkIrpPending(irp);
  1392. IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject,
  1393. irp);
  1394. return(STATUS_PENDING);
  1395. }
  1396. NTSTATUS
  1397. DiskDetectFailurePrediction(
  1398. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  1399. PFAILURE_PREDICTION_METHOD FailurePredictCapability
  1400. )
  1401. /*++
  1402. Routine Description:
  1403. Detect if device has any failure prediction capabilities. First we
  1404. check for IDE SMART capability. This is done by sending the drive an
  1405. IDENTIFY command and checking if the SMART command set bit is set.
  1406. Next we check if SCSI SMART (aka Information Exception Control Page,
  1407. X3T10/94-190 Rev 4). This is done by querying for the Information
  1408. Exception mode page.
  1409. Lastly we check if the device has IOCTL failure prediction. This mechanism
  1410. a filter driver implements IOCTL_STORAGE_PREDICT_FAILURE and will respond
  1411. with the information in the IOCTL. We do this by sending the ioctl and
  1412. if the status returned is STATUS_SUCCESS we assume that it is supported.
  1413. Arguments:
  1414. FdoExtension
  1415. *FailurePredictCapability
  1416. Return Value:
  1417. NT Status
  1418. --*/
  1419. {
  1420. PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
  1421. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  1422. BOOLEAN supportFP;
  1423. NTSTATUS status;
  1424. STORAGE_PREDICT_FAILURE checkFailure;
  1425. STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus;
  1426. BOOLEAN logErr;
  1427. PAGED_CODE();
  1428. //
  1429. // Assume no failure predict mechanisms
  1430. //
  1431. *FailurePredictCapability = FailurePredictionNone;
  1432. //
  1433. // See if this is an IDE drive that supports SMART. If so enable SMART
  1434. // and then ensure that it suports the SMART READ STATUS command
  1435. //
  1436. status = Disk

Large files files are truncated, but you can click here to view the full file