Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3429 lines
106 KiB

  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
  48. DiskReregWorker(
  49. IN PVOID Context
  50. );
  51. //
  52. // WMI reregistration globals
  53. //
  54. // Since it will take too long to do a mode sense on some drive, we
  55. // need a good way to effect the mode sense for the info exceptions
  56. // mode page so that we can determine if SMART is supported and enabled
  57. // for the drive. So the strategy is to do an asynchronous mode sense
  58. // when the device starts and then look at the info exceptions mode
  59. // page within the completion routine. Now within the completion
  60. // routine we cannot call IoWMIRegistrationControl since we are at DPC
  61. // level, so we create a stack of device objects that will be processed
  62. // by a single work item that is fired off only when the stack
  63. // transitions from empty to non empty.
  64. //
  65. WORK_QUEUE_ITEM DiskReregWorkItem;
  66. SINGLE_LIST_ENTRY DiskReregHead;
  67. KSPIN_LOCK DiskReregSpinlock;
  68. LONG DiskReregWorkItems;
  69. GUIDREGINFO DiskWmiFdoGuidList[] =
  70. {
  71. {
  72. WMI_DISK_GEOMETRY_GUID,
  73. 1,
  74. 0
  75. },
  76. {
  77. WMI_STORAGE_FAILURE_PREDICT_STATUS_GUID,
  78. 1,
  79. WMIREG_FLAG_EXPENSIVE
  80. },
  81. {
  82. WMI_STORAGE_FAILURE_PREDICT_DATA_GUID,
  83. 1,
  84. WMIREG_FLAG_EXPENSIVE
  85. },
  86. {
  87. WMI_STORAGE_FAILURE_PREDICT_FUNCTION_GUID,
  88. 1,
  89. WMIREG_FLAG_EXPENSIVE
  90. },
  91. {
  92. WMI_STORAGE_PREDICT_FAILURE_EVENT_GUID,
  93. 1,
  94. WMIREG_FLAG_EVENT_ONLY_GUID
  95. },
  96. {
  97. WMI_STORAGE_FAILURE_PREDICT_THRESHOLDS_GUID,
  98. 1,
  99. WMIREG_FLAG_EXPENSIVE
  100. },
  101. {
  102. WMI_STORAGE_SCSI_INFO_EXCEPTIONS_GUID,
  103. 1,
  104. 0
  105. }
  106. };
  107. GUID DiskPredictFailureEventGuid = WMI_STORAGE_PREDICT_FAILURE_EVENT_GUID;
  108. #define DiskGeometryGuid 0
  109. #define SmartStatusGuid 1
  110. #define SmartDataGuid 2
  111. #define SmartPerformFunction 3
  112. #define AllowDisallowPerformanceHit 1
  113. #define EnableDisableHardwareFailurePrediction 2
  114. #define EnableDisableFailurePredictionPolling 3
  115. #define GetFailurePredictionCapability 4
  116. #define EnableOfflineDiags 5
  117. #define SmartEventGuid 4
  118. #define SmartThresholdsGuid 5
  119. #define ScsiInfoExceptionsGuid 6
  120. #if 0
  121. //
  122. // Enable this to add WMI support for PDOs
  123. GUIDREGINFO DiskWmiPdoGuidList[] =
  124. {
  125. {
  126. // {25007F51-57C2-11d1-A528-00A0C9062910}
  127. { 0x25007f52, 0x57c2, 0x11d1,
  128. { 0xa5, 0x28, 0x0, 0xa0, 0xc9, 0x6, 0x29, 0x10 } },
  129. 0
  130. },
  131. };
  132. ULONG DiskDummyData[4] = { 1, 2, 3, 4};
  133. #endif
  134. #ifdef ALLOC_PRAGMA
  135. #pragma alloc_text(PAGE, DiskWmiFunctionControl)
  136. #pragma alloc_text(PAGE, DiskFdoQueryWmiRegInfo)
  137. #pragma alloc_text(PAGE, DiskFdoQueryWmiDataBlock)
  138. #pragma alloc_text(PAGE, DiskFdoSetWmiDataBlock)
  139. #pragma alloc_text(PAGE, DiskFdoSetWmiDataItem)
  140. #pragma alloc_text(PAGE, DiskFdoExecuteWmiMethod)
  141. #pragma alloc_text(PAGE, DiskDetectFailurePrediction)
  142. #pragma alloc_text(PAGE, DiskEnableDisableFailurePrediction)
  143. #pragma alloc_text(PAGE, DiskEnableDisableFailurePredictPolling)
  144. #pragma alloc_text(PAGE, DiskReadFailurePredictStatus)
  145. #pragma alloc_text(PAGE, DiskReadFailurePredictData)
  146. #pragma alloc_text(PAGE, DiskReadFailurePredictThresholds)
  147. #pragma alloc_text(PAGE, DiskGetIdentifyInfo)
  148. #pragma alloc_text(PAGE, DiskReadSmartLog)
  149. #pragma alloc_text(PAGE, DiskWriteSmartLog)
  150. #pragma alloc_text(PAGE, DiskPerformSmartCommand)
  151. #pragma alloc_text(PAGE, DiskSendFailurePredictIoctl)
  152. #pragma alloc_text(PAGE, DiskReregWorker)
  153. #pragma alloc_text(PAGE, DiskInitializeReregistration)
  154. #endif
  155. //
  156. // Note:
  157. // Some port drivers assume that the SENDCMDINPARAMS structure will always be atleast
  158. // sizeof(SENDCMDINPARAMS). So do not adjust for the [pBuffer] if it isn't being used
  159. //
  160. //
  161. // SMART/IDE specific routines
  162. //
  163. //
  164. // Read SMART data attributes.
  165. // SrbControl should be : sizeof(SRB_IO_CONTROL) + MAX[ sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + READ_ATTRIBUTE_BUFFER_SIZE ]
  166. // Attribute data returned at &SendCmdOutParams->bBuffer[0]
  167. //
  168. #define DiskReadSmartData(FdoExtension, \
  169. SrbControl, \
  170. BufferSize) \
  171. DiskPerformSmartCommand(FdoExtension, \
  172. IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS, \
  173. SMART_CMD, \
  174. READ_ATTRIBUTES, \
  175. 0, \
  176. 0, \
  177. (SrbControl), \
  178. (BufferSize))
  179. //
  180. // Read SMART data thresholds.
  181. // SrbControl should be : sizeof(SRB_IO_CONTROL) + MAX[ sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + READ_THRESHOLD_BUFFER_SIZE ]
  182. // Attribute data returned at &SendCmdOutParams->bBuffer[0]
  183. //
  184. #define DiskReadSmartThresholds(FdoExtension, \
  185. SrbControl, \
  186. BufferSize) \
  187. DiskPerformSmartCommand(FdoExtension, \
  188. IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS, \
  189. SMART_CMD, \
  190. READ_THRESHOLDS, \
  191. 0, \
  192. 0, \
  193. (SrbControl), \
  194. (BufferSize))
  195. //
  196. // Read SMART status
  197. // SrbControl should be : sizeof(SRB_IO_CONTROL) + MAX[ sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS) ]
  198. // Failure predicted if SendCmdOutParams->bBuffer[3] == 0xf4 and SendCmdOutParams->bBuffer[4] == 0x2c
  199. //
  200. #define DiskReadSmartStatus(FdoExtension, \
  201. SrbControl, \
  202. BufferSize) \
  203. DiskPerformSmartCommand(FdoExtension, \
  204. IOCTL_SCSI_MINIPORT_RETURN_STATUS, \
  205. SMART_CMD, \
  206. RETURN_SMART_STATUS, \
  207. 0, \
  208. 0, \
  209. (SrbControl), \
  210. (BufferSize))
  211. //
  212. // Read disks IDENTIFY data
  213. // SrbControl should be : sizeof(SRB_IO_CONTROL) + MAX[ sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE ]
  214. // Identify data returned at &SendCmdOutParams->bBuffer[0]
  215. //
  216. #define DiskGetIdentifyData(FdoExtension, \
  217. SrbControl, \
  218. BufferSize) \
  219. DiskPerformSmartCommand(FdoExtension, \
  220. IOCTL_SCSI_MINIPORT_IDENTIFY, \
  221. ID_CMD, \
  222. 0, \
  223. 0, \
  224. 0, \
  225. (SrbControl), \
  226. (BufferSize))
  227. //
  228. // Enable SMART
  229. //
  230. _inline NTSTATUS
  231. DiskEnableSmart(
  232. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  233. )
  234. {
  235. UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0};
  236. ULONG bufferSize = sizeof(srbControl);
  237. return DiskPerformSmartCommand(FdoExtension,
  238. IOCTL_SCSI_MINIPORT_ENABLE_SMART,
  239. SMART_CMD,
  240. ENABLE_SMART,
  241. 0,
  242. 0,
  243. (PSRB_IO_CONTROL)srbControl,
  244. &bufferSize);
  245. }
  246. //
  247. // Disable SMART
  248. //
  249. _inline NTSTATUS
  250. DiskDisableSmart(
  251. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  252. )
  253. {
  254. UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0};
  255. ULONG bufferSize = sizeof(srbControl);
  256. return DiskPerformSmartCommand(FdoExtension,
  257. IOCTL_SCSI_MINIPORT_DISABLE_SMART,
  258. SMART_CMD,
  259. DISABLE_SMART,
  260. 0,
  261. 0,
  262. (PSRB_IO_CONTROL)srbControl,
  263. &bufferSize);
  264. }
  265. //
  266. // Enable Attribute Autosave
  267. //
  268. _inline NTSTATUS
  269. DiskEnableSmartAttributeAutosave(
  270. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  271. )
  272. {
  273. UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0};
  274. ULONG bufferSize = sizeof(srbControl);
  275. return DiskPerformSmartCommand(FdoExtension,
  276. IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE,
  277. SMART_CMD,
  278. ENABLE_DISABLE_AUTOSAVE,
  279. 0xf1,
  280. 0,
  281. (PSRB_IO_CONTROL)srbControl,
  282. &bufferSize);
  283. }
  284. //
  285. // Disable Attribute Autosave
  286. //
  287. _inline NTSTATUS
  288. DiskDisableSmartAttributeAutosave(
  289. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  290. )
  291. {
  292. UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0};
  293. ULONG bufferSize = sizeof(srbControl);
  294. return DiskPerformSmartCommand(FdoExtension,
  295. IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE,
  296. SMART_CMD,
  297. ENABLE_DISABLE_AUTOSAVE,
  298. 0x00,
  299. 0,
  300. (PSRB_IO_CONTROL)srbControl,
  301. &bufferSize);
  302. }
  303. //
  304. // Initialize execution of SMART online diagnostics
  305. //
  306. _inline NTSTATUS
  307. DiskExecuteSmartDiagnostics(
  308. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  309. UCHAR Subcommand
  310. )
  311. {
  312. UCHAR srbControl[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS)] = {0};
  313. ULONG bufferSize = sizeof(srbControl);
  314. return DiskPerformSmartCommand(FdoExtension,
  315. IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS,
  316. SMART_CMD,
  317. EXECUTE_OFFLINE_DIAGS,
  318. 0,
  319. Subcommand,
  320. (PSRB_IO_CONTROL)srbControl,
  321. &bufferSize);
  322. }
  323. NTSTATUS
  324. DiskReadSmartLog(
  325. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  326. IN UCHAR SectorCount,
  327. IN UCHAR LogAddress,
  328. OUT PUCHAR Buffer
  329. )
  330. {
  331. PSRB_IO_CONTROL srbControl;
  332. NTSTATUS status;
  333. PSENDCMDOUTPARAMS sendCmdOutParams;
  334. ULONG logSize, bufferSize;
  335. PAGED_CODE();
  336. logSize = SectorCount * SMART_LOG_SECTOR_SIZE;
  337. bufferSize = sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + logSize );
  338. srbControl = ExAllocatePoolWithTag(NonPagedPool,
  339. bufferSize,
  340. DISK_TAG_SMART);
  341. if (srbControl != NULL)
  342. {
  343. status = DiskPerformSmartCommand(FdoExtension,
  344. IOCTL_SCSI_MINIPORT_READ_SMART_LOG,
  345. SMART_CMD,
  346. SMART_READ_LOG,
  347. SectorCount,
  348. LogAddress,
  349. srbControl,
  350. &bufferSize);
  351. if (NT_SUCCESS(status))
  352. {
  353. sendCmdOutParams = (PSENDCMDOUTPARAMS)((PUCHAR)srbControl +
  354. sizeof(SRB_IO_CONTROL));
  355. RtlCopyMemory(Buffer,
  356. &sendCmdOutParams->bBuffer[0],
  357. logSize);
  358. }
  359. ExFreePool(srbControl);
  360. } else {
  361. status = STATUS_INSUFFICIENT_RESOURCES;
  362. }
  363. return(status);
  364. }
  365. NTSTATUS
  366. DiskWriteSmartLog(
  367. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  368. IN UCHAR SectorCount,
  369. IN UCHAR LogAddress,
  370. IN PUCHAR Buffer
  371. )
  372. {
  373. PSRB_IO_CONTROL srbControl;
  374. NTSTATUS status;
  375. PSENDCMDINPARAMS sendCmdInParams;
  376. ULONG logSize, bufferSize;
  377. PAGED_CODE();
  378. logSize = SectorCount * SMART_LOG_SECTOR_SIZE;
  379. bufferSize = sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1 +
  380. logSize;
  381. srbControl = ExAllocatePoolWithTag(NonPagedPool,
  382. bufferSize,
  383. DISK_TAG_SMART);
  384. if (srbControl != NULL)
  385. {
  386. sendCmdInParams = (PSENDCMDINPARAMS)((PUCHAR)srbControl +
  387. sizeof(SRB_IO_CONTROL));
  388. RtlCopyMemory(&sendCmdInParams->bBuffer[0],
  389. Buffer,
  390. logSize);
  391. status = DiskPerformSmartCommand(FdoExtension,
  392. IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG,
  393. SMART_CMD,
  394. SMART_WRITE_LOG,
  395. SectorCount,
  396. LogAddress,
  397. srbControl,
  398. &bufferSize);
  399. ExFreePool(srbControl);
  400. } else {
  401. status = STATUS_INSUFFICIENT_RESOURCES;
  402. }
  403. return(status);
  404. }
  405. NTSTATUS
  406. DiskPerformSmartCommand(
  407. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  408. IN ULONG SrbControlCode,
  409. IN UCHAR Command,
  410. IN UCHAR Feature,
  411. IN UCHAR SectorCount,
  412. IN UCHAR SectorNumber,
  413. IN OUT PSRB_IO_CONTROL SrbControl,
  414. OUT PULONG BufferSize
  415. )
  416. /*++
  417. Routine Description:
  418. This routine will perform some SMART command
  419. Arguments:
  420. FdoExtension is the FDO device extension
  421. SrbControlCode is the SRB control code to use for the request
  422. Command is the SMART command to be executed. It may be SMART_CMD or
  423. ID_CMD.
  424. Feature is the value to place in the IDE feature register.
  425. SectorCount is the value to place in the IDE SectorCount register
  426. SrbControl is the buffer used to build the SRB_IO_CONTROL and pass
  427. any input parameters. It also returns the output parameters.
  428. *BufferSize on entry has total size of SrbControl and on return has
  429. the size used in SrbControl.
  430. Return Value:
  431. status
  432. --*/
  433. {
  434. PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
  435. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  436. PUCHAR buffer;
  437. PSENDCMDINPARAMS cmdInParameters;
  438. PSENDCMDOUTPARAMS cmdOutParameters;
  439. ULONG outBufferSize;
  440. NTSTATUS status;
  441. ULONG availableBufferSize;
  442. KEVENT event;
  443. PIRP irp;
  444. IO_STATUS_BLOCK ioStatus = { 0 };
  445. SCSI_REQUEST_BLOCK srb = {0};
  446. LARGE_INTEGER startingOffset;
  447. ULONG length;
  448. PIO_STACK_LOCATION irpStack;
  449. PAGED_CODE();
  450. //
  451. // Point to the 'buffer' portion of the SRB_CONTROL and compute how
  452. // much room we have left in the srb control
  453. //
  454. buffer = (PUCHAR)SrbControl;
  455. (ULONG_PTR)buffer += sizeof(SRB_IO_CONTROL);
  456. cmdInParameters = (PSENDCMDINPARAMS)buffer;
  457. cmdOutParameters = (PSENDCMDOUTPARAMS)buffer;
  458. availableBufferSize = *BufferSize - sizeof(SRB_IO_CONTROL);
  459. #if DBG
  460. //
  461. // Ensure control codes and buffer lengths passed are correct
  462. //
  463. {
  464. ULONG controlCode = 0;
  465. ULONG lengthNeeded = sizeof(SENDCMDINPARAMS);
  466. if (Command == SMART_CMD)
  467. {
  468. switch (Feature)
  469. {
  470. case ENABLE_SMART:
  471. {
  472. controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
  473. break;
  474. }
  475. case DISABLE_SMART:
  476. {
  477. controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
  478. break;
  479. }
  480. case RETURN_SMART_STATUS:
  481. {
  482. controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
  483. lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS) );
  484. break;
  485. }
  486. case ENABLE_DISABLE_AUTOSAVE:
  487. {
  488. controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
  489. break;
  490. }
  491. case SAVE_ATTRIBUTE_VALUES:
  492. {
  493. controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
  494. break;
  495. }
  496. case EXECUTE_OFFLINE_DIAGS:
  497. {
  498. controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
  499. break;
  500. }
  501. case READ_ATTRIBUTES:
  502. {
  503. controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
  504. lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + READ_ATTRIBUTE_BUFFER_SIZE );
  505. break;
  506. }
  507. case READ_THRESHOLDS:
  508. {
  509. controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
  510. lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + READ_THRESHOLD_BUFFER_SIZE );
  511. break;
  512. }
  513. case SMART_READ_LOG:
  514. {
  515. controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_LOG;
  516. lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + (SectorCount * SMART_LOG_SECTOR_SIZE) );
  517. break;
  518. }
  519. case SMART_WRITE_LOG:
  520. {
  521. controlCode = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG;
  522. lengthNeeded = lengthNeeded - 1 + (SectorCount * SMART_LOG_SECTOR_SIZE);
  523. break;
  524. }
  525. }
  526. } else if (Command == ID_CMD) {
  527. controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
  528. lengthNeeded = max( lengthNeeded, sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE );
  529. } else {
  530. ASSERT(FALSE);
  531. }
  532. ASSERT(controlCode == SrbControlCode);
  533. ASSERT(availableBufferSize >= lengthNeeded);
  534. }
  535. #endif
  536. //
  537. // Build SrbControl and input to SMART command
  538. //
  539. SrbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
  540. RtlMoveMemory (SrbControl->Signature, "SCSIDISK", 8);
  541. SrbControl->Timeout = FdoExtension->TimeOutValue;
  542. SrbControl->Length = availableBufferSize;
  543. SrbControl->ControlCode = SrbControlCode;
  544. cmdInParameters->cBufferSize = sizeof(SENDCMDINPARAMS);
  545. cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
  546. cmdInParameters->irDriveRegs.bFeaturesReg = Feature;
  547. cmdInParameters->irDriveRegs.bSectorCountReg = SectorCount;
  548. cmdInParameters->irDriveRegs.bSectorNumberReg = SectorNumber;
  549. cmdInParameters->irDriveRegs.bCylLowReg = SMART_CYL_LOW;
  550. cmdInParameters->irDriveRegs.bCylHighReg = SMART_CYL_HI;
  551. cmdInParameters->irDriveRegs.bCommandReg = Command;
  552. //
  553. // Create and send irp
  554. //
  555. KeInitializeEvent(&event, NotificationEvent, FALSE);
  556. startingOffset.QuadPart = (LONGLONG) 1;
  557. length = SrbControl->HeaderLength + SrbControl->Length;
  558. irp = IoBuildSynchronousFsdRequest(
  559. IRP_MJ_SCSI,
  560. commonExtension->LowerDeviceObject,
  561. SrbControl,
  562. length,
  563. &startingOffset,
  564. &event,
  565. &ioStatus);
  566. if (irp == NULL) {
  567. return STATUS_INSUFFICIENT_RESOURCES;
  568. }
  569. irpStack = IoGetNextIrpStackLocation(irp);
  570. //
  571. // Set major and minor codes.
  572. //
  573. irpStack->MajorFunction = IRP_MJ_SCSI;
  574. irpStack->MinorFunction = 1;
  575. //
  576. // Fill in SRB fields.
  577. //
  578. irpStack->Parameters.Others.Argument1 = &srb;
  579. srb.PathId = diskData->ScsiAddress.PathId;
  580. srb.TargetId = diskData->ScsiAddress.TargetId;
  581. srb.Lun = diskData->ScsiAddress.Lun;
  582. srb.Function = SRB_FUNCTION_IO_CONTROL;
  583. srb.Length = sizeof(SCSI_REQUEST_BLOCK);
  584. srb.SrbFlags = FdoExtension->SrbFlags;
  585. SET_FLAG(srb.SrbFlags, SRB_FLAGS_DATA_IN);
  586. SET_FLAG(srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
  587. SET_FLAG(srb.SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE);
  588. srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;
  589. srb.QueueTag = SP_UNTAGGED;
  590. srb.OriginalRequest = irp;
  591. //
  592. // Set timeout to requested value.
  593. //
  594. srb.TimeOutValue = SrbControl->Timeout;
  595. //
  596. // Set the data buffer.
  597. //
  598. srb.DataBuffer = SrbControl;
  599. srb.DataTransferLength = length;
  600. //
  601. // Flush the data buffer for output. This will insure that the data is
  602. // written back to memory. Since the data-in flag is the the port driver
  603. // will flush the data again for input which will ensure the data is not
  604. // in the cache.
  605. //
  606. KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
  607. //
  608. // Call port driver to handle this request.
  609. //
  610. status = IoCallDriver(commonExtension->LowerDeviceObject, irp);
  611. if (status == STATUS_PENDING) {
  612. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  613. status = ioStatus.Status;
  614. }
  615. return status;
  616. }
  617. NTSTATUS
  618. DiskGetIdentifyInfo(
  619. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  620. PBOOLEAN SupportSmart
  621. )
  622. {
  623. UCHAR outBuffer[sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + IDENTIFY_BUFFER_SIZE )] = {0};
  624. ULONG outBufferSize = sizeof(outBuffer);
  625. NTSTATUS status;
  626. PAGED_CODE();
  627. status = DiskGetIdentifyData(FdoExtension,
  628. (PSRB_IO_CONTROL)outBuffer,
  629. &outBufferSize);
  630. if (NT_SUCCESS(status))
  631. {
  632. PUSHORT identifyData = (PUSHORT)&(outBuffer[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS) - 1]);
  633. USHORT commandSetSupported = identifyData[82];
  634. *SupportSmart = ((commandSetSupported != 0xffff) &&
  635. (commandSetSupported != 0) &&
  636. ((commandSetSupported & 1) == 1));
  637. } else {
  638. *SupportSmart = FALSE;
  639. }
  640. DebugPrint((3, "DiskGetIdentifyInfo: SMART %s supported for device %p, status %lx\n",
  641. *SupportSmart ? "is" : "is not",
  642. FdoExtension->DeviceObject,
  643. status));
  644. return status;
  645. }
  646. //
  647. // FP Ioctl specific routines
  648. //
  649. NTSTATUS
  650. DiskSendFailurePredictIoctl(
  651. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  652. PSTORAGE_PREDICT_FAILURE checkFailure
  653. )
  654. {
  655. KEVENT event;
  656. PDEVICE_OBJECT deviceObject;
  657. IO_STATUS_BLOCK ioStatus = { 0 };
  658. PIRP irp;
  659. NTSTATUS status;
  660. PAGED_CODE();
  661. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  662. deviceObject = IoGetAttachedDeviceReference(FdoExtension->DeviceObject);
  663. irp = IoBuildDeviceIoControlRequest(
  664. IOCTL_STORAGE_PREDICT_FAILURE,
  665. deviceObject,
  666. NULL,
  667. 0,
  668. checkFailure,
  669. sizeof(STORAGE_PREDICT_FAILURE),
  670. FALSE,
  671. &event,
  672. &ioStatus);
  673. if (irp != NULL)
  674. {
  675. status = IoCallDriver(deviceObject, irp);
  676. if (status == STATUS_PENDING)
  677. {
  678. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  679. status = ioStatus.Status;
  680. }
  681. } else {
  682. status = STATUS_INSUFFICIENT_RESOURCES;
  683. }
  684. ObDereferenceObject(deviceObject);
  685. return status;
  686. }
  687. //
  688. // FP type independent routines
  689. //
  690. NTSTATUS
  691. DiskEnableDisableFailurePrediction(
  692. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  693. BOOLEAN Enable
  694. )
  695. /*++
  696. Routine Description:
  697. Enable or disable failure prediction at the hardware level
  698. Arguments:
  699. FdoExtension
  700. Enable
  701. Return Value:
  702. NT Status
  703. --*/
  704. {
  705. NTSTATUS status;
  706. PCOMMON_DEVICE_EXTENSION commonExtension = &(FdoExtension->CommonExtension);
  707. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  708. PAGED_CODE();
  709. switch(diskData->FailurePredictionCapability)
  710. {
  711. case FailurePredictionSmart:
  712. {
  713. if (Enable)
  714. {
  715. status = DiskEnableSmart(FdoExtension);
  716. } else {
  717. status = DiskDisableSmart(FdoExtension);
  718. }
  719. break;
  720. }
  721. case FailurePredictionSense:
  722. case FailurePredictionIoctl:
  723. {
  724. //
  725. // We assume that the drive is already setup properly for
  726. // failure prediction
  727. //
  728. status = STATUS_SUCCESS;
  729. break;
  730. }
  731. default:
  732. {
  733. status = STATUS_INVALID_DEVICE_REQUEST;
  734. }
  735. }
  736. return status;
  737. }
  738. NTSTATUS
  739. DiskEnableDisableFailurePredictPolling(
  740. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  741. BOOLEAN Enable,
  742. ULONG PollTimeInSeconds
  743. )
  744. /*++
  745. Routine Description:
  746. Enable or disable polling for hardware failure detection
  747. Arguments:
  748. FdoExtension
  749. Enable
  750. PollTimeInSeconds - if 0 then no change to current polling timer
  751. Return Value:
  752. NT Status
  753. --*/
  754. {
  755. NTSTATUS status;
  756. PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
  757. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  758. PAGED_CODE();
  759. if (Enable)
  760. {
  761. status = DiskEnableDisableFailurePrediction(FdoExtension,
  762. Enable);
  763. } else {
  764. status = STATUS_SUCCESS;
  765. }
  766. if (NT_SUCCESS(status))
  767. {
  768. status = ClassSetFailurePredictionPoll(FdoExtension,
  769. Enable ? diskData->FailurePredictionCapability :
  770. FailurePredictionNone,
  771. PollTimeInSeconds);
  772. //
  773. // Even if this failed we do not want to disable FP on the
  774. // hardware. FP is only ever disabled on the hardware by
  775. // specific command of the user.
  776. //
  777. }
  778. return status;
  779. }
  780. NTSTATUS
  781. DiskReadFailurePredictStatus(
  782. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  783. PSTORAGE_FAILURE_PREDICT_STATUS DiskSmartStatus
  784. )
  785. /*++
  786. Routine Description:
  787. Obtains current failure prediction status
  788. Arguments:
  789. FdoExtension
  790. DiskSmartStatus
  791. Return Value:
  792. NT Status
  793. --*/
  794. {
  795. PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
  796. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  797. NTSTATUS status;
  798. PAGED_CODE();
  799. DiskSmartStatus->PredictFailure = FALSE;
  800. switch(diskData->FailurePredictionCapability)
  801. {
  802. case FailurePredictionSmart:
  803. {
  804. UCHAR outBuffer[sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + sizeof(IDEREGS) )] = {0};
  805. ULONG outBufferSize = sizeof(outBuffer);
  806. PSENDCMDOUTPARAMS cmdOutParameters;
  807. status = DiskReadSmartStatus(FdoExtension,
  808. (PSRB_IO_CONTROL)outBuffer,
  809. &outBufferSize);
  810. if (NT_SUCCESS(status))
  811. {
  812. cmdOutParameters = (PSENDCMDOUTPARAMS)(outBuffer +
  813. sizeof(SRB_IO_CONTROL));
  814. DiskSmartStatus->Reason = 0; // Unknown;
  815. DiskSmartStatus->PredictFailure = ((cmdOutParameters->bBuffer[3] == 0xf4) &&
  816. (cmdOutParameters->bBuffer[4] == 0x2c));
  817. }
  818. break;
  819. }
  820. case FailurePredictionSense:
  821. {
  822. DiskSmartStatus->Reason = FdoExtension->FailureReason;
  823. DiskSmartStatus->PredictFailure = FdoExtension->FailurePredicted;
  824. status = STATUS_SUCCESS;
  825. break;
  826. }
  827. case FailurePredictionIoctl:
  828. case FailurePredictionNone:
  829. default:
  830. {
  831. status = STATUS_INVALID_DEVICE_REQUEST;
  832. break;
  833. }
  834. }
  835. return status;
  836. }
  837. NTSTATUS
  838. DiskReadFailurePredictData(
  839. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  840. PSTORAGE_FAILURE_PREDICT_DATA DiskSmartData
  841. )
  842. /*++
  843. Routine Description:
  844. Obtains current failure prediction data. Not available for
  845. FAILURE_PREDICT_SENSE types.
  846. Arguments:
  847. FdoExtension
  848. DiskSmartData
  849. Return Value:
  850. NT Status
  851. --*/
  852. {
  853. PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
  854. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  855. NTSTATUS status;
  856. PAGED_CODE();
  857. switch(diskData->FailurePredictionCapability)
  858. {
  859. case FailurePredictionSmart:
  860. {
  861. PUCHAR outBuffer;
  862. ULONG outBufferSize;
  863. PSENDCMDOUTPARAMS cmdOutParameters;
  864. outBufferSize = sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + READ_ATTRIBUTE_BUFFER_SIZE );
  865. outBuffer = ExAllocatePoolWithTag(NonPagedPool,
  866. outBufferSize,
  867. DISK_TAG_SMART);
  868. if (outBuffer != NULL)
  869. {
  870. status = DiskReadSmartData(FdoExtension,
  871. (PSRB_IO_CONTROL)outBuffer,
  872. &outBufferSize);
  873. if (NT_SUCCESS(status))
  874. {
  875. cmdOutParameters = (PSENDCMDOUTPARAMS)(outBuffer +
  876. sizeof(SRB_IO_CONTROL));
  877. DiskSmartData->Length = READ_ATTRIBUTE_BUFFER_SIZE;
  878. RtlCopyMemory(DiskSmartData->VendorSpecific,
  879. cmdOutParameters->bBuffer,
  880. min(READ_ATTRIBUTE_BUFFER_SIZE, sizeof(DiskSmartData->VendorSpecific)));
  881. }
  882. ExFreePool(outBuffer);
  883. } else {
  884. status = STATUS_INSUFFICIENT_RESOURCES;
  885. }
  886. break;
  887. }
  888. case FailurePredictionSense:
  889. {
  890. DiskSmartData->Length = sizeof(ULONG);
  891. *((PULONG)DiskSmartData->VendorSpecific) = FdoExtension->FailureReason;
  892. status = STATUS_SUCCESS;
  893. break;
  894. }
  895. case FailurePredictionIoctl:
  896. case FailurePredictionNone:
  897. default:
  898. {
  899. status = STATUS_INVALID_DEVICE_REQUEST;
  900. break;
  901. }
  902. }
  903. return status;
  904. }
  905. NTSTATUS
  906. DiskReadFailurePredictThresholds(
  907. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  908. PSTORAGE_FAILURE_PREDICT_THRESHOLDS DiskSmartThresholds
  909. )
  910. /*++
  911. Routine Description:
  912. Obtains current failure prediction thresholds. Not available for
  913. FAILURE_PREDICT_SENSE types.
  914. Arguments:
  915. FdoExtension
  916. DiskSmartData
  917. Return Value:
  918. NT Status
  919. --*/
  920. {
  921. PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
  922. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  923. NTSTATUS status;
  924. PAGED_CODE();
  925. switch(diskData->FailurePredictionCapability)
  926. {
  927. case FailurePredictionSmart:
  928. {
  929. PUCHAR outBuffer;
  930. PSENDCMDOUTPARAMS cmdOutParameters;
  931. ULONG outBufferSize;
  932. outBufferSize = sizeof(SRB_IO_CONTROL) + max( sizeof(SENDCMDINPARAMS), sizeof(SENDCMDOUTPARAMS) - 1 + READ_THRESHOLD_BUFFER_SIZE );
  933. outBuffer = ExAllocatePoolWithTag(NonPagedPool,
  934. outBufferSize,
  935. DISK_TAG_SMART);
  936. if (outBuffer != NULL)
  937. {
  938. status = DiskReadSmartThresholds(FdoExtension,
  939. (PSRB_IO_CONTROL)outBuffer,
  940. &outBufferSize);
  941. if (NT_SUCCESS(status))
  942. {
  943. cmdOutParameters = (PSENDCMDOUTPARAMS)(outBuffer +
  944. sizeof(SRB_IO_CONTROL));
  945. RtlCopyMemory(DiskSmartThresholds->VendorSpecific,
  946. cmdOutParameters->bBuffer,
  947. min(READ_THRESHOLD_BUFFER_SIZE, sizeof(DiskSmartThresholds->VendorSpecific)));
  948. }
  949. ExFreePool(outBuffer);
  950. } else {
  951. status = STATUS_INSUFFICIENT_RESOURCES;
  952. }
  953. break;
  954. }
  955. case FailurePredictionSense:
  956. case FailurePredictionIoctl:
  957. case FailurePredictionNone:
  958. default:
  959. {
  960. status = STATUS_INVALID_DEVICE_REQUEST;
  961. break;
  962. }
  963. }
  964. return status;
  965. }
  966. VOID
  967. DiskReregWorker(
  968. IN PVOID Context
  969. )
  970. {
  971. PDISKREREGREQUEST reregRequest;
  972. NTSTATUS status;
  973. PDEVICE_OBJECT deviceObject;
  974. PIRP irp;
  975. PAGED_CODE();
  976. do
  977. {
  978. reregRequest = (PDISKREREGREQUEST)ExInterlockedPopEntryList(
  979. &DiskReregHead,
  980. &DiskReregSpinlock);
  981. deviceObject = reregRequest->DeviceObject;
  982. irp = reregRequest->Irp;
  983. status = IoWMIRegistrationControl(deviceObject,
  984. WMIREG_ACTION_UPDATE_GUIDS);
  985. if (!NT_SUCCESS(status))
  986. {
  987. DebugPrint((1, "DiskReregWorker: Reregistration failed %x\n",
  988. status));
  989. }
  990. //
  991. // Release remove lock and free irp, now that we are done
  992. // processing this
  993. //
  994. ClassReleaseRemoveLock(deviceObject, irp);
  995. IoFreeMdl(irp->MdlAddress);
  996. IoFreeIrp(irp);
  997. ExFreePool(reregRequest);
  998. } while (InterlockedDecrement(&DiskReregWorkItems));
  999. }
  1000. NTSTATUS
  1001. DiskInitializeReregistration(
  1002. VOID
  1003. )
  1004. {
  1005. PAGED_CODE();
  1006. //
  1007. // Initialize the global work item and spinlock used to manage the
  1008. // list of disks reregistering their guids
  1009. //
  1010. ExInitializeWorkItem( &DiskReregWorkItem,
  1011. DiskReregWorker,
  1012. NULL );
  1013. KeInitializeSpinLock(&DiskReregSpinlock);
  1014. return(STATUS_SUCCESS);
  1015. }
  1016. NTSTATUS
  1017. DiskPostReregisterRequest(
  1018. PDEVICE_OBJECT DeviceObject,
  1019. PIRP Irp
  1020. )
  1021. {
  1022. PDISKREREGREQUEST reregRequest;
  1023. NTSTATUS status;
  1024. reregRequest = ExAllocatePoolWithTag(NonPagedPool,
  1025. sizeof(DISKREREGREQUEST),
  1026. DISK_TAG_SMART);
  1027. if (reregRequest != NULL)
  1028. {
  1029. //
  1030. // add the disk that needs reregistration to the stack of disks
  1031. // to reregister. If the list is transitioning from empty to
  1032. // non empty then also kick off the work item so that the
  1033. // reregistration worker can do the reregister.
  1034. //
  1035. reregRequest->DeviceObject = DeviceObject;
  1036. reregRequest->Irp = Irp;
  1037. ExInterlockedPushEntryList(
  1038. &DiskReregHead,
  1039. &reregRequest->Next,
  1040. &DiskReregSpinlock);
  1041. if (InterlockedIncrement(&DiskReregWorkItems) == 1)
  1042. {
  1043. ExQueueWorkItem( &DiskReregWorkItem, DelayedWorkQueue );
  1044. }
  1045. status = STATUS_SUCCESS;
  1046. } else {
  1047. DebugPrint((1, "DiskPostReregisterRequest: could not allocate reregRequest for %p\n",
  1048. DeviceObject));
  1049. status = STATUS_INSUFFICIENT_RESOURCES;
  1050. }
  1051. return(status);
  1052. }
  1053. NTSTATUS
  1054. DiskInfoExceptionComplete(
  1055. PDEVICE_OBJECT DeviceObject,
  1056. PIRP Irp,
  1057. PVOID Context
  1058. )
  1059. {
  1060. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  1061. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  1062. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  1063. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1064. PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
  1065. PSCSI_REQUEST_BLOCK srb = Context;
  1066. NTSTATUS status;
  1067. BOOLEAN retry;
  1068. ULONG retryInterval;
  1069. ULONG srbStatus;
  1070. BOOLEAN freeLockAndIrp = TRUE;
  1071. KIRQL oldIrql;
  1072. ASSERT(fdoExtension->CommonExtension.IsFdo);
  1073. srbStatus = SRB_STATUS(srb->SrbStatus);
  1074. //
  1075. // Check SRB status for success of completing request.
  1076. // SRB_STATUS_DATA_OVERRUN also indicates success.
  1077. //
  1078. if ((srbStatus != SRB_STATUS_SUCCESS) &&
  1079. (srbStatus != SRB_STATUS_DATA_OVERRUN))
  1080. {
  1081. DebugPrint((2, "DiskInfoExceptionComplete: IRP %p, SRB %p\n", Irp, srb));
  1082. if (TEST_FLAG(srb->SrbStatus, SRB_STATUS_QUEUE_FROZEN))
  1083. {
  1084. ClassReleaseQueue(DeviceObject);
  1085. }
  1086. retry = ClassInterpretSenseInfo(
  1087. DeviceObject,
  1088. srb,
  1089. irpStack->MajorFunction,
  1090. 0,
  1091. MAXIMUM_RETRIES -
  1092. ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
  1093. &status,
  1094. &retryInterval);
  1095. //
  1096. // If the status is verified required and the this request
  1097. // should bypass verify required then retry the request.
  1098. //
  1099. if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
  1100. status == STATUS_VERIFY_REQUIRED)
  1101. {
  1102. status = STATUS_IO_DEVICE_ERROR;
  1103. retry = TRUE;
  1104. }
  1105. if (retry && ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4)--)
  1106. {
  1107. //
  1108. // Retry request.
  1109. //
  1110. DebugPrint((1, "DiskInfoExceptionComplete: Retry request %p\n", Irp));
  1111. ASSERT(srb->DataBuffer == MmGetMdlVirtualAddress(Irp->MdlAddress));
  1112. //
  1113. // Reset byte count of transfer in SRB Extension.
  1114. //
  1115. srb->DataTransferLength = Irp->MdlAddress->ByteCount;
  1116. //
  1117. // Zero SRB statuses.
  1118. //
  1119. srb->SrbStatus = srb->ScsiStatus = 0;
  1120. //
  1121. // Set the no disconnect flag, disable synchronous data transfers and
  1122. // disable tagged queuing. This fixes some errors.
  1123. //
  1124. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT);
  1125. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  1126. CLEAR_FLAG(srb->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
  1127. srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
  1128. srb->QueueTag = SP_UNTAGGED;
  1129. //
  1130. // Set up major SCSI function.
  1131. //
  1132. nextIrpStack->MajorFunction = IRP_MJ_SCSI;
  1133. //
  1134. // Save SRB address in next stack for port driver.
  1135. //
  1136. nextIrpStack->Parameters.Scsi.Srb = srb;
  1137. IoSetCompletionRoutine(Irp,
  1138. DiskInfoExceptionComplete,
  1139. srb,
  1140. TRUE, TRUE, TRUE);
  1141. (VOID)IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  1142. return STATUS_MORE_PROCESSING_REQUIRED;
  1143. }
  1144. } else {
  1145. //
  1146. // Get the results from the mode sense
  1147. //
  1148. PMODE_INFO_EXCEPTIONS pageData;
  1149. PMODE_PARAMETER_HEADER modeData;
  1150. ULONG modeDataLength;
  1151. modeData = srb->DataBuffer;
  1152. modeDataLength = srb->DataTransferLength;
  1153. pageData = ClassFindModePage((PUCHAR) modeData,
  1154. modeDataLength,
  1155. MODE_PAGE_FAULT_REPORTING,
  1156. TRUE);
  1157. if (pageData != NULL)
  1158. {
  1159. DebugPrint((1, "DiskInfoExceptionComplete: %p supports SMART\n",
  1160. DeviceObject));
  1161. if (pageData->Dexcpt == 0)
  1162. {
  1163. diskData->FailurePredictionCapability = FailurePredictionSense;
  1164. status = DiskPostReregisterRequest(DeviceObject, Irp);
  1165. if (NT_SUCCESS(status))
  1166. {
  1167. //
  1168. // Make sure we won't free the remove lock and the irp
  1169. // since we need to keep these until after the work
  1170. // item has completed running
  1171. //
  1172. freeLockAndIrp = FALSE;
  1173. }
  1174. } else {
  1175. DebugPrint((1, "DiskInfoExceptionComplete: %p is not enabled for SMART\n",
  1176. DeviceObject));
  1177. }
  1178. } else {
  1179. DebugPrint((1, "DiskInfoExceptionComplete: %p does not supports SMART\n",
  1180. DeviceObject));
  1181. }
  1182. //
  1183. // Set status for successful request
  1184. //
  1185. status = STATUS_SUCCESS;
  1186. } // end if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)
  1187. //
  1188. // Free the srb
  1189. //
  1190. ExFreePool(srb->SenseInfoBuffer);
  1191. ExFreePool(srb->DataBuffer);
  1192. ExFreePool(srb);
  1193. if (freeLockAndIrp)
  1194. {
  1195. //
  1196. // Set status in completing IRP.
  1197. //
  1198. Irp->IoStatus.Status = status;
  1199. //
  1200. // If pending has be returned for this irp then mark the current stack as
  1201. // pending.
  1202. //
  1203. if (Irp->PendingReturned) {
  1204. IoMarkIrpPending(Irp);
  1205. }
  1206. ClassReleaseRemoveLock(DeviceObject, Irp);
  1207. IoFreeMdl(Irp->MdlAddress);
  1208. IoFreeIrp(Irp);
  1209. }
  1210. return(STATUS_MORE_PROCESSING_REQUIRED);
  1211. }
  1212. NTSTATUS
  1213. DiskInfoExceptionCheck(
  1214. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  1215. )
  1216. {
  1217. PUCHAR modeData;
  1218. PSCSI_REQUEST_BLOCK srb;
  1219. PCDB cdb;
  1220. PIRP irp;
  1221. PIO_STACK_LOCATION irpStack;
  1222. PVOID senseInfoBuffer;
  1223. ULONG isRemoved;
  1224. modeData = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1225. MODE_DATA_SIZE,
  1226. DISK_TAG_INFO_EXCEPTION);
  1227. if (modeData == NULL)
  1228. {
  1229. DebugPrint((1, "DiskInfoExceptionCheck: Can't allocate mode data "
  1230. "buffer\n"));
  1231. return(STATUS_INSUFFICIENT_RESOURCES);
  1232. }
  1233. srb = ExAllocatePoolWithTag(NonPagedPool,
  1234. SCSI_REQUEST_BLOCK_SIZE,
  1235. DISK_TAG_SRB);
  1236. if (srb == NULL)
  1237. {
  1238. ExFreePool(modeData);
  1239. DebugPrint((1, "DiskInfoExceptionCheck: Can't allocate srb "
  1240. "buffer\n"));
  1241. return(STATUS_INSUFFICIENT_RESOURCES);
  1242. }
  1243. //
  1244. // Build the MODE SENSE CDB.
  1245. //
  1246. RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
  1247. cdb = (PCDB)srb->Cdb;
  1248. srb->CdbLength = 6;
  1249. cdb = (PCDB)srb->Cdb;
  1250. //
  1251. // Set timeout value from device extension.
  1252. //
  1253. srb->TimeOutValue = FdoExtension->TimeOutValue;
  1254. cdb->MODE_SENSE.OperationCode = SCSIOP_MODE_SENSE;
  1255. cdb->MODE_SENSE.PageCode = MODE_PAGE_FAULT_REPORTING;
  1256. cdb->MODE_SENSE.AllocationLength = MODE_DATA_SIZE;
  1257. //
  1258. // Write length to SRB.
  1259. //
  1260. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  1261. //
  1262. // Set SCSI bus address.
  1263. //
  1264. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  1265. //
  1266. // Enable auto request sense.
  1267. //
  1268. srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  1269. //
  1270. // Sense buffer is in aligned nonpaged pool.
  1271. //
  1272. senseInfoBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  1273. SENSE_BUFFER_SIZE,
  1274. '7CcS');
  1275. if (senseInfoBuffer == NULL)
  1276. {
  1277. ExFreePool(srb);
  1278. ExFreePool(modeData);
  1279. DebugPrint((1, "DiskInfoExceptionCheck: Can't allocate request sense "
  1280. "buffer\n"));
  1281. return(STATUS_INSUFFICIENT_RESOURCES);
  1282. }
  1283. srb->SenseInfoBuffer = senseInfoBuffer;
  1284. srb->DataBuffer = modeData;
  1285. srb->SrbFlags = FdoExtension->SrbFlags;
  1286. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  1287. //
  1288. // Disable synchronous transfer for these requests.
  1289. //
  1290. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  1291. //
  1292. // Don't freeze the queue on an error
  1293. //
  1294. SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
  1295. srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
  1296. srb->QueueTag = SP_UNTAGGED;
  1297. //
  1298. // Build device I/O control request with METHOD_NEITHER data transfer.
  1299. // We'll queue a completion routine to cleanup the MDL's and such ourself.
  1300. //
  1301. irp = IoAllocateIrp(
  1302. (CCHAR) (FdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1),
  1303. FALSE);
  1304. if (irp == NULL)
  1305. {
  1306. ExFreePool(senseInfoBuffer);
  1307. ExFreePool(srb);
  1308. ExFreePool(modeData);
  1309. DebugPrint((1, "DiskInfoExceptionCheck: Can't allocate Irp\n"));
  1310. return(STATUS_INSUFFICIENT_RESOURCES);
  1311. }
  1312. isRemoved = ClassAcquireRemoveLock(FdoExtension->DeviceObject, irp);
  1313. if (isRemoved)
  1314. {
  1315. ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp);
  1316. IoFreeIrp(irp);
  1317. ExFreePool(senseInfoBuffer);
  1318. ExFreePool(srb);
  1319. ExFreePool(modeData);
  1320. DebugPrint((1, "DiskInfoExceptionCheck: RemoveLock says isRemoved\n"));
  1321. return(STATUS_DEVICE_DOES_NOT_EXIST);
  1322. }
  1323. //
  1324. // Get next stack location.
  1325. //
  1326. IoSetNextIrpStackLocation(irp);
  1327. irpStack = IoGetCurrentIrpStackLocation(irp);
  1328. irpStack->DeviceObject = FdoExtension->DeviceObject;
  1329. //
  1330. // Save retry count in current Irp stack.
  1331. //
  1332. irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
  1333. irpStack = IoGetNextIrpStackLocation(irp);
  1334. //
  1335. // Set up SRB for execute scsi request. Save SRB address in next stack
  1336. // for the port driver.
  1337. //
  1338. irpStack->MajorFunction = IRP_MJ_SCSI;
  1339. irpStack->Parameters.Scsi.Srb = srb;
  1340. IoSetCompletionRoutine(irp,
  1341. DiskInfoExceptionComplete,
  1342. srb,
  1343. TRUE,
  1344. TRUE,
  1345. TRUE);
  1346. irp->MdlAddress = IoAllocateMdl( modeData,
  1347. MODE_DATA_SIZE,
  1348. FALSE,
  1349. FALSE,
  1350. irp );
  1351. if (irp->MdlAddress == NULL)
  1352. {
  1353. ClassReleaseRemoveLock(FdoExtension->DeviceObject, irp);
  1354. ExFreePool(srb);
  1355. ExFreePool(modeData);
  1356. ExFreePool(senseInfoBuffer);
  1357. IoFreeIrp( irp );
  1358. DebugPrint((1, "DiskINfoExceptionCheck: Can't allocate MDL\n"));
  1359. return STATUS_INSUFFICIENT_RESOURCES;
  1360. }
  1361. MmBuildMdlForNonPagedPool(irp->MdlAddress);
  1362. //
  1363. // Set the transfer length.
  1364. //
  1365. srb->DataTransferLength = MODE_DATA_SIZE;
  1366. //
  1367. // Zero out status.
  1368. //
  1369. srb->ScsiStatus = srb->SrbStatus = 0;
  1370. srb->NextSrb = 0;
  1371. //
  1372. // Set up IRP Address.
  1373. //
  1374. srb->OriginalRequest = irp;
  1375. //
  1376. // Call the port driver with the request and wait for it to complete.
  1377. //
  1378. IoMarkIrpPending(irp);
  1379. IoCallDriver(FdoExtension->CommonExtension.LowerDeviceObject,
  1380. irp);
  1381. return(STATUS_PENDING);
  1382. }
  1383. NTSTATUS
  1384. DiskDetectFailurePrediction(
  1385. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  1386. PFAILURE_PREDICTION_METHOD FailurePredictCapability
  1387. )
  1388. /*++
  1389. Routine Description:
  1390. Detect if device has any failure prediction capabilities. First we
  1391. check for IDE SMART capability. This is done by sending the drive an
  1392. IDENTIFY command and checking if the SMART command set bit is set.
  1393. Next we check if SCSI SMART (aka Information Exception Control Page,
  1394. X3T10/94-190 Rev 4). This is done by querying for the Information
  1395. Exception mode page.
  1396. Lastly we check if the device has IOCTL failure prediction. This mechanism
  1397. a filter driver implements IOCTL_STORAGE_PREDICT_FAILURE and will respond
  1398. with the information in the IOCTL. We do this by sending the ioctl and
  1399. if the status returned is STATUS_SUCCESS we assume that it is supported.
  1400. Arguments:
  1401. FdoExtension
  1402. *FailurePredictCapability
  1403. Return Value:
  1404. NT Status
  1405. --*/
  1406. {
  1407. PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
  1408. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  1409. BOOLEAN supportFP;
  1410. NTSTATUS status;
  1411. STORAGE_PREDICT_FAILURE checkFailure;
  1412. STORAGE_FAILURE_PREDICT_STATUS diskSmartStatus;
  1413. BOOLEAN logErr;
  1414. PAGED_CODE();
  1415. //
  1416. // Assume no failure predict mechanisms
  1417. //
  1418. *FailurePredictCapability = FailurePredictionNone;
  1419. //
  1420. // See if this is an IDE drive that supports SMART. If so enable SMART
  1421. // and then ensure that it suports the SMART READ STATUS command
  1422. //
  1423. status = DiskGetIdentifyInfo(FdoExtension,
  1424. &supportFP);
  1425. if (supportFP)
  1426. {
  1427. status = DiskEnableSmart(FdoExtension);
  1428. if (NT_SUCCESS(status))
  1429. {
  1430. *FailurePredictCapability = FailurePredictionSmart;
  1431. status = DiskReadFailurePredictStatus(FdoExtension,
  1432. &diskSmartStatus);
  1433. DebugPrint((1, "Disk: Device %p %s IDE SMART\n",
  1434. FdoExtension->DeviceObject,
  1435. NT_SUCCESS(status) ? "does" : "does not"));
  1436. if (!NT_SUCCESS(status))
  1437. {
  1438. *FailurePredictCapability = FailurePredictionNone;
  1439. }
  1440. }
  1441. return(status);
  1442. }
  1443. //
  1444. // See if there is a a filter driver to intercept
  1445. // IOCTL_STORAGE_PREDICT_FAILURE
  1446. //
  1447. status = DiskSendFailurePredictIoctl(FdoExtension,
  1448. &checkFailure);
  1449. DebugPrint((1, "Disk: Device %p %s IOCTL_STORAGE_FAILURE_PREDICT\n",
  1450. FdoExtension->DeviceObject,
  1451. NT_SUCCESS(status) ? "does" : "does not"));
  1452. if (NT_SUCCESS(status))
  1453. {
  1454. *FailurePredictCapability = FailurePredictionIoctl;
  1455. if (checkFailure.PredictFailure)
  1456. {
  1457. checkFailure.PredictFailure = 512;
  1458. ClassNotifyFailurePredicted(FdoExtension,
  1459. (PUCHAR)&checkFailure,
  1460. sizeof(checkFailure),
  1461. (BOOLEAN)(FdoExtension->FailurePredicted == FALSE),
  1462. 0x11,
  1463. diskData->ScsiAddress.PathId,
  1464. diskData->ScsiAddress.TargetId,
  1465. diskData->ScsiAddress.Lun);
  1466. FdoExtension->FailurePredicted = TRUE;
  1467. }
  1468. return(status);
  1469. }
  1470. //
  1471. // Finally we assume it will not be a scsi smart drive. but
  1472. // we'll also send off an asynchronous mode sense so that if
  1473. // it is SMART we'll reregister the device object
  1474. //
  1475. DiskInfoExceptionCheck(FdoExtension);
  1476. *FailurePredictCapability = FailurePredictionNone;
  1477. return(STATUS_SUCCESS);
  1478. }
  1479. NTSTATUS
  1480. DiskWmiFunctionControl(
  1481. IN PDEVICE_OBJECT DeviceObject,
  1482. IN PIRP Irp,
  1483. IN ULONG GuidIndex,
  1484. IN CLASSENABLEDISABLEFUNCTION Function,
  1485. IN BOOLEAN Enable
  1486. )
  1487. /*++
  1488. Routine Description:
  1489. This routine is a callback into the driver to enabled or disable event
  1490. generation or data block collection. A device should only expect a
  1491. single enable when the first event or data consumer enables events or
  1492. data collection and a single disable when the last event or data
  1493. consumer disables events or data collection. Data blocks will only
  1494. receive collection enable/disable if they were registered as requiring
  1495. it.
  1496. When NT boots, failure prediction is not automatically enabled, although
  1497. it may have been persistantly enabled on a previous boot. Polling is also
  1498. not automatically enabled. When the first data block that accesses SMART
  1499. such as SmartStatusGuid, SmartDataGuid, SmartPerformFunction, or
  1500. SmartEventGuid is accessed then SMART is automatically enabled in the
  1501. hardware. Polling is enabled when SmartEventGuid is enabled and disabled
  1502. when it is disabled. Hardware SMART is only disabled when the DisableSmart
  1503. method is called. Polling is also disabled when this is called regardless
  1504. of the status of the other guids or events.
  1505. Arguments:
  1506. DeviceObject is the device whose data block is being queried
  1507. GuidIndex is the index into the list of guids provided when the
  1508. device registered
  1509. Function specifies which functionality is being enabled or disabled
  1510. Enable is TRUE then the function is being enabled else disabled
  1511. Return Value:
  1512. status
  1513. --*/
  1514. {
  1515. NTSTATUS status = STATUS_SUCCESS;
  1516. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  1517. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  1518. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  1519. ULONG enableCount;
  1520. PAGED_CODE();
  1521. if ((Function == DataBlockCollection) && Enable)
  1522. {
  1523. if ((GuidIndex == SmartStatusGuid) ||
  1524. (GuidIndex == SmartDataGuid) ||
  1525. (GuidIndex == SmartThresholdsGuid) ||
  1526. (GuidIndex == SmartPerformFunction))
  1527. {
  1528. status = DiskEnableDisableFailurePrediction(fdoExtension,
  1529. TRUE);
  1530. DebugPrint((3, "Disk: DeviceObject %p, Irp %p Enable -> %lx\n",
  1531. DeviceObject,
  1532. Irp,
  1533. status));
  1534. } else {
  1535. DebugPrint((3, "Disk: DeviceObject %p, Irp %p, GuidIndex %d %s for Collection\n",
  1536. DeviceObject, Irp,
  1537. GuidIndex,
  1538. Enable ? "Enabled" : "Disabled")); }
  1539. } else if (Function == EventGeneration) {
  1540. DebugPrint((3, "Disk: DeviceObject %p, Irp %p, GuidIndex %d %s for Event Generation\n",
  1541. DeviceObject, Irp,
  1542. GuidIndex,
  1543. Enable ? "Enabled" : "Disabled"));
  1544. if ((GuidIndex == SmartEventGuid) && Enable)
  1545. {
  1546. status = DiskEnableDisableFailurePredictPolling(fdoExtension,
  1547. Enable,
  1548. 0);
  1549. DebugPrint((3, "Disk: DeviceObject %p, Irp %p %s -> %lx\n",
  1550. DeviceObject,
  1551. Irp,
  1552. Enable ? "DiskEnableSmartPolling" : "DiskDisableSmartPolling",
  1553. status));
  1554. }
  1555. #if DBG
  1556. } else {
  1557. DebugPrint((3, "Disk: DeviceObject %p, Irp %p, GuidIndex %d %s for function %d\n",
  1558. DeviceObject, Irp,
  1559. GuidIndex,
  1560. Enable ? "Enabled" : "Disabled",
  1561. Function));
  1562. #endif
  1563. }
  1564. status = ClassWmiCompleteRequest(DeviceObject,
  1565. Irp,
  1566. status,
  1567. 0,
  1568. IO_NO_INCREMENT);
  1569. return status;
  1570. }
  1571. NTSTATUS
  1572. DiskFdoQueryWmiRegInfo(
  1573. IN PDEVICE_OBJECT DeviceObject,
  1574. OUT ULONG *RegFlags,
  1575. OUT PUNICODE_STRING InstanceName
  1576. )
  1577. /*++
  1578. Routine Description:
  1579. This routine is a callback into the driver to retrieve the list of
  1580. guids or data blocks that the driver wants to register with WMI. This
  1581. routine may not pend or block. Driver should NOT call
  1582. ClassWmiCompleteRequest.
  1583. Arguments:
  1584. DeviceObject is the device whose data block is being queried
  1585. *RegFlags returns with a set of flags that describe the guids being
  1586. registered for this device. If the device wants enable and disable
  1587. collection callbacks before receiving queries for the registered
  1588. guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
  1589. returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
  1590. the instance name is determined from the PDO associated with the
  1591. device object. Note that the PDO must have an associated devnode. If
  1592. WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
  1593. name for the device.
  1594. InstanceName returns with the instance name for the guids if
  1595. WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
  1596. caller will call ExFreePool with the buffer returned.
  1597. Return Value:
  1598. status
  1599. --*/
  1600. {
  1601. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  1602. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  1603. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  1604. NTSTATUS status;
  1605. PAGED_CODE();
  1606. SET_FLAG(DiskWmiFdoGuidList[SmartThresholdsGuid].Flags, WMIREG_FLAG_REMOVE_GUID);
  1607. SET_FLAG(DiskWmiFdoGuidList[ScsiInfoExceptionsGuid].Flags, WMIREG_FLAG_REMOVE_GUID);
  1608. switch (diskData->FailurePredictionCapability)
  1609. {
  1610. case FailurePredictionSmart:
  1611. {
  1612. CLEAR_FLAG(DiskWmiFdoGuidList[SmartThresholdsGuid].Flags, WMIREG_FLAG_REMOVE_GUID);
  1613. //
  1614. // Fall Through
  1615. //
  1616. }
  1617. case FailurePredictionIoctl:
  1618. {
  1619. CLEAR_FLAG(DiskWmiFdoGuidList[SmartStatusGuid].Flags, WMIREG_FLAG_REMOVE_GUID);
  1620. CLEAR_FLAG(DiskWmiFdoGuidList[SmartDataGuid].Flags, WMIREG_FLAG_REMOVE_GUID);
  1621. CLEAR_FLAG(DiskWmiFdoGuidList[SmartEventGuid].Flags, WMIREG_FLAG_REMOVE_GUID);
  1622. CLEAR_FLAG(DiskWmiFdoGuidList[SmartPerformFunction].Flags, WMIREG_FLAG_REMOVE_GUID);
  1623. break;
  1624. }
  1625. case FailurePredictionSense:
  1626. {
  1627. CLEAR_FLAG(DiskWmiFdoGuidList[SmartStatusGuid].Flags, WMIREG_FLAG_REMOVE_GUID);
  1628. CLEAR_FLAG(DiskWmiFdoGuidList[SmartEventGuid].Flags, WMIREG_FLAG_REMOVE_GUID);
  1629. CLEAR_FLAG(DiskWmiFdoGuidList[SmartPerformFunction].Flags, WMIREG_FLAG_REMOVE_GUID);
  1630. CLEAR_FLAG(DiskWmiFdoGuidList[ScsiInfoExceptionsGuid].Flags, WMIREG_FLAG_REMOVE_GUID);
  1631. SET_FLAG (DiskWmiFdoGuidList[SmartDataGuid].Flags, WMIREG_FLAG_REMOVE_GUID);
  1632. break;
  1633. }
  1634. default:
  1635. {
  1636. SET_FLAG (DiskWmiFdoGuidList[SmartStatusGuid].Flags, WMIREG_FLAG_REMOVE_GUID);
  1637. SET_FLAG (DiskWmiFdoGuidList[SmartDataGuid].Flags, WMIREG_FLAG_REMOVE_GUID);
  1638. SET_FLAG (DiskWmiFdoGuidList[SmartEventGuid].Flags, WMIREG_FLAG_REMOVE_GUID);
  1639. SET_FLAG (DiskWmiFdoGuidList[SmartPerformFunction].Flags, WMIREG_FLAG_REMOVE_GUID);
  1640. break;
  1641. }
  1642. }
  1643. //
  1644. // Use devnode for FDOs
  1645. *RegFlags = WMIREG_FLAG_INSTANCE_PDO;
  1646. return STATUS_SUCCESS;
  1647. }
  1648. NTSTATUS
  1649. DiskFdoQueryWmiRegInfoEx(
  1650. IN PDEVICE_OBJECT DeviceObject,
  1651. OUT ULONG *RegFlags,
  1652. OUT PUNICODE_STRING InstanceName,
  1653. OUT PUNICODE_STRING MofName
  1654. )
  1655. /*++
  1656. Routine Description:
  1657. This routine is a callback into the driver to retrieve the list of
  1658. guids or data blocks that the driver wants to register with WMI. This
  1659. routine may not pend or block. Driver should NOT call
  1660. ClassWmiCompleteRequest.
  1661. Arguments:
  1662. DeviceObject is the device whose data block is being queried
  1663. *RegFlags returns with a set of flags that describe the guids being
  1664. registered for this device. If the device wants enable and disable
  1665. collection callbacks before receiving queries for the registered
  1666. guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
  1667. returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
  1668. the instance name is determined from the PDO associated with the
  1669. device object. Note that the PDO must have an associated devnode. If
  1670. WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
  1671. name for the device.
  1672. InstanceName returns with the instance name for the guids if
  1673. WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
  1674. caller will call ExFreePool with the buffer returned.
  1675. MofName returns initialized with the mof resource name for the
  1676. binary mof resource attached to the driver's image file. If the
  1677. driver does not have a mof resource then it should leave this
  1678. parameter untouched.
  1679. Return Value:
  1680. status
  1681. --*/
  1682. {
  1683. NTSTATUS status;
  1684. status = DiskFdoQueryWmiRegInfo(DeviceObject,
  1685. RegFlags,
  1686. InstanceName);
  1687. //
  1688. // Leave MofName alone since disk doesn't have one
  1689. //
  1690. return(status);
  1691. }
  1692. NTSTATUS
  1693. DiskFdoQueryWmiDataBlock(
  1694. IN PDEVICE_OBJECT DeviceObject,
  1695. IN PIRP Irp,
  1696. IN ULONG GuidIndex,
  1697. IN ULONG BufferAvail,
  1698. OUT PUCHAR Buffer
  1699. )
  1700. /*++
  1701. Routine Description:
  1702. This routine is a callback into the driver to query for the contents of
  1703. a data block. When the driver has finished filling the data block it
  1704. must call ClassWmiCompleteRequest to complete the irp. The driver can
  1705. return STATUS_PENDING if the irp cannot be completed immediately.
  1706. Arguments:
  1707. DeviceObject is the device whose data block is being queried
  1708. Irp is the Irp that makes this request
  1709. GuidIndex is the index into the list of guids provided when the
  1710. device registered
  1711. BufferAvail on has the maximum size available to write the data
  1712. block.
  1713. Buffer on return is filled with the returned data block
  1714. Return Value:
  1715. status
  1716. --*/
  1717. {
  1718. NTSTATUS status;
  1719. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  1720. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  1721. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  1722. ULONG sizeNeeded;
  1723. PAGED_CODE();
  1724. DebugPrint((3, "Disk: DiskQueryWmiDataBlock, Device %p, Irp %p, GuiIndex %d\n"
  1725. " BufferAvail %lx Buffer %lx\n",
  1726. DeviceObject, Irp,
  1727. GuidIndex, BufferAvail, Buffer));
  1728. switch (GuidIndex)
  1729. {
  1730. case DiskGeometryGuid:
  1731. {
  1732. sizeNeeded = sizeof(DISK_GEOMETRY);
  1733. if (BufferAvail >= sizeNeeded)
  1734. {
  1735. if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
  1736. {
  1737. //
  1738. // Issue ReadCapacity to update device extension
  1739. // with information for current media.
  1740. status = DiskReadDriveCapacity(commonExtension->PartitionZeroExtension->DeviceObject);
  1741. //
  1742. // Note whether the drive is ready.
  1743. diskData->ReadyStatus = status;
  1744. if (!NT_SUCCESS(status))
  1745. {
  1746. break;
  1747. }
  1748. }
  1749. //
  1750. // Copy drive geometry information from device extension.
  1751. RtlMoveMemory(Buffer,
  1752. &(fdoExtension->DiskGeometry),
  1753. sizeof(DISK_GEOMETRY));
  1754. status = STATUS_SUCCESS;
  1755. } else {
  1756. status = STATUS_BUFFER_TOO_SMALL;
  1757. }
  1758. break;
  1759. }
  1760. case SmartStatusGuid:
  1761. {
  1762. PSTORAGE_FAILURE_PREDICT_STATUS diskSmartStatus;
  1763. ASSERT(diskData->FailurePredictionCapability != FailurePredictionNone);
  1764. sizeNeeded = sizeof(STORAGE_FAILURE_PREDICT_STATUS);
  1765. if (BufferAvail >= sizeNeeded)
  1766. {
  1767. STORAGE_PREDICT_FAILURE checkFailure;
  1768. diskSmartStatus = (PSTORAGE_FAILURE_PREDICT_STATUS)Buffer;
  1769. status = DiskSendFailurePredictIoctl(fdoExtension,
  1770. &checkFailure);
  1771. if (NT_SUCCESS(status))
  1772. {
  1773. if (diskData->FailurePredictionCapability ==
  1774. FailurePredictionSense)
  1775. {
  1776. diskSmartStatus->Reason = *((PULONG)checkFailure.VendorSpecific);
  1777. } else {
  1778. diskSmartStatus->Reason = 0; // unknown
  1779. }
  1780. diskSmartStatus->PredictFailure = (checkFailure.PredictFailure != 0);
  1781. }
  1782. } else {
  1783. status = STATUS_BUFFER_TOO_SMALL;
  1784. }
  1785. break;
  1786. }
  1787. case SmartDataGuid:
  1788. {
  1789. PSTORAGE_FAILURE_PREDICT_DATA diskSmartData;
  1790. ASSERT((diskData->FailurePredictionCapability ==
  1791. FailurePredictionSmart) ||
  1792. (diskData->FailurePredictionCapability ==
  1793. FailurePredictionIoctl));
  1794. sizeNeeded = sizeof(STORAGE_FAILURE_PREDICT_DATA);
  1795. if (BufferAvail >= sizeNeeded)
  1796. {
  1797. PSTORAGE_PREDICT_FAILURE checkFailure = (PSTORAGE_PREDICT_FAILURE)Buffer;
  1798. diskSmartData = (PSTORAGE_FAILURE_PREDICT_DATA)Buffer;
  1799. status = DiskSendFailurePredictIoctl(fdoExtension,
  1800. checkFailure);
  1801. if (NT_SUCCESS(status))
  1802. {
  1803. diskSmartData->Length = 512;
  1804. }
  1805. } else {
  1806. status = STATUS_BUFFER_TOO_SMALL;
  1807. }
  1808. break;
  1809. }
  1810. case SmartThresholdsGuid:
  1811. {
  1812. PSTORAGE_FAILURE_PREDICT_THRESHOLDS diskSmartThresholds;
  1813. ASSERT((diskData->FailurePredictionCapability ==
  1814. FailurePredictionSmart));
  1815. sizeNeeded = sizeof(STORAGE_FAILURE_PREDICT_THRESHOLDS);
  1816. if (BufferAvail >= sizeNeeded)
  1817. {
  1818. diskSmartThresholds = (PSTORAGE_FAILURE_PREDICT_THRESHOLDS)Buffer;
  1819. status = DiskReadFailurePredictThresholds(fdoExtension,
  1820. diskSmartThresholds);
  1821. } else {
  1822. status = STATUS_BUFFER_TOO_SMALL;
  1823. }
  1824. break;
  1825. }
  1826. case SmartPerformFunction:
  1827. {
  1828. sizeNeeded = 0;
  1829. status = STATUS_SUCCESS;
  1830. break;
  1831. }
  1832. case ScsiInfoExceptionsGuid:
  1833. {
  1834. PSTORAGE_SCSI_INFO_EXCEPTIONS infoExceptions;
  1835. MODE_INFO_EXCEPTIONS modeInfo;
  1836. ASSERT((diskData->FailurePredictionCapability ==
  1837. FailurePredictionSense));
  1838. sizeNeeded = sizeof(STORAGE_SCSI_INFO_EXCEPTIONS);
  1839. if (BufferAvail >= sizeNeeded)
  1840. {
  1841. infoExceptions = (PSTORAGE_SCSI_INFO_EXCEPTIONS)Buffer;
  1842. status = DiskGetInfoExceptionInformation(fdoExtension,
  1843. &modeInfo);
  1844. if (NT_SUCCESS(status))
  1845. {
  1846. infoExceptions->PageSavable = modeInfo.PSBit;
  1847. infoExceptions->Flags = modeInfo.Flags;
  1848. infoExceptions->MRIE = modeInfo.ReportMethod;
  1849. infoExceptions->Padding = 0;
  1850. REVERSE_BYTES(&infoExceptions->IntervalTimer,
  1851. &modeInfo.IntervalTimer);
  1852. REVERSE_BYTES(&infoExceptions->ReportCount,
  1853. &modeInfo.ReportCount)
  1854. }
  1855. } else {
  1856. status = STATUS_BUFFER_TOO_SMALL;
  1857. }
  1858. break;
  1859. }
  1860. default:
  1861. {
  1862. sizeNeeded = 0;
  1863. status = STATUS_WMI_GUID_NOT_FOUND;
  1864. }
  1865. }
  1866. DebugPrint((3, "Disk: DiskQueryWmiDataBlock Device %p, Irp %p returns %lx\n",
  1867. DeviceObject, Irp, status));
  1868. status = ClassWmiCompleteRequest(DeviceObject,
  1869. Irp,
  1870. status,
  1871. sizeNeeded,
  1872. IO_NO_INCREMENT);
  1873. return status;
  1874. }
  1875. NTSTATUS
  1876. DiskFdoSetWmiDataBlock(
  1877. IN PDEVICE_OBJECT DeviceObject,
  1878. IN PIRP Irp,
  1879. IN ULONG GuidIndex,
  1880. IN ULONG BufferSize,
  1881. IN PUCHAR Buffer
  1882. )
  1883. /*++
  1884. Routine Description:
  1885. This routine is a callback into the driver to query for the contents of
  1886. a data block. When the driver has finished filling the data block it
  1887. must call ClassWmiCompleteRequest to complete the irp. The driver can
  1888. return STATUS_PENDING if the irp cannot be completed immediately.
  1889. Arguments:
  1890. DeviceObject is the device whose data block is being queried
  1891. Irp is the Irp that makes this request
  1892. GuidIndex is the index into the list of guids provided when the
  1893. device registered
  1894. BufferSize has the size of the data block passed
  1895. Buffer has the new values for the data block
  1896. Return Value:
  1897. status
  1898. --*/
  1899. {
  1900. NTSTATUS status;
  1901. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  1902. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  1903. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  1904. PAGED_CODE();
  1905. DebugPrint((3, "Disk: DiskSetWmiDataBlock, Device %p, Irp %p, GuiIndex %d\n"
  1906. " BufferSize %#x Buffer %p\n",
  1907. DeviceObject, Irp,
  1908. GuidIndex, BufferSize, Buffer));
  1909. if (GuidIndex == ScsiInfoExceptionsGuid)
  1910. {
  1911. PSTORAGE_SCSI_INFO_EXCEPTIONS infoExceptions;
  1912. MODE_INFO_EXCEPTIONS modeInfo = {0};
  1913. if (BufferSize >= sizeof(STORAGE_SCSI_INFO_EXCEPTIONS))
  1914. {
  1915. infoExceptions = (PSTORAGE_SCSI_INFO_EXCEPTIONS)Buffer;
  1916. modeInfo.PageCode = MODE_PAGE_FAULT_REPORTING;
  1917. modeInfo.PageLength = sizeof(MODE_INFO_EXCEPTIONS) - 2;
  1918. modeInfo.PSBit = 0;
  1919. modeInfo.Flags = infoExceptions->Flags;
  1920. modeInfo.ReportMethod = infoExceptions->MRIE;
  1921. REVERSE_BYTES(&modeInfo.IntervalTimer[0],
  1922. &infoExceptions->IntervalTimer);
  1923. REVERSE_BYTES(&modeInfo.ReportCount[0],
  1924. &infoExceptions->ReportCount);
  1925. if (modeInfo.Perf == 1)
  1926. {
  1927. diskData->AllowFPPerfHit = FALSE;
  1928. } else {
  1929. diskData->AllowFPPerfHit = TRUE;
  1930. }
  1931. status = DiskSetInfoExceptionInformation(fdoExtension,
  1932. &modeInfo);
  1933. } else {
  1934. status = STATUS_INVALID_PARAMETER;
  1935. }
  1936. } else if (GuidIndex <= SmartThresholdsGuid)
  1937. {
  1938. status = STATUS_WMI_READ_ONLY;
  1939. } else {
  1940. status = STATUS_WMI_GUID_NOT_FOUND;
  1941. }
  1942. DebugPrint((3, "Disk: DiskSetWmiDataBlock Device %p, Irp %p returns %lx\n",
  1943. DeviceObject, Irp, status));
  1944. status = ClassWmiCompleteRequest(DeviceObject,
  1945. Irp,
  1946. status,
  1947. 0,
  1948. IO_NO_INCREMENT);
  1949. return status;
  1950. }
  1951. NTSTATUS
  1952. DiskFdoSetWmiDataItem(
  1953. IN PDEVICE_OBJECT DeviceObject,
  1954. IN PIRP Irp,
  1955. IN ULONG GuidIndex,
  1956. IN ULONG DataItemId,
  1957. IN ULONG BufferSize,
  1958. IN PUCHAR Buffer
  1959. )
  1960. /*++
  1961. Routine Description:
  1962. This routine is a callback into the driver to query for the contents of
  1963. a data block. When the driver has finished filling the data block it
  1964. must call ClassWmiCompleteRequest to complete the irp. The driver can
  1965. return STATUS_PENDING if the irp cannot be completed immediately.
  1966. Arguments:
  1967. DeviceObject is the device whose data block is being queried
  1968. Irp is the Irp that makes this request
  1969. GuidIndex is the index into the list of guids provided when the
  1970. device registered
  1971. DataItemId has the id of the data item being set
  1972. BufferSize has the size of the data item passed
  1973. Buffer has the new values for the data item
  1974. Return Value:
  1975. status
  1976. --*/
  1977. {
  1978. NTSTATUS status;
  1979. PAGED_CODE();
  1980. DebugPrint((3, "Disk: DiskSetWmiDataItem, Device %p, Irp %p, GuiIndex %d, DataId %d\n"
  1981. " BufferSize %#x Buffer %p\n",
  1982. DeviceObject, Irp,
  1983. GuidIndex, DataItemId, BufferSize, Buffer));
  1984. if (GuidIndex <= SmartThresholdsGuid)
  1985. {
  1986. status = STATUS_WMI_READ_ONLY;
  1987. } else {
  1988. status = STATUS_WMI_GUID_NOT_FOUND;
  1989. }
  1990. DebugPrint((3, "Disk: DiskSetWmiDataItem Device %p, Irp %p returns %lx\n",
  1991. DeviceObject, Irp, status));
  1992. status = ClassWmiCompleteRequest(DeviceObject,
  1993. Irp,
  1994. status,
  1995. 0,
  1996. IO_NO_INCREMENT);
  1997. return status;
  1998. }
  1999. NTSTATUS
  2000. DiskFdoExecuteWmiMethod(
  2001. IN PDEVICE_OBJECT DeviceObject,
  2002. IN PIRP Irp,
  2003. IN ULONG GuidIndex,
  2004. IN ULONG MethodId,
  2005. IN ULONG InBufferSize,
  2006. IN ULONG OutBufferSize,
  2007. IN PUCHAR Buffer
  2008. )
  2009. /*++
  2010. Routine Description:
  2011. This routine is a callback into the driver to execute a method. When the
  2012. driver has finished filling the data block it must call
  2013. ClassWmiCompleteRequest to complete the irp. The driver can
  2014. return STATUS_PENDING if the irp cannot be completed immediately.
  2015. Arguments:
  2016. DeviceObject is the device whose data block is being queried
  2017. Irp is the Irp that makes this request
  2018. GuidIndex is the index into the list of guids provided when the
  2019. device registered
  2020. MethodId has the id of the method being called
  2021. InBufferSize has the size of the data block passed in as the input to
  2022. the method.
  2023. OutBufferSize on entry has the maximum size available to write the
  2024. returned data block.
  2025. Buffer is filled with the returned data block
  2026. Return Value:
  2027. status
  2028. --*/
  2029. {
  2030. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  2031. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  2032. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  2033. ULONG sizeNeeded = 0;
  2034. NTSTATUS status;
  2035. PAGED_CODE();
  2036. DebugPrint((3, "Disk: DiskExecuteWmiMethod, DeviceObject %p, Irp %p, Guid Id %d, MethodId %d\n"
  2037. " InBufferSize %#x, OutBufferSize %#x, Buffer %p\n",
  2038. DeviceObject, Irp,
  2039. GuidIndex, MethodId, InBufferSize, OutBufferSize, Buffer));
  2040. switch(GuidIndex)
  2041. {
  2042. case SmartPerformFunction:
  2043. {
  2044. ASSERT((diskData->FailurePredictionCapability ==
  2045. FailurePredictionSmart) ||
  2046. (diskData->FailurePredictionCapability ==
  2047. FailurePredictionIoctl) ||
  2048. (diskData->FailurePredictionCapability ==
  2049. FailurePredictionSense));
  2050. switch(MethodId)
  2051. {
  2052. //
  2053. // void AllowPerformanceHit([in] boolean Allow)
  2054. //
  2055. case AllowDisallowPerformanceHit:
  2056. {
  2057. BOOLEAN allowPerfHit;
  2058. sizeNeeded = 0;
  2059. if (InBufferSize >= sizeof(BOOLEAN))
  2060. {
  2061. status = STATUS_SUCCESS;
  2062. allowPerfHit = *((PBOOLEAN)Buffer);
  2063. if (diskData->AllowFPPerfHit != allowPerfHit)
  2064. {
  2065. diskData->AllowFPPerfHit = allowPerfHit;
  2066. if (diskData->FailurePredictionCapability ==
  2067. FailurePredictionSense)
  2068. {
  2069. MODE_INFO_EXCEPTIONS modeInfo;
  2070. status = DiskGetInfoExceptionInformation(fdoExtension,
  2071. &modeInfo);
  2072. if (NT_SUCCESS(status))
  2073. {
  2074. modeInfo.Perf = allowPerfHit ? 0 : 1;
  2075. status = DiskSetInfoExceptionInformation(fdoExtension,
  2076. &modeInfo);
  2077. }
  2078. }
  2079. else
  2080. {
  2081. status = STATUS_INVALID_DEVICE_REQUEST;
  2082. }
  2083. }
  2084. DebugPrint((3, "DiskFdoWmiExecuteMethod: AllowPerformanceHit %x for device %p --> %lx\n",
  2085. allowPerfHit,
  2086. fdoExtension->DeviceObject,
  2087. status));
  2088. } else {
  2089. status = STATUS_INVALID_PARAMETER;
  2090. }
  2091. break;
  2092. }
  2093. //
  2094. // void EnableDisableHardwareFailurePrediction([in] boolean Enable)
  2095. //
  2096. case EnableDisableHardwareFailurePrediction:
  2097. {
  2098. BOOLEAN enable;
  2099. sizeNeeded = 0;
  2100. if (InBufferSize >= sizeof(BOOLEAN))
  2101. {
  2102. status = STATUS_SUCCESS;
  2103. enable = *((PBOOLEAN)Buffer);
  2104. if (!enable)
  2105. {
  2106. //
  2107. // If we are disabling we need to also disable
  2108. // polling
  2109. //
  2110. DiskEnableDisableFailurePredictPolling(
  2111. fdoExtension,
  2112. enable,
  2113. 0);
  2114. }
  2115. status = DiskEnableDisableFailurePrediction(
  2116. fdoExtension,
  2117. enable);
  2118. DebugPrint((3, "DiskFdoWmiExecuteMethod: EnableDisableHardwareFailurePrediction: %x for device %p --> %lx\n",
  2119. enable,
  2120. fdoExtension->DeviceObject,
  2121. status));
  2122. } else {
  2123. status = STATUS_INVALID_PARAMETER;
  2124. }
  2125. break;
  2126. }
  2127. //
  2128. // void EnableDisableFailurePredictionPolling(
  2129. // [in] uint32 Period,
  2130. // [in] boolean Enable)
  2131. //
  2132. case EnableDisableFailurePredictionPolling:
  2133. {
  2134. BOOLEAN enable;
  2135. ULONG period;
  2136. sizeNeeded = 0;
  2137. if (InBufferSize >= (sizeof(ULONG) + sizeof(BOOLEAN)))
  2138. {
  2139. period = *((PULONG)Buffer);
  2140. Buffer += sizeof(ULONG);
  2141. enable = *((PBOOLEAN)Buffer);
  2142. status = DiskEnableDisableFailurePredictPolling(
  2143. fdoExtension,
  2144. enable,
  2145. period);
  2146. DebugPrint((3, "DiskFdoWmiExecuteMethod: EnableDisableFailurePredictionPolling: %x %x for device %p --> %lx\n",
  2147. enable,
  2148. period,
  2149. fdoExtension->DeviceObject,
  2150. status));
  2151. } else {
  2152. status = STATUS_INVALID_PARAMETER;
  2153. }
  2154. break;
  2155. }
  2156. //
  2157. // void GetFailurePredictionCapability([out] uint32 Capability)
  2158. //
  2159. case GetFailurePredictionCapability:
  2160. {
  2161. sizeNeeded = sizeof(ULONG);
  2162. if (OutBufferSize >= sizeNeeded)
  2163. {
  2164. status = STATUS_SUCCESS;
  2165. *((PFAILURE_PREDICTION_METHOD)Buffer) = diskData->FailurePredictionCapability;
  2166. DebugPrint((3, "DiskFdoWmiExecuteMethod: GetFailurePredictionCapability: %x for device %p --> %lx\n",
  2167. *((PFAILURE_PREDICTION_METHOD)Buffer),
  2168. fdoExtension->DeviceObject,
  2169. status));
  2170. } else {
  2171. status = STATUS_BUFFER_TOO_SMALL;
  2172. }
  2173. break;
  2174. }
  2175. //
  2176. // void EnableOfflineDiags([out] boolean Success);
  2177. //
  2178. case EnableOfflineDiags:
  2179. {
  2180. sizeNeeded = sizeof(BOOLEAN);
  2181. if (OutBufferSize >= sizeNeeded)
  2182. {
  2183. if (diskData->FailurePredictionCapability ==
  2184. FailurePredictionSmart)
  2185. {
  2186. //
  2187. // Initiate or resume offline diagnostics.
  2188. // This may cause a loss of performance
  2189. // to the disk, but mayincrease the amount
  2190. // of disk checking.
  2191. //
  2192. status = DiskExecuteSmartDiagnostics(fdoExtension,
  2193. 0);
  2194. } else {
  2195. status = STATUS_INVALID_DEVICE_REQUEST;
  2196. }
  2197. *((PBOOLEAN)Buffer) = NT_SUCCESS(status);
  2198. DebugPrint((3, "DiskFdoWmiExecuteMethod: EnableOfflineDiags for device %p --> %lx\n",
  2199. fdoExtension->DeviceObject,
  2200. status));
  2201. } else {
  2202. status = STATUS_BUFFER_TOO_SMALL;
  2203. }
  2204. break;
  2205. }
  2206. //
  2207. // void ReadLogSectors([in] uint8 LogAddress,
  2208. // [in] uint8 SectorCount,
  2209. // [out] uint32 Length,
  2210. // [out, WmiSizeIs("Length")] uint8 LogSectors[]
  2211. // );
  2212. //
  2213. case ReadLogSectors:
  2214. {
  2215. if (diskData->FailurePredictionCapability ==
  2216. FailurePredictionSmart)
  2217. {
  2218. if (InBufferSize >= sizeof(READ_LOG_SECTORS_IN))
  2219. {
  2220. PREAD_LOG_SECTORS_IN inParams;
  2221. PREAD_LOG_SECTORS_OUT outParams;
  2222. ULONG readSize;
  2223. inParams = (PREAD_LOG_SECTORS_IN)Buffer;
  2224. readSize = inParams->SectorCount * SMART_LOG_SECTOR_SIZE;
  2225. sizeNeeded = FIELD_OFFSET(READ_LOG_SECTORS_OUT,
  2226. LogSectors) + readSize;
  2227. if (OutBufferSize >= sizeNeeded)
  2228. {
  2229. outParams = (PREAD_LOG_SECTORS_OUT)Buffer;
  2230. status = DiskReadSmartLog(fdoExtension,
  2231. inParams->SectorCount,
  2232. inParams->LogAddress,
  2233. outParams->LogSectors);
  2234. if (NT_SUCCESS(status))
  2235. {
  2236. outParams->Length = readSize;
  2237. } else {
  2238. //
  2239. // SMART command failure is
  2240. // indicated by successful
  2241. // execution, but no data returned
  2242. //
  2243. outParams->Length = 0;
  2244. status = STATUS_SUCCESS;
  2245. }
  2246. } else {
  2247. status = STATUS_BUFFER_TOO_SMALL;
  2248. }
  2249. } else {
  2250. status = STATUS_INVALID_PARAMETER;
  2251. }
  2252. } else {
  2253. status = STATUS_INVALID_DEVICE_REQUEST;
  2254. }
  2255. break;
  2256. }
  2257. // void WriteLogSectors([in] uint8 LogAddress,
  2258. // [in] uint8 SectorCount,
  2259. // [in] uint32 Length,
  2260. // [in, WmiSizeIs("Length")] uint8 LogSectors[],
  2261. // [out] boolean Success
  2262. // );
  2263. case WriteLogSectors:
  2264. {
  2265. if (diskData->FailurePredictionCapability ==
  2266. FailurePredictionSmart)
  2267. {
  2268. if (InBufferSize >= FIELD_OFFSET(WRITE_LOG_SECTORS_IN,
  2269. LogSectors))
  2270. {
  2271. PWRITE_LOG_SECTORS_IN inParams;
  2272. PWRITE_LOG_SECTORS_OUT outParams;
  2273. ULONG writeSize;
  2274. inParams = (PWRITE_LOG_SECTORS_IN)Buffer;
  2275. writeSize = inParams->SectorCount * SMART_LOG_SECTOR_SIZE;
  2276. if (InBufferSize >= (FIELD_OFFSET(WRITE_LOG_SECTORS_IN,
  2277. LogSectors) +
  2278. writeSize))
  2279. {
  2280. sizeNeeded = sizeof(WRITE_LOG_SECTORS_OUT);
  2281. if (OutBufferSize >= sizeNeeded)
  2282. {
  2283. outParams = (PWRITE_LOG_SECTORS_OUT)Buffer;
  2284. status = DiskWriteSmartLog(fdoExtension,
  2285. inParams->SectorCount,
  2286. inParams->LogAddress,
  2287. inParams->LogSectors);
  2288. if (NT_SUCCESS(status))
  2289. {
  2290. outParams->Success = TRUE;
  2291. } else {
  2292. outParams->Success = FALSE;
  2293. status = STATUS_SUCCESS;
  2294. }
  2295. } else {
  2296. status = STATUS_BUFFER_TOO_SMALL;
  2297. }
  2298. } else {
  2299. status = STATUS_INVALID_PARAMETER;
  2300. }
  2301. } else {
  2302. status = STATUS_INVALID_PARAMETER;
  2303. }
  2304. } else {
  2305. status = STATUS_INVALID_DEVICE_REQUEST;
  2306. }
  2307. break;
  2308. }
  2309. // void ExecuteSelfTest([in] uint8 Subcommand,
  2310. // [out,
  2311. // Values{"0", "1", "2"},
  2312. // ValueMap{"Successful Completion",
  2313. // "Captive Mode Required",
  2314. // "Unsuccessful Completion"}
  2315. // ]
  2316. // uint32 ReturnCode);
  2317. case ExecuteSelfTest:
  2318. {
  2319. if (diskData->FailurePredictionCapability ==
  2320. FailurePredictionSmart)
  2321. {
  2322. if (InBufferSize >= sizeof(EXECUTE_SELF_TEST_IN))
  2323. {
  2324. sizeNeeded = sizeof(EXECUTE_SELF_TEST_OUT);
  2325. if (OutBufferSize >= sizeNeeded)
  2326. {
  2327. PEXECUTE_SELF_TEST_IN inParam;
  2328. PEXECUTE_SELF_TEST_OUT outParam;
  2329. inParam = (PEXECUTE_SELF_TEST_IN)Buffer;
  2330. outParam = (PEXECUTE_SELF_TEST_OUT)Buffer;
  2331. if (DiskIsValidSmartSelfTest(inParam->Subcommand))
  2332. {
  2333. status = DiskExecuteSmartDiagnostics(fdoExtension,
  2334. inParam->Subcommand);
  2335. if (NT_SUCCESS(status))
  2336. {
  2337. //
  2338. // Return self test executed
  2339. // without a problem
  2340. //
  2341. outParam->ReturnCode = 0;
  2342. } else {
  2343. //
  2344. // Return Self test execution
  2345. // failed status
  2346. //
  2347. outParam->ReturnCode = 2;
  2348. status = STATUS_SUCCESS;
  2349. }
  2350. } else {
  2351. //
  2352. // If self test subcommand requires
  2353. // captive mode then return that
  2354. // status
  2355. //
  2356. outParam->ReturnCode = 1;
  2357. status = STATUS_SUCCESS;
  2358. }
  2359. } else {
  2360. status = STATUS_BUFFER_TOO_SMALL;
  2361. }
  2362. } else {
  2363. status = STATUS_INVALID_PARAMETER;
  2364. }
  2365. } else {
  2366. status = STATUS_INVALID_DEVICE_REQUEST;
  2367. }
  2368. break;
  2369. }
  2370. default :
  2371. {
  2372. sizeNeeded = 0;
  2373. status = STATUS_WMI_ITEMID_NOT_FOUND;
  2374. break;
  2375. }
  2376. }
  2377. break;
  2378. }
  2379. case DiskGeometryGuid:
  2380. case SmartStatusGuid:
  2381. case SmartDataGuid:
  2382. case SmartEventGuid:
  2383. case SmartThresholdsGuid:
  2384. case ScsiInfoExceptionsGuid:
  2385. {
  2386. sizeNeeded = 0;
  2387. status = STATUS_INVALID_DEVICE_REQUEST;
  2388. break;
  2389. }
  2390. default:
  2391. {
  2392. sizeNeeded = 0;
  2393. status = STATUS_WMI_GUID_NOT_FOUND;
  2394. }
  2395. }
  2396. DebugPrint((3, "Disk: DiskExecuteMethod Device %p, Irp %p returns %lx\n",
  2397. DeviceObject, Irp, status));
  2398. status = ClassWmiCompleteRequest(DeviceObject,
  2399. Irp,
  2400. status,
  2401. sizeNeeded,
  2402. IO_NO_INCREMENT);
  2403. return status;
  2404. }
  2405. #if 0
  2406. //
  2407. // Enable this to add WMI support for PDOs
  2408. NTSTATUS
  2409. DiskPdoQueryWmiRegInfo(
  2410. IN PDEVICE_OBJECT DeviceObject,
  2411. OUT ULONG *RegFlags,
  2412. OUT PUNICODE_STRING InstanceName
  2413. )
  2414. /*++
  2415. Routine Description:
  2416. This routine is a callback into the driver to retrieve the list of
  2417. guids or data blocks that the driver wants to register with WMI. This
  2418. routine may not pend or block. Driver should NOT call
  2419. ClassWmiCompleteRequest.
  2420. Arguments:
  2421. DeviceObject is the device whose data block is being queried
  2422. *RegFlags returns with a set of flags that describe the guids being
  2423. registered for this device. If the device wants enable and disable
  2424. collection callbacks before receiving queries for the registered
  2425. guids then it should return the WMIREG_FLAG_EXPENSIVE flag. Also the
  2426. returned flags may specify WMIREG_FLAG_INSTANCE_PDO in which case
  2427. the instance name is determined from the PDO associated with the
  2428. device object. Note that the PDO must have an associated devnode. If
  2429. WMIREG_FLAG_INSTANCE_PDO is not set then Name must return a unique
  2430. name for the device.
  2431. InstanceName returns with the instance name for the guids if
  2432. WMIREG_FLAG_INSTANCE_PDO is not set in the returned *RegFlags. The
  2433. caller will call ExFreePool with the buffer returned.
  2434. Return Value:
  2435. status
  2436. --*/
  2437. {
  2438. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  2439. PFUNCTIONAL_DEVICE_EXTENSION parentFunctionalExtension;
  2440. ANSI_STRING ansiString;
  2441. CHAR name[256];
  2442. NTSTATUS status;
  2443. //
  2444. // We need to pick a name for PDOs since they do not have a devnode
  2445. parentFunctionalExtension = commonExtension->PartitionZeroExtension;
  2446. sprintf(name,
  2447. "Disk(%d)_Partition(%d)_Start(%#I64x)_Length(%#I64x)",
  2448. parentFunctionalExtension->DeviceNumber,
  2449. commonExtension->PartitionNumber,
  2450. commonExtension->StartingOffset.QuadPart,
  2451. commonExtension->PartitionLength.QuadPart);
  2452. RtlInitAnsiString(&ansiString,
  2453. name);
  2454. status = RtlAnsiStringToUnicodeString(InstanceName,
  2455. &ansiString,
  2456. TRUE);
  2457. return status;
  2458. }
  2459. NTSTATUS
  2460. DiskPdoQueryWmiDataBlock(
  2461. IN PDEVICE_OBJECT DeviceObject,
  2462. IN PIRP Irp,
  2463. IN ULONG GuidIndex,
  2464. IN ULONG BufferAvail,
  2465. OUT PUCHAR Buffer
  2466. )
  2467. /*++
  2468. Routine Description:
  2469. This routine is a callback into the driver to query for the contents of
  2470. a data block. When the driver has finished filling the data block it
  2471. must call ClassWmiCompleteRequest to complete the irp. The driver can
  2472. return STATUS_PENDING if the irp cannot be completed immediately.
  2473. Arguments:
  2474. DeviceObject is the device whose data block is being queried
  2475. Irp is the Irp that makes this request
  2476. GuidIndex is the index into the list of guids provided when the
  2477. device registered
  2478. BufferAvail on has the maximum size available to write the data
  2479. block.
  2480. Buffer on return is filled with the returned data block
  2481. Return Value:
  2482. status
  2483. --*/
  2484. {
  2485. NTSTATUS status;
  2486. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  2487. PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
  2488. ULONG sizeNeeded;
  2489. DebugPrint((3, "Disk: DiskQueryWmiDataBlock, Device %p, Irp %p, GuiIndex %d\n"
  2490. " BufferAvail %#x Buffer %p\n",
  2491. DeviceObject, Irp,
  2492. GuidIndex, BufferAvail, Buffer));
  2493. switch (GuidIndex)
  2494. {
  2495. case 0:
  2496. {
  2497. sizeNeeded = 4 * sizeof(ULONG);
  2498. if (BufferAvail >= sizeNeeded)
  2499. {
  2500. RtlCopyMemory(Buffer, DiskDummyData, sizeNeeded);
  2501. status = STATUS_SUCCESS;
  2502. } else {
  2503. status = STATUS_BUFFER_TOO_SMALL;
  2504. }
  2505. break;
  2506. }
  2507. default:
  2508. {
  2509. status = STATUS_WMI_GUID_NOT_FOUND;
  2510. }
  2511. }
  2512. DebugPrint((3, "Disk: DiskQueryWmiDataBlock Device %p, Irp %p returns %lx\n",
  2513. DeviceObject, Irp, status));
  2514. status = ClassWmiCompleteRequest(DeviceObject,
  2515. Irp,
  2516. status,
  2517. sizeNeeded,
  2518. IO_NO_INCREMENT);
  2519. return status;
  2520. }
  2521. NTSTATUS
  2522. DiskPdoSetWmiDataBlock(
  2523. IN PDEVICE_OBJECT DeviceObject,
  2524. IN PIRP Irp,
  2525. IN ULONG GuidIndex,
  2526. IN ULONG BufferSize,
  2527. IN PUCHAR Buffer
  2528. )
  2529. /*++
  2530. Routine Description:
  2531. This routine is a callback into the driver to query for the contents of
  2532. a data block. When the driver has finished filling the data block it
  2533. must call ClassWmiCompleteRequest to complete the irp. The driver can
  2534. return STATUS_PENDING if the irp cannot be completed immediately.
  2535. Arguments:
  2536. DeviceObject is the device whose data block is being queried
  2537. Irp is the Irp that makes this request
  2538. GuidIndex is the index into the list of guids provided when the
  2539. device registered
  2540. BufferSize has the size of the data block passed
  2541. Buffer has the new values for the data block
  2542. Return Value:
  2543. status
  2544. --*/
  2545. {
  2546. NTSTATUS status;
  2547. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  2548. ULONG sizeNeeded;
  2549. DebugPrint((3, "Disk: DiskSetWmiDataBlock, Device %p, Irp %p, GuiIndex %d\n"
  2550. " BufferSize %#x Buffer %p\n",
  2551. DeviceObject, Irp,
  2552. GuidIndex, BufferSize, Buffer));
  2553. switch(GuidIndex)
  2554. {
  2555. case 0:
  2556. {
  2557. sizeNeeded = 4 * sizeof(ULONG);
  2558. if (BufferSize == sizeNeeded)
  2559. {
  2560. RtlCopyMemory(DiskDummyData, Buffer, sizeNeeded);
  2561. status = STATUS_SUCCESS;
  2562. } else {
  2563. status = STATUS_INFO_LENGTH_MISMATCH;
  2564. }
  2565. break;
  2566. }
  2567. default:
  2568. {
  2569. status = STATUS_WMI_GUID_NOT_FOUND;
  2570. }
  2571. }
  2572. DebugPrint((3, "Disk: DiskSetWmiDataBlock Device %p, Irp %p returns %lx\n",
  2573. DeviceObject, Irp, status));
  2574. status = ClassWmiCompleteRequest(DeviceObject,
  2575. Irp,
  2576. status,
  2577. 0,
  2578. IO_NO_INCREMENT);
  2579. return status;
  2580. }
  2581. NTSTATUS
  2582. DiskPdoSetWmiDataItem(
  2583. IN PDEVICE_OBJECT DeviceObject,
  2584. IN PIRP Irp,
  2585. IN ULONG GuidIndex,
  2586. IN ULONG DataItemId,
  2587. IN ULONG BufferSize,
  2588. IN PUCHAR Buffer
  2589. )
  2590. /*++
  2591. Routine Description:
  2592. This routine is a callback into the driver to query for the contents of
  2593. a data block. When the driver has finished filling the data block it
  2594. must call ClassWmiCompleteRequest to complete the irp. The driver can
  2595. return STATUS_PENDING if the irp cannot be completed immediately.
  2596. Arguments:
  2597. DeviceObject is the device whose data block is being queried
  2598. Irp is the Irp that makes this request
  2599. GuidIndex is the index into the list of guids provided when the
  2600. device registered
  2601. DataItemId has the id of the data item being set
  2602. BufferSize has the size of the data item passed
  2603. Buffer has the new values for the data item
  2604. Return Value:
  2605. status
  2606. --*/
  2607. {
  2608. NTSTATUS status;
  2609. DebugPrint((3, "Disk: DiskSetWmiDataItem, Device %p, Irp %p, GuiIndex %d, DataId %d\n"
  2610. " BufferSize %#x Buffer %p\n",
  2611. DeviceObject, Irp,
  2612. GuidIndex, DataItemId, BufferSize, Buffer));
  2613. switch(GuidIndex)
  2614. {
  2615. case 0:
  2616. {
  2617. if ((BufferSize == sizeof(ULONG)) &&
  2618. (DataItemId <= 3))
  2619. {
  2620. DiskDummyData[DataItemId] = *((PULONG)Buffer);
  2621. status = STATUS_SUCCESS;
  2622. } else {
  2623. status = STATUS_INVALID_DEVICE_REQUEST;
  2624. }
  2625. break;
  2626. }
  2627. default:
  2628. {
  2629. status = STATUS_WMI_GUID_NOT_FOUND;
  2630. }
  2631. }
  2632. DebugPrint((3, "Disk: DiskSetWmiDataItem Device %p, Irp %p returns %lx\n",
  2633. DeviceObject, Irp, status));
  2634. status = ClassWmiCompleteRequest(DeviceObject,
  2635. Irp,
  2636. status,
  2637. 0,
  2638. IO_NO_INCREMENT);
  2639. return status;
  2640. }
  2641. NTSTATUS
  2642. DiskPdoExecuteWmiMethod(
  2643. IN PDEVICE_OBJECT DeviceObject,
  2644. IN PIRP Irp,
  2645. IN ULONG GuidIndex,
  2646. IN ULONG MethodId,
  2647. IN ULONG InBufferSize,
  2648. IN ULONG OutBufferSize,
  2649. IN PUCHAR Buffer
  2650. )
  2651. /*++
  2652. Routine Description:
  2653. This routine is a callback into the driver to execute a method. When the
  2654. driver has finished filling the data block it must call
  2655. ClassWmiCompleteRequest to complete the irp. The driver can
  2656. return STATUS_PENDING if the irp cannot be completed immediately.
  2657. Arguments:
  2658. DeviceObject is the device whose data block is being queried
  2659. Irp is the Irp that makes this request
  2660. GuidIndex is the index into the list of guids provided when the
  2661. device registered
  2662. MethodId has the id of the method being called
  2663. InBufferSize has the size of the data block passed in as the input to
  2664. the method.
  2665. OutBufferSize on entry has the maximum size available to write the
  2666. returned data block.
  2667. Buffer is filled with the returned data block
  2668. Return Value:
  2669. status
  2670. --*/
  2671. {
  2672. ULONG sizeNeeded = 4 * sizeof(ULONG);
  2673. NTSTATUS status;
  2674. ULONG tempData[4];
  2675. DebugPrint((3, "Disk: DiskExecuteWmiMethod, DeviceObject %p, Irp %p, Guid Id %d, MethodId %d\n"
  2676. " InBufferSize %#x, OutBufferSize %#x, Buffer %p\n",
  2677. DeviceObject, Irp,
  2678. GuidIndex, MethodId, InBufferSize, OutBufferSize, Buffer));
  2679. switch(GuidIndex)
  2680. {
  2681. case 0:
  2682. {
  2683. if (MethodId == 1)
  2684. {
  2685. if (OutBufferSize >= sizeNeeded)
  2686. {
  2687. if (InBufferSize == sizeNeeded)
  2688. {
  2689. RtlCopyMemory(tempData, Buffer, sizeNeeded);
  2690. RtlCopyMemory(Buffer, DiskDummyData, sizeNeeded);
  2691. RtlCopyMemory(DiskDummyData, tempData, sizeNeeded);
  2692. status = STATUS_SUCCESS;
  2693. } else {
  2694. status = STATUS_INVALID_DEVICE_REQUEST;
  2695. }
  2696. } else {
  2697. status = STATUS_BUFFER_TOO_SMALL;
  2698. }
  2699. } else {
  2700. status = STATUS_INVALID_DEVICE_REQUEST;
  2701. }
  2702. break;
  2703. }
  2704. default:
  2705. {
  2706. status = STATUS_WMI_GUID_NOT_FOUND;
  2707. }
  2708. }
  2709. DebugPrint((3, "Disk: DiskExecuteMethod Device %p, Irp %p returns %lx\n",
  2710. DeviceObject, Irp, status));
  2711. status = ClassWmiCompleteRequest(DeviceObject,
  2712. Irp,
  2713. status,
  2714. 0,
  2715. IO_NO_INCREMENT);
  2716. return status;
  2717. }
  2718. #endif