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.

976 lines
28 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. KernelMode,
  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 = {0};
  254. PCDB cdb;
  255. NTSTATUS status;
  256. DebugPrint((2,
  257. "ClasspCleanupProtectedLocks: FDO lock count dropped "
  258. "to zero\n"));
  259. cdb = (PCDB) &(srb.Cdb);
  260. srb.CdbLength = 6;
  261. cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
  262. //
  263. // TRUE - prevent media removal.
  264. // FALSE - allow media removal.
  265. //
  266. cdb->MEDIA_REMOVAL.Prevent = FALSE;
  267. //
  268. // Set timeout value.
  269. //
  270. srb.TimeOutValue = fdoExtension->TimeOutValue;
  271. status = ClassSendSrbSynchronous(fdoExtension->DeviceObject,
  272. &srb,
  273. NULL,
  274. 0,
  275. FALSE);
  276. DebugPrint((2,
  277. "ClasspCleanupProtectedLocks: unlock request to drive "
  278. "returned status %lx\n", status));
  279. }
  280. }
  281. KeSetEvent(&fdoExtension->EjectSynchronizationEvent,
  282. IO_NO_INCREMENT,
  283. FALSE);
  284. KeLeaveCriticalRegion();
  285. return;
  286. }
  287. VOID
  288. ClasspCleanupDisableMcn(
  289. IN PFILE_OBJECT_EXTENSION FsContext
  290. )
  291. {
  292. PCOMMON_DEVICE_EXTENSION commonExtension =
  293. FsContext->DeviceObject->DeviceExtension;
  294. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension =
  295. commonExtension->PartitionZeroExtension;
  296. ULONG newCount = 1;
  297. PAGED_CODE();
  298. DebugPrint((ClassDebugTrace,
  299. "ClasspCleanupDisableMcn called for %p\n",
  300. FsContext->DeviceObject));
  301. DebugPrint((ClassDebugTrace,
  302. "ClasspCleanupDisableMcn - FsContext %p is disabled "
  303. "%d times\n", FsContext, FsContext->McnDisableCount));
  304. //
  305. // For each secure lock on this handle decrement the secured lock count
  306. // for the FDO. Keep track of the new value.
  307. //
  308. while(FsContext->McnDisableCount != 0) {
  309. FsContext->McnDisableCount--;
  310. ClassEnableMediaChangeDetection(fdoExtension);
  311. }
  312. return;
  313. }
  314. #if 1
  315. /*
  316. * ISSUE: REMOVE this old function implementation as soon as the
  317. * boottime pagefile problems with the new one (below)
  318. * are resolved.
  319. */
  320. NTSTATUS
  321. ClasspEjectionControl(
  322. IN PDEVICE_OBJECT Fdo,
  323. IN PIRP Irp,
  324. IN MEDIA_LOCK_TYPE LockType,
  325. IN BOOLEAN Lock
  326. )
  327. {
  328. PFUNCTIONAL_DEVICE_EXTENSION FdoExtension = Fdo->DeviceExtension;
  329. PCOMMON_DEVICE_EXTENSION commonExtension =
  330. (PCOMMON_DEVICE_EXTENSION) FdoExtension;
  331. PFILE_OBJECT_EXTENSION fsContext = NULL;
  332. NTSTATUS status;
  333. PSCSI_REQUEST_BLOCK srb = NULL;
  334. BOOLEAN countChanged = FALSE;
  335. PAGED_CODE();
  336. /*
  337. * Ensure that the user thread is not suspended while we are holding EjectSynchronizationEvent.
  338. */
  339. KeEnterCriticalRegion();
  340. status = KeWaitForSingleObject(
  341. &(FdoExtension->EjectSynchronizationEvent),
  342. UserRequest,
  343. KernelMode,
  344. FALSE,
  345. NULL);
  346. ASSERT(status == STATUS_SUCCESS);
  347. DebugPrint((2,
  348. "ClasspEjectionControl: "
  349. "Received request for %s lock type\n",
  350. LockTypeStrings[LockType]
  351. ));
  352. try {
  353. PCDB cdb;
  354. srb = ClasspAllocateSrb(FdoExtension);
  355. if(srb == NULL) {
  356. status = STATUS_INSUFFICIENT_RESOURCES;
  357. leave;
  358. }
  359. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  360. cdb = (PCDB) srb->Cdb;
  361. //
  362. // Determine if this is a "secured" request.
  363. //
  364. if(LockType == SecureMediaLock) {
  365. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  366. PFILE_OBJECT fileObject = irpStack->FileObject;
  367. //
  368. // Make sure that the file object we are supplied has a
  369. // proper FsContext before we try doing a secured lock.
  370. //
  371. if(fileObject != NULL) {
  372. fsContext = ClasspGetFsContext(commonExtension, fileObject);
  373. }
  374. if (fsContext == NULL) {
  375. //
  376. // This handle isn't setup correctly. We can't let the
  377. // operation go.
  378. //
  379. status = STATUS_INVALID_PARAMETER;
  380. leave;
  381. }
  382. }
  383. if(Lock) {
  384. //
  385. // This is a lock command. Reissue the command in case bus or
  386. // device was reset and the lock was cleared.
  387. // note: may need to decrement count if actual lock operation
  388. // failed....
  389. //
  390. switch(LockType) {
  391. case SimpleMediaLock: {
  392. FdoExtension->LockCount++;
  393. countChanged = TRUE;
  394. break;
  395. }
  396. case SecureMediaLock: {
  397. fsContext->LockCount++;
  398. FdoExtension->ProtectedLockCount++;
  399. countChanged = TRUE;
  400. break;
  401. }
  402. case InternalMediaLock: {
  403. FdoExtension->InternalLockCount++;
  404. countChanged = TRUE;
  405. break;
  406. }
  407. }
  408. } else {
  409. //
  410. // This is an unlock command. If it's a secured one then make sure
  411. // the caller has a lock outstanding or return an error.
  412. // note: may need to re-increment the count if actual unlock
  413. // operation fails....
  414. //
  415. switch(LockType) {
  416. case SimpleMediaLock: {
  417. if(FdoExtension->LockCount != 0) {
  418. FdoExtension->LockCount--;
  419. countChanged = TRUE;
  420. }
  421. break;
  422. }
  423. case SecureMediaLock: {
  424. if(fsContext->LockCount == 0) {
  425. status = STATUS_INVALID_DEVICE_STATE;
  426. leave;
  427. }
  428. fsContext->LockCount--;
  429. FdoExtension->ProtectedLockCount--;
  430. countChanged = TRUE;
  431. break;
  432. }
  433. case InternalMediaLock: {
  434. ASSERT(FdoExtension->InternalLockCount != 0);
  435. FdoExtension->InternalLockCount--;
  436. countChanged = TRUE;
  437. break;
  438. }
  439. }
  440. //
  441. // We only send an unlock command to the drive if both the
  442. // secured and unsecured lock counts have dropped to zero.
  443. //
  444. if((FdoExtension->ProtectedLockCount != 0) ||
  445. (FdoExtension->InternalLockCount != 0) ||
  446. (FdoExtension->LockCount != 0)) {
  447. status = STATUS_SUCCESS;
  448. leave;
  449. }
  450. }
  451. status = STATUS_SUCCESS;
  452. if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
  453. srb->CdbLength = 6;
  454. cdb->MEDIA_REMOVAL.OperationCode = SCSIOP_MEDIUM_REMOVAL;
  455. //
  456. // TRUE - prevent media removal.
  457. // FALSE - allow media removal.
  458. //
  459. cdb->MEDIA_REMOVAL.Prevent = Lock;
  460. //
  461. // Set timeout value.
  462. //
  463. srb->TimeOutValue = FdoExtension->TimeOutValue;
  464. //
  465. // The actual lock operation on the device isn't so important
  466. // as the internal lock counts. Ignore failures.
  467. //
  468. status = ClassSendSrbSynchronous(FdoExtension->DeviceObject,
  469. srb,
  470. NULL,
  471. 0,
  472. FALSE);
  473. }
  474. } finally {
  475. if (!NT_SUCCESS(status)) {
  476. DebugPrint((2,
  477. "ClasspEjectionControl: FAILED status %x -- "
  478. "reverting lock counts\n", status));
  479. if (countChanged) {
  480. //
  481. // have to revert to previous counts if the
  482. // lock/unlock operation actually failed.
  483. //
  484. if(Lock) {
  485. switch(LockType) {
  486. case SimpleMediaLock: {
  487. FdoExtension->LockCount--;
  488. break;
  489. }
  490. case SecureMediaLock: {
  491. fsContext->LockCount--;
  492. FdoExtension->ProtectedLockCount--;
  493. break;
  494. }
  495. case InternalMediaLock: {
  496. FdoExtension->InternalLockCount--;
  497. break;
  498. }
  499. }
  500. } else {
  501. switch(LockType) {
  502. case SimpleMediaLock: {
  503. FdoExtension->LockCount++;
  504. break;
  505. }
  506. case SecureMediaLock: {
  507. fsContext->LockCount++;
  508. FdoExtension->ProtectedLockCount++;
  509. break;
  510. }
  511. case InternalMediaLock: {
  512. FdoExtension->InternalLockCount++;
  513. break;
  514. }
  515. }
  516. }
  517. }
  518. } else {
  519. DebugPrint((2,
  520. "ClasspEjectionControl: Succeeded\n"));
  521. }
  522. DebugPrint((2,
  523. "ClasspEjectionControl: "
  524. "Current Counts: Internal: %x Secure: %x Simple: %x\n",
  525. FdoExtension->InternalLockCount,
  526. FdoExtension->ProtectedLockCount,
  527. FdoExtension->LockCount
  528. ));
  529. KeSetEvent(&(FdoExtension->EjectSynchronizationEvent),
  530. IO_NO_INCREMENT,
  531. FALSE);
  532. KeLeaveCriticalRegion();
  533. if (srb) {
  534. ClassFreeOrReuseSrb(FdoExtension, srb);
  535. }
  536. }
  537. return status;
  538. }
  539. #else
  540. /*
  541. * ISSUE: RESTORE this (see above)
  542. * This is a new implementation of the function that doesn't thrash memory
  543. * or depend on the srbLookasideList.
  544. * HOWEVER, it seems to cause pagefile initialization to fail during boot
  545. * for some reason. Need to resolve this before switching to this function.
  546. */
  547. NTSTATUS
  548. ClasspEjectionControl(
  549. IN PDEVICE_OBJECT Fdo,
  550. IN PIRP Irp,
  551. IN MEDIA_LOCK_TYPE LockType,
  552. IN BOOLEAN Lock
  553. )
  554. {
  555. PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension;
  556. PFILE_OBJECT_EXTENSION fsContext;
  557. BOOLEAN fileHandleOk = TRUE;
  558. BOOLEAN countChanged = FALSE;
  559. NTSTATUS status;
  560. PAGED_CODE();
  561. status = KeWaitForSingleObject(
  562. &fdoExt->EjectSynchronizationEvent,
  563. UserRequest,
  564. KernelMode,
  565. FALSE,
  566. NULL);
  567. ASSERT(status == STATUS_SUCCESS);
  568. /*
  569. * If this is a "secured" request, we have to make sure
  570. * that the file handle is valid.
  571. */
  572. if (LockType == SecureMediaLock){
  573. PIO_STACK_LOCATION thisSp = IoGetCurrentIrpStackLocation(Irp);
  574. /*
  575. * Make sure that the file object we are supplied has a
  576. * proper FsContext before we try doing a secured lock.
  577. */
  578. if (thisSp->FileObject){
  579. PCOMMON_DEVICE_EXTENSION commonExt = (PCOMMON_DEVICE_EXTENSION)fdoExt;
  580. fsContext = ClasspGetFsContext(commonExt, thisSp->FileObject);
  581. }
  582. else {
  583. fsContext = NULL;
  584. }
  585. if (!fsContext){
  586. ASSERT(fsContext);
  587. fileHandleOk = FALSE;
  588. }
  589. }
  590. if (fileHandleOk){
  591. /*
  592. * Adjust the lock counts and make sure they make sense.
  593. */
  594. status = STATUS_SUCCESS;
  595. if (Lock){
  596. switch(LockType) {
  597. case SimpleMediaLock:
  598. fdoExt->LockCount++;
  599. countChanged = TRUE;
  600. break;
  601. case SecureMediaLock:
  602. fsContext->LockCount++;
  603. fdoExt->ProtectedLockCount++;
  604. countChanged = TRUE;
  605. break;
  606. case InternalMediaLock:
  607. fdoExt->InternalLockCount++;
  608. countChanged = TRUE;
  609. break;
  610. }
  611. }
  612. else {
  613. /*
  614. * This is an unlock command. If it's a secured one then make sure
  615. * the caller has a lock outstanding or return an error.
  616. */
  617. switch (LockType){
  618. case SimpleMediaLock:
  619. if (fdoExt->LockCount > 0){
  620. fdoExt->LockCount--;
  621. countChanged = TRUE;
  622. }
  623. else {
  624. ASSERT(fdoExt->LockCount > 0);
  625. status = STATUS_INTERNAL_ERROR;
  626. }
  627. break;
  628. case SecureMediaLock:
  629. if (fsContext->LockCount > 0){
  630. ASSERT(fdoExt->ProtectedLockCount > 0);
  631. fsContext->LockCount--;
  632. fdoExt->ProtectedLockCount--;
  633. countChanged = TRUE;
  634. }
  635. else {
  636. ASSERT(fsContext->LockCount > 0);
  637. status = STATUS_INVALID_DEVICE_STATE;
  638. }
  639. break;
  640. case InternalMediaLock:
  641. ASSERT(fdoExt->InternalLockCount > 0);
  642. fdoExt->InternalLockCount--;
  643. countChanged = TRUE;
  644. break;
  645. }
  646. }
  647. if (NT_SUCCESS(status)){
  648. /*
  649. * We only send an unlock command to the drive if
  650. * all the lock counts have dropped to zero.
  651. */
  652. if (!Lock &&
  653. (fdoExt->ProtectedLockCount ||
  654. fdoExt->InternalLockCount ||
  655. fdoExt->LockCount)){
  656. /*
  657. * The lock count is still positive, so don't unlock yet.
  658. */
  659. status = STATUS_SUCCESS;
  660. }
  661. else if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) {
  662. /*
  663. * The device isn't removable media. don't send a cmd.
  664. */
  665. status = STATUS_SUCCESS;
  666. }
  667. else {
  668. TRANSFER_PACKET *pkt;
  669. pkt = DequeueFreeTransferPacket(Fdo, TRUE);
  670. if (pkt){
  671. KEVENT event;
  672. /*
  673. * Store the number of packets servicing the irp (one)
  674. * inside the original IRP. It will be used to counted down
  675. * to zero when the packet completes.
  676. * Initialize the original IRP's status to success.
  677. * If the packet fails, we will set it to the error status.
  678. */
  679. Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1);
  680. Irp->IoStatus.Status = STATUS_SUCCESS;
  681. /*
  682. * Set this up as a SYNCHRONOUS transfer, submit it,
  683. * and wait for the packet to complete. The result
  684. * status will be written to the original irp.
  685. */
  686. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  687. SetupEjectionTransferPacket(pkt, Lock, &event, Irp);
  688. SubmitTransferPacket(pkt);
  689. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  690. status = Irp->IoStatus.Status;
  691. }
  692. else {
  693. status = STATUS_INSUFFICIENT_RESOURCES;
  694. }
  695. }
  696. }
  697. }
  698. else {
  699. status = STATUS_INVALID_PARAMETER;
  700. }
  701. if (!NT_SUCCESS(status) && countChanged) {
  702. //
  703. // have to revert to previous counts if the
  704. // lock/unlock operation actually failed.
  705. //
  706. if(Lock) {
  707. switch(LockType) {
  708. case SimpleMediaLock: {
  709. FdoExtension->LockCount--;
  710. break;
  711. }
  712. case SecureMediaLock: {
  713. fsContext->LockCount--;
  714. FdoExtension->ProtectedLockCount--;
  715. break;
  716. }
  717. case InternalMediaLock: {
  718. FdoExtension->InternalLockCount--;
  719. break;
  720. }
  721. }
  722. } else {
  723. switch(LockType) {
  724. case SimpleMediaLock: {
  725. FdoExtension->LockCount++;
  726. break;
  727. }
  728. case SecureMediaLock: {
  729. fsContext->LockCount++;
  730. FdoExtension->ProtectedLockCount++;
  731. break;
  732. }
  733. case InternalMediaLock: {
  734. FdoExtension->InternalLockCount++;
  735. break;
  736. }
  737. }
  738. }
  739. }
  740. KeSetEvent(&fdoExt->EjectSynchronizationEvent, IO_NO_INCREMENT, FALSE);
  741. return status;
  742. }
  743. #endif
  744. PFILE_OBJECT_EXTENSION
  745. ClasspGetFsContext(
  746. IN PCOMMON_DEVICE_EXTENSION CommonExtension,
  747. IN PFILE_OBJECT FileObject
  748. )
  749. {
  750. PAGED_CODE();
  751. return GetDictionaryEntry(&(CommonExtension->FileObjectDictionary),
  752. (ULONGLONG) FileObject);
  753. }