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