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