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 */ 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 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 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 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 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 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 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