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