Source code of Windows XP (NT5)
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.

976 lines
27 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 0
  13. #include "classp.h"
  14. #include "debug.h"
  15. ULONG BreakOnClose = 0;
  16. PUCHAR LockTypeStrings[] = {
  17. "Simple",
  18. "Secure",
  19. "Internal"
  20. };
  21. PFILE_OBJECT_EXTENSION
  22. ClasspGetFsContext(
  23. IN PCOMMON_DEVICE_EXTENSION CommonExtension,
  24. IN PFILE_OBJECT FileObject
  25. );
  26. VOID
  27. ClasspCleanupDisableMcn(
  28. IN PFILE_OBJECT_EXTENSION FsContext
  29. );
  30. #ifdef ALLOC_PRAGMA
  31. #pragma alloc_text(PAGE, ClassCreateClose)
  32. #pragma alloc_text(PAGE, ClasspCreateClose)
  33. #pragma alloc_text(PAGE, ClasspCleanupProtectedLocks)
  34. #pragma alloc_text(PAGE, ClasspEjectionControl)
  35. #pragma alloc_text(PAGE, ClasspCleanupDisableMcn)
  36. #pragma alloc_text(PAGE, ClasspGetFsContext)
  37. #endif
  38. NTSTATUS
  39. ClassCreateClose(
  40. IN PDEVICE_OBJECT DeviceObject,
  41. IN PIRP Irp
  42. )
  43. /*++
  44. Routine Description:
  45. SCSI class driver create and close routine. This is called by the I/O system
  46. when the device is opened or closed.
  47. Arguments:
  48. DriverObject - Pointer to driver object created by system.
  49. Irp - IRP involved.
  50. Return Value:
  51. Device-specific drivers return value or STATUS_SUCCESS.
  52. --*/
  53. {
  54. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  55. ULONG removeState;
  56. NTSTATUS status;
  57. PAGED_CODE();
  58. //
  59. // If we're getting a close request then we know the device object hasn't
  60. // been completely destroyed. Let the driver cleanup if necessary.
  61. //
  62. removeState = ClassAcquireRemoveLock(DeviceObject, Irp);
  63. //
  64. // Invoke the device-specific routine, if one exists. Otherwise complete
  65. // with SUCCESS
  66. //
  67. if((removeState == NO_REMOVE) ||
  68. IS_CLEANUP_REQUEST(IoGetCurrentIrpStackLocation(Irp)->MajorFunction)) {
  69. status = ClasspCreateClose(DeviceObject, Irp);
  70. if((NT_SUCCESS(status)) &&
  71. (commonExtension->DevInfo->ClassCreateClose)) {
  72. return commonExtension->DevInfo->ClassCreateClose(DeviceObject, Irp);
  73. }
  74. } else {
  75. status = STATUS_DEVICE_DOES_NOT_EXIST;
  76. }
  77. Irp->IoStatus.Status = status;
  78. ClassReleaseRemoveLock(DeviceObject, Irp);
  79. ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
  80. return status;
  81. }
  82. NTSTATUS
  83. ClasspCreateClose(
  84. IN PDEVICE_OBJECT DeviceObject,
  85. IN PIRP Irp
  86. )
  87. /*++
  88. Routine Description:
  89. This routine will handle create/close operations for a given classpnp
  90. device if the class driver doesn't supply it's own handler. If there
  91. is a file object supplied for our driver (if it's a FO_DIRECT_DEVICE_OPEN
  92. file object) then it will initialize a file extension on create or destroy
  93. the extension on a close.
  94. Arguments:
  95. DeviceObject - the device object being opened or closed.
  96. Irp - the create/close irp
  97. Return Value:
  98. status
  99. --*/
  100. {
  101. PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  102. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  103. PFILE_OBJECT fileObject = irpStack->FileObject;
  104. NTSTATUS status = STATUS_SUCCESS;
  105. PAGED_CODE();
  106. //
  107. // ISSUE-2000/3/28-henrygab - if lower stack fails create/close, we end up
  108. // in an inconsistent state. re-write to verify all args and allocate all
  109. // required resources, then pass the irp down, then complete the
  110. // transaction. this is because we also cannot forward the irp, then fail
  111. // it after it has succeeded a lower-level driver.
  112. //
  113. if(irpStack->MajorFunction == IRP_MJ_CREATE) {
  114. PIO_SECURITY_CONTEXT securityContext =
  115. irpStack->Parameters.Create.SecurityContext;
  116. DebugPrint((2,
  117. "ClasspCREATEClose: create received for device %p\n",
  118. DeviceObject));
  119. DebugPrint((2,
  120. "ClasspCREATEClose: desired access %lx\n",
  121. securityContext->DesiredAccess));
  122. DebugPrint((2,
  123. "ClasspCREATEClose: file object %lx\n",
  124. irpStack->FileObject));
  125. ASSERT(BreakOnClose == FALSE);
  126. if(irpStack->FileObject != NULL) {
  127. PFILE_OBJECT_EXTENSION fsContext;
  128. //
  129. // Allocate our own file object extension for this device object.
  130. //
  131. status = AllocateDictionaryEntry(
  132. &commonExtension->FileObjectDictionary,
  133. (ULONGLONG) irpStack->FileObject,
  134. sizeof(FILE_OBJECT_EXTENSION),
  135. CLASS_TAG_FILE_OBJECT_EXTENSION,
  136. &fsContext);
  137. if(NT_SUCCESS(status)) {
  138. RtlZeroMemory(fsContext,
  139. sizeof(FILE_OBJECT_EXTENSION));
  140. fsContext->FileObject = irpStack->FileObject;
  141. fsContext->DeviceObject = DeviceObject;
  142. } else if (status == STATUS_OBJECT_NAME_COLLISION) {
  143. status = STATUS_SUCCESS;
  144. }
  145. }
  146. } else {
  147. DebugPrint((2,
  148. "ClasspCreateCLOSE: close received for device %p\n",
  149. DeviceObject));
  150. DebugPrint((2,
  151. "ClasspCreateCLOSE: file object %p\n",
  152. fileObject));
  153. if(irpStack->FileObject != NULL) {
  154. PFILE_OBJECT_EXTENSION fsContext =
  155. ClasspGetFsContext(commonExtension, irpStack->FileObject);
  156. DebugPrint((2,
  157. "ClasspCreateCLOSE: file extension %p\n",
  158. fsContext));
  159. if(fsContext != NULL) {
  160. DebugPrint((2,
  161. "ClasspCreateCLOSE: extension is ours - "
  162. "freeing\n"));
  163. ASSERT(BreakOnClose == FALSE);
  164. ClasspCleanupProtectedLocks(fsContext);
  165. ClasspCleanupDisableMcn(fsContext);
  166. FreeDictionaryEntry(&(commonExtension->FileObjectDictionary),
  167. fsContext);
  168. }
  169. }
  170. }
  171. //
  172. // Notify the lower levels about the create or close operation - give them
  173. // a chance to cleanup too.
  174. //
  175. DebugPrint((2,
  176. "ClasspCreateClose: %s for devobj %p\n",
  177. (NT_SUCCESS(status) ? "Success" : "FAILED"),
  178. DeviceObject));
  179. if(NT_SUCCESS(status)) {
  180. KEVENT event;
  181. //
  182. // Set up the event to wait on
  183. //
  184. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  185. IoCopyCurrentIrpStackLocationToNext(Irp);
  186. IoSetCompletionRoutine( Irp, ClassSignalCompletion, &event,
  187. TRUE, TRUE, TRUE);
  188. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  189. if(status == STATUS_PENDING) {
  190. KeWaitForSingleObject(&event,
  191. Executive,
  192. KernelMode,
  193. FALSE,
  194. NULL);
  195. status = Irp->IoStatus.Status;
  196. }
  197. if (!NT_SUCCESS(status)) {
  198. DebugPrint((ClassDebugError,
  199. "ClasspCreateClose: Lower driver failed, but we "
  200. "succeeded. This is a problem, lock counts will be "
  201. "out of sync between levels.\n"));
  202. }
  203. }
  204. return status;
  205. }
  206. VOID
  207. ClasspCleanupProtectedLocks(
  208. IN PFILE_OBJECT_EXTENSION FsContext
  209. )
  210. {
  211. PCOMMON_DEVICE_EXTENSION commonExtension =
  212. FsContext->DeviceObject->DeviceExtension;
  213. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
  214. commonExtension->PartitionZeroExtension;
  215. ULONG newDeviceLockCount = 1;
  216. PAGED_CODE();
  217. DebugPrint((2,
  218. "ClasspCleanupProtectedLocks called for %p\n",
  219. FsContext->DeviceObject));
  220. DebugPrint((2,
  221. "ClasspCleanupProtectedLocks - FsContext %p is locked "
  222. "%d times\n", FsContext, FsContext->LockCount));
  223. ASSERT(BreakOnClose == FALSE);
  224. //
  225. // Synchronize with ejection and ejection control requests.
  226. //
  227. KeEnterCriticalRegion();
  228. KeWaitForSingleObject(&(fdoExtension->EjectSynchronizationEvent),
  229. UserRequest,
  230. UserMode,
  231. FALSE,
  232. NULL);
  233. //
  234. // For each secure lock on this handle decrement the secured lock count
  235. // for the FDO. Keep track of the new value.
  236. //
  237. if(FsContext->LockCount != 0) {
  238. do {
  239. InterlockedDecrement(&FsContext->LockCount);
  240. newDeviceLockCount =
  241. InterlockedDecrement(&fdoExtension->ProtectedLockCount);
  242. } while(FsContext->LockCount != 0);
  243. //
  244. // If the new lock count has been dropped to zero then issue a lock
  245. // command to the device.
  246. //
  247. DebugPrint((2,
  248. "ClasspCleanupProtectedLocks: FDO secured lock count = %d "
  249. "lock count = %d\n",
  250. fdoExtension->ProtectedLockCount,
  251. fdoExtension->LockCount));
  252. if((newDeviceLockCount == 0) && (fdoExtension->LockCount == 0)) {
  253. SCSI_REQUEST_BLOCK srb;
  254. PCDB cdb;
  255. NTSTATUS status;
  256. DebugPrint((2,
  257. "ClasspCleanupProtectedLocks: FDO lock count dropped "
  258. "to zero\n"));
  259. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  260. cdb = (PCDB) &(srb.Cdb);
  261. srb.CdbLength = 6;
  262. cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
  263. //
  264. // TRUE - prevent media removal.
  265. // FALSE - allow media removal.
  266. //
  267. cdb->MEDIA_REMOVAL.Prevent = FALSE;
  268. //
  269. // Set timeout value.
  270. //
  271. srb.TimeOutValue = fdoExtension->TimeOutValue;
  272. status = ClassSendSrbSynchronous(fdoExtension->DeviceObject,
  273. &srb,
  274. NULL,
  275. 0,
  276. FALSE);
  277. DebugPrint((2,
  278. "ClasspCleanupProtectedLocks: unlock request to drive "
  279. "returned status %lx\n", status));
  280. }
  281. }
  282. KeSetEvent(&fdoExtension->EjectSynchronizationEvent,
  283. IO_NO_INCREMENT,
  284. FALSE);
  285. KeLeaveCriticalRegion();
  286. return;
  287. }
  288. VOID
  289. ClasspCleanupDisableMcn(
  290. IN PFILE_OBJECT_EXTENSION FsContext
  291. )
  292. {
  293. PCOMMON_DEVICE_EXTENSION commonExtension =
  294. FsContext->DeviceObject->DeviceExtension;
  295. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
  296. commonExtension->PartitionZeroExtension;
  297. ULONG newCount = 1;
  298. PAGED_CODE();
  299. DebugPrint((ClassDebugTrace,
  300. "ClasspCleanupDisableMcn called for %p\n",
  301. FsContext->DeviceObject));
  302. DebugPrint((ClassDebugTrace,
  303. "ClasspCleanupDisableMcn - FsContext %p is disabled "
  304. "%d times\n", FsContext, FsContext->McnDisableCount));
  305. //
  306. // For each secure lock on this handle decrement the secured lock count
  307. // for the FDO. Keep track of the new value.
  308. //
  309. while(FsContext->McnDisableCount != 0) {
  310. FsContext->McnDisableCount--;
  311. ClassEnableMediaChangeDetection(fdoExtension);
  312. }
  313. return;
  314. }
  315. #if 1
  316. /*
  317. * BUGBUG REMOVE this old function implementation as soon as the
  318. * boottime pagefile problems with the new one (below)
  319. * are resolved.
  320. */
  321. NTSTATUS
  322. ClasspEjectionControl(
  323. IN PDEVICE_OBJECT Fdo,
  324. IN PIRP Irp,
  325. IN MEDIA_LOCK_TYPE LockType,
  326. IN BOOLEAN Lock
  327. )
  328. {
  329. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = Fdo->DeviceExtension;
  330. PCOMMON_DEVICE_EXTENSION commonExtension =
  331. (PCOMMON_DEVICE_EXTENSION) FdoExtension;
  332. PFILE_OBJECT_EXTENSION fsContext = NULL;
  333. NTSTATUS status;
  334. PSCSI_REQUEST_BLOCK srb = NULL;
  335. BOOLEAN countChanged = FALSE;
  336. PAGED_CODE();
  337. //
  338. // Interlock with ejection and secure lock cleanup code. This is a
  339. // user request so we can allow the stack to get swapped out while we
  340. // wait for synchronization.
  341. //
  342. status = KeWaitForSingleObject(
  343. &(FdoExtension->EjectSynchronizationEvent),
  344. UserRequest,
  345. UserMode,
  346. FALSE,
  347. NULL);
  348. ASSERT(status == STATUS_SUCCESS);
  349. DebugPrint((2,
  350. "ClasspEjectionControl: "
  351. "Received request for %s lock type\n",
  352. LockTypeStrings[LockType]
  353. ));
  354. try {
  355. PCDB cdb;
  356. srb = ClasspAllocateSrb(FdoExtension);
  357. if(srb == NULL) {
  358. status = STATUS_INSUFFICIENT_RESOURCES;
  359. leave;
  360. }
  361. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  362. cdb = (PCDB) srb->Cdb;
  363. //
  364. // Determine if this is a "secured" request.
  365. //
  366. if(LockType == SecureMediaLock) {
  367. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  368. PFILE_OBJECT fileObject = irpStack->FileObject;
  369. //
  370. // Make sure that the file object we are supplied has a
  371. // proper FsContext before we try doing a secured lock.
  372. //
  373. if(fileObject != NULL) {
  374. fsContext = ClasspGetFsContext(commonExtension, fileObject);
  375. }
  376. if (fsContext == NULL) {
  377. //
  378. // This handle isn't setup correctly. We can't let the
  379. // operation go.
  380. //
  381. status = STATUS_INVALID_PARAMETER;
  382. leave;
  383. }
  384. }
  385. if(Lock) {
  386. //
  387. // This is a lock command. Reissue the command in case bus or
  388. // device was reset and the lock was cleared.
  389. // note: may need to decrement count if actual lock operation
  390. // failed....
  391. //
  392. switch(LockType) {
  393. case SimpleMediaLock: {
  394. FdoExtension->LockCount++;
  395. countChanged = TRUE;
  396. break;
  397. }
  398. case SecureMediaLock: {
  399. fsContext->LockCount++;
  400. FdoExtension->ProtectedLockCount++;
  401. countChanged = TRUE;
  402. break;
  403. }
  404. case InternalMediaLock: {
  405. FdoExtension->InternalLockCount++;
  406. countChanged = TRUE;
  407. break;
  408. }
  409. }
  410. } else {
  411. //
  412. // This is an unlock command. If it's a secured one then make sure
  413. // the caller has a lock outstanding or return an error.
  414. // note: may need to re-increment the count if actual unlock
  415. // operation fails....
  416. //
  417. switch(LockType) {
  418. case SimpleMediaLock: {
  419. if(FdoExtension->LockCount != 0) {
  420. FdoExtension->LockCount--;
  421. countChanged = TRUE;
  422. }
  423. break;
  424. }
  425. case SecureMediaLock: {
  426. if(fsContext->LockCount == 0) {
  427. status = STATUS_INVALID_DEVICE_STATE;
  428. leave;
  429. }
  430. fsContext->LockCount--;
  431. FdoExtension->ProtectedLockCount--;
  432. countChanged = TRUE;
  433. break;
  434. }
  435. case InternalMediaLock: {
  436. ASSERT(FdoExtension->InternalLockCount != 0);
  437. FdoExtension->InternalLockCount--;
  438. countChanged = TRUE;
  439. break;
  440. }
  441. }
  442. //
  443. // We only send an unlock command to the drive if both the
  444. // secured and unsecured lock counts have dropped to zero.
  445. //
  446. if((FdoExtension->ProtectedLockCount != 0) ||
  447. (FdoExtension->InternalLockCount != 0) ||
  448. (FdoExtension->LockCount != 0)) {
  449. status = STATUS_SUCCESS;
  450. leave;
  451. }
  452. }
  453. status = STATUS_SUCCESS;
  454. if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
  455. srb->CdbLength = 6;
  456. cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
  457. //
  458. // TRUE - prevent media removal.
  459. // FALSE - allow media removal.
  460. //
  461. cdb->MEDIA_REMOVAL.Prevent = Lock;
  462. //
  463. // Set timeout value.
  464. //
  465. srb->TimeOutValue = FdoExtension->TimeOutValue;
  466. //
  467. // The actual lock operation on the device isn't so important
  468. // as the internal lock counts. Ignore failures.
  469. //
  470. status = ClassSendSrbSynchronous(FdoExtension->DeviceObject,
  471. srb,
  472. NULL,
  473. 0,
  474. FALSE);
  475. }
  476. } finally {
  477. if (!NT_SUCCESS(status)) {
  478. DebugPrint((2,
  479. "ClasspEjectionControl: FAILED status %x -- "
  480. "reverting lock counts\n", status));
  481. if (countChanged) {
  482. //
  483. // have to revert to previous counts if the
  484. // lock/unlock operation actually failed.
  485. //
  486. if(Lock) {
  487. switch(LockType) {
  488. case SimpleMediaLock: {
  489. FdoExtension->LockCount--;
  490. break;
  491. }
  492. case SecureMediaLock: {
  493. fsContext->LockCount--;
  494. FdoExtension->ProtectedLockCount--;
  495. break;
  496. }
  497. case InternalMediaLock: {
  498. FdoExtension->InternalLockCount--;
  499. break;
  500. }
  501. }
  502. } else {
  503. switch(LockType) {
  504. case SimpleMediaLock: {
  505. FdoExtension->LockCount++;
  506. break;
  507. }
  508. case SecureMediaLock: {
  509. fsContext->LockCount++;
  510. FdoExtension->ProtectedLockCount++;
  511. break;
  512. }
  513. case InternalMediaLock: {
  514. FdoExtension->InternalLockCount++;
  515. break;
  516. }
  517. }
  518. }
  519. }
  520. } else {
  521. DebugPrint((2,
  522. "ClasspEjectionControl: Succeeded\n"));
  523. }
  524. DebugPrint((2,
  525. "ClasspEjectionControl: "
  526. "Current Counts: Internal: %x Secure: %x Simple: %x\n",
  527. FdoExtension->InternalLockCount,
  528. FdoExtension->ProtectedLockCount,
  529. FdoExtension->LockCount
  530. ));
  531. KeSetEvent(&(FdoExtension->EjectSynchronizationEvent),
  532. IO_NO_INCREMENT,
  533. FALSE);
  534. if (srb) {
  535. ClassFreeOrReuseSrb(FdoExtension, srb);
  536. }
  537. }
  538. return status;
  539. }
  540. #else
  541. /*
  542. * BUGBUG RESTORE
  543. * This is a new implementation of the function that doesn't thrash memory
  544. * or depend on the srbLookasideList.
  545. * HOWEVER, it seems to cause pagefile initialization to fail during boot
  546. * for some reason. Need to resolve this before switching to this function.
  547. */
  548. NTSTATUS
  549. ClasspEjectionControl(
  550. IN PDEVICE_OBJECT Fdo,
  551. IN PIRP Irp,
  552. IN MEDIA_LOCK_TYPE LockType,
  553. IN BOOLEAN Lock
  554. )
  555. {
  556. PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
  557. PFILE_OBJECT_EXTENSION fsContext;
  558. BOOLEAN fileHandleOk = TRUE;
  559. BOOLEAN countChanged = FALSE;
  560. NTSTATUS status;
  561. PAGED_CODE();
  562. status = KeWaitForSingleObject(
  563. &fdoExt->EjectSynchronizationEvent,
  564. UserRequest,
  565. UserMode,
  566. FALSE,
  567. NULL);
  568. ASSERT(status == STATUS_SUCCESS);
  569. /*
  570. * If this is a "secured" request, we have to make sure
  571. * that the file handle is valid.
  572. */
  573. if (LockType == SecureMediaLock){
  574. PIO_STACK_LOCATION thisSp = IoGetCurrentIrpStackLocation(Irp);
  575. /*
  576. * Make sure that the file object we are supplied has a
  577. * proper FsContext before we try doing a secured lock.
  578. */
  579. if (thisSp->FileObject){
  580. PCOMMON_DEVICE_EXTENSION commonExt = (PCOMMON_DEVICE_EXTENSION)fdoExt;
  581. fsContext = ClasspGetFsContext(commonExt, thisSp->FileObject);
  582. }
  583. else {
  584. fsContext = NULL;
  585. }
  586. if (!fsContext){
  587. ASSERT(fsContext);
  588. fileHandleOk = FALSE;
  589. }
  590. }
  591. if (fileHandleOk){
  592. /*
  593. * Adjust the lock counts and make sure they make sense.
  594. */
  595. status = STATUS_SUCCESS;
  596. if (Lock){
  597. switch(LockType) {
  598. case SimpleMediaLock:
  599. fdoExt->LockCount++;
  600. countChanged = TRUE;
  601. break;
  602. case SecureMediaLock:
  603. fsContext->LockCount++;
  604. fdoExt->ProtectedLockCount++;
  605. countChanged = TRUE;
  606. break;
  607. case InternalMediaLock:
  608. fdoExt->InternalLockCount++;
  609. countChanged = TRUE;
  610. break;
  611. }
  612. }
  613. else {
  614. /*
  615. * This is an unlock command. If it's a secured one then make sure
  616. * the caller has a lock outstanding or return an error.
  617. */
  618. switch (LockType){
  619. case SimpleMediaLock:
  620. if (fdoExt->LockCount > 0){
  621. fdoExt->LockCount--;
  622. countChanged = TRUE;
  623. }
  624. else {
  625. ASSERT(fdoExt->LockCount > 0);
  626. status = STATUS_INTERNAL_ERROR;
  627. }
  628. break;
  629. case SecureMediaLock:
  630. if (fsContext->LockCount > 0){
  631. ASSERT(fdoExt->ProtectedLockCount > 0);
  632. fsContext->LockCount--;
  633. fdoExt->ProtectedLockCount--;
  634. countChanged = TRUE;
  635. }
  636. else {
  637. ASSERT(fsContext->LockCount > 0);
  638. status = STATUS_INVALID_DEVICE_STATE;
  639. }
  640. break;
  641. case InternalMediaLock:
  642. ASSERT(fdoExt->InternalLockCount > 0);
  643. fdoExt->InternalLockCount--;
  644. countChanged = TRUE;
  645. break;
  646. }
  647. }
  648. if (NT_SUCCESS(status)){
  649. /*
  650. * We only send an unlock command to the drive if
  651. * all the lock counts have dropped to zero.
  652. */
  653. if (!Lock &&
  654. (fdoExt->ProtectedLockCount ||
  655. fdoExt->InternalLockCount ||
  656. fdoExt->LockCount)){
  657. /*
  658. * The lock count is still positive, so don't unlock yet.
  659. */
  660. status = STATUS_SUCCESS;
  661. }
  662. else if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
  663. /*
  664. * The device isn't removable media. don't send a cmd.
  665. */
  666. status = STATUS_SUCCESS;
  667. }
  668. else {
  669. TRANSFER_PACKET *pkt;
  670. pkt = DequeueFreeTransferPacket(Fdo, TRUE);
  671. if (pkt){
  672. KEVENT event;
  673. /*
  674. * Store the number of packets servicing the irp (one)
  675. * inside the original IRP. It will be used to counted down
  676. * to zero when the packet completes.
  677. * Initialize the original IRP's status to success.
  678. * If the packet fails, we will set it to the error status.
  679. */
  680. Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1);
  681. Irp->IoStatus.Status = STATUS_SUCCESS;
  682. /*
  683. * Set this up as a SYNCHRONOUS transfer, submit it,
  684. * and wait for the packet to complete. The result
  685. * status will be written to the original irp.
  686. */
  687. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  688. SetupEjectionTransferPacket(pkt, Lock, &event, Irp);
  689. SubmitTransferPacket(pkt);
  690. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  691. status = Irp->IoStatus.Status;
  692. }
  693. else {
  694. status = STATUS_INSUFFICIENT_RESOURCES;
  695. }
  696. }
  697. }
  698. }
  699. else {
  700. status = STATUS_INVALID_PARAMETER;
  701. }
  702. if (!NT_SUCCESS(status) && countChanged) {
  703. //
  704. // have to revert to previous counts if the
  705. // lock/unlock operation actually failed.
  706. //
  707. if(Lock) {
  708. switch(LockType) {
  709. case SimpleMediaLock: {
  710. FdoExtension->LockCount--;
  711. break;
  712. }
  713. case SecureMediaLock: {
  714. fsContext->LockCount--;
  715. FdoExtension->ProtectedLockCount--;
  716. break;
  717. }
  718. case InternalMediaLock: {
  719. FdoExtension->InternalLockCount--;
  720. break;
  721. }
  722. }
  723. } else {
  724. switch(LockType) {
  725. case SimpleMediaLock: {
  726. FdoExtension->LockCount++;
  727. break;
  728. }
  729. case SecureMediaLock: {
  730. fsContext->LockCount++;
  731. FdoExtension->ProtectedLockCount++;
  732. break;
  733. }
  734. case InternalMediaLock: {
  735. FdoExtension->InternalLockCount++;
  736. break;
  737. }
  738. }
  739. }
  740. }
  741. KeSetEvent(&fdoExt->EjectSynchronizationEvent, IO_NO_INCREMENT, FALSE);
  742. return status;
  743. }
  744. #endif
  745. PFILE_OBJECT_EXTENSION
  746. ClasspGetFsContext(
  747. IN PCOMMON_DEVICE_EXTENSION CommonExtension,
  748. IN PFILE_OBJECT FileObject
  749. )
  750. {
  751. PAGED_CODE();
  752. return GetDictionaryEntry(&(CommonExtension->FileObjectDictionary),
  753. (ULONGLONG) FileObject);
  754. }