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