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 } 978