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.

9466 lines
293 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1991 - 1999
  3. Module Name:
  4. class.c
  5. Abstract:
  6. SCSI class driver routines
  7. Environment:
  8. kernel mode only
  9. Notes:
  10. Revision History:
  11. --*/
  12. #define CLASS_INIT_GUID 1
  13. #include "classp.h"
  14. #include "debug.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(INIT, DriverEntry)
  17. #pragma alloc_text(PAGE, ClassAddDevice)
  18. #pragma alloc_text(PAGE, ClassClaimDevice)
  19. #pragma alloc_text(PAGE, ClassCreateDeviceObject)
  20. #pragma alloc_text(PAGE, ClassDispatchPnp)
  21. #pragma alloc_text(PAGE, ClassGetDescriptor)
  22. #pragma alloc_text(PAGE, ClassGetPdoId)
  23. #pragma alloc_text(PAGE, ClassInitialize)
  24. #pragma alloc_text(PAGE, ClassInitializeEx)
  25. #pragma alloc_text(PAGE, ClassInvalidateBusRelations)
  26. #pragma alloc_text(PAGE, ClassMarkChildMissing)
  27. #pragma alloc_text(PAGE, ClassMarkChildrenMissing)
  28. #pragma alloc_text(PAGE, ClassModeSense)
  29. #pragma alloc_text(PAGE, ClassPnpQueryFdoRelations)
  30. #pragma alloc_text(PAGE, ClassPnpStartDevice)
  31. #pragma alloc_text(PAGE, ClassQueryPnpCapabilities)
  32. #pragma alloc_text(PAGE, ClassQueryTimeOutRegistryValue)
  33. #pragma alloc_text(PAGE, ClassRemoveDevice)
  34. #pragma alloc_text(PAGE, ClassRetrieveDeviceRelations)
  35. #pragma alloc_text(PAGE, ClassUpdateInformationInRegistry)
  36. #pragma alloc_text(PAGE, ClassSendDeviceIoControlSynchronous)
  37. #pragma alloc_text(PAGE, ClassUnload)
  38. #pragma alloc_text(PAGE, ClasspAllocateReleaseRequest)
  39. #pragma alloc_text(PAGE, ClasspFreeReleaseRequest)
  40. #pragma alloc_text(PAGE, ClasspInitializeHotplugInfo)
  41. #pragma alloc_text(PAGE, ClasspRegisterMountedDeviceInterface)
  42. #pragma alloc_text(PAGE, ClasspScanForClassHacks)
  43. #pragma alloc_text(PAGE, ClasspScanForSpecialInRegistry)
  44. #endif
  45. ULONG ClassPnpAllowUnload = TRUE;
  46. ULONG ClassMaxInterleavePerCriticalIo = CLASS_MAX_INTERLEAVE_PER_CRITICAL_IO;
  47. CONST LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758};
  48. #define FirstDriveLetter 'C'
  49. #define LastDriveLetter 'Z'
  50. /*++////////////////////////////////////////////////////////////////////////////
  51. DriverEntry()
  52. Routine Description:
  53. Temporary entry point needed to initialize the class system dll.
  54. It doesn't do anything.
  55. Arguments:
  56. DriverObject - Pointer to the driver object created by the system.
  57. Return Value:
  58. STATUS_SUCCESS
  59. --*/
  60. NTSTATUS
  61. DriverEntry(
  62. IN PDRIVER_OBJECT DriverObject,
  63. IN PUNICODE_STRING RegistryPath
  64. )
  65. {
  66. return STATUS_SUCCESS;
  67. }
  68. /*++////////////////////////////////////////////////////////////////////////////
  69. ClassInitialize()
  70. Routine Description:
  71. This routine is called by a class driver during its
  72. DriverEntry routine to initialize the driver.
  73. Arguments:
  74. Argument1 - Driver Object.
  75. Argument2 - Registry Path.
  76. InitializationData - Device-specific driver's initialization data.
  77. Return Value:
  78. A valid return code for a DriverEntry routine.
  79. --*/
  80. ULONG
  81. ClassInitialize(
  82. IN PVOID Argument1,
  83. IN PVOID Argument2,
  84. IN PCLASS_INIT_DATA InitializationData
  85. )
  86. {
  87. PDRIVER_OBJECT DriverObject = Argument1;
  88. PUNICODE_STRING RegistryPath = Argument2;
  89. PCLASS_DRIVER_EXTENSION driverExtension;
  90. NTSTATUS status;
  91. PAGED_CODE();
  92. DebugPrint((3,"\n\nSCSI Class Driver\n"));
  93. ClasspInitializeDebugGlobals();
  94. //
  95. // Validate the length of this structure. This is effectively a
  96. // version check.
  97. //
  98. if (InitializationData->InitializationDataSize != sizeof(CLASS_INIT_DATA)) {
  99. //
  100. // This DebugPrint is to help third-party driver writers
  101. //
  102. DebugPrint((0,"ClassInitialize: Class driver wrong version\n"));
  103. return (ULONG) STATUS_REVISION_MISMATCH;
  104. }
  105. //
  106. // Check that each required entry is not NULL. Note that Shutdown, Flush and Error
  107. // are not required entry points.
  108. //
  109. if ((!InitializationData->FdoData.ClassDeviceControl) ||
  110. (!((InitializationData->FdoData.ClassReadWriteVerification) ||
  111. (InitializationData->ClassStartIo))) ||
  112. (!InitializationData->ClassAddDevice) ||
  113. (!InitializationData->FdoData.ClassStartDevice)) {
  114. //
  115. // This DebugPrint is to help third-party driver writers
  116. //
  117. DebugPrint((0,
  118. "ClassInitialize: Class device-specific driver missing required "
  119. "FDO entry\n"));
  120. return (ULONG) STATUS_REVISION_MISMATCH;
  121. }
  122. if ((InitializationData->ClassEnumerateDevice) &&
  123. ((!InitializationData->PdoData.ClassDeviceControl) ||
  124. (!InitializationData->PdoData.ClassStartDevice) ||
  125. (!((InitializationData->PdoData.ClassReadWriteVerification) ||
  126. (InitializationData->ClassStartIo))))) {
  127. //
  128. // This DebugPrint is to help third-party driver writers
  129. //
  130. DebugPrint((0, "ClassInitialize: Class device-specific missing "
  131. "required PDO entry\n"));
  132. return (ULONG) STATUS_REVISION_MISMATCH;
  133. }
  134. if((InitializationData->FdoData.ClassStopDevice == NULL) ||
  135. ((InitializationData->ClassEnumerateDevice != NULL) &&
  136. (InitializationData->PdoData.ClassStopDevice == NULL))) {
  137. //
  138. // This DebugPrint is to help third-party driver writers
  139. //
  140. DebugPrint((0, "ClassInitialize: Class device-specific missing "
  141. "required PDO entry\n"));
  142. ASSERT(FALSE);
  143. return (ULONG) STATUS_REVISION_MISMATCH;
  144. }
  145. //
  146. // Setup the default power handlers if the class driver didn't provide
  147. // any.
  148. //
  149. if(InitializationData->FdoData.ClassPowerDevice == NULL) {
  150. InitializationData->FdoData.ClassPowerDevice = ClassMinimalPowerHandler;
  151. }
  152. if((InitializationData->ClassEnumerateDevice != NULL) &&
  153. (InitializationData->PdoData.ClassPowerDevice == NULL)) {
  154. InitializationData->PdoData.ClassPowerDevice = ClassMinimalPowerHandler;
  155. }
  156. //
  157. // warn that unload is not supported
  158. //
  159. // ISSUE-2000/02/03-peterwie
  160. // We should think about making this a fatal error.
  161. //
  162. if(InitializationData->ClassUnload == NULL) {
  163. //
  164. // This DebugPrint is to help third-party driver writers
  165. //
  166. DebugPrint((0, "ClassInitialize: driver does not support unload %wZ\n",
  167. RegistryPath));
  168. }
  169. //
  170. // Create an extension for the driver object
  171. //
  172. status = IoAllocateDriverObjectExtension(DriverObject,
  173. CLASS_DRIVER_EXTENSION_KEY,
  174. sizeof(CLASS_DRIVER_EXTENSION),
  175. &driverExtension);
  176. if(NT_SUCCESS(status)) {
  177. //
  178. // Copy the registry path into the driver extension so we can use it later
  179. //
  180. driverExtension->RegistryPath.Length = RegistryPath->Length;
  181. driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength;
  182. driverExtension->RegistryPath.Buffer =
  183. ExAllocatePoolWithTag(PagedPool,
  184. RegistryPath->MaximumLength,
  185. '1CcS');
  186. if(driverExtension->RegistryPath.Buffer == NULL) {
  187. status = STATUS_INSUFFICIENT_RESOURCES;
  188. return status;
  189. }
  190. RtlCopyUnicodeString(
  191. &(driverExtension->RegistryPath),
  192. RegistryPath);
  193. //
  194. // Copy the initialization data into the driver extension so we can reuse
  195. // it during our add device routine
  196. //
  197. RtlCopyMemory(
  198. &(driverExtension->InitData),
  199. InitializationData,
  200. sizeof(CLASS_INIT_DATA));
  201. driverExtension->DeviceCount = 0;
  202. } else if (status == STATUS_OBJECT_NAME_COLLISION) {
  203. //
  204. // The extension already exists - get a pointer to it
  205. //
  206. driverExtension = IoGetDriverObjectExtension(DriverObject,
  207. CLASS_DRIVER_EXTENSION_KEY);
  208. ASSERT(driverExtension != NULL);
  209. } else {
  210. DebugPrint((1, "ClassInitialize: Class driver extension could not be "
  211. "allocated %lx\n", status));
  212. return status;
  213. }
  214. //
  215. // Update driver object with entry points.
  216. //
  217. DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassCreateClose;
  218. DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassCreateClose;
  219. DriverObject->MajorFunction[IRP_MJ_READ] = ClassReadWrite;
  220. DriverObject->MajorFunction[IRP_MJ_WRITE] = ClassReadWrite;
  221. DriverObject->MajorFunction[IRP_MJ_SCSI] = ClassInternalIoControl;
  222. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControlDispatch;
  223. DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ClassShutdownFlush;
  224. DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ClassShutdownFlush;
  225. DriverObject->MajorFunction[IRP_MJ_PNP] = ClassDispatchPnp;
  226. DriverObject->MajorFunction[IRP_MJ_POWER] = ClassDispatchPower;
  227. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ClassSystemControl;
  228. if (InitializationData->ClassStartIo) {
  229. DriverObject->DriverStartIo = ClasspStartIo;
  230. }
  231. if ((InitializationData->ClassUnload) && (ClassPnpAllowUnload == TRUE)) {
  232. DriverObject->DriverUnload = ClassUnload;
  233. } else {
  234. DriverObject->DriverUnload = NULL;
  235. }
  236. DriverObject->DriverExtension->AddDevice = ClassAddDevice;
  237. status = STATUS_SUCCESS;
  238. return status;
  239. } // end ClassInitialize()
  240. /*++////////////////////////////////////////////////////////////////////////////
  241. ClassInitializeEx()
  242. Routine Description:
  243. This routine is allows the caller to do any extra initialization or
  244. setup that is not done in ClassInitialize. The operation is
  245. controlled by the GUID that is passed and the contents of the Data
  246. parameter is dependent upon the GUID.
  247. This is the list of supported operations:
  248. Guid - GUID_CLASSPNP_QUERY_REGINFOEX
  249. Data - A PCLASS_QUERY_WMI_REGINFO_EX callback function pointer
  250. Initialized classpnp to callback a PCLASS_QUERY_WMI_REGINFO_EX
  251. callback instead of a PCLASS_QUERY_WMI_REGINFO callback. The
  252. former callback allows the driver to specify the name of the
  253. mof resource.
  254. Arguments:
  255. DriverObject
  256. Guid
  257. Data
  258. Return Value:
  259. Status Code
  260. --*/
  261. ULONG
  262. ClassInitializeEx(
  263. IN PDRIVER_OBJECT DriverObject,
  264. IN LPGUID Guid,
  265. IN PVOID Data
  266. )
  267. {
  268. PCLASS_DRIVER_EXTENSION driverExtension;
  269. NTSTATUS status;
  270. PAGED_CODE();
  271. driverExtension = IoGetDriverObjectExtension( DriverObject,
  272. CLASS_DRIVER_EXTENSION_KEY
  273. );
  274. if (IsEqualGUID(Guid, &ClassGuidQueryRegInfoEx))
  275. {
  276. PCLASS_QUERY_WMI_REGINFO_EX_LIST List;
  277. //
  278. // Indicate the device supports PCLASS_QUERY_REGINFO_EX
  279. // callback instead of PCLASS_QUERY_REGINFO callback.
  280. //
  281. List = (PCLASS_QUERY_WMI_REGINFO_EX_LIST)Data;
  282. if (List->Size == sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST))
  283. {
  284. driverExtension->ClassFdoQueryWmiRegInfoEx = List->ClassFdoQueryWmiRegInfoEx;
  285. driverExtension->ClassPdoQueryWmiRegInfoEx = List->ClassPdoQueryWmiRegInfoEx;
  286. status = STATUS_SUCCESS;
  287. } else {
  288. status = STATUS_INVALID_PARAMETER;
  289. }
  290. } else {
  291. status = STATUS_NOT_SUPPORTED;
  292. }
  293. return(status);
  294. } // end ClassInitializeEx()
  295. /*++////////////////////////////////////////////////////////////////////////////
  296. ClassUnload()
  297. Routine Description:
  298. called when there are no more references to the driver. this allows
  299. drivers to be updated without rebooting.
  300. Arguments:
  301. DriverObject - a pointer to the driver object that is being unloaded
  302. Status:
  303. --*/
  304. VOID
  305. ClassUnload(
  306. IN PDRIVER_OBJECT DriverObject
  307. )
  308. {
  309. PCLASS_DRIVER_EXTENSION driverExtension;
  310. NTSTATUS status;
  311. PAGED_CODE();
  312. ASSERT( DriverObject->DeviceObject == NULL );
  313. driverExtension = IoGetDriverObjectExtension( DriverObject,
  314. CLASS_DRIVER_EXTENSION_KEY
  315. );
  316. ASSERT(driverExtension != NULL);
  317. ASSERT(driverExtension->RegistryPath.Buffer != NULL);
  318. ASSERT(driverExtension->InitData.ClassUnload != NULL);
  319. DebugPrint((1, "ClassUnload: driver unloading %wZ\n",
  320. &driverExtension->RegistryPath));
  321. //
  322. // attempt to process the driver's unload routine first.
  323. //
  324. driverExtension->InitData.ClassUnload(DriverObject);
  325. //
  326. // free own allocated resources and return
  327. //
  328. ExFreePool( driverExtension->RegistryPath.Buffer );
  329. driverExtension->RegistryPath.Buffer = NULL;
  330. driverExtension->RegistryPath.Length = 0;
  331. driverExtension->RegistryPath.MaximumLength = 0;
  332. return;
  333. } // end ClassUnload()
  334. /*++////////////////////////////////////////////////////////////////////////////
  335. ClassAddDevice()
  336. Routine Description:
  337. SCSI class driver add device routine. This is called by pnp when a new
  338. physical device come into being.
  339. This routine will call out to the class driver to verify that it should
  340. own this device then will create and attach a device object and then hand
  341. it to the driver to initialize and create symbolic links
  342. Arguments:
  343. DriverObject - a pointer to the driver object that this is being created for
  344. PhysicalDeviceObject - a pointer to the physical device object
  345. Status: STATUS_NO_SUCH_DEVICE if the class driver did not want this device
  346. STATUS_SUCCESS if the creation and attachment was successful
  347. status of device creation and initialization
  348. --*/
  349. NTSTATUS
  350. ClassAddDevice(
  351. IN PDRIVER_OBJECT DriverObject,
  352. IN PDEVICE_OBJECT PhysicalDeviceObject
  353. )
  354. {
  355. PCLASS_DRIVER_EXTENSION driverExtension =
  356. IoGetDriverObjectExtension(DriverObject,
  357. CLASS_DRIVER_EXTENSION_KEY);
  358. NTSTATUS status;
  359. PAGED_CODE();
  360. status = driverExtension->InitData.ClassAddDevice(DriverObject,
  361. PhysicalDeviceObject);
  362. return status;
  363. } // end ClassAddDevice()
  364. /*++////////////////////////////////////////////////////////////////////////////
  365. ClassDispatchPnp()
  366. Routine Description:
  367. Storage class driver pnp routine. This is called by the io system when
  368. a PNP request is sent to the device.
  369. Arguments:
  370. DeviceObject - pointer to the device object
  371. Irp - pointer to the io request packet
  372. Return Value:
  373. status
  374. --*/
  375. NTSTATUS
  376. ClassDispatchPnp(
  377. IN PDEVICE_OBJECT DeviceObject,
  378. IN PIRP Irp
  379. )
  380. {
  381. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  382. BOOLEAN isFdo = commonExtension->IsFdo;
  383. PCLASS_DRIVER_EXTENSION driverExtension;
  384. PCLASS_INIT_DATA initData;
  385. PCLASS_DEV_INFO devInfo;
  386. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  387. PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
  388. NTSTATUS status = Irp->IoStatus.Status;
  389. BOOLEAN completeRequest = TRUE;
  390. BOOLEAN lockReleased = FALSE;
  391. ULONG isRemoved;
  392. PAGED_CODE();
  393. //
  394. // Extract all the useful information out of the driver object
  395. // extension
  396. //
  397. driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
  398. CLASS_DRIVER_EXTENSION_KEY);
  399. if (driverExtension){
  400. initData = &(driverExtension->InitData);
  401. if(isFdo) {
  402. devInfo = &(initData->FdoData);
  403. } else {
  404. devInfo = &(initData->PdoData);
  405. }
  406. isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
  407. DebugPrint((2, "ClassDispatchPnp (%p,%p): minor code %#x for %s %p\n",
  408. DeviceObject, Irp,
  409. irpStack->MinorFunction,
  410. isFdo ? "fdo" : "pdo",
  411. DeviceObject));
  412. DebugPrint((2, "ClassDispatchPnp (%p,%p): previous %#x, current %#x\n",
  413. DeviceObject, Irp,
  414. commonExtension->PreviousState,
  415. commonExtension->CurrentState));
  416. switch(irpStack->MinorFunction) {
  417. case IRP_MN_START_DEVICE: {
  418. //
  419. // if this is sent to the FDO we should forward it down the
  420. // attachment chain before we start the FDO.
  421. //
  422. if (isFdo) {
  423. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  424. }
  425. else {
  426. status = STATUS_SUCCESS;
  427. }
  428. if (NT_SUCCESS(status)){
  429. status = Irp->IoStatus.Status = ClassPnpStartDevice(DeviceObject);
  430. }
  431. break;
  432. }
  433. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  434. DEVICE_RELATION_TYPE type =
  435. irpStack->Parameters.QueryDeviceRelations.Type;
  436. PDEVICE_RELATIONS deviceRelations = NULL;
  437. if(!isFdo) {
  438. if(type == TargetDeviceRelation) {
  439. //
  440. // Device relations has one entry built in to it's size.
  441. //
  442. status = STATUS_INSUFFICIENT_RESOURCES;
  443. deviceRelations = ExAllocatePoolWithTag(PagedPool,
  444. sizeof(DEVICE_RELATIONS),
  445. '2CcS');
  446. if(deviceRelations != NULL) {
  447. RtlZeroMemory(deviceRelations,
  448. sizeof(DEVICE_RELATIONS));
  449. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  450. deviceRelations->Count = 1;
  451. deviceRelations->Objects[0] = DeviceObject;
  452. ObReferenceObject(deviceRelations->Objects[0]);
  453. status = STATUS_SUCCESS;
  454. }
  455. } else {
  456. //
  457. // PDO's just complete enumeration requests without altering
  458. // the status.
  459. //
  460. status = Irp->IoStatus.Status;
  461. }
  462. break;
  463. } else if (type == BusRelations) {
  464. ASSERT(commonExtension->IsInitialized);
  465. //
  466. // Make sure we support enumeration
  467. //
  468. if(initData->ClassEnumerateDevice == NULL) {
  469. //
  470. // Just send the request down to the lower driver. Perhaps
  471. // It can enumerate children.
  472. //
  473. } else {
  474. //
  475. // Re-enumerate the device
  476. //
  477. status = ClassPnpQueryFdoRelations(DeviceObject, Irp);
  478. if(!NT_SUCCESS(status)) {
  479. completeRequest = TRUE;
  480. break;
  481. }
  482. }
  483. }
  484. IoCopyCurrentIrpStackLocationToNext(Irp);
  485. ClassReleaseRemoveLock(DeviceObject, Irp);
  486. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  487. completeRequest = FALSE;
  488. break;
  489. }
  490. case IRP_MN_QUERY_ID: {
  491. BUS_QUERY_ID_TYPE idType = irpStack->Parameters.QueryId.IdType;
  492. UNICODE_STRING unicodeString;
  493. if(isFdo) {
  494. //
  495. // FDO's should just forward the query down to the lower
  496. // device objects
  497. //
  498. IoCopyCurrentIrpStackLocationToNext(Irp);
  499. ClassReleaseRemoveLock(DeviceObject, Irp);
  500. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  501. completeRequest = FALSE;
  502. break;
  503. }
  504. //
  505. // PDO's need to give an answer - this is easy for now
  506. //
  507. RtlInitUnicodeString(&unicodeString, NULL);
  508. status = ClassGetPdoId(DeviceObject,
  509. idType,
  510. &unicodeString);
  511. if(status == STATUS_NOT_IMPLEMENTED) {
  512. //
  513. // The driver doesn't implement this ID (whatever it is).
  514. // Use the status out of the IRP so that we don't mangle a
  515. // response from someone else.
  516. //
  517. status = Irp->IoStatus.Status;
  518. } else if(NT_SUCCESS(status)) {
  519. Irp->IoStatus.Information = (ULONG_PTR) unicodeString.Buffer;
  520. } else {
  521. Irp->IoStatus.Information = (ULONG_PTR) NULL;
  522. }
  523. break;
  524. }
  525. case IRP_MN_QUERY_STOP_DEVICE:
  526. case IRP_MN_QUERY_REMOVE_DEVICE: {
  527. DebugPrint((2, "ClassDispatchPnp (%p,%p): Processing QUERY_%s irp\n",
  528. DeviceObject, Irp,
  529. ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ?
  530. "STOP" : "REMOVE")));
  531. //
  532. // If this device is in use for some reason (paging, etc...)
  533. // then we need to fail the request.
  534. //
  535. if(commonExtension->PagingPathCount != 0) {
  536. DebugPrint((1, "ClassDispatchPnp (%p,%p): device is in paging "
  537. "path and cannot be removed\n",
  538. DeviceObject, Irp));
  539. status = STATUS_DEVICE_BUSY;
  540. break;
  541. }
  542. //
  543. // Check with the class driver to see if the query operation
  544. // can succeed.
  545. //
  546. if(irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) {
  547. status = devInfo->ClassStopDevice(DeviceObject,
  548. irpStack->MinorFunction);
  549. } else {
  550. status = devInfo->ClassRemoveDevice(DeviceObject,
  551. irpStack->MinorFunction);
  552. }
  553. if(NT_SUCCESS(status)) {
  554. //
  555. // ASSERT that we never get two queries in a row, as
  556. // this will severly mess up the state machine
  557. //
  558. ASSERT(commonExtension->CurrentState != irpStack->MinorFunction);
  559. commonExtension->PreviousState = commonExtension->CurrentState;
  560. commonExtension->CurrentState = irpStack->MinorFunction;
  561. if(isFdo) {
  562. DebugPrint((2, "ClassDispatchPnp (%p,%p): Forwarding QUERY_"
  563. "%s irp\n", DeviceObject, Irp,
  564. ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ?
  565. "STOP" : "REMOVE")));
  566. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  567. }
  568. }
  569. DebugPrint((2, "ClassDispatchPnp (%p,%p): Final status == %x\n",
  570. DeviceObject, Irp, status));
  571. break;
  572. }
  573. case IRP_MN_CANCEL_STOP_DEVICE:
  574. case IRP_MN_CANCEL_REMOVE_DEVICE: {
  575. //
  576. // Check with the class driver to see if the query or cancel
  577. // operation can succeed.
  578. //
  579. if(irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) {
  580. status = devInfo->ClassStopDevice(DeviceObject,
  581. irpStack->MinorFunction);
  582. ASSERTMSG("ClassDispatchPnp !! CANCEL_STOP_DEVICE should "
  583. "never be failed\n", NT_SUCCESS(status));
  584. } else {
  585. status = devInfo->ClassRemoveDevice(DeviceObject,
  586. irpStack->MinorFunction);
  587. ASSERTMSG("ClassDispatchPnp !! CANCEL_REMOVE_DEVICE should "
  588. "never be failed\n", NT_SUCCESS(status));
  589. }
  590. Irp->IoStatus.Status = status;
  591. //
  592. // We got a CANCEL - roll back to the previous state only
  593. // if the current state is the respective QUERY state.
  594. //
  595. if(((irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) &&
  596. (commonExtension->CurrentState == IRP_MN_QUERY_STOP_DEVICE)
  597. ) ||
  598. ((irpStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE) &&
  599. (commonExtension->CurrentState == IRP_MN_QUERY_REMOVE_DEVICE)
  600. )
  601. ) {
  602. commonExtension->CurrentState =
  603. commonExtension->PreviousState;
  604. commonExtension->PreviousState = 0xff;
  605. }
  606. if(isFdo) {
  607. IoCopyCurrentIrpStackLocationToNext(Irp);
  608. ClassReleaseRemoveLock(DeviceObject, Irp);
  609. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  610. completeRequest = FALSE;
  611. } else {
  612. status = STATUS_SUCCESS;
  613. }
  614. break;
  615. }
  616. case IRP_MN_STOP_DEVICE: {
  617. //
  618. // These all mean nothing to the class driver currently. The
  619. // port driver will handle all queueing when necessary.
  620. //
  621. DebugPrint((2, "ClassDispatchPnp (%p,%p): got stop request for %s\n",
  622. DeviceObject, Irp,
  623. (isFdo ? "fdo" : "pdo")
  624. ));
  625. ASSERT(commonExtension->PagingPathCount == 0);
  626. //
  627. // ISSUE-2000/02/03-peterwie
  628. // if we stop the timer here then it means no class driver can
  629. // do i/o in its ClassStopDevice routine. This is because the
  630. // retry (among other things) is tied into the tick handler
  631. // and disabling retries could cause the class driver to deadlock.
  632. // Currently no class driver we're aware of issues i/o in its
  633. // Stop routine but this is a case we may want to defend ourself
  634. // against.
  635. //
  636. if (DeviceObject->Timer) {
  637. IoStopTimer(DeviceObject);
  638. }
  639. status = devInfo->ClassStopDevice(DeviceObject, IRP_MN_STOP_DEVICE);
  640. ASSERTMSG("ClassDispatchPnp !! STOP_DEVICE should "
  641. "never be failed\n", NT_SUCCESS(status));
  642. if(isFdo) {
  643. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  644. }
  645. if(NT_SUCCESS(status)) {
  646. commonExtension->CurrentState = irpStack->MinorFunction;
  647. commonExtension->PreviousState = 0xff;
  648. }
  649. break;
  650. }
  651. case IRP_MN_REMOVE_DEVICE:
  652. case IRP_MN_SURPRISE_REMOVAL: {
  653. PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject;
  654. UCHAR removeType = irpStack->MinorFunction;
  655. if (commonExtension->PagingPathCount != 0) {
  656. DBGTRACE(ClassDebugWarning, ("ClassDispatchPnp (%p,%p): paging device is getting removed!", DeviceObject, Irp));
  657. }
  658. //
  659. // Release the lock for this IRP before calling in.
  660. //
  661. ClassReleaseRemoveLock(DeviceObject, Irp);
  662. lockReleased = TRUE;
  663. /*
  664. * Set IsRemoved before propagating the REMOVE down the stack.
  665. * This keeps class-initiated I/O (e.g. the MCN irp) from getting sent
  666. * after we propagate the remove.
  667. */
  668. commonExtension->IsRemoved = REMOVE_PENDING;
  669. /*
  670. * If a timer was started on the device, stop it.
  671. */
  672. if (DeviceObject->Timer) {
  673. IoStopTimer(DeviceObject);
  674. }
  675. /*
  676. * "Fire-and-forget" the remove irp to the lower stack.
  677. * Don't touch the irp (or the irp stack!) after this.
  678. */
  679. if (isFdo) {
  680. IoCopyCurrentIrpStackLocationToNext(Irp);
  681. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  682. ASSERT(NT_SUCCESS(status));
  683. completeRequest = FALSE;
  684. }
  685. else {
  686. status = STATUS_SUCCESS;
  687. }
  688. /*
  689. * Do our own cleanup and call the class driver's remove
  690. * cleanup routine.
  691. * For IRP_MN_REMOVE_DEVICE, this also deletes our device object,
  692. * so don't touch the extension after this.
  693. */
  694. commonExtension->PreviousState = commonExtension->CurrentState;
  695. commonExtension->CurrentState = removeType;
  696. ClassRemoveDevice(DeviceObject, removeType);
  697. break;
  698. }
  699. case IRP_MN_DEVICE_USAGE_NOTIFICATION: {
  700. switch(irpStack->Parameters.UsageNotification.Type) {
  701. case DeviceUsageTypePaging: {
  702. BOOLEAN setPagable;
  703. if((irpStack->Parameters.UsageNotification.InPath) &&
  704. (commonExtension->CurrentState != IRP_MN_START_DEVICE)) {
  705. //
  706. // Device isn't started. Don't allow adding a
  707. // paging file, but allow a removal of one.
  708. //
  709. status = STATUS_DEVICE_NOT_READY;
  710. break;
  711. }
  712. ASSERT(commonExtension->IsInitialized);
  713. /*
  714. * Ensure that this user thread is not suspended while we are holding the PathCountEvent.
  715. */
  716. KeEnterCriticalRegion();
  717. status = KeWaitForSingleObject(&commonExtension->PathCountEvent,
  718. Executive, KernelMode,
  719. FALSE, NULL);
  720. ASSERT(NT_SUCCESS(status));
  721. status = STATUS_SUCCESS;
  722. //
  723. // If the volume is removable we should try to lock it in
  724. // place or unlock it once per paging path count
  725. //
  726. if (commonExtension->IsFdo){
  727. status = ClasspEjectionControl(
  728. DeviceObject,
  729. Irp,
  730. InternalMediaLock,
  731. (BOOLEAN)irpStack->Parameters.UsageNotification.InPath);
  732. }
  733. if (!NT_SUCCESS(status)){
  734. KeSetEvent(&commonExtension->PathCountEvent, IO_NO_INCREMENT, FALSE);
  735. KeLeaveCriticalRegion();
  736. break;
  737. }
  738. //
  739. // if removing last paging device, need to set DO_POWER_PAGABLE
  740. // bit here, and possible re-set it below on failure.
  741. //
  742. setPagable = FALSE;
  743. if (!irpStack->Parameters.UsageNotification.InPath &&
  744. commonExtension->PagingPathCount == 1
  745. ) {
  746. //
  747. // removing last paging file
  748. // must have DO_POWER_PAGABLE bits set, but only
  749. // if noone set the DO_POWER_INRUSH bit
  750. //
  751. if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) {
  752. DebugPrint((2, "ClassDispatchPnp (%p,%p): Last "
  753. "paging file removed, but "
  754. "DO_POWER_INRUSH was set, so NOT "
  755. "setting DO_POWER_PAGABLE\n",
  756. DeviceObject, Irp));
  757. } else {
  758. DebugPrint((2, "ClassDispatchPnp (%p,%p): Last "
  759. "paging file removed, "
  760. "setting DO_POWER_PAGABLE\n",
  761. DeviceObject, Irp));
  762. SET_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
  763. setPagable = TRUE;
  764. }
  765. }
  766. //
  767. // forward the irp before finishing handling the
  768. // special cases
  769. //
  770. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  771. //
  772. // now deal with the failure and success cases.
  773. // note that we are not allowed to fail the irp
  774. // once it is sent to the lower drivers.
  775. //
  776. if (NT_SUCCESS(status)) {
  777. IoAdjustPagingPathCount(
  778. &commonExtension->PagingPathCount,
  779. irpStack->Parameters.UsageNotification.InPath);
  780. if (irpStack->Parameters.UsageNotification.InPath) {
  781. if (commonExtension->PagingPathCount == 1) {
  782. DebugPrint((2, "ClassDispatchPnp (%p,%p): "
  783. "Clearing PAGABLE bit\n",
  784. DeviceObject, Irp));
  785. CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
  786. }
  787. }
  788. } else {
  789. //
  790. // cleanup the changes done above
  791. //
  792. if (setPagable == TRUE) {
  793. DebugPrint((2, "ClassDispatchPnp (%p,%p): Unsetting "
  794. "PAGABLE bit due to irp failure\n",
  795. DeviceObject, Irp));
  796. CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE);
  797. setPagable = FALSE;
  798. }
  799. //
  800. // relock or unlock the media if needed.
  801. //
  802. if (commonExtension->IsFdo) {
  803. ClasspEjectionControl(
  804. DeviceObject,
  805. Irp,
  806. InternalMediaLock,
  807. (BOOLEAN)!irpStack->Parameters.UsageNotification.InPath);
  808. }
  809. }
  810. //
  811. // set the event so the next one can occur.
  812. //
  813. KeSetEvent(&commonExtension->PathCountEvent,
  814. IO_NO_INCREMENT, FALSE);
  815. KeLeaveCriticalRegion();
  816. break;
  817. }
  818. case DeviceUsageTypeHibernation: {
  819. IoAdjustPagingPathCount(
  820. &commonExtension->HibernationPathCount,
  821. irpStack->Parameters.UsageNotification.InPath
  822. );
  823. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  824. if (!NT_SUCCESS(status)) {
  825. IoAdjustPagingPathCount(
  826. &commonExtension->HibernationPathCount,
  827. !irpStack->Parameters.UsageNotification.InPath
  828. );
  829. }
  830. break;
  831. }
  832. case DeviceUsageTypeDumpFile: {
  833. IoAdjustPagingPathCount(
  834. &commonExtension->DumpPathCount,
  835. irpStack->Parameters.UsageNotification.InPath
  836. );
  837. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  838. if (!NT_SUCCESS(status)) {
  839. IoAdjustPagingPathCount(
  840. &commonExtension->DumpPathCount,
  841. !irpStack->Parameters.UsageNotification.InPath
  842. );
  843. }
  844. break;
  845. }
  846. default: {
  847. status = STATUS_INVALID_PARAMETER;
  848. break;
  849. }
  850. }
  851. break;
  852. }
  853. case IRP_MN_QUERY_CAPABILITIES: {
  854. DebugPrint((2, "ClassDispatchPnp (%p,%p): QueryCapabilities\n",
  855. DeviceObject, Irp));
  856. if(!isFdo) {
  857. status = ClassQueryPnpCapabilities(
  858. DeviceObject,
  859. irpStack->Parameters.DeviceCapabilities.Capabilities
  860. );
  861. break;
  862. } else {
  863. PDEVICE_CAPABILITIES deviceCapabilities;
  864. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  865. PCLASS_PRIVATE_FDO_DATA fdoData;
  866. fdoExtension = DeviceObject->DeviceExtension;
  867. fdoData = fdoExtension->PrivateFdoData;
  868. deviceCapabilities =
  869. irpStack->Parameters.DeviceCapabilities.Capabilities;
  870. //
  871. // forward the irp before handling the special cases
  872. //
  873. status = ClassForwardIrpSynchronous(commonExtension, Irp);
  874. if (!NT_SUCCESS(status)) {
  875. break;
  876. }
  877. //
  878. // we generally want to remove the device from the hotplug
  879. // applet, which requires the SR-OK bit to be set.
  880. // only when the user specifies that they are capable of
  881. // safely removing things do we want to clear this bit
  882. // (saved in WriteCacheEnableOverride)
  883. //
  884. // setting of this bit is done either above, or by the
  885. // lower driver.
  886. //
  887. // note: may not be started, so check we have FDO data first.
  888. //
  889. if (fdoData &&
  890. fdoData->HotplugInfo.WriteCacheEnableOverride) {
  891. if (deviceCapabilities->SurpriseRemovalOK) {
  892. DebugPrint((1, "Classpnp: Clearing SR-OK bit in "
  893. "device capabilities due to hotplug "
  894. "device or media\n"));
  895. }
  896. deviceCapabilities->SurpriseRemovalOK = FALSE;
  897. }
  898. break;
  899. } // end QUERY_CAPABILITIES for FDOs
  900. ASSERT(FALSE);
  901. break;
  902. } // end QUERY_CAPABILITIES
  903. default: {
  904. if (isFdo){
  905. IoCopyCurrentIrpStackLocationToNext(Irp);
  906. ClassReleaseRemoveLock(DeviceObject, Irp);
  907. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  908. completeRequest = FALSE;
  909. }
  910. break;
  911. }
  912. }
  913. }
  914. else {
  915. ASSERT(driverExtension);
  916. status = STATUS_INTERNAL_ERROR;
  917. }
  918. if (completeRequest){
  919. Irp->IoStatus.Status = status;
  920. if (!lockReleased){
  921. ClassReleaseRemoveLock(DeviceObject, Irp);
  922. }
  923. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  924. DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving with previous %#x, current %#x.", DeviceObject, Irp, commonExtension->PreviousState, commonExtension->CurrentState));
  925. }
  926. else {
  927. /*
  928. * The irp is already completed so don't touch it.
  929. * This may be a remove so don't touch the device extension.
  930. */
  931. DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving.", DeviceObject, Irp));
  932. }
  933. return status;
  934. } // end ClassDispatchPnp()
  935. /*++////////////////////////////////////////////////////////////////////////////
  936. ClassPnpStartDevice()
  937. Routine Description:
  938. Storage class driver routine for IRP_MN_START_DEVICE requests.
  939. This routine kicks off any device specific initialization
  940. Arguments:
  941. DeviceObject - a pointer to the device object
  942. Irp - a pointer to the io request packet
  943. Return Value:
  944. none
  945. --*/
  946. NTSTATUS ClassPnpStartDevice(IN PDEVICE_OBJECT DeviceObject)
  947. {
  948. PCLASS_DRIVER_EXTENSION driverExtension;
  949. PCLASS_INIT_DATA initData;
  950. PCLASS_DEV_INFO devInfo;
  951. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  952. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  953. BOOLEAN isFdo = commonExtension->IsFdo;
  954. BOOLEAN isMountedDevice = TRUE;
  955. UNICODE_STRING interfaceName;
  956. BOOLEAN timerStarted = FALSE;
  957. NTSTATUS status = STATUS_SUCCESS;
  958. PAGED_CODE();
  959. driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
  960. CLASS_DRIVER_EXTENSION_KEY);
  961. initData = &(driverExtension->InitData);
  962. if(isFdo) {
  963. devInfo = &(initData->FdoData);
  964. } else {
  965. devInfo = &(initData->PdoData);
  966. }
  967. ASSERT(devInfo->ClassInitDevice != NULL);
  968. ASSERT(devInfo->ClassStartDevice != NULL);
  969. if (!commonExtension->IsInitialized){
  970. //
  971. // perform FDO/PDO specific initialization
  972. //
  973. if (isFdo){
  974. STORAGE_PROPERTY_ID propertyId;
  975. //
  976. // allocate a private extension for class data
  977. //
  978. if (fdoExtension->PrivateFdoData == NULL) {
  979. fdoExtension->PrivateFdoData =
  980. ExAllocatePoolWithTag(NonPagedPool,
  981. sizeof(CLASS_PRIVATE_FDO_DATA),
  982. CLASS_TAG_PRIVATE_DATA
  983. );
  984. }
  985. if (fdoExtension->PrivateFdoData == NULL) {
  986. DebugPrint((0, "ClassPnpStartDevice: Cannot allocate for "
  987. "private fdo data\n"));
  988. return STATUS_INSUFFICIENT_RESOURCES;
  989. }
  990. //
  991. // initialize the struct's various fields.
  992. //
  993. RtlZeroMemory(fdoExtension->PrivateFdoData, sizeof(CLASS_PRIVATE_FDO_DATA));
  994. KeInitializeTimer(&fdoExtension->PrivateFdoData->Retry.Timer);
  995. KeInitializeDpc(&fdoExtension->PrivateFdoData->Retry.Dpc,
  996. ClasspRetryRequestDpc,
  997. DeviceObject);
  998. KeInitializeSpinLock(&fdoExtension->PrivateFdoData->Retry.Lock);
  999. fdoExtension->PrivateFdoData->Retry.Granularity = KeQueryTimeIncrement();
  1000. commonExtension->Reserved4 = (ULONG_PTR)(' GPH'); // debug aid
  1001. InitializeListHead(&fdoExtension->PrivateFdoData->DeferredClientIrpList);
  1002. /*
  1003. * Anchor the FDO in our static list.
  1004. * Pnp is synchronized, so we shouldn't need any synchronization here.
  1005. */
  1006. InsertTailList(&AllFdosList, &fdoExtension->PrivateFdoData->AllFdosListEntry);
  1007. //
  1008. // NOTE: the old interface allowed the class driver to allocate
  1009. // this. this was unsafe for low-memory conditions. allocate one
  1010. // unconditionally now, and modify our internal functions to use
  1011. // our own exclusively as it is the only safe way to do this.
  1012. //
  1013. status = ClasspAllocateReleaseQueueIrp(fdoExtension);
  1014. if (!NT_SUCCESS(status)) {
  1015. DebugPrint((0, "ClassPnpStartDevice: Cannot allocate the private release queue irp\n"));
  1016. return status;
  1017. }
  1018. //
  1019. // Call port driver to get adapter capabilities.
  1020. //
  1021. propertyId = StorageAdapterProperty;
  1022. status = ClassGetDescriptor(
  1023. commonExtension->LowerDeviceObject,
  1024. &propertyId,
  1025. &fdoExtension->AdapterDescriptor);
  1026. if (!NT_SUCCESS(status)) {
  1027. DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor [ADAPTER] failed %lx\n", status));
  1028. return status;
  1029. }
  1030. //
  1031. // Call port driver to get device descriptor.
  1032. //
  1033. propertyId = StorageDeviceProperty;
  1034. status = ClassGetDescriptor(
  1035. commonExtension->LowerDeviceObject,
  1036. &propertyId,
  1037. &fdoExtension->DeviceDescriptor);
  1038. if (NT_SUCCESS(status)){
  1039. ClasspScanForSpecialInRegistry(fdoExtension);
  1040. ClassScanForSpecial(fdoExtension, ClassBadItems, ClasspScanForClassHacks);
  1041. //
  1042. // allow perf to be re-enabled after a given number of failed IOs
  1043. // require this number to be at least CLASS_PERF_RESTORE_MINIMUM
  1044. //
  1045. {
  1046. ULONG t = CLASS_PERF_RESTORE_MINIMUM;
  1047. ClassGetDeviceParameter(fdoExtension,
  1048. CLASSP_REG_SUBKEY_NAME,
  1049. CLASSP_REG_PERF_RESTORE_VALUE_NAME,
  1050. &t);
  1051. if (t >= CLASS_PERF_RESTORE_MINIMUM) {
  1052. fdoExtension->PrivateFdoData->Perf.ReEnableThreshhold = t;
  1053. }
  1054. }
  1055. //
  1056. // compatibility comes first. writable cd media will not
  1057. // get a SYNCH_CACHE on power down.
  1058. //
  1059. if (fdoExtension->DeviceObject->DeviceType != FILE_DEVICE_DISK) {
  1060. SET_FLAG(fdoExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_SYNC_CACHE);
  1061. }
  1062. //
  1063. // initialize the hotplug information only after the ScanForSpecial
  1064. // routines, as it relies upon the hack flags.
  1065. //
  1066. status = ClasspInitializeHotplugInfo(fdoExtension);
  1067. if (NT_SUCCESS(status)){
  1068. /*
  1069. * Allocate/initialize TRANSFER_PACKETs and related resources.
  1070. */
  1071. status = InitializeTransferPackets(DeviceObject);
  1072. }
  1073. else {
  1074. DebugPrint((1, "ClassPnpStartDevice: Could not initialize hotplug information %lx\n", status));
  1075. }
  1076. }
  1077. else {
  1078. DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor [DEVICE] failed %lx\n", status));
  1079. }
  1080. }
  1081. //
  1082. // ISSUE - drivers need to disable write caching on the media
  1083. // if hotplug and !useroverride. perhaps we should
  1084. // allow registration of a callback to enable/disable
  1085. // write cache instead.
  1086. //
  1087. if (NT_SUCCESS(status)){
  1088. status = devInfo->ClassInitDevice(DeviceObject);
  1089. }
  1090. }
  1091. if (!NT_SUCCESS(status)){
  1092. //
  1093. // Just bail out - the remove that comes down will clean up the
  1094. // initialized scraps.
  1095. //
  1096. return status;
  1097. } else {
  1098. commonExtension->IsInitialized = TRUE;
  1099. if (commonExtension->IsFdo) {
  1100. fdoExtension->PrivateFdoData->Perf.OriginalSrbFlags = fdoExtension->SrbFlags;
  1101. }
  1102. }
  1103. //
  1104. // If device requests autorun functionality or a once a second callback
  1105. // then enable the once per second timer.
  1106. //
  1107. // NOTE: This assumes that ClassInitializeMediaChangeDetection is always
  1108. // called in the context of the ClassInitDevice callback. If called
  1109. // after then this check will have already been made and the
  1110. // once a second timer will not have been enabled.
  1111. //
  1112. if ((isFdo) &&
  1113. ((initData->ClassTick != NULL) ||
  1114. (fdoExtension->MediaChangeDetectionInfo != NULL) ||
  1115. ((fdoExtension->FailurePredictionInfo != NULL) &&
  1116. (fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone))))
  1117. {
  1118. ClasspEnableTimer(DeviceObject);
  1119. timerStarted = TRUE;
  1120. }
  1121. //
  1122. // NOTE: the timer looks at commonExtension->CurrentState now
  1123. // to prevent Media Change Notification code from running
  1124. // until the device is started, but allows the device
  1125. // specific tick handler to run. therefore it is imperative
  1126. // that commonExtension->CurrentState not be updated until
  1127. // the device specific startdevice handler has finished.
  1128. //
  1129. status = devInfo->ClassStartDevice(DeviceObject);
  1130. if (NT_SUCCESS(status)){
  1131. commonExtension->CurrentState = IRP_MN_START_DEVICE;
  1132. if((isFdo) && (initData->ClassEnumerateDevice != NULL)) {
  1133. isMountedDevice = FALSE;
  1134. }
  1135. if((DeviceObject->DeviceType != FILE_DEVICE_DISK) &&
  1136. (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)) {
  1137. isMountedDevice = FALSE;
  1138. }
  1139. if(isMountedDevice) {
  1140. ClasspRegisterMountedDeviceInterface(DeviceObject);
  1141. }
  1142. if((commonExtension->IsFdo) &&
  1143. (devInfo->ClassWmiInfo.GuidRegInfo != NULL)) {
  1144. IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_REGISTER);
  1145. }
  1146. }
  1147. else {
  1148. if (timerStarted) {
  1149. ClasspDisableTimer(DeviceObject);
  1150. }
  1151. }
  1152. return status;
  1153. }
  1154. /*++////////////////////////////////////////////////////////////////////////////
  1155. ClassReadWrite()
  1156. Routine Description:
  1157. This is the system entry point for read and write requests. The
  1158. device-specific handler is invoked to perform any validation necessary.
  1159. If the device object is a PDO (partition object) then the request will
  1160. simply be adjusted for Partition0 and issued to the lower device driver.
  1161. IF the device object is an FDO (paritition 0 object), the number of bytes
  1162. in the request are checked against the maximum byte counts that the adapter
  1163. supports and requests are broken up into
  1164. smaller sizes if necessary.
  1165. Arguments:
  1166. DeviceObject - a pointer to the device object for this request
  1167. Irp - IO request
  1168. Return Value:
  1169. NT Status
  1170. --*/
  1171. NTSTATUS ClassReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
  1172. {
  1173. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  1174. PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject;
  1175. PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
  1176. LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset;
  1177. ULONG transferByteCount = currentIrpStack->Parameters.Read.Length;
  1178. ULONG isRemoved;
  1179. NTSTATUS status;
  1180. /*
  1181. * Grab the remove lock. If we can't acquire it, bail out.
  1182. */
  1183. isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
  1184. if (isRemoved) {
  1185. Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
  1186. ClassReleaseRemoveLock(DeviceObject, Irp);
  1187. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  1188. status = STATUS_DEVICE_DOES_NOT_EXIST;
  1189. }
  1190. else if (TEST_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME) &&
  1191. (currentIrpStack->MinorFunction != CLASSP_VOLUME_VERIFY_CHECKED) &&
  1192. !TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)){
  1193. /*
  1194. * DO_VERIFY_VOLUME is set for the device object,
  1195. * but this request is not itself a verify request.
  1196. * So fail this request.
  1197. */
  1198. IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
  1199. Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
  1200. Irp->IoStatus.Information = 0;
  1201. ClassReleaseRemoveLock(DeviceObject, Irp);
  1202. ClassCompleteRequest(DeviceObject, Irp, 0);
  1203. status = STATUS_VERIFY_REQUIRED;
  1204. }
  1205. else {
  1206. /*
  1207. * Since we've bypassed the verify-required tests we don't need to repeat
  1208. * them with this IRP - in particular we don't want to worry about
  1209. * hitting them at the partition 0 level if the request has come through
  1210. * a non-zero partition.
  1211. */
  1212. currentIrpStack->MinorFunction = CLASSP_VOLUME_VERIFY_CHECKED;
  1213. /*
  1214. * Call the miniport driver's pre-pass filter to check if we
  1215. * should continue with this transfer.
  1216. */
  1217. ASSERT(commonExtension->DevInfo->ClassReadWriteVerification);
  1218. status = commonExtension->DevInfo->ClassReadWriteVerification(DeviceObject, Irp);
  1219. if (!NT_SUCCESS(status)){
  1220. ASSERT(Irp->IoStatus.Status == status);
  1221. ASSERT(status != STATUS_INSUFFICIENT_RESOURCES);
  1222. ClassReleaseRemoveLock(DeviceObject, Irp);
  1223. ClassCompleteRequest (DeviceObject, Irp, IO_NO_INCREMENT);
  1224. }
  1225. else if (status == STATUS_PENDING){
  1226. /*
  1227. * ClassReadWriteVerification queued this request.
  1228. * So don't touch the irp anymore.
  1229. */
  1230. }
  1231. else {
  1232. if (transferByteCount == 0) {
  1233. /*
  1234. * Several parts of the code turn 0 into 0xffffffff,
  1235. * so don't process a zero-length request any further.
  1236. */
  1237. Irp->IoStatus.Status = STATUS_SUCCESS;
  1238. Irp->IoStatus.Information = 0;
  1239. ClassReleaseRemoveLock(DeviceObject, Irp);
  1240. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  1241. status = STATUS_SUCCESS;
  1242. }
  1243. else {
  1244. /*
  1245. * If the driver has its own StartIo routine, call it.
  1246. */
  1247. if (commonExtension->DriverExtension->InitData.ClassStartIo) {
  1248. IoMarkIrpPending(Irp);
  1249. IoStartPacket(DeviceObject, Irp, NULL, NULL);
  1250. status = STATUS_PENDING;
  1251. }
  1252. else {
  1253. /*
  1254. * The driver does not have its own StartIo routine.
  1255. * So process this request ourselves.
  1256. */
  1257. /*
  1258. * Add partition byte offset to make starting byte relative to
  1259. * beginning of disk.
  1260. */
  1261. currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
  1262. commonExtension->StartingOffset.QuadPart;
  1263. if (commonExtension->IsFdo){
  1264. /*
  1265. * Add in any skew for the disk manager software.
  1266. */
  1267. currentIrpStack->Parameters.Read.ByteOffset.QuadPart +=
  1268. commonExtension->PartitionZeroExtension->DMByteSkew;
  1269. /*
  1270. * Perform the actual transfer(s) on the hardware
  1271. * to service this request.
  1272. */
  1273. status = ServiceTransferRequest(DeviceObject, Irp);
  1274. }
  1275. else {
  1276. /*
  1277. * This is a child PDO enumerated for our FDO by e.g. disk.sys
  1278. * and owned by e.g. partmgr. Send it down to the next device
  1279. * and the same irp will come back to us for the FDO.
  1280. */
  1281. IoCopyCurrentIrpStackLocationToNext(Irp);
  1282. ClassReleaseRemoveLock(DeviceObject, Irp);
  1283. status = IoCallDriver(lowerDeviceObject, Irp);
  1284. }
  1285. }
  1286. }
  1287. }
  1288. }
  1289. return status;
  1290. }
  1291. VOID InterpretCapacityData(PDEVICE_OBJECT Fdo, PREAD_CAPACITY_DATA ReadCapacityData)
  1292. {
  1293. PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
  1294. ULONG cylinderSize;
  1295. ULONG bytesPerSector;
  1296. ULONG tmp;
  1297. ULONG lastSector;
  1298. /*
  1299. * Read the bytesPerSector value, which is big-endian in the returned buffer.
  1300. * Default to the standard 512 bytes.
  1301. */
  1302. tmp = ReadCapacityData->BytesPerBlock;
  1303. ((PFOUR_BYTE)&bytesPerSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
  1304. ((PFOUR_BYTE)&bytesPerSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
  1305. ((PFOUR_BYTE)&bytesPerSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
  1306. ((PFOUR_BYTE)&bytesPerSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
  1307. if (bytesPerSector == 0) {
  1308. bytesPerSector = 512;
  1309. }
  1310. else {
  1311. /*
  1312. * Clear all but the highest set bit.
  1313. * That will give us a bytesPerSector value that is a power of 2.
  1314. */
  1315. if (bytesPerSector & (bytesPerSector-1)){
  1316. DBGWARN(("FDO %ph has non-standard sector size 0x%x.", Fdo, bytesPerSector));
  1317. do {
  1318. bytesPerSector &= bytesPerSector-1;
  1319. }
  1320. while (bytesPerSector & (bytesPerSector-1));
  1321. }
  1322. }
  1323. fdoExt->DiskGeometry.BytesPerSector = bytesPerSector;
  1324. WHICH_BIT(fdoExt->DiskGeometry.BytesPerSector, fdoExt->SectorShift);
  1325. /*
  1326. * LogicalBlockAddress is the last sector of the logical drive, in big-endian.
  1327. * It tells us the size of the drive (#sectors is lastSector+1).
  1328. */
  1329. tmp = ReadCapacityData->LogicalBlockAddress;
  1330. ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3;
  1331. ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2;
  1332. ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1;
  1333. ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0;
  1334. if (fdoExt->DMActive){
  1335. DebugPrint((1, "ClassReadDriveCapacity: reducing number of sectors by %d\n", fdoExt->DMSkew));
  1336. lastSector -= fdoExt->DMSkew;
  1337. }
  1338. /*
  1339. * Check to see if we have a geometry we should be using already.
  1340. * If not, we set part of the disk geometry to garbage values that will be filled in by the caller (e.g. disk.sys).
  1341. *
  1342. * So the first call to ClassReadDriveCapacity always sets a meaningless geometry.
  1343. * TracksPerCylinder and SectorsPerTrack are kind of meaningless anyway wrt I/O,
  1344. * because I/O is always targeted to a logical sector number.
  1345. * All that really matters is BytesPerSector and the number of sectors.
  1346. */
  1347. cylinderSize = fdoExt->DiskGeometry.TracksPerCylinder * fdoExt->DiskGeometry.SectorsPerTrack;
  1348. if (cylinderSize == 0){
  1349. fdoExt->DiskGeometry.TracksPerCylinder = 0xff;
  1350. fdoExt->DiskGeometry.SectorsPerTrack = 0x3f;
  1351. cylinderSize = fdoExt->DiskGeometry.TracksPerCylinder * fdoExt->DiskGeometry.SectorsPerTrack;
  1352. }
  1353. /*
  1354. * Calculate number of cylinders.
  1355. * If there are zero cylinders, then the device lied AND it's
  1356. * smaller than 0xff*0x3f (about 16k sectors, usually 8 meg)
  1357. * this can fit into a single LONGLONG, so create another usable
  1358. * geometry, even if it's unusual looking.
  1359. * This allows small, non-standard devices, such as Sony's Memory Stick, to show up as having a partition.
  1360. */
  1361. fdoExt->DiskGeometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/cylinderSize);
  1362. if (fdoExt->DiskGeometry.Cylinders.QuadPart == (LONGLONG)0) {
  1363. fdoExt->DiskGeometry.SectorsPerTrack = 1;
  1364. fdoExt->DiskGeometry.TracksPerCylinder = 1;
  1365. fdoExt->DiskGeometry.Cylinders.QuadPart = lastSector + 1;
  1366. }
  1367. /*
  1368. * Calculate media capacity in bytes.
  1369. * For this purpose we treat the entire LUN as is if it is one partition. Disk will deal with actual partitioning.
  1370. */
  1371. fdoExt->CommonExtension.PartitionLength.QuadPart =
  1372. ((LONGLONG)(lastSector + 1)) << fdoExt->SectorShift;
  1373. /*
  1374. * Is this removable or fixed media
  1375. */
  1376. if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){
  1377. fdoExt->DiskGeometry.MediaType = RemovableMedia;
  1378. }
  1379. else {
  1380. fdoExt->DiskGeometry.MediaType = FixedMedia;
  1381. }
  1382. }
  1383. /*++////////////////////////////////////////////////////////////////////////////
  1384. ClassReadDriveCapacity()
  1385. Routine Description:
  1386. This routine sends a READ CAPACITY to the requested device, updates
  1387. the geometry information in the device object and returns
  1388. when it is complete. This routine is synchronous.
  1389. This routine must be called with the remove lock held or some other
  1390. assurance that the Fdo will not be removed while processing.
  1391. Arguments:
  1392. DeviceObject - Supplies a pointer to the device object that represents
  1393. the device whose capacity is to be read.
  1394. Return Value:
  1395. Status is returned.
  1396. --*/
  1397. NTSTATUS ClassReadDriveCapacity(IN PDEVICE_OBJECT Fdo)
  1398. {
  1399. PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
  1400. PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
  1401. READ_CAPACITY_DATA PTRALIGN readCapacityData = {0};
  1402. NTSTATUS status;
  1403. PMDL driveCapMdl;
  1404. driveCapMdl = BuildDeviceInputMdl(&readCapacityData, sizeof(READ_CAPACITY_DATA));
  1405. if (driveCapMdl){
  1406. TRANSFER_PACKET *pkt = DequeueFreeTransferPacket(Fdo, TRUE);
  1407. if (pkt){
  1408. KEVENT event;
  1409. NTSTATUS pktStatus;
  1410. IRP pseudoIrp = {0};
  1411. /*
  1412. * Our engine needs an "original irp" to write the status back to
  1413. * and to count down packets (one in this case).
  1414. * Just use a pretend irp for this.
  1415. */
  1416. pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1);
  1417. pseudoIrp.IoStatus.Status = STATUS_SUCCESS;
  1418. pseudoIrp.IoStatus.Information = 0;
  1419. pseudoIrp.MdlAddress = driveCapMdl;
  1420. /*
  1421. * Set this up as a SYNCHRONOUS transfer, submit it,
  1422. * and wait for the packet to complete. The result
  1423. * status will be written to the original irp.
  1424. */
  1425. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1426. SetupDriveCapacityTransferPacket( pkt,
  1427. &readCapacityData,
  1428. sizeof(READ_CAPACITY_DATA),
  1429. &event,
  1430. &pseudoIrp);
  1431. SubmitTransferPacket(pkt);
  1432. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1433. status = pseudoIrp.IoStatus.Status;
  1434. /*
  1435. * If we got an UNDERRUN, retry exactly once.
  1436. * (The transfer_packet engine didn't retry because the result
  1437. * status was success).
  1438. */
  1439. if (NT_SUCCESS(status) &&
  1440. (pseudoIrp.IoStatus.Information < sizeof(READ_CAPACITY_DATA))){
  1441. DBGERR(("ClassReadDriveCapacity: read len (%xh) < %xh, retrying ...", (ULONG)pseudoIrp.IoStatus.Information, sizeof(READ_CAPACITY_DATA)));
  1442. pkt = DequeueFreeTransferPacket(Fdo, TRUE);
  1443. if (pkt){
  1444. pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1);
  1445. pseudoIrp.IoStatus.Status = STATUS_SUCCESS;
  1446. pseudoIrp.IoStatus.Information = 0;
  1447. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1448. SetupDriveCapacityTransferPacket( pkt,
  1449. &readCapacityData,
  1450. sizeof(READ_CAPACITY_DATA),
  1451. &event,
  1452. &pseudoIrp);
  1453. SubmitTransferPacket(pkt);
  1454. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  1455. status = pseudoIrp.IoStatus.Status;
  1456. if (pseudoIrp.IoStatus.Information < sizeof(READ_CAPACITY_DATA)){
  1457. status = STATUS_DEVICE_BUSY;
  1458. }
  1459. }
  1460. else {
  1461. status = STATUS_INSUFFICIENT_RESOURCES;
  1462. }
  1463. }
  1464. if (NT_SUCCESS(status)){
  1465. /*
  1466. * The request succeeded. Read out and store the drive information.
  1467. */
  1468. InterpretCapacityData(Fdo, &readCapacityData);
  1469. /*
  1470. * If the media is not removable, then store the readCapacityData.
  1471. * This is so that runtime memory failures don't cause disk.sys to put
  1472. * the paging disk in an error state.
  1473. */
  1474. if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){
  1475. fdoData->LastKnownDriveCapacityData = readCapacityData;
  1476. fdoData->IsCachedDriveCapDataValid = TRUE;
  1477. }
  1478. }
  1479. else {
  1480. /*
  1481. * The request failed.
  1482. */
  1483. //
  1484. // ISSUE - 2000/02/04 - henrygab - non-512-byte sector sizes and failed geometry update
  1485. // what happens when the disk's sector size is bigger than
  1486. // 512 bytes and we hit this code path? this is untested.
  1487. //
  1488. // If the read capacity fails, set the geometry to reasonable parameter
  1489. // so things don't fail at unexpected places. Zero the geometry
  1490. // except for the bytes per sector and sector shift.
  1491. //
  1492. /*
  1493. * This request can sometimes fail legitimately
  1494. * (e.g. when a SCSI device is attached but turned off)
  1495. * so this is not necessarily a device/driver bug.
  1496. */
  1497. DBGTRACE(ClassDebugWarning, ("ClassReadDriveCapacity on Fdo %xh failed with status %xh.", Fdo, status));
  1498. /*
  1499. * Write in a default disk geometry which we HOPE is right (??).
  1500. */
  1501. RtlZeroMemory(&fdoExt->DiskGeometry, sizeof(DISK_GEOMETRY));
  1502. fdoExt->DiskGeometry.BytesPerSector = 512;
  1503. fdoExt->SectorShift = 9;
  1504. fdoExt->CommonExtension.PartitionLength.QuadPart = (LONGLONG) 0;
  1505. /*
  1506. * Is this removable or fixed media
  1507. */
  1508. if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){
  1509. fdoExt->DiskGeometry.MediaType = RemovableMedia;
  1510. }
  1511. else {
  1512. fdoExt->DiskGeometry.MediaType = FixedMedia;
  1513. }
  1514. }
  1515. }
  1516. else {
  1517. status = STATUS_INSUFFICIENT_RESOURCES;
  1518. }
  1519. FreeDeviceInputMdl(driveCapMdl);
  1520. }
  1521. else {
  1522. status = STATUS_INSUFFICIENT_RESOURCES;
  1523. }
  1524. /*
  1525. * Don't let memory failures (either here or in the port driver) in the ReadDriveCapacity call
  1526. * put the paging disk in an error state such that paging fails.
  1527. * Return the last known drive capacity (which may possibly be slightly out of date, even on
  1528. * fixed media, e.g. for storage cabinets that can grow a logical disk).
  1529. */
  1530. if ((status == STATUS_INSUFFICIENT_RESOURCES) && fdoData->IsCachedDriveCapDataValid){
  1531. ASSERT(fdoExt->DiskGeometry.MediaType == FixedMedia);
  1532. DBGWARN(("ClassReadDriveCapacity: defaulting to cached DriveCapacity data"));
  1533. InterpretCapacityData(Fdo, &fdoData->LastKnownDriveCapacityData);
  1534. status = STATUS_SUCCESS;
  1535. }
  1536. return status;
  1537. }
  1538. /*++////////////////////////////////////////////////////////////////////////////
  1539. ClassSendStartUnit()
  1540. Routine Description:
  1541. Send command to SCSI unit to start or power up.
  1542. Because this command is issued asynchronounsly, that is, without
  1543. waiting on it to complete, the IMMEDIATE flag is not set. This
  1544. means that the CDB will not return until the drive has powered up.
  1545. This should keep subsequent requests from being submitted to the
  1546. device before it has completely spun up.
  1547. This routine is called from the InterpretSense routine, when a
  1548. request sense returns data indicating that a drive must be
  1549. powered up.
  1550. This routine may also be called from a class driver's error handler,
  1551. or anytime a non-critical start device should be sent to the device.
  1552. Arguments:
  1553. Fdo - The functional device object for the stopped device.
  1554. Return Value:
  1555. None.
  1556. --*/
  1557. VOID
  1558. ClassSendStartUnit(
  1559. IN PDEVICE_OBJECT Fdo
  1560. )
  1561. {
  1562. PIO_STACK_LOCATION irpStack;
  1563. PIRP irp;
  1564. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  1565. PSCSI_REQUEST_BLOCK srb;
  1566. PCOMPLETION_CONTEXT context;
  1567. PCDB cdb;
  1568. //
  1569. // Allocate Srb from nonpaged pool.
  1570. //
  1571. context = ExAllocatePoolWithTag(NonPagedPool,
  1572. sizeof(COMPLETION_CONTEXT),
  1573. '6CcS');
  1574. if(context == NULL) {
  1575. //
  1576. // ISSUE-2000/02/03-peterwie
  1577. // This code path was inheritted from the NT 4.0 class2.sys driver.
  1578. // It needs to be changed to survive low-memory conditions.
  1579. //
  1580. KeBugCheck(SCSI_DISK_DRIVER_INTERNAL);
  1581. }
  1582. //
  1583. // Save the device object in the context for use by the completion
  1584. // routine.
  1585. //
  1586. context->DeviceObject = Fdo;
  1587. srb = &context->Srb;
  1588. //
  1589. // Zero out srb.
  1590. //
  1591. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  1592. //
  1593. // Write length to SRB.
  1594. //
  1595. srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  1596. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  1597. //
  1598. // Set timeout value large enough for drive to spin up.
  1599. //
  1600. srb->TimeOutValue = START_UNIT_TIMEOUT;
  1601. //
  1602. // Set the transfer length.
  1603. //
  1604. srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER |
  1605. SRB_FLAGS_DISABLE_AUTOSENSE |
  1606. SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  1607. //
  1608. // Build the start unit CDB.
  1609. //
  1610. srb->CdbLength = 6;
  1611. cdb = (PCDB)srb->Cdb;
  1612. cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
  1613. cdb->START_STOP.Start = 1;
  1614. cdb->START_STOP.Immediate = 0;
  1615. cdb->START_STOP.LogicalUnitNumber = srb->Lun;
  1616. //
  1617. // Build the asynchronous request to be sent to the port driver.
  1618. // Since this routine is called from a DPC the IRP should always be
  1619. // available.
  1620. //
  1621. irp = IoAllocateIrp(Fdo->StackSize, FALSE);
  1622. if(irp == NULL) {
  1623. //
  1624. // ISSUE-2000/02/03-peterwie
  1625. // This code path was inheritted from the NT 4.0 class2.sys driver.
  1626. // It needs to be changed to survive low-memory conditions.
  1627. //
  1628. KeBugCheck(SCSI_DISK_DRIVER_INTERNAL);
  1629. }
  1630. ClassAcquireRemoveLock(Fdo, irp);
  1631. IoSetCompletionRoutine(irp,
  1632. (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion,
  1633. context,
  1634. TRUE,
  1635. TRUE,
  1636. TRUE);
  1637. irpStack = IoGetNextIrpStackLocation(irp);
  1638. irpStack->MajorFunction = IRP_MJ_SCSI;
  1639. srb->OriginalRequest = irp;
  1640. //
  1641. // Store the SRB address in next stack for port driver.
  1642. //
  1643. irpStack->Parameters.Scsi.Srb = srb;
  1644. //
  1645. // Call the port driver with the IRP.
  1646. //
  1647. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
  1648. return;
  1649. } // end StartUnit()
  1650. /*++////////////////////////////////////////////////////////////////////////////
  1651. ClassAsynchronousCompletion() ISSUE-2000/02/18-henrygab - why public?!
  1652. Routine Description:
  1653. This routine is called when an asynchronous I/O request
  1654. which was issused by the class driver completes. Examples of such requests
  1655. are release queue or START UNIT. This routine releases the queue if
  1656. necessary. It then frees the context and the IRP.
  1657. Arguments:
  1658. DeviceObject - The device object for the logical unit; however since this
  1659. is the top stack location the value is NULL.
  1660. Irp - Supplies a pointer to the Irp to be processed.
  1661. Context - Supplies the context to be used to process this request.
  1662. Return Value:
  1663. None.
  1664. --*/
  1665. NTSTATUS
  1666. ClassAsynchronousCompletion(
  1667. PDEVICE_OBJECT DeviceObject,
  1668. PIRP Irp,
  1669. PVOID Context
  1670. )
  1671. {
  1672. PCOMPLETION_CONTEXT context = Context;
  1673. PSCSI_REQUEST_BLOCK srb;
  1674. if(DeviceObject == NULL) {
  1675. DeviceObject = context->DeviceObject;
  1676. }
  1677. srb = &context->Srb;
  1678. //
  1679. // If this is an execute srb, then check the return status and make sure.
  1680. // the queue is not frozen.
  1681. //
  1682. if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
  1683. //
  1684. // Check for a frozen queue.
  1685. //
  1686. if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  1687. //
  1688. // Unfreeze the queue getting the device object from the context.
  1689. //
  1690. ClassReleaseQueue(context->DeviceObject);
  1691. }
  1692. }
  1693. { // free port-allocated sense buffer if we can detect
  1694. if (((PCOMMON_DEVICE_EXTENSION)(DeviceObject->DeviceExtension))->IsFdo) {
  1695. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  1696. if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
  1697. FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
  1698. }
  1699. } else {
  1700. ASSERT(!TEST_FLAG(srb->SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
  1701. }
  1702. }
  1703. //
  1704. // Free the context and the Irp.
  1705. //
  1706. if (Irp->MdlAddress != NULL) {
  1707. MmUnlockPages(Irp->MdlAddress);
  1708. IoFreeMdl(Irp->MdlAddress);
  1709. Irp->MdlAddress = NULL;
  1710. }
  1711. ClassReleaseRemoveLock(DeviceObject, Irp);
  1712. ExFreePool(context);
  1713. IoFreeIrp(Irp);
  1714. //
  1715. // Indicate the I/O system should stop processing the Irp completion.
  1716. //
  1717. return STATUS_MORE_PROCESSING_REQUIRED;
  1718. } // end ClassAsynchronousCompletion()
  1719. NTSTATUS
  1720. ServiceTransferRequest(
  1721. PDEVICE_OBJECT Fdo,
  1722. PIRP Irp
  1723. )
  1724. /*++
  1725. Routine description:
  1726. This routine processes Io requests, splitting them if they
  1727. are larger than what the hardware can handle at a time. If
  1728. there isn't enough memory available, the request is placed
  1729. in a queue, to be processed at a later time
  1730. If this is a high priority paging request, all regular Io
  1731. are throttled to provide Mm with better thoroughput
  1732. Arguments:
  1733. Fdo - The functional device object processing the request
  1734. Irp - The Io request to be processed
  1735. Return Value:
  1736. STATUS_SUCCESS if successful, an error code otherwise
  1737. --*/
  1738. {
  1739. PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
  1740. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  1741. PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExtension->PartitionZeroExtension->AdapterDescriptor;
  1742. PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
  1743. IO_PAGING_PRIORITY priority = (TEST_FLAG(Irp->Flags, IRP_PAGING_IO)) ? IoGetPagingIoPriority(Irp) : IoPagingPriorityInvalid;
  1744. BOOLEAN deferClientIrp = FALSE;
  1745. KIRQL oldIrql;
  1746. NTSTATUS status;
  1747. //
  1748. // If this is a high priority request, hold off all other Io requests
  1749. //
  1750. if (priority == IoPagingPriorityHigh)
  1751. {
  1752. KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
  1753. if (fdoData->NumHighPriorityPagingIo == 0)
  1754. {
  1755. //
  1756. // Entering throttle mode
  1757. //
  1758. KeQuerySystemTime(&fdoData->ThrottleStartTime);
  1759. }
  1760. fdoData->NumHighPriorityPagingIo++;
  1761. fdoData->MaxInterleavedNormalIo += ClassMaxInterleavePerCriticalIo;
  1762. KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
  1763. }
  1764. else
  1765. {
  1766. if (fdoData->NumHighPriorityPagingIo != 0)
  1767. {
  1768. //
  1769. // This request wasn't flagged as critical and atleast one critical request
  1770. // is currently outstanding. Queue this request until all of those are done
  1771. // but only if the interleave threshold has been reached
  1772. //
  1773. KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
  1774. if (fdoData->NumHighPriorityPagingIo != 0)
  1775. {
  1776. if (fdoData->MaxInterleavedNormalIo == 0)
  1777. {
  1778. deferClientIrp = TRUE;
  1779. }
  1780. else
  1781. {
  1782. fdoData->MaxInterleavedNormalIo--;
  1783. }
  1784. }
  1785. KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
  1786. }
  1787. }
  1788. if (!deferClientIrp)
  1789. {
  1790. PIO_STACK_LOCATION currentSp = IoGetCurrentIrpStackLocation(Irp);
  1791. ULONG entireXferLen = currentSp->Parameters.Read.Length;
  1792. PUCHAR bufPtr = MmGetMdlVirtualAddress(Irp->MdlAddress);
  1793. LARGE_INTEGER targetLocation = currentSp->Parameters.Read.ByteOffset;
  1794. PTRANSFER_PACKET pkt;
  1795. SINGLE_LIST_ENTRY pktList;
  1796. PSINGLE_LIST_ENTRY slistEntry;
  1797. ULONG hwMaxXferLen;
  1798. ULONG numPackets;
  1799. ULONG i;
  1800. /*
  1801. * We precomputed fdoData->HwMaxXferLen using (MaximumPhysicalPages-1).
  1802. * If the buffer is page-aligned, that's one less page crossing so we can add the page back in.
  1803. * Note: adapters that return MaximumPhysicalPages=0x10 depend on this to
  1804. * transfer aligned 64K requests in one piece.
  1805. * Also note: make sure adding PAGE_SIZE back in doesn't wrap to zero.
  1806. */
  1807. if (((ULONG_PTR)bufPtr & (PAGE_SIZE-1)) || (fdoData->HwMaxXferLen > 0xffffffff-PAGE_SIZE)){
  1808. hwMaxXferLen = fdoData->HwMaxXferLen;
  1809. }
  1810. else {
  1811. ASSERT((PAGE_SIZE%fdoExt->DiskGeometry.BytesPerSector) == 0);
  1812. hwMaxXferLen = min(fdoData->HwMaxXferLen+PAGE_SIZE, adapterDesc->MaximumTransferLength);
  1813. }
  1814. /*
  1815. * Compute the number of hw xfers we'll have to do.
  1816. * Calculate this without allowing for an overflow condition.
  1817. */
  1818. ASSERT(hwMaxXferLen >= PAGE_SIZE);
  1819. numPackets = entireXferLen/hwMaxXferLen;
  1820. if (entireXferLen % hwMaxXferLen){
  1821. numPackets++;
  1822. }
  1823. /*
  1824. * First get all the TRANSFER_PACKETs that we'll need at once.
  1825. * Use our 'simple' slist functions since we don't need interlocked.
  1826. */
  1827. SimpleInitSlistHdr(&pktList);
  1828. for (i = 0; i < numPackets; i++){
  1829. pkt = DequeueFreeTransferPacket(Fdo, TRUE);
  1830. if (pkt){
  1831. SimplePushSlist(&pktList, (PSINGLE_LIST_ENTRY)&pkt->SlistEntry);
  1832. }
  1833. else {
  1834. break;
  1835. }
  1836. }
  1837. if (i == numPackets){
  1838. NTSTATUS pktStat;
  1839. /*
  1840. * Initialize the original IRP's status to success.
  1841. * If any of the packets fail, they will set it to an error status.
  1842. * The IoStatus.Information field will be incremented to the
  1843. * transfer length as the pieces complete.
  1844. */
  1845. Irp->IoStatus.Status = STATUS_SUCCESS;
  1846. Irp->IoStatus.Information = 0;
  1847. /*
  1848. * Store the number of transfer pieces inside the original IRP.
  1849. * It will be used to count down the pieces as they complete.
  1850. */
  1851. Irp->Tail.Overlay.DriverContext[0] = LongToPtr(numPackets);
  1852. /*
  1853. * For the common 1-packet case, we want to allow for an optimization by BlkCache
  1854. * (and also potentially synchronous storage drivers) which may complete the
  1855. * downward request synchronously.
  1856. * In that synchronous completion case, we want to _not_ mark the original irp pending
  1857. * and thereby save on the top-level APC.
  1858. * It's critical to coordinate this with the completion routine so that we mark the original irp
  1859. * pending if-and-only-if we return STATUS_PENDING for it.
  1860. */
  1861. if (numPackets > 1){
  1862. IoMarkIrpPending(Irp);
  1863. status = STATUS_PENDING;
  1864. }
  1865. else {
  1866. status = STATUS_SUCCESS;
  1867. }
  1868. /*
  1869. * Transmit the pieces of the transfer.
  1870. */
  1871. while (entireXferLen > 0){
  1872. ULONG thisPieceLen = MIN(hwMaxXferLen, entireXferLen);
  1873. /*
  1874. * Set up a TRANSFER_PACKET for this piece and send it.
  1875. */
  1876. slistEntry = SimplePopSlist(&pktList);
  1877. ASSERT(slistEntry);
  1878. pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
  1879. SetupReadWriteTransferPacket( pkt,
  1880. bufPtr,
  1881. thisPieceLen,
  1882. targetLocation,
  1883. Irp);
  1884. pktStat = SubmitTransferPacket(pkt);
  1885. /*
  1886. * If any of the packets completes with pending, we MUST return pending.
  1887. * Also, if a packet completes with an error, return pending; this is because
  1888. * in the completion routine we mark the original irp pending if the packet failed
  1889. * (since we may retry, thereby switching threads).
  1890. */
  1891. if (pktStat != STATUS_SUCCESS){
  1892. status = STATUS_PENDING;
  1893. }
  1894. entireXferLen -= thisPieceLen;
  1895. bufPtr += thisPieceLen;
  1896. targetLocation.QuadPart += thisPieceLen;
  1897. }
  1898. ASSERT(SimpleIsSlistEmpty(&pktList));
  1899. }
  1900. else if (i >= 1){
  1901. /*
  1902. * We were unable to get all the TRANSFER_PACKETs we need,
  1903. * but we did get at least one.
  1904. * That means that we are in extreme low-memory stress.
  1905. * We'll try doing this transfer using a single packet.
  1906. * The port driver is certainly also in stress, so use one-page
  1907. * transfers.
  1908. */
  1909. /*
  1910. * Free all but one of the TRANSFER_PACKETs.
  1911. */
  1912. while (i-- > 1){
  1913. slistEntry = SimplePopSlist(&pktList);
  1914. ASSERT(slistEntry);
  1915. pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
  1916. EnqueueFreeTransferPacket(Fdo, pkt);
  1917. }
  1918. /*
  1919. * Get the single TRANSFER_PACKET that we'll be using.
  1920. */
  1921. slistEntry = SimplePopSlist(&pktList);
  1922. ASSERT(slistEntry);
  1923. ASSERT(SimpleIsSlistEmpty(&pktList));
  1924. pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry);
  1925. DBGWARN(("Insufficient packets available in ServiceTransferRequest - entering lowMemRetry with pkt=%xh.", pkt));
  1926. /*
  1927. * Set default status and the number of transfer packets (one)
  1928. * inside the original irp.
  1929. */
  1930. Irp->IoStatus.Status = STATUS_SUCCESS;
  1931. Irp->IoStatus.Information = 0;
  1932. Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1);
  1933. IoMarkIrpPending(Irp);
  1934. /*
  1935. * Set up the TRANSFER_PACKET for a lowMem transfer and launch.
  1936. */
  1937. SetupReadWriteTransferPacket( pkt,
  1938. bufPtr,
  1939. entireXferLen,
  1940. targetLocation,
  1941. Irp);
  1942. InitLowMemRetry(pkt, bufPtr, entireXferLen, targetLocation);
  1943. StepLowMemRetry(pkt);
  1944. status = STATUS_PENDING;
  1945. }
  1946. else {
  1947. /*
  1948. * We were unable to get ANY TRANSFER_PACKETs.
  1949. * Defer this client irp until some TRANSFER_PACKETs free up.
  1950. */
  1951. DBGWARN(("No packets available in ServiceTransferRequest - deferring transfer (Irp=%xh)...", Irp));
  1952. if (priority == IoPagingPriorityHigh)
  1953. {
  1954. KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
  1955. if (fdoData->MaxInterleavedNormalIo < ClassMaxInterleavePerCriticalIo)
  1956. {
  1957. fdoData->MaxInterleavedNormalIo = 0;
  1958. }
  1959. else
  1960. {
  1961. fdoData->MaxInterleavedNormalIo -= ClassMaxInterleavePerCriticalIo;
  1962. }
  1963. fdoData->NumHighPriorityPagingIo--;
  1964. if (fdoData->NumHighPriorityPagingIo == 0)
  1965. {
  1966. LARGE_INTEGER period;
  1967. //
  1968. // Exiting throttle mode
  1969. //
  1970. KeQuerySystemTime(&fdoData->ThrottleStopTime);
  1971. period.QuadPart = fdoData->ThrottleStopTime.QuadPart - fdoData->ThrottleStartTime.QuadPart;
  1972. fdoData->LongestThrottlePeriod.QuadPart = max(fdoData->LongestThrottlePeriod.QuadPart, period.QuadPart);
  1973. ClassLogThrottleComplete(fdoExt, period);
  1974. }
  1975. KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
  1976. }
  1977. deferClientIrp = TRUE;
  1978. }
  1979. }
  1980. if (deferClientIrp)
  1981. {
  1982. IoMarkIrpPending(Irp);
  1983. EnqueueDeferredClientIrp(fdoData, Irp);
  1984. status = STATUS_PENDING;
  1985. }
  1986. return status;
  1987. }
  1988. /*++////////////////////////////////////////////////////////////////////////////
  1989. ClassIoComplete()
  1990. Routine Description:
  1991. This routine executes when the port driver has completed a request.
  1992. It looks at the SRB status in the completing SRB and if not success
  1993. it checks for valid request sense buffer information. If valid, the
  1994. info is used to update status with more precise message of type of
  1995. error. This routine deallocates the SRB.
  1996. This routine should only be placed on the stack location for a class
  1997. driver FDO.
  1998. Arguments:
  1999. Fdo - Supplies the device object which represents the logical
  2000. unit.
  2001. Irp - Supplies the Irp which has completed.
  2002. Context - Supplies a pointer to the SRB.
  2003. Return Value:
  2004. NT status
  2005. --*/
  2006. NTSTATUS
  2007. ClassIoComplete(
  2008. IN PDEVICE_OBJECT Fdo,
  2009. IN PIRP Irp,
  2010. IN PVOID Context
  2011. )
  2012. {
  2013. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  2014. PSCSI_REQUEST_BLOCK srb = Context;
  2015. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  2016. PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
  2017. NTSTATUS status;
  2018. BOOLEAN retry;
  2019. BOOLEAN callStartNextPacket;
  2020. ASSERT(fdoExtension->CommonExtension.IsFdo);
  2021. #if DBG
  2022. if (srb->Function == SRB_FUNCTION_FLUSH){
  2023. DBGLOGFLUSHINFO(fdoData, FALSE, FALSE, TRUE);
  2024. }
  2025. #endif
  2026. //
  2027. // Check SRB status for success of completing request.
  2028. //
  2029. if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  2030. ULONG retryInterval;
  2031. DebugPrint((2, "ClassIoComplete: IRP %p, SRB %p\n", Irp, srb));
  2032. //
  2033. // Release the queue if it is frozen.
  2034. //
  2035. if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  2036. ClassReleaseQueue(Fdo);
  2037. }
  2038. retry = ClassInterpretSenseInfo(
  2039. Fdo,
  2040. srb,
  2041. irpStack->MajorFunction,
  2042. irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ?
  2043. irpStack->Parameters.DeviceIoControl.IoControlCode :
  2044. 0,
  2045. MAXIMUM_RETRIES -
  2046. ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
  2047. &status,
  2048. &retryInterval);
  2049. //
  2050. // If the status is verified required and the this request
  2051. // should bypass verify required then retry the request.
  2052. //
  2053. if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
  2054. status == STATUS_VERIFY_REQUIRED) {
  2055. status = STATUS_IO_DEVICE_ERROR;
  2056. retry = TRUE;
  2057. }
  2058. if (retry && ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4)--) {
  2059. //
  2060. // Retry request.
  2061. //
  2062. DebugPrint((1, "Retry request %p\n", Irp));
  2063. if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
  2064. FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
  2065. }
  2066. RetryRequest(Fdo, Irp, srb, FALSE, retryInterval);
  2067. return STATUS_MORE_PROCESSING_REQUIRED;
  2068. }
  2069. } else {
  2070. //
  2071. // Set status for successful request
  2072. //
  2073. fdoData->LoggedTURFailureSinceLastIO = FALSE;
  2074. ClasspPerfIncrementSuccessfulIo(fdoExtension);
  2075. status = STATUS_SUCCESS;
  2076. } // end if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS)
  2077. //
  2078. // ensure we have returned some info, and it matches what the
  2079. // original request wanted for PAGING operations only
  2080. //
  2081. if ((NT_SUCCESS(status)) && TEST_FLAG(Irp->Flags, IRP_PAGING_IO)) {
  2082. ASSERT(Irp->IoStatus.Information != 0);
  2083. ASSERT(irpStack->Parameters.Read.Length == Irp->IoStatus.Information);
  2084. }
  2085. //
  2086. // remember if the caller wanted to skip calling IoStartNextPacket.
  2087. // for legacy reasons, we cannot call IoStartNextPacket for IoDeviceControl
  2088. // calls. this setting only affects device objects with StartIo routines.
  2089. //
  2090. callStartNextPacket = !TEST_FLAG(srb->SrbFlags, SRB_FLAGS_DONT_START_NEXT_PACKET);
  2091. if (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) {
  2092. callStartNextPacket = FALSE;
  2093. }
  2094. //
  2095. // Free the srb
  2096. //
  2097. if(!TEST_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT)) {
  2098. if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
  2099. FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb);
  2100. }
  2101. if (fdoExtension->CommonExtension.IsSrbLookasideListInitialized){
  2102. ClassFreeOrReuseSrb(fdoExtension, srb);
  2103. }
  2104. else {
  2105. DBGWARN(("ClassIoComplete is freeing an SRB (possibly) on behalf of another driver."));
  2106. ExFreePool(srb);
  2107. }
  2108. } else {
  2109. DebugPrint((2, "ClassIoComplete: Not Freeing srb @ %p because "
  2110. "SRB_CLASS_FLAGS_PERSISTANT set\n", srb));
  2111. if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) {
  2112. DebugPrint((2, "ClassIoComplete: Not Freeing sensebuffer @ %p "
  2113. " because SRB_CLASS_FLAGS_PERSISTANT set\n",
  2114. srb->SenseInfoBuffer));
  2115. }
  2116. }
  2117. //
  2118. // Set status in completing IRP.
  2119. //
  2120. Irp->IoStatus.Status = status;
  2121. //
  2122. // Set the hard error if necessary.
  2123. //
  2124. if (!NT_SUCCESS(status) &&
  2125. IoIsErrorUserInduced(status) &&
  2126. (Irp->Tail.Overlay.Thread != NULL)
  2127. ) {
  2128. //
  2129. // Store DeviceObject for filesystem, and clear
  2130. // in IoStatus.Information field.
  2131. //
  2132. IoSetHardErrorOrVerifyDevice(Irp, Fdo);
  2133. Irp->IoStatus.Information = 0;
  2134. }
  2135. //
  2136. // If pending has be returned for this irp then mark the current stack as
  2137. // pending.
  2138. //
  2139. if (Irp->PendingReturned) {
  2140. IoMarkIrpPending(Irp);
  2141. }
  2142. if (fdoExtension->CommonExtension.DriverExtension->InitData.ClassStartIo) {
  2143. if (callStartNextPacket) {
  2144. KIRQL oldIrql;
  2145. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  2146. IoStartNextPacket(Fdo, FALSE);
  2147. KeLowerIrql(oldIrql);
  2148. }
  2149. }
  2150. ClassReleaseRemoveLock(Fdo, Irp);
  2151. return status;
  2152. } // end ClassIoComplete()
  2153. /*++////////////////////////////////////////////////////////////////////////////
  2154. ClassSendSrbSynchronous()
  2155. Routine Description:
  2156. This routine is called by SCSI device controls to complete an
  2157. SRB and send it to the port driver synchronously (ie wait for
  2158. completion). The CDB is already completed along with the SRB CDB
  2159. size and request timeout value.
  2160. Arguments:
  2161. Fdo - Supplies the functional device object which represents the target.
  2162. Srb - Supplies a partially initialized SRB. The SRB cannot come from zone.
  2163. BufferAddress - Supplies the address of the buffer.
  2164. BufferLength - Supplies the length in bytes of the buffer.
  2165. WriteToDevice - Indicates the data should be transfer to the device.
  2166. Return Value:
  2167. NTSTATUS indicating the final results of the operation.
  2168. If NT_SUCCESS(), then the amount of usable data is contained in the field
  2169. Srb->DataTransferLength
  2170. --*/
  2171. NTSTATUS
  2172. ClassSendSrbSynchronous(
  2173. PDEVICE_OBJECT Fdo,
  2174. PSCSI_REQUEST_BLOCK Srb,
  2175. PVOID BufferAddress,
  2176. ULONG BufferLength,
  2177. BOOLEAN WriteToDevice
  2178. )
  2179. {
  2180. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  2181. PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
  2182. IO_STATUS_BLOCK ioStatus;
  2183. ULONG controlType;
  2184. PIRP irp;
  2185. PIO_STACK_LOCATION irpStack;
  2186. KEVENT event;
  2187. PUCHAR senseInfoBuffer;
  2188. ULONG retryCount = MAXIMUM_RETRIES;
  2189. NTSTATUS status;
  2190. BOOLEAN retry;
  2191. //
  2192. // NOTE: This code is only pagable because we are not freezing
  2193. // the queue. Allowing the queue to be frozen from a pagable
  2194. // routine could leave the queue frozen as we try to page in
  2195. // the code to unfreeze the queue. The result would be a nice
  2196. // case of deadlock. Therefore, since we are unfreezing the
  2197. // queue regardless of the result, just set the NO_FREEZE_QUEUE
  2198. // flag in the SRB.
  2199. //
  2200. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  2201. ASSERT(fdoExtension->CommonExtension.IsFdo);
  2202. //
  2203. // Write length to SRB.
  2204. //
  2205. Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  2206. //
  2207. // Set SCSI bus address.
  2208. //
  2209. Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  2210. //
  2211. // Enable auto request sense.
  2212. //
  2213. Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  2214. //
  2215. // Sense buffer is in aligned nonpaged pool.
  2216. //
  2217. //
  2218. senseInfoBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  2219. SENSE_BUFFER_SIZE,
  2220. '7CcS');
  2221. if (senseInfoBuffer == NULL) {
  2222. DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate request sense "
  2223. "buffer\n"));
  2224. return(STATUS_INSUFFICIENT_RESOURCES);
  2225. }
  2226. Srb->SenseInfoBuffer = senseInfoBuffer;
  2227. Srb->DataBuffer = BufferAddress;
  2228. //
  2229. // Start retries here.
  2230. //
  2231. retry:
  2232. //
  2233. // use fdoextension's flags by default.
  2234. // do not move out of loop, as the flag may change due to errors
  2235. // sending this command.
  2236. //
  2237. Srb->SrbFlags = fdoExtension->SrbFlags;
  2238. if(BufferAddress != NULL) {
  2239. if(WriteToDevice) {
  2240. SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_OUT);
  2241. } else {
  2242. SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN);
  2243. }
  2244. }
  2245. //
  2246. // Initialize the QueueAction field.
  2247. //
  2248. Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
  2249. //
  2250. // Disable synchronous transfer for these requests.
  2251. //
  2252. SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  2253. SET_FLAG(Srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
  2254. //
  2255. // Set the event object to the unsignaled state.
  2256. // It will be used to signal request completion.
  2257. //
  2258. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2259. //
  2260. // Build device I/O control request with METHOD_NEITHER data transfer.
  2261. // We'll queue a completion routine to cleanup the MDL's and such ourself.
  2262. //
  2263. irp = IoAllocateIrp(
  2264. (CCHAR) (fdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1),
  2265. FALSE);
  2266. if(irp == NULL) {
  2267. ExFreePool(senseInfoBuffer);
  2268. DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate Irp\n"));
  2269. return(STATUS_INSUFFICIENT_RESOURCES);
  2270. }
  2271. //
  2272. // Get next stack location.
  2273. //
  2274. irpStack = IoGetNextIrpStackLocation(irp);
  2275. //
  2276. // Set up SRB for execute scsi request. Save SRB address in next stack
  2277. // for the port driver.
  2278. //
  2279. irpStack->MajorFunction = IRP_MJ_SCSI;
  2280. irpStack->Parameters.Scsi.Srb = Srb;
  2281. IoSetCompletionRoutine(irp,
  2282. ClasspSendSynchronousCompletion,
  2283. Srb,
  2284. TRUE,
  2285. TRUE,
  2286. TRUE);
  2287. irp->UserIosb = &ioStatus;
  2288. irp->UserEvent = &event;
  2289. if(BufferAddress) {
  2290. //
  2291. // Build an MDL for the data buffer and stick it into the irp. The
  2292. // completion routine will unlock the pages and free the MDL.
  2293. //
  2294. irp->MdlAddress = IoAllocateMdl( BufferAddress,
  2295. BufferLength,
  2296. FALSE,
  2297. FALSE,
  2298. irp );
  2299. if (irp->MdlAddress == NULL) {
  2300. ExFreePool(senseInfoBuffer);
  2301. Srb->SenseInfoBuffer = NULL;
  2302. IoFreeIrp( irp );
  2303. DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate MDL\n"));
  2304. return STATUS_INSUFFICIENT_RESOURCES;
  2305. }
  2306. try {
  2307. //
  2308. // the io manager unlocks these pages upon completion
  2309. //
  2310. MmProbeAndLockPages( irp->MdlAddress,
  2311. KernelMode,
  2312. (WriteToDevice ? IoReadAccess :
  2313. IoWriteAccess));
  2314. } except(EXCEPTION_EXECUTE_HANDLER) {
  2315. status = GetExceptionCode();
  2316. ExFreePool(senseInfoBuffer);
  2317. Srb->SenseInfoBuffer = NULL;
  2318. IoFreeMdl(irp->MdlAddress);
  2319. IoFreeIrp(irp);
  2320. DebugPrint((1, "ClassSendSrbSynchronous: Exception %lx "
  2321. "locking buffer\n", status));
  2322. return status;
  2323. }
  2324. }
  2325. //
  2326. // Set the transfer length.
  2327. //
  2328. Srb->DataTransferLength = BufferLength;
  2329. //
  2330. // Zero out status.
  2331. //
  2332. Srb->ScsiStatus = Srb->SrbStatus = 0;
  2333. Srb->NextSrb = 0;
  2334. //
  2335. // Set up IRP Address.
  2336. //
  2337. Srb->OriginalRequest = irp;
  2338. //
  2339. // Call the port driver with the request and wait for it to complete.
  2340. //
  2341. status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp);
  2342. if (status == STATUS_PENDING) {
  2343. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  2344. status = ioStatus.Status;
  2345. }
  2346. ASSERT(SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_PENDING);
  2347. ASSERT(status != STATUS_PENDING);
  2348. ASSERT(!(Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN));
  2349. //
  2350. // Check that request completed without error.
  2351. //
  2352. if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  2353. ULONG retryInterval;
  2354. DBGTRACE(ClassDebugWarning, ("ClassSendSrbSynchronous - srb %ph failed (op=%s srbstat=%s(%xh), irpstat=%xh, sense=%s/%s/%s)", Srb, DBGGETSCSIOPSTR(Srb),
  2355. DBGGETSRBSTATUSSTR(Srb), (ULONG)Srb->SrbStatus, status, DBGGETSENSECODESTR(Srb),
  2356. DBGGETADSENSECODESTR(Srb), DBGGETADSENSEQUALIFIERSTR(Srb)));
  2357. //
  2358. // assert that the queue is not frozen
  2359. //
  2360. ASSERT(!TEST_FLAG(Srb->SrbStatus, SRB_STATUS_QUEUE_FROZEN));
  2361. //
  2362. // Update status and determine if request should be retried.
  2363. //
  2364. retry = ClassInterpretSenseInfo(Fdo,
  2365. Srb,
  2366. IRP_MJ_SCSI,
  2367. 0,
  2368. MAXIMUM_RETRIES - retryCount,
  2369. &status,
  2370. &retryInterval);
  2371. if (retry) {
  2372. if ((status == STATUS_DEVICE_NOT_READY &&
  2373. ((PSENSE_DATA) senseInfoBuffer)->AdditionalSenseCode ==
  2374. SCSI_ADSENSE_LUN_NOT_READY) ||
  2375. (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)) {
  2376. LARGE_INTEGER delay;
  2377. //
  2378. // Delay for at least 2 seconds.
  2379. //
  2380. if(retryInterval < 2) {
  2381. retryInterval = 2;
  2382. }
  2383. delay.QuadPart = (LONGLONG)( - 10 * 1000 * (LONGLONG)1000 * retryInterval);
  2384. //
  2385. // Stall for a while to let the device become ready
  2386. //
  2387. KeDelayExecutionThread(KernelMode, FALSE, &delay);
  2388. }
  2389. //
  2390. // If retries are not exhausted then retry this operation.
  2391. //
  2392. if (retryCount--) {
  2393. if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) {
  2394. FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb);
  2395. }
  2396. goto retry;
  2397. }
  2398. }
  2399. } else {
  2400. fdoData->LoggedTURFailureSinceLastIO = FALSE;
  2401. status = STATUS_SUCCESS;
  2402. }
  2403. //
  2404. // required even though we allocated our own, since the port driver may
  2405. // have allocated one also
  2406. //
  2407. if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) {
  2408. FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb);
  2409. }
  2410. Srb->SenseInfoBuffer = NULL;
  2411. ExFreePool(senseInfoBuffer);
  2412. return status;
  2413. }
  2414. /*++////////////////////////////////////////////////////////////////////////////
  2415. ClassInterpretSenseInfo()
  2416. Routine Description:
  2417. This routine interprets the data returned from the SCSI
  2418. request sense. It determines the status to return in the
  2419. IRP and whether this request can be retried.
  2420. Arguments:
  2421. DeviceObject - Supplies the device object associated with this request.
  2422. Srb - Supplies the scsi request block which failed.
  2423. MajorFunctionCode - Supplies the function code to be used for logging.
  2424. IoDeviceCode - Supplies the device code to be used for logging.
  2425. Status - Returns the status for the request.
  2426. Return Value:
  2427. BOOLEAN TRUE: Drivers should retry this request.
  2428. FALSE: Drivers should not retry this request.
  2429. --*/
  2430. BOOLEAN
  2431. ClassInterpretSenseInfo(
  2432. IN PDEVICE_OBJECT Fdo,
  2433. IN PSCSI_REQUEST_BLOCK Srb,
  2434. IN UCHAR MajorFunctionCode,
  2435. IN ULONG IoDeviceCode,
  2436. IN ULONG RetryCount,
  2437. OUT NTSTATUS *Status,
  2438. OUT OPTIONAL ULONG *RetryInterval
  2439. )
  2440. {
  2441. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  2442. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  2443. PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
  2444. PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
  2445. BOOLEAN retry = TRUE;
  2446. BOOLEAN logError = FALSE;
  2447. BOOLEAN unhandledError = FALSE;
  2448. BOOLEAN incrementErrorCount = FALSE;
  2449. ULONG badSector = 0;
  2450. ULONG uniqueId = 0;
  2451. NTSTATUS logStatus;
  2452. ULONG readSector;
  2453. ULONG index;
  2454. ULONG retryInterval = 0;
  2455. KIRQL oldIrql;
  2456. logStatus = -1;
  2457. if(TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) {
  2458. //
  2459. // Log anything remotely incorrect about paging i/o
  2460. //
  2461. logError = TRUE;
  2462. uniqueId = 301;
  2463. logStatus = IO_WARNING_PAGING_FAILURE;
  2464. }
  2465. //
  2466. // Check that request sense buffer is valid.
  2467. //
  2468. ASSERT(fdoExtension->CommonExtension.IsFdo);
  2469. //
  2470. // must handle the SRB_STATUS_INTERNAL_ERROR case first,
  2471. // as it has all the flags set.
  2472. //
  2473. if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_INTERNAL_ERROR) {
  2474. DebugPrint((ClassDebugSenseInfo,
  2475. "ClassInterpretSenseInfo: Internal Error code is %x\n",
  2476. Srb->InternalStatus));
  2477. retry = FALSE;
  2478. *Status = Srb->InternalStatus;
  2479. } else if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
  2480. (Srb->SenseInfoBufferLength >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength))) {
  2481. UCHAR addlSenseCode;
  2482. UCHAR addlSenseCodeQual;
  2483. //
  2484. // Zero the additional sense code and additional sense code qualifier
  2485. // if they were not returned by the device.
  2486. //
  2487. readSector = senseBuffer->AdditionalSenseLength +
  2488. offsetof(SENSE_DATA, AdditionalSenseLength);
  2489. if (readSector > Srb->SenseInfoBufferLength) {
  2490. readSector = Srb->SenseInfoBufferLength;
  2491. }
  2492. addlSenseCode = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCode)) ?
  2493. senseBuffer->AdditionalSenseCode : 0;
  2494. addlSenseCodeQual = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCodeQualifier)) ?
  2495. senseBuffer->AdditionalSenseCodeQualifier : 0;
  2496. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: Error code is %x\n", senseBuffer->ErrorCode));
  2497. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: Sense key is %x\n", senseBuffer->SenseKey));
  2498. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: Additional sense code is %x\n", addlSenseCode));
  2499. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: Additional sense code qualifier is %x\n", addlSenseCodeQual));
  2500. switch (senseBuffer->SenseKey & 0xf) {
  2501. case SCSI_SENSE_NOT_READY: {
  2502. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2503. "Device not ready\n"));
  2504. *Status = STATUS_DEVICE_NOT_READY;
  2505. switch (addlSenseCode) {
  2506. case SCSI_ADSENSE_LUN_NOT_READY: {
  2507. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2508. "Lun not ready\n"));
  2509. retryInterval = NOT_READY_RETRY_INTERVAL;
  2510. switch (addlSenseCodeQual) {
  2511. case SCSI_SENSEQ_OPERATION_IN_PROGRESS: {
  2512. DEVICE_EVENT_BECOMING_READY notReady = {0};
  2513. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2514. "Operation In Progress\n"));
  2515. notReady.Version = 1;
  2516. notReady.Reason = 2;
  2517. notReady.Estimated100msToReady = retryInterval * 10;
  2518. ClasspSendNotification(fdoExtension,
  2519. &GUID_IO_DEVICE_BECOMING_READY,
  2520. sizeof(DEVICE_EVENT_BECOMING_READY),
  2521. &notReady);
  2522. break;
  2523. }
  2524. case SCSI_SENSEQ_BECOMING_READY: {
  2525. DEVICE_EVENT_BECOMING_READY notReady = {0};
  2526. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2527. "In process of becoming ready\n"));
  2528. notReady.Version = 1;
  2529. notReady.Reason = 1;
  2530. notReady.Estimated100msToReady = retryInterval * 10;
  2531. ClasspSendNotification(fdoExtension,
  2532. &GUID_IO_DEVICE_BECOMING_READY,
  2533. sizeof(DEVICE_EVENT_BECOMING_READY),
  2534. &notReady);
  2535. break;
  2536. }
  2537. case SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS: {
  2538. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2539. "Long write in progress\n"));
  2540. retry = FALSE;
  2541. break;
  2542. }
  2543. case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: {
  2544. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2545. "Manual intervention required\n"));
  2546. *Status = STATUS_NO_MEDIA_IN_DEVICE;
  2547. retry = FALSE;
  2548. break;
  2549. }
  2550. case SCSI_SENSEQ_FORMAT_IN_PROGRESS: {
  2551. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2552. "Format in progress\n"));
  2553. retry = FALSE;
  2554. break;
  2555. }
  2556. case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: {
  2557. if(!TEST_FLAG(fdoExtension->ScanForSpecialFlags,
  2558. CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK)) {
  2559. DebugPrint((ClassDebugSenseInfo,
  2560. "ClassInterpretSenseInfo: "
  2561. "not ready, cause unknown\n"));
  2562. /*
  2563. Many non-WHQL certified drives (mostly CD-RW) return
  2564. this when they have no media instead of the obvious
  2565. choice of:
  2566. SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
  2567. These drives should not pass WHQL certification due
  2568. to this discrepency.
  2569. */
  2570. retry = FALSE;
  2571. break;
  2572. } else {
  2573. //
  2574. // Treat this as init command required and fall through.
  2575. //
  2576. }
  2577. }
  2578. case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
  2579. default: {
  2580. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2581. "Initializing command required\n"));
  2582. retryInterval = 0; // go back to default
  2583. //
  2584. // This sense code/additional sense code
  2585. // combination may indicate that the device
  2586. // needs to be started. Send an start unit if this
  2587. // is a disk device.
  2588. //
  2589. if (TEST_FLAG(fdoExtension->DeviceFlags, DEV_SAFE_START_UNIT) &&
  2590. !TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY)){
  2591. ClassSendStartUnit(Fdo);
  2592. }
  2593. break;
  2594. }
  2595. } // end switch (addlSenseCodeQual)
  2596. break;
  2597. }
  2598. case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: {
  2599. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2600. "No Media in device.\n"));
  2601. *Status = STATUS_NO_MEDIA_IN_DEVICE;
  2602. retry = FALSE;
  2603. //
  2604. // signal MCN that there isn't any media in the device
  2605. //
  2606. if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
  2607. DebugPrint((ClassDebugError, "ClassInterpretSenseInfo: "
  2608. "No Media in a non-removable device %p\n",
  2609. Fdo));
  2610. }
  2611. if (addlSenseCodeQual == 0xCC){
  2612. /*
  2613. * The IMAPI filter returns this ASCQ value when it is burning CD-R media.
  2614. * We want to indicate that the media is not present to most applications;
  2615. * but RSM has to know that the media is still in the drive (i.e. the drive is not free).
  2616. */
  2617. ClassSetMediaChangeState(fdoExtension, MediaUnavailable, FALSE);
  2618. }
  2619. else {
  2620. ClassSetMediaChangeState(fdoExtension, MediaNotPresent, FALSE);
  2621. }
  2622. break;
  2623. }
  2624. } // end switch (addlSenseCode)
  2625. break;
  2626. } // end SCSI_SENSE_NOT_READY
  2627. case SCSI_SENSE_DATA_PROTECT: {
  2628. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2629. "Media write protected\n"));
  2630. *Status = STATUS_MEDIA_WRITE_PROTECTED;
  2631. retry = FALSE;
  2632. break;
  2633. } // end SCSI_SENSE_DATA_PROTECT
  2634. case SCSI_SENSE_MEDIUM_ERROR: {
  2635. DebugPrint((ClassDebugSenseInfo,"ClassInterpretSenseInfo: "
  2636. "Medium Error (bad block)\n"));
  2637. *Status = STATUS_DEVICE_DATA_ERROR;
  2638. retry = FALSE;
  2639. logError = TRUE;
  2640. uniqueId = 256;
  2641. logStatus = IO_ERR_BAD_BLOCK;
  2642. //
  2643. // Check if this error is due to unknown format
  2644. //
  2645. if (addlSenseCode == SCSI_ADSENSE_INVALID_MEDIA){
  2646. switch (addlSenseCodeQual) {
  2647. case SCSI_SENSEQ_UNKNOWN_FORMAT: {
  2648. *Status = STATUS_UNRECOGNIZED_MEDIA;
  2649. //
  2650. // Log error only if this is a paging request
  2651. //
  2652. if(!TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) {
  2653. logError = FALSE;
  2654. }
  2655. break;
  2656. }
  2657. case SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED: {
  2658. *Status = STATUS_CLEANER_CARTRIDGE_INSTALLED;
  2659. logError = FALSE;
  2660. break;
  2661. }
  2662. default: {
  2663. break;
  2664. }
  2665. } // end switch addlSenseCodeQual
  2666. } // end SCSI_ADSENSE_INVALID_MEDIA
  2667. break;
  2668. } // end SCSI_SENSE_MEDIUM_ERROR
  2669. case SCSI_SENSE_HARDWARE_ERROR: {
  2670. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2671. "Hardware error\n"));
  2672. *Status = STATUS_IO_DEVICE_ERROR;
  2673. logError = TRUE;
  2674. uniqueId = 257;
  2675. logStatus = IO_ERR_CONTROLLER_ERROR;
  2676. break;
  2677. } // end SCSI_SENSE_HARDWARE_ERROR
  2678. case SCSI_SENSE_ILLEGAL_REQUEST: {
  2679. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2680. "Illegal SCSI request\n"));
  2681. *Status = STATUS_INVALID_DEVICE_REQUEST;
  2682. retry = FALSE;
  2683. switch (addlSenseCode) {
  2684. case SCSI_ADSENSE_ILLEGAL_COMMAND: {
  2685. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2686. "Illegal command\n"));
  2687. break;
  2688. }
  2689. case SCSI_ADSENSE_ILLEGAL_BLOCK: {
  2690. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2691. "Illegal block address\n"));
  2692. *Status = STATUS_NONEXISTENT_SECTOR;
  2693. /*
  2694. * need to set the retry interval here due to inability
  2695. * to set it in the ClassError routine (disk relies upon
  2696. * this setting).
  2697. */
  2698. retryInterval = 5;
  2699. break;
  2700. }
  2701. case SCSI_ADSENSE_INVALID_LUN: {
  2702. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2703. "Invalid LUN\n"));
  2704. *Status = STATUS_NO_SUCH_DEVICE;
  2705. break;
  2706. }
  2707. case SCSI_ADSENSE_MUSIC_AREA: {
  2708. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2709. "Music area\n"));
  2710. break;
  2711. }
  2712. case SCSI_ADSENSE_DATA_AREA: {
  2713. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2714. "Data area\n"));
  2715. break;
  2716. }
  2717. case SCSI_ADSENSE_VOLUME_OVERFLOW: {
  2718. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2719. "Volume overflow\n"));
  2720. break;
  2721. }
  2722. case SCSI_ADSENSE_COPY_PROTECTION_FAILURE: {
  2723. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2724. "Copy protection failure\n"));
  2725. *Status = STATUS_COPY_PROTECTION_FAILURE;
  2726. switch (addlSenseCodeQual) {
  2727. case SCSI_SENSEQ_AUTHENTICATION_FAILURE:
  2728. DebugPrint((ClassDebugSenseInfo,
  2729. "ClassInterpretSenseInfo: "
  2730. "Authentication failure\n"));
  2731. *Status = STATUS_CSS_AUTHENTICATION_FAILURE;
  2732. break;
  2733. case SCSI_SENSEQ_KEY_NOT_PRESENT:
  2734. DebugPrint((ClassDebugSenseInfo,
  2735. "ClassInterpretSenseInfo: "
  2736. "Key not present\n"));
  2737. *Status = STATUS_CSS_KEY_NOT_PRESENT;
  2738. break;
  2739. case SCSI_SENSEQ_KEY_NOT_ESTABLISHED:
  2740. DebugPrint((ClassDebugSenseInfo,
  2741. "ClassInterpretSenseInfo: "
  2742. "Key not established\n"));
  2743. *Status = STATUS_CSS_KEY_NOT_ESTABLISHED;
  2744. break;
  2745. case SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION:
  2746. DebugPrint((ClassDebugSenseInfo,
  2747. "ClassInterpretSenseInfo: "
  2748. "Read of scrambled sector w/o "
  2749. "authentication\n"));
  2750. *Status = STATUS_CSS_SCRAMBLED_SECTOR;
  2751. break;
  2752. case SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT:
  2753. DebugPrint((ClassDebugSenseInfo,
  2754. "ClassInterpretSenseInfo: "
  2755. "Media region does not logical unit "
  2756. "region\n"));
  2757. *Status = STATUS_CSS_REGION_MISMATCH;
  2758. break;
  2759. case SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR:
  2760. DebugPrint((ClassDebugSenseInfo,
  2761. "ClassInterpretSenseInfo: "
  2762. "Region set error -- region may "
  2763. "be permanent\n"));
  2764. *Status = STATUS_CSS_RESETS_EXHAUSTED;
  2765. break;
  2766. } // end switch of ASCQ for COPY_PROTECTION_FAILURE
  2767. break;
  2768. }
  2769. case SCSI_ADSENSE_INVALID_CDB: {
  2770. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2771. "Invalid CDB\n"));
  2772. //
  2773. // Note: the retry interval is not typically used.
  2774. // it is set here only because a ClassErrorHandler
  2775. // cannot set the retryInterval, and the error may
  2776. // require a few commands to be sent to clear whatever
  2777. // caused this condition (i.e. disk clears the write
  2778. // cache, requiring at least two commands)
  2779. //
  2780. // hopefully, this shortcoming can be changed for
  2781. // blackcomb.
  2782. //
  2783. retryInterval = 3;
  2784. break;
  2785. }
  2786. } // end switch (addlSenseCode)
  2787. break;
  2788. } // end SCSI_SENSE_ILLEGAL_REQUEST
  2789. case SCSI_SENSE_UNIT_ATTENTION: {
  2790. PVPB vpb;
  2791. ULONG count;
  2792. //
  2793. // A media change may have occured so increment the change
  2794. // count for the physical device
  2795. //
  2796. count = InterlockedIncrement(&fdoExtension->MediaChangeCount);
  2797. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2798. "Media change count for device %d incremented to %#lx\n",
  2799. fdoExtension->DeviceNumber, count));
  2800. switch (addlSenseCode) {
  2801. case SCSI_ADSENSE_MEDIUM_CHANGED: {
  2802. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2803. "Media changed\n"));
  2804. if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
  2805. DebugPrint((ClassDebugError, "ClassInterpretSenseInfo: "
  2806. "Media Changed on non-removable device %p\n",
  2807. Fdo));
  2808. }
  2809. ClassSetMediaChangeState(fdoExtension, MediaPresent, FALSE);
  2810. break;
  2811. }
  2812. case SCSI_ADSENSE_BUS_RESET: {
  2813. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2814. "Bus reset\n"));
  2815. break;
  2816. }
  2817. case SCSI_ADSENSE_OPERATOR_REQUEST: {
  2818. switch (addlSenseCodeQual) {
  2819. case SCSI_SENSEQ_MEDIUM_REMOVAL: {
  2820. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2821. "Ejection request received!\n"));
  2822. ClassSendEjectionNotification(fdoExtension);
  2823. break;
  2824. }
  2825. case SCSI_SENSEQ_WRITE_PROTECT_ENABLE: {
  2826. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2827. "Operator selected write permit?! "
  2828. "(unsupported!)\n"));
  2829. break;
  2830. }
  2831. case SCSI_SENSEQ_WRITE_PROTECT_DISABLE: {
  2832. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2833. "Operator selected write protect?! "
  2834. "(unsupported!)\n"));
  2835. break;
  2836. }
  2837. }
  2838. }
  2839. default: {
  2840. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2841. "Unit attention\n"));
  2842. break;
  2843. }
  2844. } // end switch (addlSenseCode)
  2845. if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA))
  2846. {
  2847. //
  2848. // TODO : Is the media lockable?
  2849. //
  2850. if ((ClassGetVpb(Fdo) != NULL) && (ClassGetVpb(Fdo)->Flags & VPB_MOUNTED))
  2851. {
  2852. //
  2853. // Set bit to indicate that media may have changed
  2854. // and volume needs verification.
  2855. //
  2856. SET_FLAG(Fdo->Flags, DO_VERIFY_VOLUME);
  2857. *Status = STATUS_VERIFY_REQUIRED;
  2858. retry = FALSE;
  2859. }
  2860. else {
  2861. *Status = STATUS_IO_DEVICE_ERROR;
  2862. }
  2863. }
  2864. else
  2865. {
  2866. *Status = STATUS_IO_DEVICE_ERROR;
  2867. }
  2868. break;
  2869. } // end SCSI_SENSE_UNIT_ATTENTION
  2870. case SCSI_SENSE_ABORTED_COMMAND: {
  2871. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2872. "Command aborted\n"));
  2873. *Status = STATUS_IO_DEVICE_ERROR;
  2874. retryInterval = 1;
  2875. break;
  2876. } // end SCSI_SENSE_ABORTED_COMMAND
  2877. case SCSI_SENSE_BLANK_CHECK: {
  2878. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2879. "Media blank check\n"));
  2880. retry = FALSE;
  2881. *Status = STATUS_NO_DATA_DETECTED;
  2882. break;
  2883. } // end SCSI_SENSE_BLANK_CHECK
  2884. case SCSI_SENSE_RECOVERED_ERROR: {
  2885. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2886. "Recovered error\n"));
  2887. *Status = STATUS_SUCCESS;
  2888. retry = FALSE;
  2889. logError = TRUE;
  2890. uniqueId = 258;
  2891. switch(addlSenseCode) {
  2892. case SCSI_ADSENSE_SEEK_ERROR:
  2893. case SCSI_ADSENSE_TRACK_ERROR: {
  2894. logStatus = IO_ERR_SEEK_ERROR;
  2895. break;
  2896. }
  2897. case SCSI_ADSENSE_REC_DATA_NOECC:
  2898. case SCSI_ADSENSE_REC_DATA_ECC: {
  2899. logStatus = IO_RECOVERED_VIA_ECC;
  2900. break;
  2901. }
  2902. case SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED: {
  2903. UCHAR wmiEventData[sizeof(ULONG)+sizeof(UCHAR)] = {0};
  2904. *((PULONG)wmiEventData) = sizeof(UCHAR);
  2905. wmiEventData[sizeof(ULONG)] = addlSenseCodeQual;
  2906. //
  2907. // Don't log another eventlog if we have already logged once
  2908. // NOTE: this should have been interlocked, but the structure
  2909. // was publicly defined to use a BOOLEAN (char). Since
  2910. // media only reports these errors once per X minutes,
  2911. // the potential race condition is nearly non-existant.
  2912. // the worst case is duplicate log entries, so ignore.
  2913. //
  2914. if (fdoExtension->FailurePredicted == 0) {
  2915. logError = TRUE;
  2916. }
  2917. fdoExtension->FailurePredicted = TRUE;
  2918. fdoExtension->FailureReason = addlSenseCodeQual;
  2919. logStatus = IO_WRN_FAILURE_PREDICTED;
  2920. ClassNotifyFailurePredicted(fdoExtension,
  2921. (PUCHAR)wmiEventData,
  2922. sizeof(wmiEventData),
  2923. FALSE, // do not log error
  2924. 4, // unique error value
  2925. Srb->PathId,
  2926. Srb->TargetId,
  2927. Srb->Lun);
  2928. break;
  2929. }
  2930. default: {
  2931. logStatus = IO_ERR_CONTROLLER_ERROR;
  2932. break;
  2933. }
  2934. } // end switch(addlSenseCode)
  2935. if (senseBuffer->IncorrectLength) {
  2936. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2937. "Incorrect length detected.\n"));
  2938. *Status = STATUS_INVALID_BLOCK_LENGTH ;
  2939. }
  2940. break;
  2941. } // end SCSI_SENSE_RECOVERED_ERROR
  2942. case SCSI_SENSE_NO_SENSE: {
  2943. //
  2944. // Check other indicators.
  2945. //
  2946. if (senseBuffer->IncorrectLength) {
  2947. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2948. "Incorrect length detected.\n"));
  2949. *Status = STATUS_INVALID_BLOCK_LENGTH ;
  2950. retry = FALSE;
  2951. } else {
  2952. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2953. "No specific sense key\n"));
  2954. *Status = STATUS_IO_DEVICE_ERROR;
  2955. retry = TRUE;
  2956. }
  2957. break;
  2958. } // end SCSI_SENSE_NO_SENSE
  2959. default: {
  2960. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2961. "Unrecognized sense code\n"));
  2962. *Status = STATUS_IO_DEVICE_ERROR;
  2963. break;
  2964. }
  2965. } // end switch (senseBuffer->SenseKey & 0xf)
  2966. //
  2967. // Try to determine the bad sector from the inquiry data.
  2968. //
  2969. if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_READ ||
  2970. ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY ||
  2971. ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_WRITE)) {
  2972. for (index = 0; index < 4; index++) {
  2973. badSector = (badSector << 8) | senseBuffer->Information[index];
  2974. }
  2975. readSector = 0;
  2976. for (index = 0; index < 4; index++) {
  2977. readSector = (readSector << 8) | Srb->Cdb[index+2];
  2978. }
  2979. index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) |
  2980. ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb;
  2981. //
  2982. // Make sure the bad sector is within the read sectors.
  2983. //
  2984. if (!(badSector >= readSector && badSector < readSector + index)) {
  2985. badSector = readSector;
  2986. }
  2987. }
  2988. } else {
  2989. //
  2990. // Request sense buffer not valid. No sense information
  2991. // to pinpoint the error. Return general request fail.
  2992. //
  2993. DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: "
  2994. "Request sense info not valid. SrbStatus %2x\n",
  2995. SRB_STATUS(Srb->SrbStatus)));
  2996. retry = TRUE;
  2997. switch (SRB_STATUS(Srb->SrbStatus)) {
  2998. case SRB_STATUS_INVALID_LUN:
  2999. case SRB_STATUS_INVALID_TARGET_ID:
  3000. case SRB_STATUS_NO_DEVICE:
  3001. case SRB_STATUS_NO_HBA:
  3002. case SRB_STATUS_INVALID_PATH_ID: {
  3003. *Status = STATUS_NO_SUCH_DEVICE;
  3004. retry = FALSE;
  3005. break;
  3006. }
  3007. case SRB_STATUS_COMMAND_TIMEOUT:
  3008. case SRB_STATUS_TIMEOUT: {
  3009. //
  3010. // Update the error count for the device.
  3011. //
  3012. incrementErrorCount = TRUE;
  3013. *Status = STATUS_IO_TIMEOUT;
  3014. break;
  3015. }
  3016. case SRB_STATUS_ABORTED: {
  3017. //
  3018. // Update the error count for the device.
  3019. //
  3020. incrementErrorCount = TRUE;
  3021. *Status = STATUS_IO_TIMEOUT;
  3022. retryInterval = 1;
  3023. break;
  3024. }
  3025. case SRB_STATUS_SELECTION_TIMEOUT: {
  3026. logError = TRUE;
  3027. logStatus = IO_ERR_NOT_READY;
  3028. uniqueId = 260;
  3029. *Status = STATUS_DEVICE_NOT_CONNECTED;
  3030. retry = FALSE;
  3031. break;
  3032. }
  3033. case SRB_STATUS_DATA_OVERRUN: {
  3034. *Status = STATUS_DATA_OVERRUN;
  3035. retry = FALSE;
  3036. break;
  3037. }
  3038. case SRB_STATUS_PHASE_SEQUENCE_FAILURE: {
  3039. //
  3040. // Update the error count for the device.
  3041. //
  3042. incrementErrorCount = TRUE;
  3043. *Status = STATUS_IO_DEVICE_ERROR;
  3044. //
  3045. // If there was phase sequence error then limit the number of
  3046. // retries.
  3047. //
  3048. if (RetryCount > 1 ) {
  3049. retry = FALSE;
  3050. }
  3051. break;
  3052. }
  3053. case SRB_STATUS_REQUEST_FLUSHED: {
  3054. //
  3055. // If the status needs verification bit is set. Then set
  3056. // the status to need verification and no retry; otherwise,
  3057. // just retry the request.
  3058. //
  3059. if (TEST_FLAG(Fdo->Flags, DO_VERIFY_VOLUME)) {
  3060. *Status = STATUS_VERIFY_REQUIRED;
  3061. retry = FALSE;
  3062. } else {
  3063. *Status = STATUS_IO_DEVICE_ERROR;
  3064. }
  3065. break;
  3066. }
  3067. case SRB_STATUS_INVALID_REQUEST: {
  3068. *Status = STATUS_INVALID_DEVICE_REQUEST;
  3069. retry = FALSE;
  3070. break;
  3071. }
  3072. case SRB_STATUS_UNEXPECTED_BUS_FREE:
  3073. case SRB_STATUS_PARITY_ERROR:
  3074. //
  3075. // Update the error count for the device
  3076. // and fall through to below
  3077. //
  3078. incrementErrorCount = TRUE;
  3079. case SRB_STATUS_BUS_RESET: {
  3080. *Status = STATUS_IO_DEVICE_ERROR;
  3081. break;
  3082. }
  3083. case SRB_STATUS_ERROR: {
  3084. *Status = STATUS_IO_DEVICE_ERROR;
  3085. if (Srb->ScsiStatus == 0) {
  3086. //
  3087. // This is some strange return code. Update the error
  3088. // count for the device.
  3089. //
  3090. incrementErrorCount = TRUE;
  3091. } if (Srb->ScsiStatus == SCSISTAT_BUSY) {
  3092. *Status = STATUS_DEVICE_NOT_READY;
  3093. } if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) {
  3094. *Status = STATUS_DEVICE_BUSY;
  3095. retry = FALSE;
  3096. logError = FALSE;
  3097. }
  3098. break;
  3099. }
  3100. default: {
  3101. logError = TRUE;
  3102. logStatus = IO_ERR_CONTROLLER_ERROR;
  3103. uniqueId = 259;
  3104. *Status = STATUS_IO_DEVICE_ERROR;
  3105. unhandledError = TRUE;
  3106. break;
  3107. }
  3108. }
  3109. //
  3110. // NTRAID #183546 - if we support GESN subtype NOT_READY events, and
  3111. // we know from a previous poll when the device will be ready (ETA)
  3112. // we should delay the retry more appropriately than just guessing.
  3113. //
  3114. /*
  3115. if (fdoExtension->MediaChangeDetectionInfo &&
  3116. fdoExtension->MediaChangeDetectionInfo->Gesn.Supported &&
  3117. TEST_FLAG(fdoExtension->MediaChangeDetectionInfo->Gesn.EventMask,
  3118. NOTIFICATION_DEVICE_BUSY_CLASS_MASK)
  3119. ) {
  3120. // check if Gesn.ReadyTime if greater than current tick count
  3121. // if so, delay that long (from 1 to 30 seconds max?)
  3122. // else, leave the guess of time alone.
  3123. }
  3124. */
  3125. }
  3126. if (incrementErrorCount) {
  3127. //
  3128. // if any error count occurred, delay the retry of this io by
  3129. // at least one second, if caller supports it.
  3130. //
  3131. if (retryInterval == 0) {
  3132. retryInterval = 1;
  3133. }
  3134. ClasspPerfIncrementErrorCount(fdoExtension);
  3135. }
  3136. //
  3137. // If there is a class specific error handler call it.
  3138. //
  3139. if (fdoExtension->CommonExtension.DevInfo->ClassError != NULL) {
  3140. fdoExtension->CommonExtension.DevInfo->ClassError(Fdo,
  3141. Srb,
  3142. Status,
  3143. &retry);
  3144. }
  3145. //
  3146. // If the caller wants to know the suggested retry interval tell them.
  3147. //
  3148. if(ARGUMENT_PRESENT(RetryInterval)) {
  3149. *RetryInterval = retryInterval;
  3150. }
  3151. //
  3152. // The RESERVE(6) / RELEASE(6) commands are optional. So
  3153. // if they aren't supported, try the 10-byte equivalents
  3154. //
  3155. if (((PCDB)Srb->Cdb)->CDB6GENERIC.OperationCode == SCSIOP_RESERVE_UNIT ||
  3156. ((PCDB)Srb->Cdb)->CDB6GENERIC.OperationCode == SCSIOP_RELEASE_UNIT)
  3157. {
  3158. if (*Status == STATUS_INVALID_DEVICE_REQUEST)
  3159. {
  3160. PCDB cdb = (PCDB)Srb->Cdb;
  3161. Srb->CdbLength = 10;
  3162. cdb->CDB10.OperationCode = (cdb->CDB6GENERIC.OperationCode == SCSIOP_RESERVE_UNIT) ? SCSIOP_RESERVE_UNIT10 : SCSIOP_RELEASE_UNIT10;
  3163. SET_FLAG(fdoExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_RESERVE6);
  3164. retry = TRUE;
  3165. }
  3166. }
  3167. /*
  3168. * LOG the error:
  3169. * Always log the error in our internal log.
  3170. * If logError is set, also log the error in the system log.
  3171. */
  3172. {
  3173. ULONG totalSize;
  3174. ULONG senseBufferSize = 0;
  3175. IO_ERROR_LOG_PACKET staticErrLogEntry = {0};
  3176. CLASS_ERROR_LOG_DATA staticErrLogData = {0};
  3177. //
  3178. // Calculate the total size of the error log entry.
  3179. // add to totalSize in the order that they are used.
  3180. // the advantage to calculating all the sizes here is
  3181. // that we don't have to do a bunch of extraneous checks
  3182. // later on in this code path.
  3183. //
  3184. totalSize = sizeof(IO_ERROR_LOG_PACKET) // required
  3185. + sizeof(CLASS_ERROR_LOG_DATA);// struct for ease
  3186. //
  3187. // also save any available extra sense data, up to the maximum errlog
  3188. // packet size . WMI should be used for real-time analysis.
  3189. // the event log should only be used for post-mortem debugging.
  3190. //
  3191. if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) {
  3192. ULONG validSenseBytes;
  3193. BOOLEAN validSense;
  3194. //
  3195. // make sure we can at least access the AdditionalSenseLength field
  3196. //
  3197. validSense = RTL_CONTAINS_FIELD(senseBuffer,
  3198. Srb->SenseInfoBufferLength,
  3199. AdditionalSenseLength);
  3200. if (validSense) {
  3201. //
  3202. // if extra info exists, copy the maximum amount of available
  3203. // sense data that is safe into the the errlog.
  3204. //
  3205. validSenseBytes = senseBuffer->AdditionalSenseLength
  3206. + offsetof(SENSE_DATA, AdditionalSenseLength);
  3207. //
  3208. // this is invalid because it causes overflow!
  3209. // whoever sent this type of request would cause
  3210. // a system crash.
  3211. //
  3212. ASSERT(validSenseBytes < MAX_ADDITIONAL_SENSE_BYTES);
  3213. //
  3214. // set to save the most sense buffer possible
  3215. //
  3216. senseBufferSize = max(validSenseBytes, sizeof(SENSE_DATA));
  3217. senseBufferSize = min(senseBufferSize, Srb->SenseInfoBufferLength);
  3218. } else {
  3219. //
  3220. // it's smaller than required to read the total number of
  3221. // valid bytes, so just use the SenseInfoBufferLength field.
  3222. //
  3223. senseBufferSize = Srb->SenseInfoBufferLength;
  3224. }
  3225. /*
  3226. * Bump totalSize by the number of extra senseBuffer bytes
  3227. * (beyond the default sense buffer within CLASS_ERROR_LOG_DATA).
  3228. * Make sure to never allocate more than ERROR_LOG_MAXIMUM_SIZE.
  3229. */
  3230. if (senseBufferSize > sizeof(SENSE_DATA)){
  3231. totalSize += senseBufferSize-sizeof(SENSE_DATA);
  3232. if (totalSize > ERROR_LOG_MAXIMUM_SIZE){
  3233. senseBufferSize -= totalSize-ERROR_LOG_MAXIMUM_SIZE;
  3234. totalSize = ERROR_LOG_MAXIMUM_SIZE;
  3235. }
  3236. }
  3237. }
  3238. //
  3239. // If we've used up all of our retry attempts, set the final status to
  3240. // reflect the appropriate result.
  3241. //
  3242. // ISSUE: the test below should also check RetryCount to determine if we will actually retry,
  3243. // but there is no easy test because we'd have to consider the original retry count
  3244. // for the op; besides, InterpretTransferPacketError sometimes ignores the retry
  3245. // decision returned by this function. So just ErrorRetried to be true in the majority case.
  3246. //
  3247. if (retry){
  3248. staticErrLogEntry.FinalStatus = STATUS_SUCCESS;
  3249. staticErrLogData.ErrorRetried = TRUE;
  3250. } else {
  3251. staticErrLogEntry.FinalStatus = *Status;
  3252. }
  3253. if (TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) {
  3254. staticErrLogData.ErrorPaging = TRUE;
  3255. }
  3256. if (unhandledError) {
  3257. staticErrLogData.ErrorUnhandled = TRUE;
  3258. }
  3259. //
  3260. // Calculate the device offset if there is a geometry.
  3261. //
  3262. staticErrLogEntry.DeviceOffset.QuadPart = (LONGLONG)badSector;
  3263. staticErrLogEntry.DeviceOffset.QuadPart *= (LONGLONG)fdoExtension->DiskGeometry.BytesPerSector;
  3264. if (logStatus == -1){
  3265. staticErrLogEntry.ErrorCode = STATUS_IO_DEVICE_ERROR;
  3266. } else {
  3267. staticErrLogEntry.ErrorCode = logStatus;
  3268. }
  3269. /*
  3270. * The dump data follows the IO_ERROR_LOG_PACKET
  3271. */
  3272. staticErrLogEntry.DumpDataSize = (USHORT)totalSize - sizeof(IO_ERROR_LOG_PACKET);
  3273. staticErrLogEntry.SequenceNumber = 0;
  3274. staticErrLogEntry.MajorFunctionCode = MajorFunctionCode;
  3275. staticErrLogEntry.IoControlCode = IoDeviceCode;
  3276. staticErrLogEntry.RetryCount = (UCHAR) RetryCount;
  3277. staticErrLogEntry.UniqueErrorValue = uniqueId;
  3278. KeQueryTickCount(&staticErrLogData.TickCount);
  3279. staticErrLogData.PortNumber = (ULONG)-1;
  3280. /*
  3281. * Save the entire contents of the SRB.
  3282. */
  3283. staticErrLogData.Srb = *Srb;
  3284. /*
  3285. * For our private log, save just the default length of the SENSE_DATA.
  3286. */
  3287. if (senseBufferSize != 0){
  3288. RtlCopyMemory(&staticErrLogData.SenseData, senseBuffer, min(senseBufferSize, sizeof(SENSE_DATA)));
  3289. }
  3290. /*
  3291. * Save the error log in our context.
  3292. * We only save the default sense buffer length.
  3293. */
  3294. KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
  3295. fdoData->ErrorLogs[fdoData->ErrorLogNextIndex] = staticErrLogData;
  3296. fdoData->ErrorLogNextIndex++;
  3297. fdoData->ErrorLogNextIndex %= NUM_ERROR_LOG_ENTRIES;
  3298. KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
  3299. /*
  3300. * If logError is set, also save this log in the system's error log.
  3301. * But make sure we don't log TUR failures over and over
  3302. * (e.g. if an external drive was switched off and we're still sending TUR's to it every second).
  3303. */
  3304. if (logError)
  3305. {
  3306. //
  3307. // We do not want to log certain system events repetitively
  3308. //
  3309. switch (((PCDB)Srb->Cdb)->CDB10.OperationCode)
  3310. {
  3311. case SCSIOP_TEST_UNIT_READY:
  3312. {
  3313. if (fdoData->LoggedTURFailureSinceLastIO)
  3314. {
  3315. logError = FALSE;
  3316. }
  3317. else
  3318. {
  3319. fdoData->LoggedTURFailureSinceLastIO = TRUE;
  3320. }
  3321. break;
  3322. }
  3323. case SCSIOP_SYNCHRONIZE_CACHE:
  3324. {
  3325. if (fdoData->LoggedSYNCFailure)
  3326. {
  3327. logError = FALSE;
  3328. }
  3329. else
  3330. {
  3331. fdoData->LoggedSYNCFailure = TRUE;
  3332. }
  3333. break;
  3334. }
  3335. }
  3336. }
  3337. if (logError){
  3338. PIO_ERROR_LOG_PACKET errorLogEntry;
  3339. PCLASS_ERROR_LOG_DATA errlogData;
  3340. errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(Fdo, (UCHAR)totalSize);
  3341. if (errorLogEntry){
  3342. errlogData = (PCLASS_ERROR_LOG_DATA)errorLogEntry->DumpData;
  3343. *errorLogEntry = staticErrLogEntry;
  3344. *errlogData = staticErrLogData;
  3345. /*
  3346. * For the system log, copy as much of the sense buffer as possible.
  3347. */
  3348. if (senseBufferSize != 0) {
  3349. RtlCopyMemory(&errlogData->SenseData, senseBuffer, senseBufferSize);
  3350. }
  3351. /*
  3352. * Write the error log packet to the system error logging thread.
  3353. * It will be freed by the kernel.
  3354. */
  3355. IoWriteErrorLogEntry(errorLogEntry);
  3356. }
  3357. }
  3358. }
  3359. return retry;
  3360. } // end ClassInterpretSenseInfo()
  3361. /*++////////////////////////////////////////////////////////////////////////////
  3362. ClassModeSense()
  3363. Routine Description:
  3364. This routine sends a mode sense command to a target ID and returns
  3365. when it is complete.
  3366. Arguments:
  3367. Fdo - Supplies the functional device object associated with this request.
  3368. ModeSenseBuffer - Supplies a buffer to store the sense data.
  3369. Length - Supplies the length in bytes of the mode sense buffer.
  3370. PageMode - Supplies the page or pages of mode sense data to be retrived.
  3371. Return Value:
  3372. Length of the transferred data is returned.
  3373. --*/
  3374. ULONG ClassModeSense( IN PDEVICE_OBJECT Fdo,
  3375. IN PCHAR ModeSenseBuffer,
  3376. IN ULONG Length,
  3377. IN UCHAR PageMode)
  3378. {
  3379. ULONG lengthTransferred = 0;
  3380. PMDL senseBufferMdl;
  3381. PAGED_CODE();
  3382. senseBufferMdl = BuildDeviceInputMdl(ModeSenseBuffer, Length);
  3383. if (senseBufferMdl){
  3384. TRANSFER_PACKET *pkt = DequeueFreeTransferPacket(Fdo, TRUE);
  3385. if (pkt){
  3386. KEVENT event;
  3387. NTSTATUS pktStatus;
  3388. IRP pseudoIrp = {0};
  3389. /*
  3390. * Store the number of packets servicing the irp (one)
  3391. * inside the original IRP. It will be used to counted down
  3392. * to zero when the packet completes.
  3393. * Initialize the original IRP's status to success.
  3394. * If the packet fails, we will set it to the error status.
  3395. */
  3396. pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1);
  3397. pseudoIrp.IoStatus.Status = STATUS_SUCCESS;
  3398. pseudoIrp.IoStatus.Information = 0;
  3399. pseudoIrp.MdlAddress = senseBufferMdl;
  3400. /*
  3401. * Set this up as a SYNCHRONOUS transfer, submit it,
  3402. * and wait for the packet to complete. The result
  3403. * status will be written to the original irp.
  3404. */
  3405. ASSERT(Length <= 0x0ff);
  3406. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  3407. SetupModeSenseTransferPacket(pkt, &event, ModeSenseBuffer, (UCHAR)Length, PageMode, &pseudoIrp);
  3408. SubmitTransferPacket(pkt);
  3409. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  3410. if (NT_SUCCESS(pseudoIrp.IoStatus.Status)){
  3411. lengthTransferred = (ULONG)pseudoIrp.IoStatus.Information;
  3412. }
  3413. else {
  3414. /*
  3415. * This request can sometimes fail legitimately
  3416. * (e.g. when a SCSI device is attached but turned off)
  3417. * so this is not necessarily a device/driver bug.
  3418. */
  3419. DBGTRACE(ClassDebugWarning, ("ClassModeSense on Fdo %ph failed with status %xh.", Fdo, pseudoIrp.IoStatus.Status));
  3420. }
  3421. }
  3422. FreeDeviceInputMdl(senseBufferMdl);
  3423. }
  3424. return lengthTransferred;
  3425. }
  3426. /*++////////////////////////////////////////////////////////////////////////////
  3427. ClassFindModePage()
  3428. Routine Description:
  3429. This routine scans through the mode sense data and finds the requested
  3430. mode sense page code.
  3431. Arguments:
  3432. ModeSenseBuffer - Supplies a pointer to the mode sense data.
  3433. Length - Indicates the length of valid data.
  3434. PageMode - Supplies the page mode to be searched for.
  3435. Use6Byte - Indicates whether 6 or 10 byte mode sense was used.
  3436. Return Value:
  3437. A pointer to the the requested mode page. If the mode page was not found
  3438. then NULL is return.
  3439. --*/
  3440. PVOID
  3441. ClassFindModePage(
  3442. IN PCHAR ModeSenseBuffer,
  3443. IN ULONG Length,
  3444. IN UCHAR PageMode,
  3445. IN BOOLEAN Use6Byte
  3446. )
  3447. {
  3448. PUCHAR limit;
  3449. ULONG parameterHeaderLength;
  3450. PVOID result = NULL;
  3451. limit = ModeSenseBuffer + Length;
  3452. parameterHeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10);
  3453. if (Length >= parameterHeaderLength) {
  3454. PMODE_PARAMETER_HEADER10 modeParam10;
  3455. ULONG blockDescriptorLength;
  3456. /*
  3457. * Skip the mode select header and block descriptors.
  3458. */
  3459. if (Use6Byte){
  3460. blockDescriptorLength = ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength;
  3461. }
  3462. else {
  3463. modeParam10 = (PMODE_PARAMETER_HEADER10) ModeSenseBuffer;
  3464. blockDescriptorLength = modeParam10->BlockDescriptorLength[1];
  3465. }
  3466. ModeSenseBuffer += parameterHeaderLength + blockDescriptorLength;
  3467. //
  3468. // ModeSenseBuffer now points at pages. Walk the pages looking for the
  3469. // requested page until the limit is reached.
  3470. //
  3471. while (ModeSenseBuffer +
  3472. RTL_SIZEOF_THROUGH_FIELD(MODE_DISCONNECT_PAGE, PageLength) < limit) {
  3473. if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) {
  3474. /*
  3475. * found the mode page. make sure it's safe to touch it all
  3476. * before returning the pointer to caller
  3477. */
  3478. if (ModeSenseBuffer + ((PMODE_DISCONNECT_PAGE)ModeSenseBuffer)->PageLength > limit) {
  3479. /*
  3480. * Return NULL since the page is not safe to access in full
  3481. */
  3482. result = NULL;
  3483. }
  3484. else {
  3485. result = ModeSenseBuffer;
  3486. }
  3487. break;
  3488. }
  3489. //
  3490. // Advance to the next page which is 4-byte-aligned offset after this page.
  3491. //
  3492. ModeSenseBuffer +=
  3493. ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength +
  3494. RTL_SIZEOF_THROUGH_FIELD(MODE_DISCONNECT_PAGE, PageLength);
  3495. }
  3496. }
  3497. return result;
  3498. } // end ClassFindModePage()
  3499. /*++////////////////////////////////////////////////////////////////////////////
  3500. ClassSendSrbAsynchronous()
  3501. Routine Description:
  3502. This routine takes a partially built Srb and an Irp and sends it down to
  3503. the port driver.
  3504. This routine must be called with the remove lock held for the specified
  3505. Irp.
  3506. Arguments:
  3507. Fdo - Supplies the functional device object for the orginal request.
  3508. Srb - Supplies a paritally build ScsiRequestBlock. In particular, the
  3509. CDB and the SRB timeout value must be filled in. The SRB must not be
  3510. allocated from zone.
  3511. Irp - Supplies the requesting Irp.
  3512. BufferAddress - Supplies a pointer to the buffer to be transfered.
  3513. BufferLength - Supplies the length of data transfer.
  3514. WriteToDevice - Indicates the data transfer will be from system memory to
  3515. device.
  3516. Return Value:
  3517. Returns STATUS_PENDING if the request is dispatched (since the
  3518. completion routine may change the irp's status value we cannot simply
  3519. return the value of the dispatch)
  3520. or returns a status value to indicate why it failed.
  3521. --*/
  3522. NTSTATUS
  3523. ClassSendSrbAsynchronous(
  3524. PDEVICE_OBJECT Fdo,
  3525. PSCSI_REQUEST_BLOCK Srb,
  3526. PIRP Irp,
  3527. PVOID BufferAddress,
  3528. ULONG BufferLength,
  3529. BOOLEAN WriteToDevice
  3530. )
  3531. {
  3532. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  3533. PIO_STACK_LOCATION irpStack;
  3534. ULONG savedFlags;
  3535. //
  3536. // Write length to SRB.
  3537. //
  3538. Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  3539. //
  3540. // Set SCSI bus address.
  3541. //
  3542. Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  3543. //
  3544. // This is a violation of the SCSI spec but it is required for
  3545. // some targets.
  3546. //
  3547. // Srb->Cdb[1] |= deviceExtension->Lun << 5;
  3548. //
  3549. // Indicate auto request sense by specifying buffer and size.
  3550. //
  3551. Srb->SenseInfoBuffer = fdoExtension->SenseData;
  3552. Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  3553. Srb->DataBuffer = BufferAddress;
  3554. //
  3555. // Save the class driver specific flags away.
  3556. //
  3557. savedFlags = Srb->SrbFlags & SRB_FLAGS_CLASS_DRIVER_RESERVED;
  3558. //
  3559. // Allow the caller to specify that they do not wish
  3560. // IoStartNextPacket() to be called in the completion routine.
  3561. //
  3562. SET_FLAG(savedFlags, (Srb->SrbFlags & SRB_FLAGS_DONT_START_NEXT_PACKET));
  3563. //
  3564. // If caller wants to this request to be tagged, save this fact.
  3565. //
  3566. if ( TEST_FLAG(Srb->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE) &&
  3567. ( SRB_SIMPLE_TAG_REQUEST == Srb->QueueAction ||
  3568. SRB_HEAD_OF_QUEUE_TAG_REQUEST == Srb->QueueAction ||
  3569. SRB_ORDERED_QUEUE_TAG_REQUEST == Srb->QueueAction ) ) {
  3570. SET_FLAG(savedFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
  3571. }
  3572. if (BufferAddress != NULL) {
  3573. //
  3574. // Build Mdl if necessary.
  3575. //
  3576. if (Irp->MdlAddress == NULL) {
  3577. if (IoAllocateMdl(BufferAddress,
  3578. BufferLength,
  3579. FALSE,
  3580. FALSE,
  3581. Irp) == NULL) {
  3582. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  3583. //
  3584. // ClassIoComplete() would have free'd the srb
  3585. //
  3586. if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) {
  3587. FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb);
  3588. }
  3589. ClassFreeOrReuseSrb(fdoExtension, Srb);
  3590. ClassReleaseRemoveLock(Fdo, Irp);
  3591. ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT);
  3592. return STATUS_INSUFFICIENT_RESOURCES;
  3593. }
  3594. MmBuildMdlForNonPagedPool(Irp->MdlAddress);
  3595. } else {
  3596. //
  3597. // Make sure the buffer requested matches the MDL.
  3598. //
  3599. ASSERT(BufferAddress == MmGetMdlVirtualAddress(Irp->MdlAddress));
  3600. }
  3601. //
  3602. // Set read flag.
  3603. //
  3604. Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN;
  3605. } else {
  3606. //
  3607. // Clear flags.
  3608. //
  3609. Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER;
  3610. }
  3611. //
  3612. // Restore saved flags.
  3613. //
  3614. SET_FLAG(Srb->SrbFlags, savedFlags);
  3615. //
  3616. // Disable synchronous transfer for these requests.
  3617. //
  3618. SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  3619. //
  3620. // Set the transfer length.
  3621. //
  3622. Srb->DataTransferLength = BufferLength;
  3623. //
  3624. // Zero out status.
  3625. //
  3626. Srb->ScsiStatus = Srb->SrbStatus = 0;
  3627. Srb->NextSrb = 0;
  3628. //
  3629. // Save a few parameters in the current stack location.
  3630. //
  3631. irpStack = IoGetCurrentIrpStackLocation(Irp);
  3632. //
  3633. // Save retry count in current Irp stack.
  3634. //
  3635. irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
  3636. //
  3637. // Set up IoCompletion routine address.
  3638. //
  3639. IoSetCompletionRoutine(Irp, ClassIoComplete, Srb, TRUE, TRUE, TRUE);
  3640. //
  3641. // Get next stack location and
  3642. // set major function code.
  3643. //
  3644. irpStack = IoGetNextIrpStackLocation(Irp);
  3645. irpStack->MajorFunction = IRP_MJ_SCSI;
  3646. //
  3647. // Save SRB address in next stack for port driver.
  3648. //
  3649. irpStack->Parameters.Scsi.Srb = Srb;
  3650. //
  3651. // Set up Irp Address.
  3652. //
  3653. Srb->OriginalRequest = Irp;
  3654. //
  3655. // Call the port driver to process the request.
  3656. //
  3657. IoMarkIrpPending(Irp);
  3658. IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp);
  3659. return STATUS_PENDING;
  3660. } // end ClassSendSrbAsynchronous()
  3661. /*++////////////////////////////////////////////////////////////////////////////
  3662. ClassDeviceControlDispatch()
  3663. Routine Description:
  3664. The routine is the common class driver device control dispatch entry point.
  3665. This routine is invokes the device-specific drivers DeviceControl routine,
  3666. (which may call the Class driver's common DeviceControl routine).
  3667. Arguments:
  3668. DeviceObject - Supplies a pointer to the device object for this request.
  3669. Irp - Supplies the Irp making the request.
  3670. Return Value:
  3671. Returns the status returned from the device-specific driver.
  3672. --*/
  3673. NTSTATUS
  3674. ClassDeviceControlDispatch(
  3675. PDEVICE_OBJECT DeviceObject,
  3676. PIRP Irp
  3677. )
  3678. {
  3679. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  3680. ULONG isRemoved;
  3681. isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
  3682. if(isRemoved) {
  3683. ClassReleaseRemoveLock(DeviceObject, Irp);
  3684. Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
  3685. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  3686. return STATUS_DEVICE_DOES_NOT_EXIST;
  3687. }
  3688. //
  3689. // Call the class specific driver DeviceControl routine.
  3690. // If it doesn't handle it, it will call back into ClassDeviceControl.
  3691. //
  3692. ASSERT(commonExtension->DevInfo->ClassDeviceControl);
  3693. return commonExtension->DevInfo->ClassDeviceControl(DeviceObject,Irp);
  3694. } // end ClassDeviceControlDispatch()
  3695. /*++////////////////////////////////////////////////////////////////////////////
  3696. ClassDeviceControl()
  3697. Routine Description:
  3698. The routine is the common class driver device control dispatch function.
  3699. This routine is called by a class driver when it get an unrecognized
  3700. device control request. This routine will perform the correct action for
  3701. common requests such as lock media. If the device request is unknown it
  3702. passed down to the next level.
  3703. This routine must be called with the remove lock held for the specified
  3704. irp.
  3705. Arguments:
  3706. DeviceObject - Supplies a pointer to the device object for this request.
  3707. Irp - Supplies the Irp making the request.
  3708. Return Value:
  3709. Returns back a STATUS_PENDING or a completion status.
  3710. --*/
  3711. NTSTATUS
  3712. ClassDeviceControl(
  3713. PDEVICE_OBJECT DeviceObject,
  3714. PIRP Irp
  3715. )
  3716. {
  3717. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  3718. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  3719. PIO_STACK_LOCATION nextStack = NULL;
  3720. ULONG controlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
  3721. PSCSI_REQUEST_BLOCK srb = NULL;
  3722. PCDB cdb = NULL;
  3723. NTSTATUS status;
  3724. ULONG modifiedIoControlCode;
  3725. //
  3726. // If this is a pass through I/O control, set the minor function code
  3727. // and device address and pass it to the port driver.
  3728. //
  3729. if ((controlCode == IOCTL_SCSI_PASS_THROUGH) ||
  3730. (controlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)) {
  3731. PSCSI_PASS_THROUGH scsiPass;
  3732. //
  3733. // Validiate the user buffer.
  3734. //
  3735. #if defined (_WIN64)
  3736. if (IoIs32bitProcess(Irp)) {
  3737. if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32)){
  3738. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  3739. ClassReleaseRemoveLock(DeviceObject, Irp);
  3740. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  3741. status = STATUS_INVALID_PARAMETER;
  3742. goto SetStatusAndReturn;
  3743. }
  3744. }
  3745. else
  3746. #endif
  3747. {
  3748. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  3749. sizeof(SCSI_PASS_THROUGH)) {
  3750. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  3751. ClassReleaseRemoveLock(DeviceObject, Irp);
  3752. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  3753. status = STATUS_INVALID_PARAMETER;
  3754. goto SetStatusAndReturn;
  3755. }
  3756. }
  3757. IoCopyCurrentIrpStackLocationToNext(Irp);
  3758. nextStack = IoGetNextIrpStackLocation(Irp);
  3759. nextStack->MinorFunction = 1;
  3760. ClassReleaseRemoveLock(DeviceObject, Irp);
  3761. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  3762. goto SetStatusAndReturn;
  3763. }
  3764. Irp->IoStatus.Information = 0;
  3765. switch (controlCode) {
  3766. case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: {
  3767. PMOUNTDEV_UNIQUE_ID uniqueId;
  3768. if (!commonExtension->MountedDeviceInterfaceName.Buffer) {
  3769. status = STATUS_INVALID_PARAMETER;
  3770. break;
  3771. }
  3772. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  3773. sizeof(MOUNTDEV_UNIQUE_ID)) {
  3774. status = STATUS_BUFFER_TOO_SMALL;
  3775. Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
  3776. break;
  3777. }
  3778. uniqueId = Irp->AssociatedIrp.SystemBuffer;
  3779. uniqueId->UniqueIdLength =
  3780. commonExtension->MountedDeviceInterfaceName.Length;
  3781. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  3782. sizeof(USHORT) + uniqueId->UniqueIdLength) {
  3783. status = STATUS_BUFFER_OVERFLOW;
  3784. Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID);
  3785. break;
  3786. }
  3787. RtlCopyMemory(uniqueId->UniqueId,
  3788. commonExtension->MountedDeviceInterfaceName.Buffer,
  3789. uniqueId->UniqueIdLength);
  3790. status = STATUS_SUCCESS;
  3791. Irp->IoStatus.Information = sizeof(USHORT) +
  3792. uniqueId->UniqueIdLength;
  3793. break;
  3794. }
  3795. case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: {
  3796. PMOUNTDEV_NAME name;
  3797. ASSERT(commonExtension->DeviceName.Buffer);
  3798. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  3799. sizeof(MOUNTDEV_NAME)) {
  3800. status = STATUS_BUFFER_TOO_SMALL;
  3801. Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
  3802. break;
  3803. }
  3804. name = Irp->AssociatedIrp.SystemBuffer;
  3805. name->NameLength = commonExtension->DeviceName.Length;
  3806. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  3807. sizeof(USHORT) + name->NameLength) {
  3808. status = STATUS_BUFFER_OVERFLOW;
  3809. Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME);
  3810. break;
  3811. }
  3812. RtlCopyMemory(name->Name, commonExtension->DeviceName.Buffer,
  3813. name->NameLength);
  3814. status = STATUS_SUCCESS;
  3815. Irp->IoStatus.Information = sizeof(USHORT) + name->NameLength;
  3816. break;
  3817. }
  3818. case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: {
  3819. PMOUNTDEV_SUGGESTED_LINK_NAME suggestedName;
  3820. WCHAR driveLetterNameBuffer[10] = {0};
  3821. RTL_QUERY_REGISTRY_TABLE queryTable[2] = {0};
  3822. PWSTR valueName;
  3823. UNICODE_STRING driveLetterName;
  3824. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  3825. sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) {
  3826. status = STATUS_BUFFER_TOO_SMALL;
  3827. Irp->IoStatus.Information = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
  3828. break;
  3829. }
  3830. valueName = ExAllocatePoolWithTag(
  3831. PagedPool,
  3832. commonExtension->DeviceName.Length + sizeof(WCHAR),
  3833. '8CcS');
  3834. if (!valueName) {
  3835. status = STATUS_INSUFFICIENT_RESOURCES;
  3836. break;
  3837. }
  3838. RtlCopyMemory(valueName, commonExtension->DeviceName.Buffer,
  3839. commonExtension->DeviceName.Length);
  3840. valueName[commonExtension->DeviceName.Length/sizeof(WCHAR)] = 0;
  3841. driveLetterName.Buffer = driveLetterNameBuffer;
  3842. driveLetterName.MaximumLength = sizeof(driveLetterNameBuffer);
  3843. driveLetterName.Length = 0;
  3844. queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED |
  3845. RTL_QUERY_REGISTRY_DIRECT;
  3846. queryTable[0].Name = valueName;
  3847. queryTable[0].EntryContext = &driveLetterName;
  3848. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
  3849. L"\\Registry\\Machine\\System\\DISK",
  3850. queryTable, NULL, NULL);
  3851. if (!NT_SUCCESS(status)) {
  3852. ExFreePool(valueName);
  3853. break;
  3854. }
  3855. if (driveLetterName.Length == 4 &&
  3856. driveLetterName.Buffer[0] == '%' &&
  3857. driveLetterName.Buffer[1] == ':') {
  3858. driveLetterName.Buffer[0] = 0xFF;
  3859. } else if (driveLetterName.Length != 4 ||
  3860. driveLetterName.Buffer[0] < FirstDriveLetter ||
  3861. driveLetterName.Buffer[0] > LastDriveLetter ||
  3862. driveLetterName.Buffer[1] != ':') {
  3863. status = STATUS_NOT_FOUND;
  3864. ExFreePool(valueName);
  3865. break;
  3866. }
  3867. suggestedName = Irp->AssociatedIrp.SystemBuffer;
  3868. suggestedName->UseOnlyIfThereAreNoOtherLinks = TRUE;
  3869. suggestedName->NameLength = 28;
  3870. Irp->IoStatus.Information =
  3871. FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME, Name) + 28;
  3872. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  3873. Irp->IoStatus.Information) {
  3874. Irp->IoStatus.Information =
  3875. sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
  3876. status = STATUS_BUFFER_OVERFLOW;
  3877. ExFreePool(valueName);
  3878. break;
  3879. }
  3880. RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE,
  3881. L"\\Registry\\Machine\\System\\DISK",
  3882. valueName);
  3883. ExFreePool(valueName);
  3884. RtlCopyMemory(suggestedName->Name, L"\\DosDevices\\", 24);
  3885. suggestedName->Name[12] = driveLetterName.Buffer[0];
  3886. suggestedName->Name[13] = ':';
  3887. //
  3888. // NT_SUCCESS(status) based on RtlQueryRegistryValues
  3889. //
  3890. status = STATUS_SUCCESS;
  3891. break;
  3892. }
  3893. default:
  3894. status = STATUS_PENDING;
  3895. break;
  3896. }
  3897. if (status != STATUS_PENDING) {
  3898. ClassReleaseRemoveLock(DeviceObject, Irp);
  3899. Irp->IoStatus.Status = status;
  3900. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3901. return status;
  3902. }
  3903. if (commonExtension->IsFdo){
  3904. PULONG_PTR function;
  3905. srb = ExAllocatePoolWithTag(NonPagedPool,
  3906. sizeof(SCSI_REQUEST_BLOCK) +
  3907. (sizeof(ULONG_PTR) * 2),
  3908. '9CcS');
  3909. if (srb == NULL) {
  3910. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  3911. ClassReleaseRemoveLock(DeviceObject, Irp);
  3912. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  3913. status = STATUS_INSUFFICIENT_RESOURCES;
  3914. goto SetStatusAndReturn;
  3915. }
  3916. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  3917. cdb = (PCDB)srb->Cdb;
  3918. //
  3919. // Save the function code and the device object in the memory after
  3920. // the SRB.
  3921. //
  3922. function = (PULONG_PTR) ((PSCSI_REQUEST_BLOCK) (srb + 1));
  3923. *function = (ULONG_PTR) DeviceObject;
  3924. function++;
  3925. *function = (ULONG_PTR) controlCode;
  3926. } else {
  3927. srb = NULL;
  3928. }
  3929. //
  3930. // Change the device type to storage for the switch statement, but only
  3931. // if from a legacy device type
  3932. //
  3933. if (((controlCode & 0xffff0000) == (IOCTL_DISK_BASE << 16)) ||
  3934. ((controlCode & 0xffff0000) == (IOCTL_TAPE_BASE << 16)) ||
  3935. ((controlCode & 0xffff0000) == (IOCTL_CDROM_BASE << 16))
  3936. ) {
  3937. modifiedIoControlCode = (controlCode & ~0xffff0000);
  3938. modifiedIoControlCode |= (IOCTL_STORAGE_BASE << 16);
  3939. } else {
  3940. modifiedIoControlCode = controlCode;
  3941. }
  3942. DBGTRACE(ClassDebugTrace, ("> ioctl %xh (%s)", modifiedIoControlCode, DBGGETIOCTLSTR(modifiedIoControlCode)));
  3943. switch (modifiedIoControlCode) {
  3944. case IOCTL_STORAGE_GET_HOTPLUG_INFO: {
  3945. if (srb) {
  3946. ExFreePool(srb);
  3947. srb = NULL;
  3948. }
  3949. if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  3950. sizeof(STORAGE_HOTPLUG_INFO)) {
  3951. //
  3952. // Indicate unsuccessful status and no data transferred.
  3953. //
  3954. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  3955. Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO);
  3956. ClassReleaseRemoveLock(DeviceObject, Irp);
  3957. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  3958. status = STATUS_BUFFER_TOO_SMALL;
  3959. } else if(!commonExtension->IsFdo) {
  3960. //
  3961. // Just forward this down and return
  3962. //
  3963. IoCopyCurrentIrpStackLocationToNext(Irp);
  3964. ClassReleaseRemoveLock(DeviceObject, Irp);
  3965. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  3966. } else {
  3967. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  3968. PSTORAGE_HOTPLUG_INFO info;
  3969. fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)commonExtension;
  3970. info = Irp->AssociatedIrp.SystemBuffer;
  3971. *info = fdoExtension->PrivateFdoData->HotplugInfo;
  3972. Irp->IoStatus.Status = STATUS_SUCCESS;
  3973. Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO);
  3974. ClassReleaseRemoveLock(DeviceObject, Irp);
  3975. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  3976. status = STATUS_SUCCESS;
  3977. }
  3978. break;
  3979. }
  3980. case IOCTL_STORAGE_SET_HOTPLUG_INFO: {
  3981. if (srb)
  3982. {
  3983. ExFreePool(srb);
  3984. srb = NULL;
  3985. }
  3986. if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
  3987. sizeof(STORAGE_HOTPLUG_INFO)) {
  3988. //
  3989. // Indicate unsuccessful status and no data transferred.
  3990. //
  3991. Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
  3992. ClassReleaseRemoveLock(DeviceObject, Irp);
  3993. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  3994. status = STATUS_INFO_LENGTH_MISMATCH;
  3995. goto SetStatusAndReturn;
  3996. }
  3997. if(!commonExtension->IsFdo) {
  3998. //
  3999. // Just forward this down and return
  4000. //
  4001. IoCopyCurrentIrpStackLocationToNext(Irp);
  4002. ClassReleaseRemoveLock(DeviceObject, Irp);
  4003. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  4004. } else {
  4005. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)commonExtension;
  4006. PSTORAGE_HOTPLUG_INFO info = Irp->AssociatedIrp.SystemBuffer;
  4007. status = STATUS_SUCCESS;
  4008. if (info->Size != fdoExtension->PrivateFdoData->HotplugInfo.Size)
  4009. {
  4010. status = STATUS_INVALID_PARAMETER_1;
  4011. }
  4012. if (info->MediaRemovable != fdoExtension->PrivateFdoData->HotplugInfo.MediaRemovable)
  4013. {
  4014. status = STATUS_INVALID_PARAMETER_2;
  4015. }
  4016. if (info->MediaHotplug != fdoExtension->PrivateFdoData->HotplugInfo.MediaHotplug)
  4017. {
  4018. status = STATUS_INVALID_PARAMETER_3;
  4019. }
  4020. if (info->WriteCacheEnableOverride != fdoExtension->PrivateFdoData->HotplugInfo.WriteCacheEnableOverride)
  4021. {
  4022. status = STATUS_INVALID_PARAMETER_5;
  4023. }
  4024. if (NT_SUCCESS(status))
  4025. {
  4026. fdoExtension->PrivateFdoData->HotplugInfo.DeviceHotplug = info->DeviceHotplug;
  4027. //
  4028. // Store the user-defined override in the registry
  4029. //
  4030. ClassSetDeviceParameter(fdoExtension,
  4031. CLASSP_REG_SUBKEY_NAME,
  4032. CLASSP_REG_REMOVAL_POLICY_VALUE_NAME,
  4033. (info->DeviceHotplug) ? RemovalPolicyExpectSurpriseRemoval : RemovalPolicyExpectOrderlyRemoval);
  4034. }
  4035. Irp->IoStatus.Status = status;
  4036. ClassReleaseRemoveLock(DeviceObject, Irp);
  4037. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  4038. }
  4039. break;
  4040. }
  4041. case IOCTL_STORAGE_CHECK_VERIFY:
  4042. case IOCTL_STORAGE_CHECK_VERIFY2: {
  4043. PIRP irp2 = NULL;
  4044. PIO_STACK_LOCATION newStack;
  4045. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
  4046. DebugPrint((1,"DeviceIoControl: Check verify\n"));
  4047. //
  4048. // If a buffer for a media change count was provided, make sure it's
  4049. // big enough to hold the result
  4050. //
  4051. if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
  4052. //
  4053. // If the buffer is too small to hold the media change count
  4054. // then return an error to the caller
  4055. //
  4056. if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  4057. sizeof(ULONG)) {
  4058. DebugPrint((3,"DeviceIoControl: media count "
  4059. "buffer too small\n"));
  4060. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  4061. Irp->IoStatus.Information = sizeof(ULONG);
  4062. if(srb != NULL) {
  4063. ExFreePool(srb);
  4064. }
  4065. ClassReleaseRemoveLock(DeviceObject, Irp);
  4066. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  4067. status = STATUS_BUFFER_TOO_SMALL;
  4068. goto SetStatusAndReturn;
  4069. }
  4070. }
  4071. if(!commonExtension->IsFdo) {
  4072. //
  4073. // If this is a PDO then we should just forward the request down
  4074. //
  4075. ASSERT(!srb);
  4076. IoCopyCurrentIrpStackLocationToNext(Irp);
  4077. ClassReleaseRemoveLock(DeviceObject, Irp);
  4078. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  4079. goto SetStatusAndReturn;
  4080. } else {
  4081. fdoExtension = DeviceObject->DeviceExtension;
  4082. }
  4083. if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) {
  4084. //
  4085. // The caller has provided a valid buffer. Allocate an additional
  4086. // irp and stick the CheckVerify completion routine on it. We will
  4087. // then send this down to the port driver instead of the irp the
  4088. // caller sent in
  4089. //
  4090. DebugPrint((2,"DeviceIoControl: Check verify wants "
  4091. "media count\n"));
  4092. //
  4093. // Allocate a new irp to send the TestUnitReady to the port driver
  4094. //
  4095. irp2 = IoAllocateIrp((CCHAR) (DeviceObject->StackSize + 3), FALSE);
  4096. if(irp2 == NULL) {
  4097. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  4098. Irp->IoStatus.Information = 0;
  4099. ASSERT(srb);
  4100. ExFreePool(srb);
  4101. ClassReleaseRemoveLock(DeviceObject, Irp);
  4102. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  4103. status = STATUS_INSUFFICIENT_RESOURCES;
  4104. goto SetStatusAndReturn;
  4105. break;
  4106. }
  4107. //
  4108. // Make sure to acquire the lock for the new irp.
  4109. //
  4110. ClassAcquireRemoveLock(DeviceObject, irp2);
  4111. irp2->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
  4112. IoSetNextIrpStackLocation(irp2);
  4113. //
  4114. // Set the top stack location and shove the master Irp into the
  4115. // top location
  4116. //
  4117. newStack = IoGetCurrentIrpStackLocation(irp2);
  4118. newStack->Parameters.Others.Argument1 = Irp;
  4119. newStack->DeviceObject = DeviceObject;
  4120. //
  4121. // Stick the check verify completion routine onto the stack
  4122. // and prepare the irp for the port driver
  4123. //
  4124. IoSetCompletionRoutine(irp2,
  4125. ClassCheckVerifyComplete,
  4126. NULL,
  4127. TRUE,
  4128. TRUE,
  4129. TRUE);
  4130. IoSetNextIrpStackLocation(irp2);
  4131. newStack = IoGetCurrentIrpStackLocation(irp2);
  4132. newStack->DeviceObject = DeviceObject;
  4133. newStack->MajorFunction = irpStack->MajorFunction;
  4134. newStack->MinorFunction = irpStack->MinorFunction;
  4135. //
  4136. // Mark the master irp as pending - whether the lower level
  4137. // driver completes it immediately or not this should allow it
  4138. // to go all the way back up.
  4139. //
  4140. IoMarkIrpPending(Irp);
  4141. Irp = irp2;
  4142. }
  4143. //
  4144. // Test Unit Ready
  4145. //
  4146. srb->CdbLength = 6;
  4147. cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY;
  4148. //
  4149. // Set timeout value.
  4150. //
  4151. srb->TimeOutValue = fdoExtension->TimeOutValue;
  4152. //
  4153. // If this was a CV2 then mark the request as low-priority so we don't
  4154. // spin up the drive just to satisfy it.
  4155. //
  4156. if(controlCode == IOCTL_STORAGE_CHECK_VERIFY2) {
  4157. SET_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY);
  4158. }
  4159. //
  4160. // Since this routine will always hand the request to the
  4161. // port driver if there isn't a data transfer to be done
  4162. // we don't have to worry about completing the request here
  4163. // on an error
  4164. //
  4165. //
  4166. // This routine uses a completion routine so we don't want to release
  4167. // the remove lock until then.
  4168. //
  4169. status = ClassSendSrbAsynchronous(DeviceObject,
  4170. srb,
  4171. Irp,
  4172. NULL,
  4173. 0,
  4174. FALSE);
  4175. break;
  4176. }
  4177. case IOCTL_STORAGE_MEDIA_REMOVAL:
  4178. case IOCTL_STORAGE_EJECTION_CONTROL: {
  4179. PPREVENT_MEDIA_REMOVAL mediaRemoval = Irp->AssociatedIrp.SystemBuffer;
  4180. DebugPrint((3, "DiskIoControl: ejection control\n"));
  4181. if(srb) {
  4182. ExFreePool(srb);
  4183. }
  4184. if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
  4185. sizeof(PREVENT_MEDIA_REMOVAL)) {
  4186. //
  4187. // Indicate unsuccessful status and no data transferred.
  4188. //
  4189. Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
  4190. ClassReleaseRemoveLock(DeviceObject, Irp);
  4191. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  4192. status = STATUS_INFO_LENGTH_MISMATCH;
  4193. goto SetStatusAndReturn;
  4194. }
  4195. if(!commonExtension->IsFdo) {
  4196. //
  4197. // Just forward this down and return
  4198. //
  4199. IoCopyCurrentIrpStackLocationToNext(Irp);
  4200. ClassReleaseRemoveLock(DeviceObject, Irp);
  4201. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  4202. }
  4203. else {
  4204. // i don't believe this assertion is valid. this is a request
  4205. // from user-mode, so they could request this for any device
  4206. // they want? also, we handle it properly.
  4207. // ASSERT(TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA));
  4208. status = ClasspEjectionControl(
  4209. DeviceObject,
  4210. Irp,
  4211. ((modifiedIoControlCode ==
  4212. IOCTL_STORAGE_EJECTION_CONTROL) ? SecureMediaLock :
  4213. SimpleMediaLock),
  4214. mediaRemoval->PreventMediaRemoval);
  4215. Irp->IoStatus.Status = status;
  4216. ClassReleaseRemoveLock(DeviceObject, Irp);
  4217. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  4218. }
  4219. break;
  4220. }
  4221. case IOCTL_STORAGE_MCN_CONTROL: {
  4222. DebugPrint((3, "DiskIoControl: MCN control\n"));
  4223. if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
  4224. sizeof(PREVENT_MEDIA_REMOVAL)) {
  4225. //
  4226. // Indicate unsuccessful status and no data transferred.
  4227. //
  4228. Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
  4229. Irp->IoStatus.Information = 0;
  4230. if(srb) {
  4231. ExFreePool(srb);
  4232. }
  4233. ClassReleaseRemoveLock(DeviceObject, Irp);
  4234. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  4235. status = STATUS_INFO_LENGTH_MISMATCH;
  4236. goto SetStatusAndReturn;
  4237. }
  4238. if(!commonExtension->IsFdo) {
  4239. //
  4240. // Just forward this down and return
  4241. //
  4242. if(srb) {
  4243. ExFreePool(srb);
  4244. }
  4245. IoCopyCurrentIrpStackLocationToNext(Irp);
  4246. ClassReleaseRemoveLock(DeviceObject, Irp);
  4247. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  4248. } else {
  4249. //
  4250. // Call to the FDO - handle the ejection control.
  4251. //
  4252. status = ClasspMcnControl(DeviceObject->DeviceExtension,
  4253. Irp,
  4254. srb);
  4255. }
  4256. goto SetStatusAndReturn;
  4257. }
  4258. case IOCTL_STORAGE_RESERVE:
  4259. case IOCTL_STORAGE_RELEASE: {
  4260. //
  4261. // Reserve logical unit.
  4262. //
  4263. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
  4264. if(!commonExtension->IsFdo) {
  4265. IoCopyCurrentIrpStackLocationToNext(Irp);
  4266. ClassReleaseRemoveLock(DeviceObject, Irp);
  4267. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  4268. goto SetStatusAndReturn;
  4269. } else {
  4270. fdoExtension = DeviceObject->DeviceExtension;
  4271. }
  4272. if (TEST_FLAG(fdoExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_RESERVE6))
  4273. {
  4274. srb->CdbLength = 10;
  4275. cdb->CDB10.OperationCode = (modifiedIoControlCode == IOCTL_STORAGE_RESERVE) ? SCSIOP_RESERVE_UNIT10 : SCSIOP_RELEASE_UNIT10;
  4276. }
  4277. else
  4278. {
  4279. srb->CdbLength = 6;
  4280. cdb->CDB6GENERIC.OperationCode = (modifiedIoControlCode == IOCTL_STORAGE_RESERVE) ? SCSIOP_RESERVE_UNIT : SCSIOP_RELEASE_UNIT;
  4281. }
  4282. //
  4283. // Set timeout value.
  4284. //
  4285. srb->TimeOutValue = fdoExtension->TimeOutValue;
  4286. //
  4287. // Send reserves as tagged requests.
  4288. //
  4289. if ( IOCTL_STORAGE_RESERVE == modifiedIoControlCode ) {
  4290. SET_FLAG( srb->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE );
  4291. srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
  4292. }
  4293. status = ClassSendSrbAsynchronous(DeviceObject,
  4294. srb,
  4295. Irp,
  4296. NULL,
  4297. 0,
  4298. FALSE);
  4299. break;
  4300. }
  4301. case IOCTL_STORAGE_EJECT_MEDIA:
  4302. case IOCTL_STORAGE_LOAD_MEDIA:
  4303. case IOCTL_STORAGE_LOAD_MEDIA2:{
  4304. //
  4305. // Eject media.
  4306. //
  4307. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL;
  4308. if(!commonExtension->IsFdo) {
  4309. IoCopyCurrentIrpStackLocationToNext(Irp);
  4310. ClassReleaseRemoveLock(DeviceObject, Irp);
  4311. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  4312. goto SetStatusAndReturn;
  4313. } else {
  4314. fdoExtension = DeviceObject->DeviceExtension;
  4315. }
  4316. if(commonExtension->PagingPathCount != 0) {
  4317. DebugPrint((1, "ClassDeviceControl: call to eject paging device - "
  4318. "failure\n"));
  4319. status = STATUS_FILES_OPEN;
  4320. Irp->IoStatus.Status = status;
  4321. Irp->IoStatus.Information = 0;
  4322. if(srb) {
  4323. ExFreePool(srb);
  4324. }
  4325. ClassReleaseRemoveLock(DeviceObject, Irp);
  4326. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  4327. goto SetStatusAndReturn;
  4328. }
  4329. //
  4330. // Synchronize with ejection control and ejection cleanup code as
  4331. // well as other eject/load requests.
  4332. //
  4333. KeEnterCriticalRegion();
  4334. KeWaitForSingleObject(&(fdoExtension->EjectSynchronizationEvent),
  4335. UserRequest,
  4336. KernelMode,
  4337. FALSE,
  4338. NULL);
  4339. if(fdoExtension->ProtectedLockCount != 0) {
  4340. DebugPrint((1, "ClassDeviceControl: call to eject protected locked "
  4341. "device - failure\n"));
  4342. status = STATUS_DEVICE_BUSY;
  4343. Irp->IoStatus.Status = status;
  4344. Irp->IoStatus.Information = 0;
  4345. if(srb) {
  4346. ExFreePool(srb);
  4347. }
  4348. ClassReleaseRemoveLock(DeviceObject, Irp);
  4349. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  4350. KeSetEvent(&fdoExtension->EjectSynchronizationEvent,
  4351. IO_NO_INCREMENT,
  4352. FALSE);
  4353. KeLeaveCriticalRegion();
  4354. goto SetStatusAndReturn;
  4355. }
  4356. srb->CdbLength = 6;
  4357. cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT;
  4358. cdb->START_STOP.LoadEject = 1;
  4359. if(modifiedIoControlCode == IOCTL_STORAGE_EJECT_MEDIA) {
  4360. cdb->START_STOP.Start = 0;
  4361. } else {
  4362. cdb->START_STOP.Start = 1;
  4363. }
  4364. //
  4365. // Set timeout value.
  4366. //
  4367. srb->TimeOutValue = fdoExtension->TimeOutValue;
  4368. status = ClassSendSrbAsynchronous(DeviceObject,
  4369. srb,
  4370. Irp,
  4371. NULL,
  4372. 0,
  4373. FALSE);
  4374. KeSetEvent(&fdoExtension->EjectSynchronizationEvent, IO_NO_INCREMENT, FALSE);
  4375. KeLeaveCriticalRegion();
  4376. break;
  4377. }
  4378. case IOCTL_STORAGE_FIND_NEW_DEVICES: {
  4379. if(srb) {
  4380. ExFreePool(srb);
  4381. }
  4382. if(commonExtension->IsFdo) {
  4383. IoInvalidateDeviceRelations(
  4384. ((PFUNCTIONAL_DEVICE_EXTENSION) commonExtension)->LowerPdo,
  4385. BusRelations);
  4386. status = STATUS_SUCCESS;
  4387. Irp->IoStatus.Status = status;
  4388. ClassReleaseRemoveLock(DeviceObject, Irp);
  4389. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  4390. }
  4391. else {
  4392. IoCopyCurrentIrpStackLocationToNext(Irp);
  4393. ClassReleaseRemoveLock(DeviceObject, Irp);
  4394. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  4395. }
  4396. break;
  4397. }
  4398. case IOCTL_STORAGE_GET_DEVICE_NUMBER: {
  4399. if(srb) {
  4400. ExFreePool(srb);
  4401. }
  4402. if(irpStack->Parameters.DeviceIoControl.OutputBufferLength >=
  4403. sizeof(STORAGE_DEVICE_NUMBER)) {
  4404. PSTORAGE_DEVICE_NUMBER deviceNumber =
  4405. Irp->AssociatedIrp.SystemBuffer;
  4406. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
  4407. commonExtension->PartitionZeroExtension;
  4408. deviceNumber->DeviceType = fdoExtension->CommonExtension.DeviceObject->DeviceType;
  4409. deviceNumber->DeviceNumber = fdoExtension->DeviceNumber;
  4410. deviceNumber->PartitionNumber = commonExtension->PartitionNumber;
  4411. status = STATUS_SUCCESS;
  4412. Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER);
  4413. } else {
  4414. status = STATUS_BUFFER_TOO_SMALL;
  4415. Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER);
  4416. }
  4417. Irp->IoStatus.Status = status;
  4418. ClassReleaseRemoveLock(DeviceObject, Irp);
  4419. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  4420. break;
  4421. }
  4422. default: {
  4423. DebugPrint((4, "IoDeviceControl: Unsupported device IOCTL %x for %p\n",
  4424. controlCode, DeviceObject));
  4425. //
  4426. // Pass the device control to the next driver.
  4427. //
  4428. if(srb) {
  4429. ExFreePool(srb);
  4430. }
  4431. //
  4432. // Copy the Irp stack parameters to the next stack location.
  4433. //
  4434. IoCopyCurrentIrpStackLocationToNext(Irp);
  4435. ClassReleaseRemoveLock(DeviceObject, Irp);
  4436. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  4437. break;
  4438. }
  4439. } // end switch( ...
  4440. SetStatusAndReturn:
  4441. DBGTRACE(ClassDebugTrace, ("< ioctl %xh (%s): status %xh.", modifiedIoControlCode, DBGGETIOCTLSTR(modifiedIoControlCode), status));
  4442. return status;
  4443. } // end ClassDeviceControl()
  4444. /*++////////////////////////////////////////////////////////////////////////////
  4445. ClassShutdownFlush()
  4446. Routine Description:
  4447. This routine is called for a shutdown and flush IRPs. These are sent by the
  4448. system before it actually shuts down or when the file system does a flush.
  4449. If it exists, the device-specific driver's routine will be invoked. If there
  4450. wasn't one specified, the Irp will be completed with an Invalid device request.
  4451. Arguments:
  4452. DriverObject - Pointer to device object to being shutdown by system.
  4453. Irp - IRP involved.
  4454. Return Value:
  4455. NT Status
  4456. --*/
  4457. NTSTATUS
  4458. ClassShutdownFlush(
  4459. IN PDEVICE_OBJECT DeviceObject,
  4460. IN PIRP Irp
  4461. )
  4462. {
  4463. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  4464. ULONG isRemoved;
  4465. NTSTATUS status;
  4466. isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
  4467. if(isRemoved) {
  4468. ClassReleaseRemoveLock(DeviceObject, Irp);
  4469. Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
  4470. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  4471. return STATUS_DEVICE_DOES_NOT_EXIST;
  4472. }
  4473. if (commonExtension->DevInfo->ClassShutdownFlush) {
  4474. //
  4475. // Call the device-specific driver's routine.
  4476. //
  4477. return commonExtension->DevInfo->ClassShutdownFlush(DeviceObject, Irp);
  4478. }
  4479. //
  4480. // Device-specific driver doesn't support this.
  4481. //
  4482. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  4483. ClassReleaseRemoveLock(DeviceObject, Irp);
  4484. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  4485. return STATUS_INVALID_DEVICE_REQUEST;
  4486. } // end ClassShutdownFlush()
  4487. /*++////////////////////////////////////////////////////////////////////////////
  4488. ClassCreateDeviceObject()
  4489. Routine Description:
  4490. This routine creates an object for the physical device specified and
  4491. sets up the deviceExtension's function pointers for each entry point
  4492. in the device-specific driver.
  4493. Arguments:
  4494. DriverObject - Pointer to driver object created by system.
  4495. ObjectNameBuffer - Dir. name of the object to create.
  4496. LowerDeviceObject - Pointer to the lower device object
  4497. IsFdo - should this be an fdo or a pdo
  4498. DeviceObject - Pointer to the device object pointer we will return.
  4499. Return Value:
  4500. NTSTATUS
  4501. --*/
  4502. NTSTATUS
  4503. ClassCreateDeviceObject(
  4504. IN PDRIVER_OBJECT DriverObject,
  4505. IN PCCHAR ObjectNameBuffer,
  4506. IN PDEVICE_OBJECT LowerDevice,
  4507. IN BOOLEAN IsFdo,
  4508. IN OUT PDEVICE_OBJECT *DeviceObject
  4509. )
  4510. {
  4511. BOOLEAN isPartitionable;
  4512. STRING ntNameString;
  4513. UNICODE_STRING ntUnicodeString;
  4514. NTSTATUS status, status2;
  4515. PDEVICE_OBJECT deviceObject = NULL;
  4516. ULONG characteristics;
  4517. PCLASS_DRIVER_EXTENSION
  4518. driverExtension = IoGetDriverObjectExtension(DriverObject,
  4519. CLASS_DRIVER_EXTENSION_KEY);
  4520. PCLASS_DEV_INFO devInfo;
  4521. PAGED_CODE();
  4522. *DeviceObject = NULL;
  4523. RtlInitUnicodeString(&ntUnicodeString, NULL);
  4524. DebugPrint((2, "ClassCreateFdo: Create device object\n"));
  4525. ASSERT(LowerDevice);
  4526. //
  4527. // Make sure that if we're making PDO's we have an enumeration routine
  4528. //
  4529. isPartitionable = (driverExtension->InitData.ClassEnumerateDevice != NULL);
  4530. ASSERT(IsFdo || isPartitionable);
  4531. //
  4532. // Grab the correct dev-info structure out of the init data
  4533. //
  4534. if(IsFdo) {
  4535. devInfo = &(driverExtension->InitData.FdoData);
  4536. } else {
  4537. devInfo = &(driverExtension->InitData.PdoData);
  4538. }
  4539. characteristics = devInfo->DeviceCharacteristics;
  4540. if(ARGUMENT_PRESENT(ObjectNameBuffer)) {
  4541. DebugPrint((2, "ClassCreateFdo: Name is %s\n", ObjectNameBuffer));
  4542. RtlInitString(&ntNameString, ObjectNameBuffer);
  4543. status = RtlAnsiStringToUnicodeString(&ntUnicodeString, &ntNameString, TRUE);
  4544. if (!NT_SUCCESS(status)) {
  4545. DebugPrint((1,
  4546. "ClassCreateFdo: Cannot convert string %s\n",
  4547. ObjectNameBuffer));
  4548. ntUnicodeString.Buffer = NULL;
  4549. return status;
  4550. }
  4551. } else {
  4552. DebugPrint((2, "ClassCreateFdo: Object will be unnamed\n"));
  4553. if(IsFdo == FALSE) {
  4554. //
  4555. // PDO's have to have some sort of name.
  4556. //
  4557. SET_FLAG(characteristics, FILE_AUTOGENERATED_DEVICE_NAME);
  4558. }
  4559. RtlInitUnicodeString(&ntUnicodeString, NULL);
  4560. }
  4561. status = IoCreateDevice(DriverObject,
  4562. devInfo->DeviceExtensionSize,
  4563. &ntUnicodeString,
  4564. devInfo->DeviceType,
  4565. devInfo->DeviceCharacteristics,
  4566. FALSE,
  4567. &deviceObject);
  4568. if (!NT_SUCCESS(status)) {
  4569. DebugPrint((1, "ClassCreateFdo: Can not create device object %lx\n",
  4570. status));
  4571. ASSERT(deviceObject == NULL);
  4572. //
  4573. // buffer is not used any longer here.
  4574. //
  4575. if (ntUnicodeString.Buffer != NULL) {
  4576. DebugPrint((1, "ClassCreateFdo: Freeing unicode name buffer\n"));
  4577. ExFreePool(ntUnicodeString.Buffer);
  4578. RtlInitUnicodeString(&ntUnicodeString, NULL);
  4579. }
  4580. } else {
  4581. PCOMMON_DEVICE_EXTENSION commonExtension = deviceObject->DeviceExtension;
  4582. RtlZeroMemory(
  4583. deviceObject->DeviceExtension,
  4584. devInfo->DeviceExtensionSize);
  4585. //
  4586. // Setup version code
  4587. //
  4588. commonExtension->Version = 0x03;
  4589. //
  4590. // Setup the remove lock and event
  4591. //
  4592. commonExtension->IsRemoved = NO_REMOVE;
  4593. commonExtension->RemoveLock = 0;
  4594. KeInitializeEvent(&commonExtension->RemoveEvent,
  4595. SynchronizationEvent,
  4596. FALSE);
  4597. #if DBG
  4598. KeInitializeSpinLock(&commonExtension->RemoveTrackingSpinlock);
  4599. commonExtension->RemoveTrackingList = NULL;
  4600. #else
  4601. commonExtension->RemoveTrackingSpinlock = (ULONG_PTR) -1;
  4602. commonExtension->RemoveTrackingList = (PVOID) -1;
  4603. #endif
  4604. //
  4605. // Acquire the lock once. This reference will be released when the
  4606. // remove IRP has been received.
  4607. //
  4608. ClassAcquireRemoveLock(deviceObject, (PIRP) deviceObject);
  4609. //
  4610. // Store a pointer to the driver extension so we don't have to do
  4611. // lookups to get it.
  4612. //
  4613. commonExtension->DriverExtension = driverExtension;
  4614. //
  4615. // Fill in entry points
  4616. //
  4617. commonExtension->DevInfo = devInfo;
  4618. //
  4619. // Initialize some of the common values in the structure
  4620. //
  4621. commonExtension->DeviceObject = deviceObject;
  4622. commonExtension->LowerDeviceObject = NULL;
  4623. if(IsFdo) {
  4624. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PVOID) commonExtension;
  4625. commonExtension->PartitionZeroExtension = deviceObject->DeviceExtension;
  4626. //
  4627. // Set the initial device object flags.
  4628. //
  4629. SET_FLAG(deviceObject->Flags, DO_POWER_PAGABLE);
  4630. //
  4631. // Clear the PDO list
  4632. //
  4633. commonExtension->ChildList = NULL;
  4634. commonExtension->DriverData =
  4635. ((PFUNCTIONAL_DEVICE_EXTENSION) deviceObject->DeviceExtension + 1);
  4636. if(isPartitionable) {
  4637. commonExtension->PartitionNumber = 0;
  4638. } else {
  4639. commonExtension->PartitionNumber = (ULONG) (-1L);
  4640. }
  4641. fdoExtension->DevicePowerState = PowerDeviceD0;
  4642. KeInitializeEvent(&fdoExtension->EjectSynchronizationEvent,
  4643. SynchronizationEvent,
  4644. TRUE);
  4645. KeInitializeEvent(&fdoExtension->ChildLock,
  4646. SynchronizationEvent,
  4647. TRUE);
  4648. status = ClasspAllocateReleaseRequest(deviceObject);
  4649. if(!NT_SUCCESS(status)) {
  4650. IoDeleteDevice(deviceObject);
  4651. *DeviceObject = NULL;
  4652. if (ntUnicodeString.Buffer != NULL) {
  4653. DebugPrint((1, "ClassCreateFdo: Freeing unicode name buffer\n"));
  4654. ExFreePool(ntUnicodeString.Buffer);
  4655. RtlInitUnicodeString(&ntUnicodeString, NULL);
  4656. }
  4657. return status;
  4658. }
  4659. } else {
  4660. PPHYSICAL_DEVICE_EXTENSION pdoExtension =
  4661. deviceObject->DeviceExtension;
  4662. PFUNCTIONAL_DEVICE_EXTENSION p0Extension =
  4663. LowerDevice->DeviceExtension;
  4664. SET_FLAG(deviceObject->Flags, DO_POWER_PAGABLE);
  4665. commonExtension->PartitionZeroExtension = p0Extension;
  4666. //
  4667. // Stick this onto the PDO list
  4668. //
  4669. ClassAddChild(p0Extension, pdoExtension, TRUE);
  4670. commonExtension->DriverData = (PVOID) (pdoExtension + 1);
  4671. //
  4672. // Get the top of stack for the lower device - this allows
  4673. // filters to get stuck in between the partitions and the
  4674. // physical disk.
  4675. //
  4676. commonExtension->LowerDeviceObject =
  4677. IoGetAttachedDeviceReference(LowerDevice);
  4678. //
  4679. // Pnp will keep a reference to the lower device object long
  4680. // after this partition has been deleted. Dereference now so
  4681. // we don't have to deal with it later.
  4682. //
  4683. ObDereferenceObject(commonExtension->LowerDeviceObject);
  4684. }
  4685. KeInitializeEvent(&commonExtension->PathCountEvent, SynchronizationEvent, TRUE);
  4686. commonExtension->IsFdo = IsFdo;
  4687. commonExtension->DeviceName = ntUnicodeString;
  4688. commonExtension->PreviousState = 0xff;
  4689. InitializeDictionary(&(commonExtension->FileObjectDictionary));
  4690. commonExtension->CurrentState = IRP_MN_STOP_DEVICE;
  4691. }
  4692. *DeviceObject = deviceObject;
  4693. return status;
  4694. } // end ClassCreateDeviceObject()
  4695. /*++////////////////////////////////////////////////////////////////////////////
  4696. ClassClaimDevice()
  4697. Routine Description:
  4698. This function claims a device in the port driver. The port driver object
  4699. is updated with the correct driver object if the device is successfully
  4700. claimed.
  4701. Arguments:
  4702. LowerDeviceObject - Supplies the base port device object.
  4703. Release - Indicates the logical unit should be released rather than claimed.
  4704. Return Value:
  4705. Returns a status indicating success or failure of the operation.
  4706. --*/
  4707. NTSTATUS
  4708. ClassClaimDevice(
  4709. IN PDEVICE_OBJECT LowerDeviceObject,
  4710. IN BOOLEAN Release
  4711. )
  4712. {
  4713. IO_STATUS_BLOCK ioStatus;
  4714. PIRP irp;
  4715. PIO_STACK_LOCATION irpStack;
  4716. KEVENT event;
  4717. NTSTATUS status;
  4718. SCSI_REQUEST_BLOCK srb = {0};
  4719. PAGED_CODE();
  4720. srb.Length = sizeof(SCSI_REQUEST_BLOCK);
  4721. srb.Function = Release ? SRB_FUNCTION_RELEASE_DEVICE :
  4722. SRB_FUNCTION_CLAIM_DEVICE;
  4723. //
  4724. // Set the event object to the unsignaled state.
  4725. // It will be used to signal request completion
  4726. //
  4727. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  4728. //
  4729. // Build synchronous request with no transfer.
  4730. //
  4731. irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE,
  4732. LowerDeviceObject,
  4733. NULL,
  4734. 0,
  4735. NULL,
  4736. 0,
  4737. TRUE,
  4738. &event,
  4739. &ioStatus);
  4740. if (irp == NULL) {
  4741. DebugPrint((1, "ClassClaimDevice: Can't allocate Irp\n"));
  4742. return STATUS_INSUFFICIENT_RESOURCES;
  4743. }
  4744. irpStack = IoGetNextIrpStackLocation(irp);
  4745. //
  4746. // Save SRB address in next stack for port driver.
  4747. //
  4748. irpStack->Parameters.Scsi.Srb = &srb;
  4749. //
  4750. // Set up IRP Address.
  4751. //
  4752. srb.OriginalRequest = irp;
  4753. //
  4754. // Call the port driver with the request and wait for it to complete.
  4755. //
  4756. status = IoCallDriver(LowerDeviceObject, irp);
  4757. if (status == STATUS_PENDING) {
  4758. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  4759. status = ioStatus.Status;
  4760. }
  4761. //
  4762. // If this is a release request, then just decrement the reference count
  4763. // and return. The status does not matter.
  4764. //
  4765. if (Release) {
  4766. // ObDereferenceObject(LowerDeviceObject);
  4767. return STATUS_SUCCESS;
  4768. }
  4769. if (!NT_SUCCESS(status)) {
  4770. return status;
  4771. }
  4772. ASSERT(srb.DataBuffer != NULL);
  4773. ASSERT(!TEST_FLAG(srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER));
  4774. return status;
  4775. } // end ClassClaimDevice()
  4776. /*++////////////////////////////////////////////////////////////////////////////
  4777. ClassInternalIoControl()
  4778. Routine Description:
  4779. This routine passes internal device controls to the port driver.
  4780. Internal device controls are used by higher level drivers both for ioctls
  4781. and to pass through scsi requests.
  4782. If the IoControlCode does not match any of the handled ioctls and is
  4783. a valid system address then the request will be treated as an SRB and
  4784. passed down to the lower driver. If the IoControlCode is not a valid
  4785. system address the ioctl will be failed.
  4786. Callers must therefore be extremely cautious to pass correct, initialized
  4787. values to this function.
  4788. Arguments:
  4789. DeviceObject - Supplies a pointer to the device object for this request.
  4790. Irp - Supplies the Irp making the request.
  4791. Return Value:
  4792. Returns back a STATUS_PENDING or a completion status.
  4793. --*/
  4794. NTSTATUS
  4795. ClassInternalIoControl(
  4796. IN PDEVICE_OBJECT DeviceObject,
  4797. IN PIRP Irp
  4798. )
  4799. {
  4800. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  4801. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  4802. PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
  4803. ULONG isRemoved;
  4804. PSCSI_REQUEST_BLOCK srb;
  4805. isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp);
  4806. if(isRemoved) {
  4807. Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
  4808. ClassReleaseRemoveLock(DeviceObject, Irp);
  4809. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  4810. return STATUS_DEVICE_DOES_NOT_EXIST;
  4811. }
  4812. //
  4813. // Get a pointer to the SRB.
  4814. //
  4815. srb = irpStack->Parameters.Scsi.Srb;
  4816. //
  4817. // Set the parameters in the next stack location.
  4818. //
  4819. if(commonExtension->IsFdo) {
  4820. nextStack->Parameters.Scsi.Srb = srb;
  4821. nextStack->MajorFunction = IRP_MJ_SCSI;
  4822. nextStack->MinorFunction = IRP_MN_SCSI_CLASS;
  4823. } else {
  4824. IoCopyCurrentIrpStackLocationToNext(Irp);
  4825. }
  4826. ClassReleaseRemoveLock(DeviceObject, Irp);
  4827. return IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  4828. } // end ClassInternalIoControl()
  4829. /*++////////////////////////////////////////////////////////////////////////////
  4830. ClassQueryTimeOutRegistryValue()
  4831. Routine Description:
  4832. This routine determines whether a reg key for a user-specified timeout
  4833. value exists. This should be called at initialization time.
  4834. Arguments:
  4835. DeviceObject - Pointer to the device object we are retrieving the timeout
  4836. value for
  4837. Return Value:
  4838. None, but it sets a new default timeout for a class of devices.
  4839. --*/
  4840. ULONG
  4841. ClassQueryTimeOutRegistryValue(
  4842. IN PDEVICE_OBJECT DeviceObject
  4843. )
  4844. {
  4845. //
  4846. // Find the appropriate reg. key
  4847. //
  4848. PCLASS_DRIVER_EXTENSION
  4849. driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
  4850. CLASS_DRIVER_EXTENSION_KEY);
  4851. PUNICODE_STRING registryPath = &(driverExtension->RegistryPath);
  4852. PRTL_QUERY_REGISTRY_TABLE parameters = NULL;
  4853. PWSTR path;
  4854. NTSTATUS status;
  4855. LONG timeOut = 0;
  4856. ULONG zero = 0;
  4857. ULONG size;
  4858. PAGED_CODE();
  4859. if (!registryPath) {
  4860. return 0;
  4861. }
  4862. parameters = ExAllocatePoolWithTag(NonPagedPool,
  4863. sizeof(RTL_QUERY_REGISTRY_TABLE)*2,
  4864. '1BcS');
  4865. if (!parameters) {
  4866. return 0;
  4867. }
  4868. size = registryPath->MaximumLength + sizeof(WCHAR);
  4869. path = ExAllocatePoolWithTag(NonPagedPool, size, '2BcS');
  4870. if (!path) {
  4871. ExFreePool(parameters);
  4872. return 0;
  4873. }
  4874. RtlZeroMemory(path,size);
  4875. RtlCopyMemory(path, registryPath->Buffer, size - sizeof(WCHAR));
  4876. //
  4877. // Check for the Timeout value.
  4878. //
  4879. RtlZeroMemory(parameters,
  4880. (sizeof(RTL_QUERY_REGISTRY_TABLE)*2));
  4881. parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  4882. parameters[0].Name = L"TimeOutValue";
  4883. parameters[0].EntryContext = &timeOut;
  4884. parameters[0].DefaultType = REG_DWORD;
  4885. parameters[0].DefaultData = &zero;
  4886. parameters[0].DefaultLength = sizeof(ULONG);
  4887. status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
  4888. path,
  4889. parameters,
  4890. NULL,
  4891. NULL);
  4892. if (!(NT_SUCCESS(status))) {
  4893. timeOut = 0;
  4894. }
  4895. ExFreePool(parameters);
  4896. ExFreePool(path);
  4897. DebugPrint((2,
  4898. "ClassQueryTimeOutRegistryValue: Timeout value %d\n",
  4899. timeOut));
  4900. return timeOut;
  4901. } // end ClassQueryTimeOutRegistryValue()
  4902. /*++////////////////////////////////////////////////////////////////////////////
  4903. ClassCheckVerifyComplete() ISSUE-2000/02/18-henrygab - why public?!
  4904. Routine Description:
  4905. This routine executes when the port driver has completed a check verify
  4906. ioctl. It will set the status of the master Irp, copy the media change
  4907. count and complete the request.
  4908. Arguments:
  4909. Fdo - Supplies the functional device object which represents the logical unit.
  4910. Irp - Supplies the Irp which has completed.
  4911. Context - NULL
  4912. Return Value:
  4913. NT status
  4914. --*/
  4915. NTSTATUS
  4916. ClassCheckVerifyComplete(
  4917. IN PDEVICE_OBJECT Fdo,
  4918. IN PIRP Irp,
  4919. IN PVOID Context
  4920. )
  4921. {
  4922. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  4923. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  4924. PIRP originalIrp;
  4925. ASSERT_FDO(Fdo);
  4926. originalIrp = irpStack->Parameters.Others.Argument1;
  4927. //
  4928. // Copy the media change count and status
  4929. //
  4930. *((PULONG) (originalIrp->AssociatedIrp.SystemBuffer)) =
  4931. fdoExtension->MediaChangeCount;
  4932. DebugPrint((2, "ClassCheckVerifyComplete - Media change count for"
  4933. "device %d is %lx - saved as %lx\n",
  4934. fdoExtension->DeviceNumber,
  4935. fdoExtension->MediaChangeCount,
  4936. *((PULONG) originalIrp->AssociatedIrp.SystemBuffer)));
  4937. originalIrp->IoStatus.Status = Irp->IoStatus.Status;
  4938. originalIrp->IoStatus.Information = sizeof(ULONG);
  4939. ClassReleaseRemoveLock(Fdo, originalIrp);
  4940. ClassCompleteRequest(Fdo, originalIrp, IO_DISK_INCREMENT);
  4941. IoFreeIrp(Irp);
  4942. return STATUS_MORE_PROCESSING_REQUIRED;
  4943. } // end ClassCheckVerifyComplete()
  4944. /*++////////////////////////////////////////////////////////////////////////////
  4945. ClassGetDescriptor()
  4946. Routine Description:
  4947. This routine will perform a query for the specified property id and will
  4948. allocate a non-paged buffer to store the data in. It is the responsibility
  4949. of the caller to ensure that this buffer is freed.
  4950. This routine must be run at IRQL_PASSIVE_LEVEL
  4951. Arguments:
  4952. DeviceObject - the device to query
  4953. DeviceInfo - a location to store a pointer to the buffer we allocate
  4954. Return Value:
  4955. status
  4956. if status is unsuccessful *DeviceInfo will be set to NULL, else the
  4957. buffer allocated on behalf of the caller.
  4958. --*/
  4959. NTSTATUS
  4960. ClassGetDescriptor(
  4961. IN PDEVICE_OBJECT DeviceObject,
  4962. IN PSTORAGE_PROPERTY_ID PropertyId,
  4963. OUT PSTORAGE_DESCRIPTOR_HEADER *Descriptor
  4964. )
  4965. {
  4966. STORAGE_PROPERTY_QUERY query = {0};
  4967. IO_STATUS_BLOCK ioStatus;
  4968. PSTORAGE_DESCRIPTOR_HEADER descriptor = NULL;
  4969. ULONG length;
  4970. UCHAR pass = 0;
  4971. PAGED_CODE();
  4972. //
  4973. // Set the passed-in descriptor pointer to NULL as default
  4974. //
  4975. *Descriptor = NULL;
  4976. query.PropertyId = *PropertyId;
  4977. query.QueryType = PropertyStandardQuery;
  4978. //
  4979. // On the first pass we just want to get the first few
  4980. // bytes of the descriptor so we can read it's size
  4981. //
  4982. descriptor = (PVOID)&query;
  4983. ASSERT(sizeof(STORAGE_PROPERTY_QUERY) >= (sizeof(ULONG)*2));
  4984. ClassSendDeviceIoControlSynchronous(
  4985. IOCTL_STORAGE_QUERY_PROPERTY,
  4986. DeviceObject,
  4987. &query,
  4988. sizeof(STORAGE_PROPERTY_QUERY),
  4989. sizeof(ULONG) * 2,
  4990. FALSE,
  4991. &ioStatus
  4992. );
  4993. if(!NT_SUCCESS(ioStatus.Status)) {
  4994. DebugPrint((1, "ClassGetDescriptor: error %lx trying to "
  4995. "query properties #1\n", ioStatus.Status));
  4996. return ioStatus.Status;
  4997. }
  4998. if (descriptor->Size == 0) {
  4999. //
  5000. // This DebugPrint is to help third-party driver writers
  5001. //
  5002. DebugPrint((0, "ClassGetDescriptor: size returned was zero?! (status "
  5003. "%x\n", ioStatus.Status));
  5004. return STATUS_UNSUCCESSFUL;
  5005. }
  5006. //
  5007. // This time we know how much data there is so we can
  5008. // allocate a buffer of the correct size
  5009. //
  5010. length = descriptor->Size;
  5011. ASSERT(length >= sizeof(STORAGE_PROPERTY_QUERY));
  5012. length = max(length, sizeof(STORAGE_PROPERTY_QUERY));
  5013. descriptor = ExAllocatePoolWithTag(NonPagedPool, length, '4BcS');
  5014. if(descriptor == NULL) {
  5015. DebugPrint((1, "ClassGetDescriptor: unable to memory for descriptor "
  5016. "(%d bytes)\n", length));
  5017. return STATUS_INSUFFICIENT_RESOURCES;
  5018. }
  5019. //
  5020. // setup the query again, as it was overwritten above
  5021. //
  5022. RtlZeroMemory(&query, sizeof(STORAGE_PROPERTY_QUERY));
  5023. query.PropertyId = *PropertyId;
  5024. query.QueryType = PropertyStandardQuery;
  5025. //
  5026. // copy the input to the new outputbuffer
  5027. //
  5028. RtlCopyMemory(descriptor,
  5029. &query,
  5030. sizeof(STORAGE_PROPERTY_QUERY)
  5031. );
  5032. ClassSendDeviceIoControlSynchronous(
  5033. IOCTL_STORAGE_QUERY_PROPERTY,
  5034. DeviceObject,
  5035. descriptor,
  5036. sizeof(STORAGE_PROPERTY_QUERY),
  5037. length,
  5038. FALSE,
  5039. &ioStatus
  5040. );
  5041. if(!NT_SUCCESS(ioStatus.Status)) {
  5042. DebugPrint((1, "ClassGetDescriptor: error %lx trying to "
  5043. "query properties #1\n", ioStatus.Status));
  5044. ExFreePool(descriptor);
  5045. return ioStatus.Status;
  5046. }
  5047. //
  5048. // return the memory we've allocated to the caller
  5049. //
  5050. *Descriptor = descriptor;
  5051. return ioStatus.Status;
  5052. } // end ClassGetDescriptor()
  5053. /*++////////////////////////////////////////////////////////////////////////////
  5054. ClassSignalCompletion()
  5055. Routine Description:
  5056. This completion routine will signal the event given as context and then
  5057. return STATUS_MORE_PROCESSING_REQUIRED to stop event completion. It is
  5058. the responsibility of the routine waiting on the event to complete the
  5059. request and free the event.
  5060. Arguments:
  5061. DeviceObject - a pointer to the device object
  5062. Irp - a pointer to the irp
  5063. Event - a pointer to the event to signal
  5064. Return Value:
  5065. STATUS_MORE_PROCESSING_REQUIRED
  5066. --*/
  5067. NTSTATUS
  5068. ClassSignalCompletion(
  5069. IN PDEVICE_OBJECT DeviceObject,
  5070. IN PIRP Irp,
  5071. IN PKEVENT Event
  5072. )
  5073. {
  5074. KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
  5075. return STATUS_MORE_PROCESSING_REQUIRED;
  5076. } // end ClassSignalCompletion()
  5077. /*++////////////////////////////////////////////////////////////////////////////
  5078. ClassPnpQueryFdoRelations()
  5079. Routine Description:
  5080. This routine will call the driver's enumeration routine to update the
  5081. list of PDO's. It will then build a response to the
  5082. IRP_MN_QUERY_DEVICE_RELATIONS and place it into the information field in
  5083. the irp.
  5084. Arguments:
  5085. Fdo - a pointer to the functional device object we are enumerating
  5086. Irp - a pointer to the enumeration request
  5087. Return Value:
  5088. status
  5089. --*/
  5090. NTSTATUS
  5091. ClassPnpQueryFdoRelations(
  5092. IN PDEVICE_OBJECT Fdo,
  5093. IN PIRP Irp
  5094. )
  5095. {
  5096. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  5097. PCLASS_DRIVER_EXTENSION
  5098. driverExtension = IoGetDriverObjectExtension(Fdo->DriverObject,
  5099. CLASS_DRIVER_EXTENSION_KEY);
  5100. NTSTATUS status;
  5101. PAGED_CODE();
  5102. //
  5103. // If there's already an enumeration in progress then don't start another
  5104. // one.
  5105. //
  5106. if(InterlockedIncrement(&(fdoExtension->EnumerationInterlock)) == 1) {
  5107. status = driverExtension->InitData.ClassEnumerateDevice(Fdo);
  5108. }
  5109. Irp->IoStatus.Information = (ULONG_PTR) NULL;
  5110. Irp->IoStatus.Status = ClassRetrieveDeviceRelations(
  5111. Fdo,
  5112. BusRelations,
  5113. &((PDEVICE_RELATIONS) Irp->IoStatus.Information));
  5114. InterlockedDecrement(&(fdoExtension->EnumerationInterlock));
  5115. return Irp->IoStatus.Status;
  5116. } // end ClassPnpQueryFdoRelations()
  5117. /*++////////////////////////////////////////////////////////////////////////////
  5118. ClassMarkChildrenMissing()
  5119. Routine Description:
  5120. This routine will call ClassMarkChildMissing() for all children.
  5121. It acquires the ChildLock before calling ClassMarkChildMissing().
  5122. Arguments:
  5123. Fdo - the "bus's" device object, such as the disk FDO for non-removable
  5124. disks with multiple partitions.
  5125. Return Value:
  5126. None
  5127. --*/
  5128. VOID
  5129. ClassMarkChildrenMissing(
  5130. IN PFUNCTIONAL_DEVICE_EXTENSION Fdo
  5131. )
  5132. {
  5133. PCOMMON_DEVICE_EXTENSION commonExtension = &(Fdo->CommonExtension);
  5134. PPHYSICAL_DEVICE_EXTENSION nextChild = commonExtension->ChildList;
  5135. PAGED_CODE();
  5136. ClassAcquireChildLock(Fdo);
  5137. while (nextChild){
  5138. PPHYSICAL_DEVICE_EXTENSION tmpChild;
  5139. /*
  5140. * ClassMarkChildMissing will also dequeue the child extension.
  5141. * So get the next pointer before calling ClassMarkChildMissing.
  5142. */
  5143. tmpChild = nextChild;
  5144. nextChild = tmpChild->CommonExtension.ChildList;
  5145. ClassMarkChildMissing(tmpChild, FALSE);
  5146. }
  5147. ClassReleaseChildLock(Fdo);
  5148. return;
  5149. } // end ClassMarkChildrenMissing()
  5150. /*++////////////////////////////////////////////////////////////////////////////
  5151. ClassMarkChildMissing()
  5152. Routine Description:
  5153. This routine will make an active child "missing." If the device has never
  5154. been enumerated then it will be deleted on the spot. If the device has
  5155. not been enumerated then it will be marked as missing so that we can
  5156. not report it in the next device enumeration.
  5157. Arguments:
  5158. Child - the child device to be marked as missing.
  5159. AcquireChildLock - TRUE if the child lock should be acquired before removing
  5160. the missing child. FALSE if the child lock is already
  5161. acquired by this thread.
  5162. Return Value:
  5163. returns whether or not the child device object has previously been reported
  5164. to PNP.
  5165. --*/
  5166. BOOLEAN
  5167. ClassMarkChildMissing(
  5168. IN PPHYSICAL_DEVICE_EXTENSION Child,
  5169. IN BOOLEAN AcquireChildLock
  5170. )
  5171. {
  5172. BOOLEAN returnValue = Child->IsEnumerated;
  5173. PAGED_CODE();
  5174. ASSERT_PDO(Child->DeviceObject);
  5175. Child->IsMissing = TRUE;
  5176. //
  5177. // Make sure this child is not in the active list.
  5178. //
  5179. ClassRemoveChild(Child->CommonExtension.PartitionZeroExtension,
  5180. Child,
  5181. AcquireChildLock);
  5182. if(Child->IsEnumerated == FALSE) {
  5183. PCOMMON_DEVICE_EXTENSION commonExtension = Child->DeviceObject->DeviceExtension;
  5184. commonExtension->IsRemoved = REMOVE_PENDING;
  5185. ClassRemoveDevice(Child->DeviceObject, IRP_MN_REMOVE_DEVICE);
  5186. }
  5187. return returnValue;
  5188. } // end ClassMarkChildMissing()
  5189. /*++////////////////////////////////////////////////////////////////////////////
  5190. ClassRetrieveDeviceRelations()
  5191. Routine Description:
  5192. This routine will allocate a buffer to hold the specified list of
  5193. relations. It will then fill in the list with referenced device pointers
  5194. and will return the request.
  5195. Arguments:
  5196. Fdo - pointer to the FDO being queried
  5197. RelationType - what type of relations are being queried
  5198. DeviceRelations - a location to store a pointer to the response
  5199. Return Value:
  5200. status
  5201. --*/
  5202. NTSTATUS
  5203. ClassRetrieveDeviceRelations(
  5204. IN PDEVICE_OBJECT Fdo,
  5205. IN DEVICE_RELATION_TYPE RelationType,
  5206. OUT PDEVICE_RELATIONS *DeviceRelations
  5207. )
  5208. {
  5209. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  5210. ULONG count = 0;
  5211. ULONG i;
  5212. PPHYSICAL_DEVICE_EXTENSION nextChild;
  5213. ULONG relationsSize;
  5214. PDEVICE_RELATIONS deviceRelations = NULL;
  5215. NTSTATUS status;
  5216. PAGED_CODE();
  5217. ClassAcquireChildLock(fdoExtension);
  5218. nextChild = fdoExtension->CommonExtension.ChildList;
  5219. //
  5220. // Count the number of PDO's attached to this disk
  5221. //
  5222. while(nextChild != NULL) {
  5223. PCOMMON_DEVICE_EXTENSION commonExtension;
  5224. commonExtension = &(nextChild->CommonExtension);
  5225. ASSERTMSG("ClassPnp internal error: missing child on active list\n",
  5226. (nextChild->IsMissing == FALSE));
  5227. nextChild = commonExtension->ChildList;
  5228. count++;
  5229. };
  5230. relationsSize = (sizeof(DEVICE_RELATIONS) +
  5231. (count * sizeof(PDEVICE_OBJECT)));
  5232. deviceRelations = ExAllocatePoolWithTag(PagedPool, relationsSize, '5BcS');
  5233. if(deviceRelations == NULL) {
  5234. DebugPrint((1, "ClassRetrieveDeviceRelations: unable to allocate "
  5235. "%d bytes for device relations\n", relationsSize));
  5236. ClassReleaseChildLock(fdoExtension);
  5237. return STATUS_INSUFFICIENT_RESOURCES;
  5238. }
  5239. RtlZeroMemory(deviceRelations, relationsSize);
  5240. nextChild = fdoExtension->CommonExtension.ChildList;
  5241. i = count - 1;
  5242. while(nextChild != NULL) {
  5243. PCOMMON_DEVICE_EXTENSION commonExtension;
  5244. commonExtension = &(nextChild->CommonExtension);
  5245. ASSERTMSG("ClassPnp internal error: missing child on active list\n",
  5246. (nextChild->IsMissing == FALSE));
  5247. deviceRelations->Objects[i--] = nextChild->DeviceObject;
  5248. status = ObReferenceObjectByPointer(
  5249. nextChild->DeviceObject,
  5250. 0,
  5251. NULL,
  5252. KernelMode);
  5253. ASSERT(NT_SUCCESS(status));
  5254. nextChild->IsEnumerated = TRUE;
  5255. nextChild = commonExtension->ChildList;
  5256. }
  5257. ASSERTMSG("Child list has changed: ", i == -1);
  5258. deviceRelations->Count = count;
  5259. *DeviceRelations = deviceRelations;
  5260. ClassReleaseChildLock(fdoExtension);
  5261. return STATUS_SUCCESS;
  5262. } // end ClassRetrieveDeviceRelations()
  5263. /*++////////////////////////////////////////////////////////////////////////////
  5264. ClassGetPdoId()
  5265. Routine Description:
  5266. This routine will call into the driver to retrieve a copy of one of it's
  5267. id strings.
  5268. Arguments:
  5269. Pdo - a pointer to the pdo being queried
  5270. IdType - which type of id string is being queried
  5271. IdString - an allocated unicode string structure which the driver
  5272. can fill in.
  5273. Return Value:
  5274. status
  5275. --*/
  5276. NTSTATUS
  5277. ClassGetPdoId(
  5278. IN PDEVICE_OBJECT Pdo,
  5279. IN BUS_QUERY_ID_TYPE IdType,
  5280. IN PUNICODE_STRING IdString
  5281. )
  5282. {
  5283. PCLASS_DRIVER_EXTENSION
  5284. driverExtension = IoGetDriverObjectExtension(Pdo->DriverObject,
  5285. CLASS_DRIVER_EXTENSION_KEY);
  5286. ASSERT_PDO(Pdo);
  5287. ASSERT(driverExtension->InitData.ClassQueryId);
  5288. PAGED_CODE();
  5289. return driverExtension->InitData.ClassQueryId( Pdo, IdType, IdString);
  5290. } // end ClassGetPdoId()
  5291. /*++////////////////////////////////////////////////////////////////////////////
  5292. ClassQueryPnpCapabilities()
  5293. Routine Description:
  5294. This routine will call into the class driver to retrieve it's pnp
  5295. capabilities.
  5296. Arguments:
  5297. PhysicalDeviceObject - The physical device object to retrieve properties
  5298. for.
  5299. Return Value:
  5300. status
  5301. --*/
  5302. NTSTATUS
  5303. ClassQueryPnpCapabilities(
  5304. IN PDEVICE_OBJECT DeviceObject,
  5305. IN PDEVICE_CAPABILITIES Capabilities
  5306. )
  5307. {
  5308. PCLASS_DRIVER_EXTENSION driverExtension =
  5309. ClassGetDriverExtension(DeviceObject->DriverObject);
  5310. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  5311. PCLASS_QUERY_PNP_CAPABILITIES queryRoutine = NULL;
  5312. PAGED_CODE();
  5313. ASSERT(DeviceObject);
  5314. ASSERT(Capabilities);
  5315. if(commonExtension->IsFdo) {
  5316. queryRoutine = driverExtension->InitData.FdoData.ClassQueryPnpCapabilities;
  5317. } else {
  5318. queryRoutine = driverExtension->InitData.PdoData.ClassQueryPnpCapabilities;
  5319. }
  5320. if(queryRoutine) {
  5321. return queryRoutine(DeviceObject,
  5322. Capabilities);
  5323. } else {
  5324. return STATUS_NOT_IMPLEMENTED;
  5325. }
  5326. } // end ClassQueryPnpCapabilities()
  5327. /*++////////////////////////////////////////////////////////////////////////////
  5328. ClassInvalidateBusRelations()
  5329. Routine Description:
  5330. This routine re-enumerates the devices on the "bus". It will call into
  5331. the driver's ClassEnumerate routine to update the device objects
  5332. immediately. It will then schedule a bus re-enumeration for pnp by calling
  5333. IoInvalidateDeviceRelations.
  5334. Arguments:
  5335. Fdo - a pointer to the functional device object for this bus
  5336. Return Value:
  5337. none
  5338. --*/
  5339. VOID
  5340. ClassInvalidateBusRelations(
  5341. IN PDEVICE_OBJECT Fdo
  5342. )
  5343. {
  5344. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  5345. PCLASS_DRIVER_EXTENSION
  5346. driverExtension = IoGetDriverObjectExtension(Fdo->DriverObject,
  5347. CLASS_DRIVER_EXTENSION_KEY);
  5348. NTSTATUS status = STATUS_SUCCESS;
  5349. PAGED_CODE();
  5350. ASSERT_FDO(Fdo);
  5351. ASSERT(driverExtension->InitData.ClassEnumerateDevice != NULL);
  5352. if(InterlockedIncrement(&(fdoExtension->EnumerationInterlock)) == 1) {
  5353. status = driverExtension->InitData.ClassEnumerateDevice(Fdo);
  5354. }
  5355. InterlockedDecrement(&(fdoExtension->EnumerationInterlock));
  5356. if(!NT_SUCCESS(status)) {
  5357. DebugPrint((1, "ClassInvalidateBusRelations: EnumerateDevice routine "
  5358. "returned %lx\n", status));
  5359. }
  5360. IoInvalidateDeviceRelations(fdoExtension->LowerPdo, BusRelations);
  5361. return;
  5362. } // end ClassInvalidateBusRelations()
  5363. /*++////////////////////////////////////////////////////////////////////////////
  5364. ClassRemoveDevice() ISSUE-2000/02/18-henrygab - why public?!
  5365. Routine Description:
  5366. This routine is called to handle the "removal" of a device. It will
  5367. forward the request downwards if necesssary, call into the driver
  5368. to release any necessary resources (memory, events, etc) and then
  5369. will delete the device object.
  5370. Arguments:
  5371. DeviceObject - a pointer to the device object being removed
  5372. RemoveType - indicates what type of remove this is (regular or surprise).
  5373. Return Value:
  5374. status
  5375. --*/
  5376. NTSTATUS
  5377. ClassRemoveDevice(
  5378. IN PDEVICE_OBJECT DeviceObject,
  5379. IN UCHAR RemoveType
  5380. )
  5381. {
  5382. PCLASS_DRIVER_EXTENSION
  5383. driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject,
  5384. CLASS_DRIVER_EXTENSION_KEY);
  5385. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  5386. PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject;
  5387. PCLASS_WMI_INFO classWmiInfo;
  5388. BOOLEAN proceedWithRemove = TRUE;
  5389. NTSTATUS status;
  5390. PAGED_CODE();
  5391. /*
  5392. * Deregister from WMI.
  5393. */
  5394. classWmiInfo = commonExtension->IsFdo ?
  5395. &driverExtension->InitData.FdoData.ClassWmiInfo :
  5396. &driverExtension->InitData.PdoData.ClassWmiInfo;
  5397. if (classWmiInfo->GuidRegInfo){
  5398. status = IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_DEREGISTER);
  5399. DBGTRACE(ClassDebugInfo, ("ClassRemoveDevice: IoWMIRegistrationControl(%p, WMI_ACTION_DEREGISTER) --> %lx", DeviceObject, status));
  5400. }
  5401. /*
  5402. * If we exposed a "shingle" (a named device interface openable by CreateFile)
  5403. * then delete it now.
  5404. */
  5405. if (commonExtension->MountedDeviceInterfaceName.Buffer){
  5406. IoSetDeviceInterfaceState(&commonExtension->MountedDeviceInterfaceName, FALSE);
  5407. RtlFreeUnicodeString(&commonExtension->MountedDeviceInterfaceName);
  5408. RtlInitUnicodeString(&commonExtension->MountedDeviceInterfaceName, NULL);
  5409. }
  5410. //
  5411. // If this is a surprise removal we leave the device around - which means
  5412. // we don't have to (or want to) drop the remove lock and wait for pending
  5413. // requests to complete.
  5414. //
  5415. if (RemoveType == IRP_MN_REMOVE_DEVICE){
  5416. //
  5417. // Release the lock we acquired when the device object was created.
  5418. //
  5419. ClassReleaseRemoveLock(DeviceObject, (PIRP) DeviceObject);
  5420. DebugPrint((1, "ClasspRemoveDevice - Reference count is now %d\n",
  5421. commonExtension->RemoveLock));
  5422. KeWaitForSingleObject(&commonExtension->RemoveEvent,
  5423. Executive,
  5424. KernelMode,
  5425. FALSE,
  5426. NULL);
  5427. DebugPrint((1, "ClasspRemoveDevice - removing device %p\n", DeviceObject));
  5428. if(commonExtension->IsFdo) {
  5429. DebugPrint((1, "ClasspRemoveDevice - FDO %p has received a "
  5430. "remove request.\n", DeviceObject));
  5431. }
  5432. else {
  5433. PPHYSICAL_DEVICE_EXTENSION pdoExtension = DeviceObject->DeviceExtension;
  5434. if (pdoExtension->IsMissing){
  5435. /*
  5436. * The child partition PDO is missing, so we are going to go ahead
  5437. * and delete it for the remove.
  5438. */
  5439. DBGTRACE(ClassDebugWarning, ("ClasspRemoveDevice - PDO %p is missing and will be removed", DeviceObject));
  5440. }
  5441. else {
  5442. /*
  5443. * We got a remove for a child partition PDO which is not actually missing.
  5444. * So we will NOT actually delete it.
  5445. */
  5446. DBGTRACE(ClassDebugWarning, ("ClasspRemoveDevice - PDO %p still exists and will be removed when it disappears", DeviceObject));
  5447. //
  5448. // Reacquire the remove lock for the next time this comes around.
  5449. //
  5450. ClassAcquireRemoveLock(DeviceObject, (PIRP) DeviceObject);
  5451. //
  5452. // the device wasn't missing so it's not really been removed.
  5453. //
  5454. commonExtension->IsRemoved = NO_REMOVE;
  5455. IoInvalidateDeviceRelations(
  5456. commonExtension->PartitionZeroExtension->LowerPdo,
  5457. BusRelations);
  5458. proceedWithRemove = FALSE;
  5459. }
  5460. }
  5461. }
  5462. if (proceedWithRemove){
  5463. /*
  5464. * Call the class driver's remove handler.
  5465. * All this is supposed to do is clean up its data and device interfaces.
  5466. */
  5467. ASSERT(commonExtension->DevInfo->ClassRemoveDevice);
  5468. status = commonExtension->DevInfo->ClassRemoveDevice(DeviceObject, RemoveType);
  5469. ASSERT(NT_SUCCESS(status));
  5470. status = STATUS_SUCCESS;
  5471. if (commonExtension->IsFdo){
  5472. PDEVICE_OBJECT pdo;
  5473. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  5474. ClasspDisableTimer(fdoExtension->DeviceObject);
  5475. if (RemoveType == IRP_MN_REMOVE_DEVICE){
  5476. PPHYSICAL_DEVICE_EXTENSION child;
  5477. //
  5478. // Cleanup the media detection resources now that the class driver
  5479. // has stopped it's timer (if any) and we can be sure they won't
  5480. // call us to do detection again.
  5481. //
  5482. ClassCleanupMediaChangeDetection(fdoExtension);
  5483. //
  5484. // Cleanup any Failure Prediction stuff
  5485. //
  5486. if (fdoExtension->FailurePredictionInfo) {
  5487. ExFreePool(fdoExtension->FailurePredictionInfo);
  5488. fdoExtension->FailurePredictionInfo = NULL;
  5489. }
  5490. /*
  5491. * Ordinarily all child PDOs will be removed by the time
  5492. * that the parent gets the REMOVE_DEVICE.
  5493. * However, if a child PDO has been created but has not
  5494. * been announced in a QueryDeviceRelations, then it is
  5495. * just a private data structure unknown to pnp, and we have
  5496. * to delete it ourselves.
  5497. */
  5498. ClassAcquireChildLock(fdoExtension);
  5499. while (child = ClassRemoveChild(fdoExtension, NULL, FALSE)){
  5500. PCOMMON_DEVICE_EXTENSION childCommonExtension = child->DeviceObject->DeviceExtension;
  5501. //
  5502. // Yank the pdo. This routine will unlink the device from the
  5503. // pdo list so NextPdo will point to the next one when it's
  5504. // complete.
  5505. //
  5506. child->IsMissing = TRUE;
  5507. childCommonExtension->IsRemoved = REMOVE_PENDING;
  5508. ClassRemoveDevice(child->DeviceObject, IRP_MN_REMOVE_DEVICE);
  5509. }
  5510. ClassReleaseChildLock(fdoExtension);
  5511. }
  5512. else if (RemoveType == IRP_MN_SURPRISE_REMOVAL){
  5513. /*
  5514. * This is a surprise-remove on the parent FDO.
  5515. * We will mark the child PDOs as missing so that they
  5516. * will actually get deleted when they get a REMOVE_DEVICE.
  5517. */
  5518. ClassMarkChildrenMissing(fdoExtension);
  5519. }
  5520. if (RemoveType == IRP_MN_REMOVE_DEVICE){
  5521. ClasspFreeReleaseRequest(DeviceObject);
  5522. //
  5523. // Free FDO-specific data structs
  5524. //
  5525. if (fdoExtension->PrivateFdoData){
  5526. /*
  5527. * Remove the FDO from the static list.
  5528. * Pnp is synchronized so this shouldn't need any synchronization.
  5529. */
  5530. RemoveEntryList(&fdoExtension->PrivateFdoData->AllFdosListEntry);
  5531. InitializeListHead(&fdoExtension->PrivateFdoData->AllFdosListEntry);
  5532. DestroyAllTransferPackets(DeviceObject);
  5533. ExFreePool(fdoExtension->PrivateFdoData);
  5534. fdoExtension->PrivateFdoData = NULL;
  5535. }
  5536. if (commonExtension->DeviceName.Buffer) {
  5537. ExFreePool(commonExtension->DeviceName.Buffer);
  5538. RtlInitUnicodeString(&commonExtension->DeviceName, NULL);
  5539. }
  5540. if (fdoExtension->AdapterDescriptor) {
  5541. ExFreePool(fdoExtension->AdapterDescriptor);
  5542. fdoExtension->AdapterDescriptor = NULL;
  5543. }
  5544. if (fdoExtension->DeviceDescriptor) {
  5545. ExFreePool(fdoExtension->DeviceDescriptor);
  5546. fdoExtension->DeviceDescriptor = NULL;
  5547. }
  5548. //
  5549. // Detach our device object from the stack - there's no reason
  5550. // to hold off our cleanup any longer.
  5551. //
  5552. IoDetachDevice(lowerDeviceObject);
  5553. }
  5554. }
  5555. else {
  5556. /*
  5557. * This is a child partition PDO.
  5558. * We have already determined that it was previously marked
  5559. * as missing. So if this is a REMOVE_DEVICE, we will actually
  5560. * delete it.
  5561. */
  5562. if (RemoveType == IRP_MN_REMOVE_DEVICE){
  5563. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = commonExtension->PartitionZeroExtension;
  5564. PPHYSICAL_DEVICE_EXTENSION pdoExtension = (PPHYSICAL_DEVICE_EXTENSION)commonExtension;
  5565. //
  5566. // See if this device is in the child list (if this was a suprise
  5567. // removal it might be) and remove it.
  5568. //
  5569. ClassRemoveChild(fdoExtension, pdoExtension, TRUE);
  5570. }
  5571. }
  5572. commonExtension->PartitionLength.QuadPart = 0;
  5573. if (RemoveType == IRP_MN_REMOVE_DEVICE){
  5574. IoDeleteDevice(DeviceObject);
  5575. }
  5576. }
  5577. return STATUS_SUCCESS;
  5578. } // end ClassRemoveDevice()
  5579. /*++////////////////////////////////////////////////////////////////////////////
  5580. ClassGetDriverExtension()
  5581. Routine Description:
  5582. This routine will return the classpnp's driver extension.
  5583. Arguments:
  5584. DriverObject - the driver object for which to get classpnp's extension
  5585. Return Value:
  5586. Either NULL if none, or a pointer to the driver extension
  5587. --*/
  5588. PCLASS_DRIVER_EXTENSION
  5589. ClassGetDriverExtension(
  5590. IN PDRIVER_OBJECT DriverObject
  5591. )
  5592. {
  5593. return IoGetDriverObjectExtension(DriverObject, CLASS_DRIVER_EXTENSION_KEY);
  5594. } // end ClassGetDriverExtension()
  5595. /*++////////////////////////////////////////////////////////////////////////////
  5596. ClasspStartIo()
  5597. Routine Description:
  5598. This routine wraps the class driver's start io routine. If the device
  5599. is being removed it will complete any requests with
  5600. STATUS_DEVICE_DOES_NOT_EXIST and fire up the next packet.
  5601. Arguments:
  5602. Return Value:
  5603. none
  5604. --*/
  5605. VOID
  5606. ClasspStartIo(
  5607. IN PDEVICE_OBJECT DeviceObject,
  5608. IN PIRP Irp
  5609. )
  5610. {
  5611. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  5612. //
  5613. // We're already holding the remove lock so just check the variable and
  5614. // see what's going on.
  5615. //
  5616. if(commonExtension->IsRemoved) {
  5617. Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
  5618. ClassAcquireRemoveLock(DeviceObject, (PIRP) ClasspStartIo);
  5619. ClassReleaseRemoveLock(DeviceObject, Irp);
  5620. ClassCompleteRequest(DeviceObject, Irp, IO_DISK_INCREMENT);
  5621. IoStartNextPacket(DeviceObject, FALSE);
  5622. ClassReleaseRemoveLock(DeviceObject, (PIRP) ClasspStartIo);
  5623. return;
  5624. }
  5625. commonExtension->DriverExtension->InitData.ClassStartIo(
  5626. DeviceObject,
  5627. Irp);
  5628. return;
  5629. } // ClasspStartIo()
  5630. /*++////////////////////////////////////////////////////////////////////////////
  5631. ClassUpdateInformationInRegistry()
  5632. Routine Description:
  5633. This routine has knowledge about the layout of the device map information
  5634. in the registry. It will update this information to include a value
  5635. entry specifying the dos device name that is assumed to get assigned
  5636. to this NT device name. For more information on this assigning of the
  5637. dos device name look in the drive support routine in the hal that assigns
  5638. all dos names.
  5639. Since some versions of some device's firmware did not work and some
  5640. vendors did not bother to follow the specification, the entire inquiry
  5641. information must also be stored in the registry so than someone can
  5642. figure out the firmware version.
  5643. Arguments:
  5644. DeviceObject - A pointer to the device object for the tape device.
  5645. Return Value:
  5646. None
  5647. --*/
  5648. VOID
  5649. ClassUpdateInformationInRegistry(
  5650. IN PDEVICE_OBJECT Fdo,
  5651. IN PCHAR DeviceName,
  5652. IN ULONG DeviceNumber,
  5653. IN PINQUIRYDATA InquiryData,
  5654. IN ULONG InquiryDataLength
  5655. )
  5656. {
  5657. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  5658. NTSTATUS status;
  5659. SCSI_ADDRESS scsiAddress = {0};
  5660. OBJECT_ATTRIBUTES objectAttributes = {0};
  5661. STRING string;
  5662. UNICODE_STRING unicodeName = {0};
  5663. UNICODE_STRING unicodeRegistryPath = {0};
  5664. UNICODE_STRING unicodeData = {0};
  5665. HANDLE targetKey;
  5666. IO_STATUS_BLOCK ioStatus;
  5667. UCHAR buffer[256] = {0};
  5668. PAGED_CODE();
  5669. ASSERT(DeviceName);
  5670. fdoExtension = Fdo->DeviceExtension;
  5671. targetKey = NULL;
  5672. TRY {
  5673. //
  5674. // Issue GET_ADDRESS Ioctl to determine path, target, and lun information.
  5675. //
  5676. ClassSendDeviceIoControlSynchronous(
  5677. IOCTL_SCSI_GET_ADDRESS,
  5678. Fdo,
  5679. &scsiAddress,
  5680. 0,
  5681. sizeof(SCSI_ADDRESS),
  5682. FALSE,
  5683. &ioStatus
  5684. );
  5685. if (!NT_SUCCESS(ioStatus.Status)) {
  5686. status = ioStatus.Status;
  5687. DebugPrint((1,
  5688. "UpdateInformationInRegistry: Get Address failed %lx\n",
  5689. status));
  5690. LEAVE;
  5691. } else {
  5692. DebugPrint((1,
  5693. "GetAddress: Port %x, Path %x, Target %x, Lun %x\n",
  5694. scsiAddress.PortNumber,
  5695. scsiAddress.PathId,
  5696. scsiAddress.TargetId,
  5697. scsiAddress.Lun));
  5698. }
  5699. _snprintf(buffer,
  5700. sizeof(buffer)-1,
  5701. "\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi\\Scsi Port %d\\Scsi Bus %d\\Target Id %d\\Logical Unit Id %d",
  5702. scsiAddress.PortNumber,
  5703. scsiAddress.PathId,
  5704. scsiAddress.TargetId,
  5705. scsiAddress.Lun);
  5706. RtlInitString(&string, (PUCHAR)buffer);
  5707. status = RtlAnsiStringToUnicodeString(&unicodeRegistryPath,
  5708. &string,
  5709. TRUE);
  5710. if (!NT_SUCCESS(status)) {
  5711. LEAVE;
  5712. }
  5713. //
  5714. // Open the registry key for the scsi information for this
  5715. // scsibus, target, lun.
  5716. //
  5717. InitializeObjectAttributes(&objectAttributes,
  5718. &unicodeRegistryPath,
  5719. OBJ_CASE_INSENSITIVE,
  5720. NULL,
  5721. NULL);
  5722. status = ZwOpenKey(&targetKey,
  5723. KEY_READ | KEY_WRITE,
  5724. &objectAttributes);
  5725. if (!NT_SUCCESS(status)) {
  5726. LEAVE;
  5727. }
  5728. //
  5729. // Now construct and attempt to create the registry value
  5730. // specifying the device name in the appropriate place in the
  5731. // device map.
  5732. //
  5733. RtlInitUnicodeString(&unicodeName, L"DeviceName");
  5734. _snprintf(buffer, sizeof(buffer)-1, "%s%d", DeviceName, DeviceNumber);
  5735. RtlInitString(&string, (PUCHAR)buffer);
  5736. status = RtlAnsiStringToUnicodeString(&unicodeData,
  5737. &string,
  5738. TRUE);
  5739. if (NT_SUCCESS(status)) {
  5740. status = ZwSetValueKey(targetKey,
  5741. &unicodeName,
  5742. 0,
  5743. REG_SZ,
  5744. unicodeData.Buffer,
  5745. unicodeData.Length);
  5746. }
  5747. //
  5748. // if they sent in data, update the registry
  5749. //
  5750. if (InquiryDataLength) {
  5751. ASSERT(InquiryData);
  5752. RtlInitUnicodeString(&unicodeName, L"InquiryData");
  5753. status = ZwSetValueKey(targetKey,
  5754. &unicodeName,
  5755. 0,
  5756. REG_BINARY,
  5757. InquiryData,
  5758. InquiryDataLength);
  5759. }
  5760. // that's all, except to clean up.
  5761. } FINALLY {
  5762. if (unicodeData.Buffer) {
  5763. RtlFreeUnicodeString(&unicodeData);
  5764. }
  5765. if (unicodeRegistryPath.Buffer) {
  5766. RtlFreeUnicodeString(&unicodeRegistryPath);
  5767. }
  5768. if (targetKey) {
  5769. ZwClose(targetKey);
  5770. }
  5771. }
  5772. } // end ClassUpdateInformationInRegistry()
  5773. /*++////////////////////////////////////////////////////////////////////////////
  5774. ClasspSendSynchronousCompletion()
  5775. Routine Description:
  5776. This completion routine will set the user event in the irp after
  5777. freeing the irp and the associated MDL (if any).
  5778. Arguments:
  5779. DeviceObject - the device object which requested the completion routine
  5780. Irp - the irp being completed
  5781. Context - unused
  5782. Return Value:
  5783. STATUS_MORE_PROCESSING_REQUIRED
  5784. --*/
  5785. NTSTATUS
  5786. ClasspSendSynchronousCompletion(
  5787. IN PDEVICE_OBJECT DeviceObject,
  5788. IN PIRP Irp,
  5789. IN PVOID Context
  5790. )
  5791. {
  5792. DebugPrint((3, "ClasspSendSynchronousCompletion: %p %p %p\n",
  5793. DeviceObject, Irp, Context));
  5794. //
  5795. // First set the status and information fields in the io status block
  5796. // provided by the caller.
  5797. //
  5798. *(Irp->UserIosb) = Irp->IoStatus;
  5799. //
  5800. // Unlock the pages for the data buffer.
  5801. //
  5802. if(Irp->MdlAddress) {
  5803. MmUnlockPages(Irp->MdlAddress);
  5804. IoFreeMdl(Irp->MdlAddress);
  5805. }
  5806. //
  5807. // Signal the caller's event.
  5808. //
  5809. KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
  5810. //
  5811. // Free the MDL and the IRP.
  5812. //
  5813. IoFreeIrp(Irp);
  5814. return STATUS_MORE_PROCESSING_REQUIRED;
  5815. } // end ClasspSendSynchronousCompletion()
  5816. /*++
  5817. ISSUE-2000/02/20-henrygab Not documented ClasspRegisterMountedDeviceInterface
  5818. --*/
  5819. VOID
  5820. ClasspRegisterMountedDeviceInterface(
  5821. IN PDEVICE_OBJECT DeviceObject
  5822. )
  5823. {
  5824. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  5825. BOOLEAN isFdo = commonExtension->IsFdo;
  5826. PDEVICE_OBJECT pdo;
  5827. UNICODE_STRING interfaceName;
  5828. NTSTATUS status;
  5829. if(isFdo) {
  5830. PFUNCTIONAL_DEVICE_EXTENSION functionalExtension;
  5831. functionalExtension =
  5832. (PFUNCTIONAL_DEVICE_EXTENSION) commonExtension;
  5833. pdo = functionalExtension->LowerPdo;
  5834. } else {
  5835. pdo = DeviceObject;
  5836. }
  5837. status = IoRegisterDeviceInterface(
  5838. pdo,
  5839. &MOUNTDEV_MOUNTED_DEVICE_GUID,
  5840. NULL,
  5841. &interfaceName
  5842. );
  5843. if(NT_SUCCESS(status)) {
  5844. //
  5845. // Copy the interface name before setting the interface state - the
  5846. // name is needed by the components we notify.
  5847. //
  5848. commonExtension->MountedDeviceInterfaceName = interfaceName;
  5849. status = IoSetDeviceInterfaceState(&interfaceName, TRUE);
  5850. if(!NT_SUCCESS(status)) {
  5851. RtlFreeUnicodeString(&interfaceName);
  5852. }
  5853. }
  5854. if(!NT_SUCCESS(status)) {
  5855. RtlInitUnicodeString(&(commonExtension->MountedDeviceInterfaceName),
  5856. NULL);
  5857. }
  5858. return;
  5859. } // end ClasspRegisterMountedDeviceInterface()
  5860. /*++////////////////////////////////////////////////////////////////////////////
  5861. ClassSendDeviceIoControlSynchronous()
  5862. Routine Description:
  5863. This routine is based upon IoBuildDeviceIoControlRequest(). It has been
  5864. modified to reduce code and memory by not double-buffering the io, using
  5865. the same buffer for both input and output, allocating and deallocating
  5866. the mdl on behalf of the caller, and waiting for the io to complete.
  5867. This routine also works around the rare cases in which APC's are disabled.
  5868. Since IoBuildDeviceIoControl() used APC's to signal completion, this had
  5869. led to a number of difficult-to-detect hangs, where the irp was completed,
  5870. but the event passed to IoBuild..() was still being waited upon by the
  5871. caller.
  5872. Arguments:
  5873. IoControlCode - the IOCTL to send
  5874. TargetDeviceObject - the device object that should handle the ioctl
  5875. Buffer - the input and output buffer, or NULL if no input/output
  5876. InputBufferLength - the number of bytes prepared for the IOCTL in Buffer
  5877. OutputBufferLength - the number of bytes to be filled in upon success
  5878. InternalDeviceIoControl - if TRUE, uses IRP_MJ_INTERNAL_DEVICE_CONTROL
  5879. IoStatus - the status block that contains the results of the operation
  5880. Return Value:
  5881. --*/
  5882. VOID
  5883. ClassSendDeviceIoControlSynchronous(
  5884. IN ULONG IoControlCode,
  5885. IN PDEVICE_OBJECT TargetDeviceObject,
  5886. IN OUT PVOID Buffer OPTIONAL,
  5887. IN ULONG InputBufferLength,
  5888. IN ULONG OutputBufferLength,
  5889. IN BOOLEAN InternalDeviceIoControl,
  5890. OUT PIO_STATUS_BLOCK IoStatus
  5891. )
  5892. {
  5893. PIRP irp;
  5894. PIO_STACK_LOCATION irpSp;
  5895. ULONG method;
  5896. PAGED_CODE();
  5897. irp = NULL;
  5898. method = IoControlCode & 3;
  5899. #if DBG // Begin Argument Checking (nop in fre version)
  5900. ASSERT(ARGUMENT_PRESENT(IoStatus));
  5901. if ((InputBufferLength != 0) || (OutputBufferLength != 0)) {
  5902. ASSERT(ARGUMENT_PRESENT(Buffer));
  5903. }
  5904. else {
  5905. ASSERT(!ARGUMENT_PRESENT(Buffer));
  5906. }
  5907. #endif
  5908. //
  5909. // Begin by allocating the IRP for this request. Do not charge quota to
  5910. // the current process for this IRP.
  5911. //
  5912. irp = IoAllocateIrp(TargetDeviceObject->StackSize, FALSE);
  5913. if (!irp) {
  5914. IoStatus->Information = 0;
  5915. IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
  5916. return;
  5917. }
  5918. //
  5919. // Get a pointer to the stack location of the first driver which will be
  5920. // invoked. This is where the function codes and the parameters are set.
  5921. //
  5922. irpSp = IoGetNextIrpStackLocation(irp);
  5923. //
  5924. // Set the major function code based on the type of device I/O control
  5925. // function the caller has specified.
  5926. //
  5927. if (InternalDeviceIoControl) {
  5928. irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  5929. } else {
  5930. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  5931. }
  5932. //
  5933. // Copy the caller's parameters to the service-specific portion of the
  5934. // IRP for those parameters that are the same for all four methods.
  5935. //
  5936. irpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength;
  5937. irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength;
  5938. irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode;
  5939. //
  5940. // Get the method bits from the I/O control code to determine how the
  5941. // buffers are to be passed to the driver.
  5942. //
  5943. switch (method)
  5944. {
  5945. //
  5946. // case 0
  5947. //
  5948. case METHOD_BUFFERED:
  5949. {
  5950. if ((InputBufferLength != 0) || (OutputBufferLength != 0))
  5951. {
  5952. irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  5953. max(InputBufferLength, OutputBufferLength),
  5954. CLASS_TAG_DEVICE_CONTROL);
  5955. if (irp->AssociatedIrp.SystemBuffer == NULL)
  5956. {
  5957. IoFreeIrp(irp);
  5958. IoStatus->Information = 0;
  5959. IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
  5960. return;
  5961. }
  5962. if (InputBufferLength != 0)
  5963. {
  5964. RtlCopyMemory(irp->AssociatedIrp.SystemBuffer, Buffer, InputBufferLength);
  5965. }
  5966. }
  5967. irp->UserBuffer = Buffer;
  5968. break;
  5969. }
  5970. //
  5971. // case 1, case 2
  5972. //
  5973. case METHOD_IN_DIRECT:
  5974. case METHOD_OUT_DIRECT:
  5975. {
  5976. if (InputBufferLength != 0)
  5977. {
  5978. irp->AssociatedIrp.SystemBuffer = Buffer;
  5979. }
  5980. if (OutputBufferLength != 0)
  5981. {
  5982. irp->MdlAddress = IoAllocateMdl(Buffer,
  5983. OutputBufferLength,
  5984. FALSE,
  5985. FALSE,
  5986. (PIRP) NULL);
  5987. if (irp->MdlAddress == NULL)
  5988. {
  5989. IoFreeIrp(irp);
  5990. IoStatus->Information = 0;
  5991. IoStatus->Status = STATUS_INSUFFICIENT_RESOURCES;
  5992. return;
  5993. }
  5994. try
  5995. {
  5996. MmProbeAndLockPages(irp->MdlAddress,
  5997. KernelMode,
  5998. (method == METHOD_IN_DIRECT) ? IoReadAccess : IoWriteAccess);
  5999. }
  6000. except(EXCEPTION_EXECUTE_HANDLER)
  6001. {
  6002. IoFreeMdl(irp->MdlAddress);
  6003. IoFreeIrp(irp);
  6004. IoStatus->Information = 0;
  6005. IoStatus->Status = GetExceptionCode();
  6006. return;
  6007. }
  6008. }
  6009. break;
  6010. }
  6011. //
  6012. // case 3
  6013. //
  6014. case METHOD_NEITHER:
  6015. {
  6016. ASSERT(!"ClassSendDeviceIoControlSynchronous does not support METHOD_NEITHER Ioctls");
  6017. IoFreeIrp(irp);
  6018. IoStatus->Information = 0;
  6019. IoStatus->Status = STATUS_NOT_SUPPORTED;
  6020. return;
  6021. }
  6022. }
  6023. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  6024. //
  6025. // send the irp synchronously
  6026. //
  6027. ClassSendIrpSynchronous(TargetDeviceObject, irp);
  6028. //
  6029. // copy the iostatus block for the caller
  6030. //
  6031. *IoStatus = irp->IoStatus;
  6032. //
  6033. // free any allocated resources
  6034. //
  6035. switch (method) {
  6036. case METHOD_BUFFERED: {
  6037. ASSERT(irp->UserBuffer == Buffer);
  6038. //
  6039. // first copy the buffered result, if any
  6040. // Note that there are no security implications in
  6041. // not checking for success since only drivers can
  6042. // call into this routine anyways...
  6043. //
  6044. if (OutputBufferLength != 0) {
  6045. RtlCopyMemory(Buffer, // irp->UserBuffer
  6046. irp->AssociatedIrp.SystemBuffer,
  6047. OutputBufferLength
  6048. );
  6049. }
  6050. //
  6051. // then free the memory allocated to buffer the io
  6052. //
  6053. if ((InputBufferLength !=0) || (OutputBufferLength != 0)) {
  6054. ExFreePool(irp->AssociatedIrp.SystemBuffer);
  6055. irp->AssociatedIrp.SystemBuffer = NULL;
  6056. }
  6057. break;
  6058. }
  6059. case METHOD_IN_DIRECT:
  6060. case METHOD_OUT_DIRECT: {
  6061. //
  6062. // we alloc a mdl if there is an output buffer specified
  6063. // free it here after unlocking the pages
  6064. //
  6065. if (OutputBufferLength != 0) {
  6066. ASSERT(irp->MdlAddress != NULL);
  6067. MmUnlockPages(irp->MdlAddress);
  6068. IoFreeMdl(irp->MdlAddress);
  6069. irp->MdlAddress = (PMDL) NULL;
  6070. }
  6071. break;
  6072. }
  6073. case METHOD_NEITHER: {
  6074. ASSERT(!"Code is out of date");
  6075. break;
  6076. }
  6077. }
  6078. //
  6079. // we always have allocated an irp. free it here.
  6080. //
  6081. IoFreeIrp(irp);
  6082. irp = (PIRP) NULL;
  6083. //
  6084. // return the io status block's status to the caller
  6085. //
  6086. return;
  6087. } // end ClassSendDeviceIoControlSynchronous()
  6088. /*++////////////////////////////////////////////////////////////////////////////
  6089. ClassForwardIrpSynchronous()
  6090. Routine Description:
  6091. Forwards a given irp to the next lower device object.
  6092. Arguments:
  6093. CommonExtension - the common class extension
  6094. Irp - the request to forward down the stack
  6095. Return Value:
  6096. --*/
  6097. NTSTATUS
  6098. ClassForwardIrpSynchronous(
  6099. IN PCOMMON_DEVICE_EXTENSION CommonExtension,
  6100. IN PIRP Irp
  6101. )
  6102. {
  6103. IoCopyCurrentIrpStackLocationToNext(Irp);
  6104. return ClassSendIrpSynchronous(CommonExtension->LowerDeviceObject, Irp);
  6105. } // end ClassForwardIrpSynchronous()
  6106. /*++////////////////////////////////////////////////////////////////////////////
  6107. ClassSendIrpSynchronous()
  6108. Routine Description:
  6109. This routine sends the given irp to the given device object, and waits for
  6110. it to complete. On debug versions, will print out a debug message and
  6111. optionally assert for "lost" irps based upon classpnp's globals
  6112. Arguments:
  6113. TargetDeviceObject - the device object to handle this irp
  6114. Irp - the request to be sent
  6115. Return Value:
  6116. --*/
  6117. NTSTATUS
  6118. ClassSendIrpSynchronous(
  6119. IN PDEVICE_OBJECT TargetDeviceObject,
  6120. IN PIRP Irp
  6121. )
  6122. {
  6123. KEVENT event;
  6124. NTSTATUS status;
  6125. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  6126. ASSERT(TargetDeviceObject != NULL);
  6127. ASSERT(Irp != NULL);
  6128. ASSERT(Irp->StackCount >= TargetDeviceObject->StackSize);
  6129. //
  6130. // ISSUE-2000/02/20-henrygab What if APCs are disabled?
  6131. // May need to enter critical section before IoCallDriver()
  6132. // until the event is hit?
  6133. //
  6134. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  6135. IoSetCompletionRoutine(Irp, ClassSignalCompletion, &event,
  6136. TRUE, TRUE, TRUE);
  6137. status = IoCallDriver(TargetDeviceObject, Irp);
  6138. if (status == STATUS_PENDING) {
  6139. #if DBG
  6140. LARGE_INTEGER timeout;
  6141. timeout.QuadPart = (LONGLONG)(-1 * 10 * 1000 * (LONGLONG)1000 *
  6142. ClasspnpGlobals.SecondsToWaitForIrps);
  6143. do {
  6144. status = KeWaitForSingleObject(&event,
  6145. Executive,
  6146. KernelMode,
  6147. FALSE,
  6148. &timeout);
  6149. if (status == STATUS_TIMEOUT) {
  6150. //
  6151. // This DebugPrint should almost always be investigated by the
  6152. // party who sent the irp and/or the current owner of the irp.
  6153. // Synchronous Irps should not take this long (currently 30
  6154. // seconds) without good reason. This points to a potentially
  6155. // serious problem in the underlying device stack.
  6156. //
  6157. DebugPrint((0, "ClassSendIrpSynchronous: (%p) irp %p did not "
  6158. "complete within %x seconds\n",
  6159. TargetDeviceObject, Irp,
  6160. ClasspnpGlobals.SecondsToWaitForIrps
  6161. ));
  6162. if (ClasspnpGlobals.BreakOnLostIrps != 0) {
  6163. ASSERT(!" - Irp failed to complete within 30 seconds - ");
  6164. }
  6165. }
  6166. } while (status==STATUS_TIMEOUT);
  6167. #else
  6168. KeWaitForSingleObject(&event,
  6169. Executive,
  6170. KernelMode,
  6171. FALSE,
  6172. NULL);
  6173. #endif
  6174. status = Irp->IoStatus.Status;
  6175. }
  6176. return status;
  6177. } // end ClassSendIrpSynchronous()
  6178. /*++////////////////////////////////////////////////////////////////////////////
  6179. ClassGetVpb()
  6180. Routine Description:
  6181. This routine returns the current VPB (Volume Parameter Block) for the
  6182. given device object.
  6183. The Vpb field is only visible in the ntddk.h (not the wdm.h) definition
  6184. of DEVICE_OBJECT; hence this exported function.
  6185. Arguments:
  6186. DeviceObject - the device to get the VPB for
  6187. Return Value:
  6188. the VPB, or NULL if none.
  6189. --*/
  6190. PVPB
  6191. ClassGetVpb(
  6192. IN PDEVICE_OBJECT DeviceObject
  6193. )
  6194. {
  6195. return DeviceObject->Vpb;
  6196. } // end ClassGetVpb()
  6197. /*++
  6198. ISSUE-2000/02/20-henrygab Not documented ClasspAllocateReleaseRequest
  6199. --*/
  6200. NTSTATUS
  6201. ClasspAllocateReleaseRequest(
  6202. IN PDEVICE_OBJECT Fdo
  6203. )
  6204. {
  6205. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  6206. PIO_STACK_LOCATION irpStack;
  6207. KeInitializeSpinLock(&(fdoExtension->ReleaseQueueSpinLock));
  6208. fdoExtension->ReleaseQueueNeeded = FALSE;
  6209. fdoExtension->ReleaseQueueInProgress = FALSE;
  6210. fdoExtension->ReleaseQueueIrpFromPool = FALSE;
  6211. //
  6212. // The class driver is responsible for allocating a properly sized irp,
  6213. // or ClassReleaseQueue will attempt to do it on the first error.
  6214. //
  6215. fdoExtension->ReleaseQueueIrp = NULL;
  6216. //
  6217. // Write length to SRB.
  6218. //
  6219. fdoExtension->ReleaseQueueSrb.Length = sizeof(SCSI_REQUEST_BLOCK);
  6220. return STATUS_SUCCESS;
  6221. } // end ClasspAllocateReleaseRequest()
  6222. /*++
  6223. ISSUE-2000/02/20-henrygab Not documented ClasspFreeReleaseRequest
  6224. --*/
  6225. VOID
  6226. ClasspFreeReleaseRequest(
  6227. IN PDEVICE_OBJECT Fdo
  6228. )
  6229. {
  6230. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  6231. //KIRQL oldIrql;
  6232. ASSERT(fdoExtension->CommonExtension.IsRemoved != NO_REMOVE);
  6233. //
  6234. // free anything the driver allocated
  6235. //
  6236. if (fdoExtension->ReleaseQueueIrp) {
  6237. if (fdoExtension->ReleaseQueueIrpFromPool) {
  6238. ExFreePool(fdoExtension->ReleaseQueueIrp);
  6239. } else {
  6240. IoFreeIrp(fdoExtension->ReleaseQueueIrp);
  6241. }
  6242. fdoExtension->ReleaseQueueIrp = NULL;
  6243. }
  6244. //
  6245. // free anything that we allocated
  6246. //
  6247. if ((fdoExtension->PrivateFdoData) &&
  6248. (fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated)) {
  6249. ExFreePool(fdoExtension->PrivateFdoData->ReleaseQueueIrp);
  6250. fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated = FALSE;
  6251. fdoExtension->PrivateFdoData->ReleaseQueueIrp = NULL;
  6252. }
  6253. return;
  6254. } // end ClasspFreeReleaseRequest()
  6255. /*++////////////////////////////////////////////////////////////////////////////
  6256. ClassReleaseQueue()
  6257. Routine Description:
  6258. This routine issues an internal device control command
  6259. to the port driver to release a frozen queue. The call
  6260. is issued asynchronously as ClassReleaseQueue will be invoked
  6261. from the IO completion DPC (and will have no context to
  6262. wait for a synchronous call to complete).
  6263. This routine must be called with the remove lock held.
  6264. Arguments:
  6265. Fdo - The functional device object for the device with the frozen queue.
  6266. Return Value:
  6267. None.
  6268. --*/
  6269. VOID
  6270. ClassReleaseQueue(
  6271. IN PDEVICE_OBJECT Fdo
  6272. )
  6273. {
  6274. ClasspReleaseQueue(Fdo, NULL);
  6275. return;
  6276. } // end ClassReleaseQueue()
  6277. /*++////////////////////////////////////////////////////////////////////////////
  6278. ClasspAllocateReleaseQueueIrp()
  6279. Routine Description:
  6280. This routine allocates the release queue irp held in classpnp's private
  6281. extension. This was added to allow no-memory conditions to be more
  6282. survivable.
  6283. Return Value:
  6284. NT_SUCCESS value.
  6285. Notes:
  6286. Does not grab the spinlock. Should only be called from StartDevice()
  6287. routine. May be called elsewhere for poorly-behaved drivers that cause
  6288. the queue to lockup before the device is started. This should *never*
  6289. occur, since it's illegal to send a request to a non-started PDO. This
  6290. condition is checked for in ClasspReleaseQueue().
  6291. --*/
  6292. NTSTATUS
  6293. ClasspAllocateReleaseQueueIrp(
  6294. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  6295. )
  6296. {
  6297. KIRQL oldIrql;
  6298. UCHAR lowerStackSize;
  6299. //
  6300. // do an initial check w/o the spinlock
  6301. //
  6302. if (FdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) {
  6303. return STATUS_SUCCESS;
  6304. }
  6305. lowerStackSize = FdoExtension->CommonExtension.LowerDeviceObject->StackSize;
  6306. //
  6307. // don't allocate one if one is in progress! this means whoever called
  6308. // this routine didn't check if one was in progress.
  6309. //
  6310. ASSERT(!(FdoExtension->ReleaseQueueInProgress));
  6311. FdoExtension->PrivateFdoData->ReleaseQueueIrp =
  6312. ExAllocatePoolWithTag(NonPagedPool,
  6313. IoSizeOfIrp(lowerStackSize),
  6314. CLASS_TAG_RELEASE_QUEUE
  6315. );
  6316. if (FdoExtension->PrivateFdoData->ReleaseQueueIrp == NULL) {
  6317. DebugPrint((0, "ClassPnpStartDevice: Cannot allocate for "
  6318. "release queue irp\n"));
  6319. return STATUS_INSUFFICIENT_RESOURCES;
  6320. }
  6321. IoInitializeIrp(FdoExtension->PrivateFdoData->ReleaseQueueIrp,
  6322. IoSizeOfIrp(lowerStackSize),
  6323. lowerStackSize);
  6324. FdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated = TRUE;
  6325. return STATUS_SUCCESS;
  6326. }
  6327. /*++////////////////////////////////////////////////////////////////////////////
  6328. ClasspReleaseQueue()
  6329. Routine Description:
  6330. This routine issues an internal device control command
  6331. to the port driver to release a frozen queue. The call
  6332. is issued asynchronously as ClassReleaseQueue will be invoked
  6333. from the IO completion DPC (and will have no context to
  6334. wait for a synchronous call to complete).
  6335. This routine must be called with the remove lock held.
  6336. Arguments:
  6337. Fdo - The functional device object for the device with the frozen queue.
  6338. ReleaseQueueIrp - If this irp is supplied then the test to determine whether
  6339. a release queue request is in progress will be ignored.
  6340. The irp provided must be the IRP originally allocated
  6341. for release queue requests (so this parameter can only
  6342. really be provided by the release queue completion
  6343. routine.)
  6344. Return Value:
  6345. None.
  6346. --*/
  6347. VOID
  6348. ClasspReleaseQueue(
  6349. IN PDEVICE_OBJECT Fdo,
  6350. IN PIRP ReleaseQueueIrp OPTIONAL
  6351. )
  6352. {
  6353. PIO_STACK_LOCATION irpStack;
  6354. PIRP irp;
  6355. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  6356. PDEVICE_OBJECT lowerDevice;
  6357. PSCSI_REQUEST_BLOCK srb;
  6358. KIRQL currentIrql;
  6359. lowerDevice = fdoExtension->CommonExtension.LowerDeviceObject;
  6360. //
  6361. // we raise irql seperately so we're not swapped out or suspended
  6362. // while holding the release queue irp in this routine. this lets
  6363. // us release the spin lock before lowering irql.
  6364. //
  6365. KeRaiseIrql(DISPATCH_LEVEL, &currentIrql);
  6366. KeAcquireSpinLockAtDpcLevel(&(fdoExtension->ReleaseQueueSpinLock));
  6367. //
  6368. // make sure that if they passed us an irp, it matches our allocated irp.
  6369. //
  6370. ASSERT((ReleaseQueueIrp == NULL) ||
  6371. (ReleaseQueueIrp == fdoExtension->PrivateFdoData->ReleaseQueueIrp));
  6372. //
  6373. // ASSERT that we've already allocated this. (should not occur)
  6374. // try to allocate it anyways, then finally bugcheck if
  6375. // there's still no memory...
  6376. //
  6377. ASSERT(fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated);
  6378. if (!fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) {
  6379. ClasspAllocateReleaseQueueIrp(fdoExtension);
  6380. }
  6381. if (!fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) {
  6382. KeBugCheckEx(SCSI_DISK_DRIVER_INTERNAL, 0x12, (ULONG_PTR)Fdo, 0x0, 0x0);
  6383. }
  6384. if ((fdoExtension->ReleaseQueueInProgress) && (ReleaseQueueIrp == NULL)) {
  6385. //
  6386. // Someone is already using the irp - just set the flag to indicate that
  6387. // we need to release the queue again.
  6388. //
  6389. fdoExtension->ReleaseQueueNeeded = TRUE;
  6390. KeReleaseSpinLockFromDpcLevel(&(fdoExtension->ReleaseQueueSpinLock));
  6391. KeLowerIrql(currentIrql);
  6392. return;
  6393. }
  6394. //
  6395. // Mark that there is a release queue in progress and drop the spinlock.
  6396. //
  6397. fdoExtension->ReleaseQueueInProgress = TRUE;
  6398. if (ReleaseQueueIrp) {
  6399. irp = ReleaseQueueIrp;
  6400. } else {
  6401. irp = fdoExtension->PrivateFdoData->ReleaseQueueIrp;
  6402. }
  6403. srb = &(fdoExtension->ReleaseQueueSrb);
  6404. KeReleaseSpinLockFromDpcLevel(&(fdoExtension->ReleaseQueueSpinLock));
  6405. ASSERT(irp != NULL);
  6406. irpStack = IoGetNextIrpStackLocation(irp);
  6407. irpStack->MajorFunction = IRP_MJ_SCSI;
  6408. srb->OriginalRequest = irp;
  6409. //
  6410. // Store the SRB address in next stack for port driver.
  6411. //
  6412. irpStack->Parameters.Scsi.Srb = srb;
  6413. //
  6414. // If this device is removable then flush the queue. This will also
  6415. // release it.
  6416. //
  6417. if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){
  6418. srb->Function = SRB_FUNCTION_FLUSH_QUEUE;
  6419. }
  6420. else {
  6421. srb->Function = SRB_FUNCTION_RELEASE_QUEUE;
  6422. }
  6423. ClassAcquireRemoveLock(Fdo, irp);
  6424. IoSetCompletionRoutine(irp,
  6425. ClassReleaseQueueCompletion,
  6426. Fdo,
  6427. TRUE,
  6428. TRUE,
  6429. TRUE);
  6430. IoCallDriver(lowerDevice, irp);
  6431. KeLowerIrql(currentIrql);
  6432. return;
  6433. } // end ClassReleaseQueue()
  6434. /*++////////////////////////////////////////////////////////////////////////////
  6435. ClassReleaseQueueCompletion()
  6436. Routine Description:
  6437. This routine is called when an asynchronous I/O request
  6438. which was issused by the class driver completes. Examples of such requests
  6439. are release queue or START UNIT. This routine releases the queue if
  6440. necessary. It then frees the context and the IRP.
  6441. Arguments:
  6442. DeviceObject - The device object for the logical unit; however since this
  6443. is the top stack location the value is NULL.
  6444. Irp - Supplies a pointer to the Irp to be processed.
  6445. Context - Supplies the context to be used to process this request.
  6446. Return Value:
  6447. None.
  6448. --*/
  6449. NTSTATUS
  6450. ClassReleaseQueueCompletion(
  6451. PDEVICE_OBJECT DeviceObject,
  6452. PIRP Irp,
  6453. PVOID Context
  6454. )
  6455. {
  6456. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  6457. KIRQL oldIrql;
  6458. BOOLEAN releaseQueueNeeded;
  6459. DeviceObject = Context;
  6460. fdoExtension = DeviceObject->DeviceExtension;
  6461. ClassReleaseRemoveLock(DeviceObject, Irp);
  6462. //
  6463. // Grab the spinlock and clear the release queue in progress flag so others
  6464. // can run. Save (and clear) the state of the release queue needed flag
  6465. // so that we can issue a new release queue outside the spinlock.
  6466. //
  6467. KeAcquireSpinLock(&(fdoExtension->ReleaseQueueSpinLock), &oldIrql);
  6468. releaseQueueNeeded = fdoExtension->ReleaseQueueNeeded;
  6469. fdoExtension->ReleaseQueueNeeded = FALSE;
  6470. fdoExtension->ReleaseQueueInProgress = FALSE;
  6471. KeReleaseSpinLock(&(fdoExtension->ReleaseQueueSpinLock), oldIrql);
  6472. //
  6473. // If we need a release queue then issue one now. Another processor may
  6474. // have already started one in which case we'll try to issue this one after
  6475. // it is done - but we should never recurse more than one deep.
  6476. //
  6477. if(releaseQueueNeeded) {
  6478. ClasspReleaseQueue(DeviceObject, Irp);
  6479. }
  6480. //
  6481. // Indicate the I/O system should stop processing the Irp completion.
  6482. //
  6483. return STATUS_MORE_PROCESSING_REQUIRED;
  6484. } // ClassAsynchronousCompletion()
  6485. /*++////////////////////////////////////////////////////////////////////////////
  6486. ClassAcquireChildLock()
  6487. Routine Description:
  6488. This routine acquires the lock protecting children PDOs. It may be
  6489. acquired recursively by the same thread, but must be release by the
  6490. thread once for each acquisition.
  6491. Arguments:
  6492. FdoExtension - the device whose child list is protected.
  6493. Return Value:
  6494. None
  6495. --*/
  6496. VOID
  6497. ClassAcquireChildLock(
  6498. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  6499. )
  6500. {
  6501. PAGED_CODE();
  6502. if(FdoExtension->ChildLockOwner != KeGetCurrentThread()) {
  6503. KeWaitForSingleObject(&FdoExtension->ChildLock,
  6504. Executive, KernelMode,
  6505. FALSE, NULL);
  6506. ASSERT(FdoExtension->ChildLockOwner == NULL);
  6507. ASSERT(FdoExtension->ChildLockAcquisitionCount == 0);
  6508. FdoExtension->ChildLockOwner = KeGetCurrentThread();
  6509. } else {
  6510. ASSERT(FdoExtension->ChildLockAcquisitionCount != 0);
  6511. }
  6512. FdoExtension->ChildLockAcquisitionCount++;
  6513. return;
  6514. }
  6515. /*++////////////////////////////////////////////////////////////////////////////
  6516. ClassReleaseChildLock() ISSUE-2000/02/18-henrygab - not documented
  6517. Routine Description:
  6518. This routine releases the lock protecting children PDOs. It must be
  6519. called once for each time ClassAcquireChildLock was called.
  6520. Arguments:
  6521. FdoExtension - the device whose child list is protected
  6522. Return Value:
  6523. None.
  6524. --*/
  6525. VOID
  6526. ClassReleaseChildLock(
  6527. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  6528. )
  6529. {
  6530. ASSERT(FdoExtension->ChildLockOwner == KeGetCurrentThread());
  6531. ASSERT(FdoExtension->ChildLockAcquisitionCount != 0);
  6532. FdoExtension->ChildLockAcquisitionCount -= 1;
  6533. if(FdoExtension->ChildLockAcquisitionCount == 0) {
  6534. FdoExtension->ChildLockOwner = NULL;
  6535. KeSetEvent(&FdoExtension->ChildLock, IO_NO_INCREMENT, FALSE);
  6536. }
  6537. return;
  6538. } // end ClassReleaseChildLock(
  6539. /*++////////////////////////////////////////////////////////////////////////////
  6540. ClassAddChild()
  6541. Routine Description:
  6542. This routine will insert a new child into the head of the child list.
  6543. Arguments:
  6544. Parent - the child's parent (contains the head of the list)
  6545. Child - the child to be inserted.
  6546. AcquireLock - whether the child lock should be acquired (TRUE) or whether
  6547. it's already been acquired by or on behalf of the caller
  6548. (FALSE).
  6549. Return Value:
  6550. None.
  6551. --*/
  6552. VOID
  6553. ClassAddChild(
  6554. IN PFUNCTIONAL_DEVICE_EXTENSION Parent,
  6555. IN PPHYSICAL_DEVICE_EXTENSION Child,
  6556. IN BOOLEAN AcquireLock
  6557. )
  6558. {
  6559. if(AcquireLock) {
  6560. ClassAcquireChildLock(Parent);
  6561. }
  6562. #if DBG
  6563. //
  6564. // Make sure this child's not already in the list.
  6565. //
  6566. {
  6567. PPHYSICAL_DEVICE_EXTENSION testChild;
  6568. for (testChild = Parent->CommonExtension.ChildList;
  6569. testChild != NULL;
  6570. testChild = testChild->CommonExtension.ChildList) {
  6571. ASSERT(testChild != Child);
  6572. }
  6573. }
  6574. #endif
  6575. Child->CommonExtension.ChildList = Parent->CommonExtension.ChildList;
  6576. Parent->CommonExtension.ChildList = Child;
  6577. if(AcquireLock) {
  6578. ClassReleaseChildLock(Parent);
  6579. }
  6580. return;
  6581. } // end ClassAddChild()
  6582. /*++////////////////////////////////////////////////////////////////////////////
  6583. ClassRemoveChild()
  6584. Routine Description:
  6585. This routine will remove a child from the child list.
  6586. Arguments:
  6587. Parent - the parent to be removed from.
  6588. Child - the child to be removed or NULL if the first child should be
  6589. removed.
  6590. AcquireLock - whether the child lock should be acquired (TRUE) or whether
  6591. it's already been acquired by or on behalf of the caller
  6592. (FALSE).
  6593. Return Value:
  6594. A pointer to the child which was removed or NULL if no such child could
  6595. be found in the list (or if Child was NULL but the list is empty).
  6596. --*/
  6597. PPHYSICAL_DEVICE_EXTENSION
  6598. ClassRemoveChild(
  6599. IN PFUNCTIONAL_DEVICE_EXTENSION Parent,
  6600. IN PPHYSICAL_DEVICE_EXTENSION Child,
  6601. IN BOOLEAN AcquireLock
  6602. )
  6603. {
  6604. if(AcquireLock) {
  6605. ClassAcquireChildLock(Parent);
  6606. }
  6607. TRY {
  6608. PCOMMON_DEVICE_EXTENSION previousChild = &Parent->CommonExtension;
  6609. //
  6610. // If the list is empty then bail out now.
  6611. //
  6612. if(Parent->CommonExtension.ChildList == NULL) {
  6613. Child = NULL;
  6614. LEAVE;
  6615. }
  6616. //
  6617. // If the caller specified a child then find the child object before
  6618. // it. If none was specified then the FDO is the child object before
  6619. // the one we want to remove.
  6620. //
  6621. if(Child != NULL) {
  6622. //
  6623. // Scan through the child list to find the entry which points to
  6624. // this one.
  6625. //
  6626. do {
  6627. ASSERT(previousChild != &Child->CommonExtension);
  6628. if(previousChild->ChildList == Child) {
  6629. break;
  6630. }
  6631. previousChild = &previousChild->ChildList->CommonExtension;
  6632. } while(previousChild != NULL);
  6633. if(previousChild == NULL) {
  6634. Child = NULL;
  6635. LEAVE;
  6636. }
  6637. }
  6638. //
  6639. // Save the next child away then unlink it from the list.
  6640. //
  6641. Child = previousChild->ChildList;
  6642. previousChild->ChildList = Child->CommonExtension.ChildList;
  6643. Child->CommonExtension.ChildList = NULL;
  6644. } FINALLY {
  6645. if(AcquireLock) {
  6646. ClassReleaseChildLock(Parent);
  6647. }
  6648. }
  6649. return Child;
  6650. } // end ClassRemoveChild()
  6651. /*++
  6652. ISSUE-2000/02/20-henrygab Not documented ClasspRetryRequestDpc
  6653. --*/
  6654. VOID
  6655. ClasspRetryRequestDpc(
  6656. IN PKDPC Dpc,
  6657. IN PDEVICE_OBJECT DeviceObject,
  6658. IN PVOID Arg1,
  6659. IN PVOID Arg2
  6660. )
  6661. {
  6662. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  6663. PCOMMON_DEVICE_EXTENSION commonExtension;
  6664. PCLASS_PRIVATE_FDO_DATA fdoData;
  6665. PCLASS_RETRY_INFO retryList;
  6666. KIRQL irql;
  6667. commonExtension = DeviceObject->DeviceExtension;
  6668. ASSERT(commonExtension->IsFdo);
  6669. fdoExtension = DeviceObject->DeviceExtension;
  6670. fdoData = fdoExtension->PrivateFdoData;
  6671. KeAcquireSpinLock(&fdoData->Retry.Lock, &irql);
  6672. {
  6673. LARGE_INTEGER now;
  6674. KeQueryTickCount(&now);
  6675. //
  6676. // if CurrentTick is less than now
  6677. // fire another DPC
  6678. // else
  6679. // retry entire list
  6680. // endif
  6681. //
  6682. if (now.QuadPart < fdoData->Retry.Tick.QuadPart) {
  6683. ClasspRetryDpcTimer(fdoData);
  6684. retryList = NULL;
  6685. } else {
  6686. retryList = fdoData->Retry.ListHead;
  6687. fdoData->Retry.ListHead = NULL;
  6688. fdoData->Retry.Delta.QuadPart = (LONGLONG)0;
  6689. fdoData->Retry.Tick.QuadPart = (LONGLONG)0;
  6690. }
  6691. }
  6692. KeReleaseSpinLock(&fdoData->Retry.Lock, irql);
  6693. while (retryList != NULL) {
  6694. PIRP irp;
  6695. irp = CONTAINING_RECORD(retryList, IRP, Tail.Overlay.DriverContext[0]);
  6696. DebugPrint((ClassDebugDelayedRetry, "ClassRetry: -- %p\n", irp));
  6697. retryList = retryList->Next;
  6698. #if DBG
  6699. irp->Tail.Overlay.DriverContext[0] = ULongToPtr(0xdddddddd); // invalidate data
  6700. irp->Tail.Overlay.DriverContext[1] = ULongToPtr(0xdddddddd); // invalidate data
  6701. irp->Tail.Overlay.DriverContext[2] = ULongToPtr(0xdddddddd); // invalidate data
  6702. irp->Tail.Overlay.DriverContext[3] = ULongToPtr(0xdddddddd); // invalidate data
  6703. #endif
  6704. IoCallDriver(commonExtension->LowerDeviceObject, irp);
  6705. }
  6706. return;
  6707. } // end ClasspRetryRequestDpc()
  6708. /*++
  6709. ISSUE-2000/02/20-henrygab Not documented ClassRetryRequest
  6710. --*/
  6711. VOID
  6712. ClassRetryRequest(
  6713. IN PDEVICE_OBJECT SelfDeviceObject,
  6714. IN PIRP Irp,
  6715. IN LARGE_INTEGER TimeDelta100ns // in 100ns units
  6716. )
  6717. {
  6718. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  6719. PCLASS_PRIVATE_FDO_DATA fdoData;
  6720. PCLASS_RETRY_INFO retryInfo;
  6721. PCLASS_RETRY_INFO *previousNext;
  6722. LARGE_INTEGER delta;
  6723. KIRQL irql;
  6724. //
  6725. // this checks we aren't destroying irps
  6726. //
  6727. ASSERT(sizeof(CLASS_RETRY_INFO) <= (4*sizeof(PVOID)));
  6728. fdoExtension = SelfDeviceObject->DeviceExtension;
  6729. fdoData = fdoExtension->PrivateFdoData;
  6730. if (!fdoExtension->CommonExtension.IsFdo) {
  6731. //
  6732. // this debug print/assertion should ALWAYS be investigated.
  6733. // ClassRetryRequest can currently only be used by FDO's
  6734. //
  6735. DebugPrint((ClassDebugError, "ClassRetryRequestEx: LOST IRP %p\n", Irp));
  6736. ASSERT(!"ClassRetryRequestEx Called From PDO? LOST IRP");
  6737. return;
  6738. }
  6739. if (TimeDelta100ns.QuadPart < 0) {
  6740. ASSERT(!"ClassRetryRequest - must use positive delay");
  6741. TimeDelta100ns.QuadPart *= -1;
  6742. }
  6743. /*
  6744. * We are going to queue the irp and send it down in a timer DPC.
  6745. * This means that we may be causing the irp to complete on a different thread than the issuing thread.
  6746. * So mark the irp pending.
  6747. */
  6748. IoMarkIrpPending(Irp);
  6749. //
  6750. // prepare what we can out of the loop
  6751. //
  6752. retryInfo = (PCLASS_RETRY_INFO)(&Irp->Tail.Overlay.DriverContext[0]);
  6753. RtlZeroMemory(retryInfo, sizeof(CLASS_RETRY_INFO));
  6754. delta.QuadPart = (TimeDelta100ns.QuadPart / fdoData->Retry.Granularity);
  6755. if (TimeDelta100ns.QuadPart % fdoData->Retry.Granularity) {
  6756. delta.QuadPart ++; // round up to next tick
  6757. }
  6758. if (delta.QuadPart == (LONGLONG)0) {
  6759. delta.QuadPart = MINIMUM_RETRY_UNITS;
  6760. }
  6761. //
  6762. // now determine if we should fire another DPC or not
  6763. //
  6764. KeAcquireSpinLock(&fdoData->Retry.Lock, &irql);
  6765. //
  6766. // always add request to the list
  6767. //
  6768. retryInfo->Next = fdoData->Retry.ListHead;
  6769. fdoData->Retry.ListHead = retryInfo;
  6770. if (fdoData->Retry.Delta.QuadPart == (LONGLONG)0) {
  6771. DebugPrint((ClassDebugDelayedRetry, "ClassRetry: +++ %p\n", Irp));
  6772. //
  6773. // must be exactly one item on list
  6774. //
  6775. ASSERT(fdoData->Retry.ListHead != NULL);
  6776. ASSERT(fdoData->Retry.ListHead->Next == NULL);
  6777. //
  6778. // if currentDelta is zero, always fire a DPC
  6779. //
  6780. KeQueryTickCount(&fdoData->Retry.Tick);
  6781. fdoData->Retry.Tick.QuadPart += delta.QuadPart;
  6782. fdoData->Retry.Delta.QuadPart = delta.QuadPart;
  6783. ClasspRetryDpcTimer(fdoData);
  6784. } else if (delta.QuadPart > fdoData->Retry.Delta.QuadPart) {
  6785. //
  6786. // if delta is greater than the list's current delta,
  6787. // increase the DPC handling time by difference
  6788. // and update the delta to new larger value
  6789. // allow the DPC to re-fire itself if needed
  6790. //
  6791. DebugPrint((ClassDebugDelayedRetry, "ClassRetry: ++ %p\n", Irp));
  6792. //
  6793. // must be at least two items on list
  6794. //
  6795. ASSERT(fdoData->Retry.ListHead != NULL);
  6796. ASSERT(fdoData->Retry.ListHead->Next != NULL);
  6797. fdoData->Retry.Tick.QuadPart -= fdoData->Retry.Delta.QuadPart;
  6798. fdoData->Retry.Tick.QuadPart += delta.QuadPart;
  6799. fdoData->Retry.Delta.QuadPart = delta.QuadPart;
  6800. } else {
  6801. //
  6802. // just inserting it on the list was enough
  6803. //
  6804. DebugPrint((ClassDebugDelayedRetry, "ClassRetry: ++ %p\n", Irp));
  6805. }
  6806. KeReleaseSpinLock(&fdoData->Retry.Lock, irql);
  6807. } // end ClassRetryRequest()
  6808. /*++
  6809. ISSUE-2000/02/20-henrygab Not documented ClasspRetryDpcTimer
  6810. --*/
  6811. VOID
  6812. ClasspRetryDpcTimer(
  6813. IN PCLASS_PRIVATE_FDO_DATA FdoData
  6814. )
  6815. {
  6816. LARGE_INTEGER fire;
  6817. ASSERT(FdoData->Retry.Tick.QuadPart != (LONGLONG)0);
  6818. ASSERT(FdoData->Retry.ListHead != NULL); // never fire an empty list
  6819. //
  6820. // fire == (CurrentTick - now) * (100ns per tick)
  6821. //
  6822. // NOTE: Overflow is nearly impossible and is ignored here
  6823. //
  6824. KeQueryTickCount(&fire);
  6825. fire.QuadPart = FdoData->Retry.Tick.QuadPart - fire.QuadPart;
  6826. fire.QuadPart *= FdoData->Retry.Granularity;
  6827. //
  6828. // fire is now multiples of 100ns until should fire the timer.
  6829. // if timer should already have expired, or would fire too quickly,
  6830. // fire it in some arbitrary number of ticks to prevent infinitely
  6831. // recursing.
  6832. //
  6833. if (fire.QuadPart < MINIMUM_RETRY_UNITS) {
  6834. fire.QuadPart = MINIMUM_RETRY_UNITS;
  6835. }
  6836. DebugPrint((ClassDebugDelayedRetry,
  6837. "ClassRetry: ======= %I64x ticks\n",
  6838. fire.QuadPart));
  6839. //
  6840. // must use negative to specify relative time to fire
  6841. //
  6842. fire.QuadPart = fire.QuadPart * ((LONGLONG)-1);
  6843. //
  6844. // set the timer, since this is the first addition
  6845. //
  6846. KeSetTimerEx(&FdoData->Retry.Timer, fire, 0, &FdoData->Retry.Dpc);
  6847. return;
  6848. } // end ClasspRetryDpcTimer()
  6849. NTSTATUS
  6850. ClasspInitializeHotplugInfo(
  6851. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  6852. )
  6853. {
  6854. PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
  6855. DEVICE_REMOVAL_POLICY deviceRemovalPolicy = 0;
  6856. NTSTATUS status;
  6857. ULONG resultLength = 0;
  6858. ULONG writeCacheOverride;
  6859. PAGED_CODE();
  6860. //
  6861. // start with some default settings
  6862. //
  6863. RtlZeroMemory(&(fdoData->HotplugInfo), sizeof(STORAGE_HOTPLUG_INFO));
  6864. //
  6865. // set the size (aka version)
  6866. //
  6867. fdoData->HotplugInfo.Size = sizeof(STORAGE_HOTPLUG_INFO);
  6868. //
  6869. // set if the device has removable media
  6870. //
  6871. if (FdoExtension->DeviceDescriptor->RemovableMedia) {
  6872. fdoData->HotplugInfo.MediaRemovable = TRUE;
  6873. } else {
  6874. fdoData->HotplugInfo.MediaRemovable = FALSE;
  6875. }
  6876. //
  6877. // this refers to devices which, for reasons not yet understood,
  6878. // do not fail PREVENT_MEDIA_REMOVAL requests even though they
  6879. // have no way to lock the media into the drive. this allows
  6880. // the filesystems to turn off delayed-write caching for these
  6881. // devices as well.
  6882. //
  6883. if (TEST_FLAG(FdoExtension->PrivateFdoData->HackFlags,
  6884. FDO_HACK_CANNOT_LOCK_MEDIA)) {
  6885. fdoData->HotplugInfo.MediaHotplug = TRUE;
  6886. } else {
  6887. fdoData->HotplugInfo.MediaHotplug = FALSE;
  6888. }
  6889. //
  6890. // Look into the registry to see if the user has chosen
  6891. // to override the default setting for the removal policy
  6892. //
  6893. ClassGetDeviceParameter(FdoExtension,
  6894. CLASSP_REG_SUBKEY_NAME,
  6895. CLASSP_REG_REMOVAL_POLICY_VALUE_NAME,
  6896. (PULONG)&deviceRemovalPolicy);
  6897. if (deviceRemovalPolicy == 0)
  6898. {
  6899. //
  6900. // Query the default removal policy from the kernel
  6901. //
  6902. status = IoGetDeviceProperty(FdoExtension->LowerPdo,
  6903. DevicePropertyRemovalPolicy,
  6904. sizeof(DEVICE_REMOVAL_POLICY),
  6905. (PVOID)&deviceRemovalPolicy,
  6906. &resultLength);
  6907. if (!NT_SUCCESS(status))
  6908. {
  6909. return status;
  6910. }
  6911. if (resultLength != sizeof(DEVICE_REMOVAL_POLICY))
  6912. {
  6913. return STATUS_UNSUCCESSFUL;
  6914. }
  6915. }
  6916. //
  6917. // use this info to set the DeviceHotplug setting
  6918. // don't rely on DeviceCapabilities, since it can't properly
  6919. // determine device relations, etc. let the kernel figure this
  6920. // stuff out instead.
  6921. //
  6922. if (deviceRemovalPolicy == RemovalPolicyExpectSurpriseRemoval) {
  6923. fdoData->HotplugInfo.DeviceHotplug = TRUE;
  6924. } else {
  6925. fdoData->HotplugInfo.DeviceHotplug = FALSE;
  6926. }
  6927. //
  6928. // this refers to the *filesystem* caching, but has to be included
  6929. // here since it's a per-device setting. this may change to be
  6930. // stored by the system in the future.
  6931. //
  6932. writeCacheOverride = FALSE;
  6933. ClassGetDeviceParameter(FdoExtension,
  6934. CLASSP_REG_SUBKEY_NAME,
  6935. CLASSP_REG_WRITE_CACHE_VALUE_NAME,
  6936. &writeCacheOverride);
  6937. if (writeCacheOverride) {
  6938. fdoData->HotplugInfo.WriteCacheEnableOverride = TRUE;
  6939. } else {
  6940. fdoData->HotplugInfo.WriteCacheEnableOverride = FALSE;
  6941. }
  6942. return STATUS_SUCCESS;
  6943. }
  6944. VOID
  6945. ClasspScanForClassHacks(
  6946. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  6947. IN ULONG_PTR Data
  6948. )
  6949. {
  6950. PAGED_CODE();
  6951. //
  6952. // remove invalid flags and save
  6953. //
  6954. CLEAR_FLAG(Data, FDO_HACK_INVALID_FLAGS);
  6955. SET_FLAG(FdoExtension->PrivateFdoData->HackFlags, Data);
  6956. return;
  6957. }
  6958. VOID
  6959. ClasspScanForSpecialInRegistry(
  6960. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension
  6961. )
  6962. {
  6963. HANDLE deviceParameterHandle; // device instance key
  6964. HANDLE classParameterHandle; // classpnp subkey
  6965. OBJECT_ATTRIBUTES objectAttributes = {0};
  6966. UNICODE_STRING subkeyName;
  6967. NTSTATUS status;
  6968. //
  6969. // seeded in the ENUM tree by ClassInstaller
  6970. //
  6971. ULONG deviceHacks;
  6972. RTL_QUERY_REGISTRY_TABLE queryTable[2] = {0}; // null terminated array
  6973. PAGED_CODE();
  6974. deviceParameterHandle = NULL;
  6975. classParameterHandle = NULL;
  6976. deviceHacks = 0;
  6977. status = IoOpenDeviceRegistryKey(FdoExtension->LowerPdo,
  6978. PLUGPLAY_REGKEY_DEVICE,
  6979. KEY_WRITE,
  6980. &deviceParameterHandle
  6981. );
  6982. if (!NT_SUCCESS(status)) {
  6983. goto cleanupScanForSpecial;
  6984. }
  6985. RtlInitUnicodeString(&subkeyName, CLASSP_REG_SUBKEY_NAME);
  6986. InitializeObjectAttributes(&objectAttributes,
  6987. &subkeyName,
  6988. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  6989. deviceParameterHandle,
  6990. NULL
  6991. );
  6992. status = ZwOpenKey( &classParameterHandle,
  6993. KEY_READ,
  6994. &objectAttributes
  6995. );
  6996. if (!NT_SUCCESS(status)) {
  6997. goto cleanupScanForSpecial;
  6998. }
  6999. //
  7000. // Setup the structure to read
  7001. //
  7002. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  7003. queryTable[0].Name = CLASSP_REG_HACK_VALUE_NAME;
  7004. queryTable[0].EntryContext = &deviceHacks;
  7005. queryTable[0].DefaultType = REG_DWORD;
  7006. queryTable[0].DefaultData = &deviceHacks;
  7007. queryTable[0].DefaultLength = 0;
  7008. //
  7009. // read values
  7010. //
  7011. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  7012. (PWSTR)classParameterHandle,
  7013. &queryTable[0],
  7014. NULL,
  7015. NULL
  7016. );
  7017. if (!NT_SUCCESS(status)) {
  7018. goto cleanupScanForSpecial;
  7019. }
  7020. //
  7021. // remove unknown values and save...
  7022. //
  7023. CLEAR_FLAG(deviceHacks, FDO_HACK_INVALID_FLAGS);
  7024. SET_FLAG(FdoExtension->PrivateFdoData->HackFlags, deviceHacks);
  7025. cleanupScanForSpecial:
  7026. if (deviceParameterHandle) {
  7027. ZwClose(deviceParameterHandle);
  7028. }
  7029. if (classParameterHandle) {
  7030. ZwClose(classParameterHandle);
  7031. }
  7032. //
  7033. // we should modify the system hive to include another key for us to grab
  7034. // settings from. in this case: Classpnp\HackFlags
  7035. //
  7036. // the use of a DWORD value for the HackFlags allows 32 hacks w/o
  7037. // significant use of the registry, and also reduces OEM exposure.
  7038. //
  7039. // definition of bit flags:
  7040. // 0x00000001 -- Device succeeds PREVENT_MEDIUM_REMOVAL, but
  7041. // cannot actually prevent removal.
  7042. // 0x00000002 -- Device hard-hangs or times out for GESN requests.
  7043. // 0xfffffffc -- Currently reserved, may be used later.
  7044. //
  7045. return;
  7046. }
  7047. VOID
  7048. ClassLogThrottleComplete(
  7049. IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
  7050. IN LARGE_INTEGER Period
  7051. )
  7052. /*++
  7053. Routine description:
  7054. This routine logs a system event stating :
  7055. The driver for device %1 delayed non-paging Io requests for %2 ms to recover from a low memory condition
  7056. Arguments:
  7057. FdoExtension - The extension associated with the device object
  7058. Period - The time in 100ns spent in throttle mode
  7059. Return Value:
  7060. None
  7061. --*/
  7062. {
  7063. WCHAR stringPeriod[40] = { 0 };
  7064. UCHAR packetSize;
  7065. PIO_ERROR_LOG_PACKET logEntry;
  7066. Period = Convert100nsToMilliseconds(Period);
  7067. _itow(Period.LowPart, stringPeriod, 10);
  7068. packetSize = sizeof(IO_ERROR_LOG_PACKET) + wcslen(stringPeriod) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
  7069. logEntry = IoAllocateErrorLogEntry(FdoExtension->DeviceObject, packetSize);
  7070. if (logEntry)
  7071. {
  7072. PWCHAR stringOffset = (PWCHAR)(logEntry + 1);
  7073. RtlZeroMemory(logEntry, packetSize);
  7074. logEntry->MajorFunctionCode = IRP_MJ_WRITE;
  7075. logEntry->RetryCount = 0;
  7076. logEntry->DumpDataSize = 0;
  7077. logEntry->NumberOfStrings = 1;
  7078. logEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
  7079. logEntry->ErrorCode = IO_INFO_THROTTLE_COMPLETE;
  7080. logEntry->UniqueErrorValue = 0;
  7081. logEntry->FinalStatus = STATUS_SUCCESS;
  7082. wcsncpy(stringOffset, stringPeriod, wcslen(stringPeriod) + 1);
  7083. IoWriteErrorLogEntry(logEntry);
  7084. }
  7085. }