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 #include <stddef.h> 27 28 #include <initguid.h> 29 #include <mountdev.h> 30 31 #ifdef ALLOC_PRAGMA 32 #pragma alloc_text(INIT, DriverEntry) 33 #pragma alloc_text(PAGE, ClassAddDevice) 34 #pragma alloc_text(PAGE, ClassClaimDevice) 35 #pragma alloc_text(PAGE, ClassCreateDeviceObject) 36 #pragma alloc_text(PAGE, ClassDispatchPnp) 37 #pragma alloc_text(PAGE, ClassGetDescriptor) 38 #pragma alloc_text(PAGE, ClassGetPdoId) 39 #pragma alloc_text(PAGE, ClassInitialize) 40 #pragma alloc_text(PAGE, ClassInitializeEx) 41 #pragma alloc_text(PAGE, ClassInvalidateBusRelations) 42 #pragma alloc_text(PAGE, ClassMarkChildMissing) 43 #pragma alloc_text(PAGE, ClassMarkChildrenMissing) 44 #pragma alloc_text(PAGE, ClassModeSense) 45 #pragma alloc_text(PAGE, ClassPnpQueryFdoRelations) 46 #pragma alloc_text(PAGE, ClassPnpStartDevice) 47 #pragma alloc_text(PAGE, ClassQueryPnpCapabilities) 48 #pragma alloc_text(PAGE, ClassQueryTimeOutRegistryValue) 49 #pragma alloc_text(PAGE, ClassRemoveDevice) 50 #pragma alloc_text(PAGE, ClassRetrieveDeviceRelations) 51 #pragma alloc_text(PAGE, ClassUpdateInformationInRegistry) 52 #pragma alloc_text(PAGE, ClassSendDeviceIoControlSynchronous) 53 #pragma alloc_text(PAGE, ClassUnload) 54 #pragma alloc_text(PAGE, ClasspAllocateReleaseRequest) 55 #pragma alloc_text(PAGE, ClasspFreeReleaseRequest) 56 #pragma alloc_text(PAGE, ClasspInitializeHotplugInfo) 57 #pragma alloc_text(PAGE, ClasspRegisterMountedDeviceInterface) 58 #pragma alloc_text(PAGE, ClasspScanForClassHacks) 59 #pragma alloc_text(PAGE, ClasspScanForSpecialInRegistry) 60 #endif 61 62 ULONG ClassPnpAllowUnload = TRUE; 63 64 65 #define FirstDriveLetter 'C' 66 #define LastDriveLetter 'Z' 67 68 69 70 /*++//////////////////////////////////////////////////////////////////////////// 71 72 DriverEntry() 73 74 Routine Description: 75 76 Temporary entry point needed to initialize the class system dll. 77 It doesn't do anything. 78 79 Arguments: 80 81 DriverObject - Pointer to the driver object created by the system. 82 83 Return Value: 84 85 STATUS_SUCCESS 86 87 --*/ 88 NTSTATUS 89 NTAPI 90 DriverEntry( 91 IN PDRIVER_OBJECT DriverObject, 92 IN PUNICODE_STRING RegistryPath 93 ) 94 { 95 return STATUS_SUCCESS; 96 } 97 98 /*++//////////////////////////////////////////////////////////////////////////// 99 100 ClassInitialize() 101 102 Routine Description: 103 104 This routine is called by a class driver during its 105 DriverEntry routine to initialize the driver. 106 107 Arguments: 108 109 Argument1 - Driver Object. 110 Argument2 - Registry Path. 111 InitializationData - Device-specific driver's initialization data. 112 113 Return Value: 114 115 A valid return code for a DriverEntry routine. 116 117 --*/ 118 ULONG 119 NTAPI 120 ClassInitialize( 121 IN PVOID Argument1, 122 IN PVOID Argument2, 123 IN PCLASS_INIT_DATA InitializationData 124 ) 125 { 126 PDRIVER_OBJECT DriverObject = Argument1; 127 PUNICODE_STRING RegistryPath = Argument2; 128 129 PCLASS_DRIVER_EXTENSION driverExtension; 130 131 NTSTATUS status; 132 133 PAGED_CODE(); 134 135 DebugPrint((3,"\n\nSCSI Class Driver\n")); 136 137 ClasspInitializeDebugGlobals(); 138 139 // 140 // Validate the length of this structure. This is effectively a 141 // version check. 142 // 143 144 if (InitializationData->InitializationDataSize != sizeof(CLASS_INIT_DATA)) { 145 146 // 147 // This DebugPrint is to help third-party driver writers 148 // 149 150 DebugPrint((0,"ClassInitialize: Class driver wrong version\n")); 151 return (ULONG) STATUS_REVISION_MISMATCH; 152 } 153 154 // 155 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error 156 // are not required entry points. 157 // 158 159 if ((!InitializationData->FdoData.ClassDeviceControl) || 160 (!((InitializationData->FdoData.ClassReadWriteVerification) || 161 (InitializationData->ClassStartIo))) || 162 (!InitializationData->ClassAddDevice) || 163 (!InitializationData->FdoData.ClassStartDevice)) { 164 165 // 166 // This DebugPrint is to help third-party driver writers 167 // 168 169 DebugPrint((0, 170 "ClassInitialize: Class device-specific driver missing required " 171 "FDO entry\n")); 172 173 return (ULONG) STATUS_REVISION_MISMATCH; 174 } 175 176 if ((InitializationData->ClassEnumerateDevice) && 177 ((!InitializationData->PdoData.ClassDeviceControl) || 178 (!InitializationData->PdoData.ClassStartDevice) || 179 (!((InitializationData->PdoData.ClassReadWriteVerification) || 180 (InitializationData->ClassStartIo))))) { 181 182 // 183 // This DebugPrint is to help third-party driver writers 184 // 185 186 DebugPrint((0, "ClassInitialize: Class device-specific missing " 187 "required PDO entry\n")); 188 189 return (ULONG) STATUS_REVISION_MISMATCH; 190 } 191 192 if((InitializationData->FdoData.ClassStopDevice == NULL) || 193 ((InitializationData->ClassEnumerateDevice != NULL) && 194 (InitializationData->PdoData.ClassStopDevice == NULL))) { 195 196 // 197 // This DebugPrint is to help third-party driver writers 198 // 199 200 DebugPrint((0, "ClassInitialize: Class device-specific missing " 201 "required PDO entry\n")); 202 ASSERT(FALSE); 203 return (ULONG) STATUS_REVISION_MISMATCH; 204 } 205 206 // 207 // Setup the default power handlers if the class driver didn't provide 208 // any. 209 // 210 211 if(InitializationData->FdoData.ClassPowerDevice == NULL) { 212 InitializationData->FdoData.ClassPowerDevice = ClassMinimalPowerHandler; 213 } 214 215 if((InitializationData->ClassEnumerateDevice != NULL) && 216 (InitializationData->PdoData.ClassPowerDevice == NULL)) { 217 InitializationData->PdoData.ClassPowerDevice = ClassMinimalPowerHandler; 218 } 219 220 // 221 // warn that unload is not supported 222 // 223 // ISSUE-2000/02/03-peterwie 224 // We should think about making this a fatal error. 225 // 226 227 if(InitializationData->ClassUnload == NULL) { 228 229 // 230 // This DebugPrint is to help third-party driver writers 231 // 232 233 DebugPrint((0, "ClassInitialize: driver does not support unload %wZ\n", 234 RegistryPath)); 235 } 236 237 // 238 // Create an extension for the driver object 239 // 240 241 status = IoAllocateDriverObjectExtension(DriverObject, 242 CLASS_DRIVER_EXTENSION_KEY, 243 sizeof(CLASS_DRIVER_EXTENSION), 244 (PVOID *)&driverExtension); 245 246 if(NT_SUCCESS(status)) { 247 248 // 249 // Copy the registry path into the driver extension so we can use it later 250 // 251 252 driverExtension->RegistryPath.Length = RegistryPath->Length; 253 driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength; 254 255 driverExtension->RegistryPath.Buffer = 256 ExAllocatePoolWithTag(PagedPool, 257 RegistryPath->MaximumLength, 258 '1CcS'); 259 260 if(driverExtension->RegistryPath.Buffer == NULL) { 261 262 status = STATUS_INSUFFICIENT_RESOURCES; 263 return status; 264 } 265 266 RtlCopyUnicodeString( 267 &(driverExtension->RegistryPath), 268 RegistryPath); 269 270 // 271 // Copy the initialization data into the driver extension so we can reuse 272 // it during our add device routine 273 // 274 275 RtlCopyMemory( 276 &(driverExtension->InitData), 277 InitializationData, 278 sizeof(CLASS_INIT_DATA)); 279 280 driverExtension->DeviceCount = 0; 281 282 } else if (status == STATUS_OBJECT_NAME_COLLISION) { 283 284 // 285 // The extension already exists - get a pointer to it 286 // 287 288 driverExtension = IoGetDriverObjectExtension(DriverObject, 289 CLASS_DRIVER_EXTENSION_KEY); 290 291 ASSERT(driverExtension != NULL); 292 293 } else { 294 295 DebugPrint((1, "ClassInitialize: Class driver extension could not be " 296 "allocated %lx\n", status)); 297 return status; 298 } 299 300 // 301 // Update driver object with entry points. 302 // 303 304 DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassCreateClose; 305 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassCreateClose; 306 DriverObject->MajorFunction[IRP_MJ_READ] = ClassReadWrite; 307 DriverObject->MajorFunction[IRP_MJ_WRITE] = ClassReadWrite; 308 DriverObject->MajorFunction[IRP_MJ_SCSI] = ClassInternalIoControl; 309 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControlDispatch; 310 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ClassShutdownFlush; 311 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ClassShutdownFlush; 312 DriverObject->MajorFunction[IRP_MJ_PNP] = ClassDispatchPnp; 313 DriverObject->MajorFunction[IRP_MJ_POWER] = ClassDispatchPower; 314 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ClassSystemControl; 315 316 if (InitializationData->ClassStartIo) { 317 DriverObject->DriverStartIo = ClasspStartIo; 318 } 319 320 if ((InitializationData->ClassUnload) && (ClassPnpAllowUnload != FALSE)) { 321 DriverObject->DriverUnload = ClassUnload; 322 } else { 323 DriverObject->DriverUnload = NULL; 324 } 325 326 DriverObject->DriverExtension->AddDevice = ClassAddDevice; 327 328 DbgPrint("Driver is ready to go\n"); 329 status = STATUS_SUCCESS; 330 return status; 331 } // end ClassInitialize() 332 333 /*++//////////////////////////////////////////////////////////////////////////// 334 335 ClassInitializeEx() 336 337 Routine Description: 338 339 This routine is allows the caller to do any extra initialization or 340 setup that is not done in ClassInitialize. The operation is 341 controlled by the GUID that is passed and the contents of the Data 342 parameter is dependent upon the GUID. 343 344 This is the list of supported operations: 345 346 Guid - GUID_CLASSPNP_QUERY_REGINFOEX 347 Data - A PCLASS_QUERY_WMI_REGINFO_EX callback function pointer 348 349 Initialized classpnp to callback a PCLASS_QUERY_WMI_REGINFO_EX 350 callback instead of a PCLASS_QUERY_WMI_REGINFO callback. The 351 former callback allows the driver to specify the name of the 352 mof resource. 353 354 Arguments: 355 356 DriverObject 357 Guid 358 Data 359 360 Return Value: 361 362 Status Code 363 364 --*/ 365 ULONG 366 NTAPI 367 ClassInitializeEx( 368 IN PDRIVER_OBJECT DriverObject, 369 IN LPGUID Guid, 370 IN PVOID Data 371 ) 372 { 373 PCLASS_DRIVER_EXTENSION driverExtension; 374 375 NTSTATUS status; 376 377 PAGED_CODE(); 378 379 driverExtension = IoGetDriverObjectExtension( DriverObject, 380 CLASS_DRIVER_EXTENSION_KEY 381 ); 382 if (IsEqualGUID(Guid, &ClassGuidQueryRegInfoEx)) 383 { 384 PCLASS_QUERY_WMI_REGINFO_EX_LIST List; 385 386 // 387 // Indicate the device supports PCLASS_QUERY_REGINFO_EX 388 // callback instead of PCLASS_QUERY_REGINFO callback. 389 // 390 List = (PCLASS_QUERY_WMI_REGINFO_EX_LIST)Data; 391 392 if (List->Size == sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST)) 393 { 394 driverExtension->ClassFdoQueryWmiRegInfoEx = List->ClassFdoQueryWmiRegInfoEx; 395 driverExtension->ClassPdoQueryWmiRegInfoEx = List->ClassPdoQueryWmiRegInfoEx; 396 status = STATUS_SUCCESS; 397 } else { 398 status = STATUS_INVALID_PARAMETER; 399 } 400 } else { 401 status = STATUS_NOT_SUPPORTED; 402 } 403 404 return(status); 405 406 } // end ClassInitializeEx() 407 408 /*++//////////////////////////////////////////////////////////////////////////// 409 410 ClassUnload() 411 412 Routine Description: 413 414 called when there are no more references to the driver. this allows 415 drivers to be updated without rebooting. 416 417 Arguments: 418 419 DriverObject - a pointer to the driver object that is being unloaded 420 421 Status: 422 423 --*/ 424 VOID 425 NTAPI 426 ClassUnload( 427 IN PDRIVER_OBJECT DriverObject 428 ) 429 { 430 PCLASS_DRIVER_EXTENSION driverExtension; 431 //NTSTATUS status; 432 433 PAGED_CODE(); 434 435 ASSERT( DriverObject->DeviceObject == NULL ); 436 437 driverExtension = IoGetDriverObjectExtension( DriverObject, 438 CLASS_DRIVER_EXTENSION_KEY 439 ); 440 441 ASSERT(driverExtension != NULL); 442 ASSERT(driverExtension->RegistryPath.Buffer != NULL); 443 ASSERT(driverExtension->InitData.ClassUnload != NULL); 444 445 DebugPrint((1, "ClassUnload: driver unloading %wZ\n", 446 &driverExtension->RegistryPath)); 447 448 // 449 // attempt to process the driver's unload routine first. 450 // 451 452 driverExtension->InitData.ClassUnload(DriverObject); 453 454 // 455 // free own allocated resources and return 456 // 457 458 ExFreePool( driverExtension->RegistryPath.Buffer ); 459 driverExtension->RegistryPath.Buffer = NULL; 460 driverExtension->RegistryPath.Length = 0; 461 driverExtension->RegistryPath.MaximumLength = 0; 462 463 return; 464 } // end ClassUnload() 465 466 /*++//////////////////////////////////////////////////////////////////////////// 467 468 ClassAddDevice() 469 470 Routine Description: 471 472 SCSI class driver add device routine. This is called by pnp when a new 473 physical device come into being. 474 475 This routine will call out to the class driver to verify that it should 476 own this device then will create and attach a device object and then hand 477 it to the driver to initialize and create symbolic links 478 479 Arguments: 480 481 DriverObject - a pointer to the driver object that this is being created for 482 PhysicalDeviceObject - a pointer to the physical device object 483 484 Status: STATUS_NO_SUCH_DEVICE if the class driver did not want this device 485 STATUS_SUCCESS if the creation and attachment was successful 486 status of device creation and initialization 487 488 --*/ 489 NTSTATUS 490 NTAPI 491 ClassAddDevice( 492 IN PDRIVER_OBJECT DriverObject, 493 IN PDEVICE_OBJECT PhysicalDeviceObject 494 ) 495 { 496 PCLASS_DRIVER_EXTENSION driverExtension = 497 IoGetDriverObjectExtension(DriverObject, 498 CLASS_DRIVER_EXTENSION_KEY); 499 500 NTSTATUS status; 501 502 PAGED_CODE(); 503 504 DbgPrint("got a device\n"); 505 status = driverExtension->InitData.ClassAddDevice(DriverObject, 506 PhysicalDeviceObject); 507 return status; 508 } // end ClassAddDevice() 509 510 /*++//////////////////////////////////////////////////////////////////////////// 511 512 ClassDispatchPnp() 513 514 Routine Description: 515 516 Storage class driver pnp routine. This is called by the io system when 517 a PNP request is sent to the device. 518 519 Arguments: 520 521 DeviceObject - pointer to the device object 522 523 Irp - pointer to the io request packet 524 525 Return Value: 526 527 status 528 529 --*/ 530 NTSTATUS 531 NTAPI 532 ClassDispatchPnp( 533 IN PDEVICE_OBJECT DeviceObject, 534 IN PIRP Irp 535 ) 536 { 537 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 538 BOOLEAN isFdo = commonExtension->IsFdo; 539 540 PCLASS_DRIVER_EXTENSION driverExtension; 541 PCLASS_INIT_DATA initData; 542 PCLASS_DEV_INFO devInfo; 543 544 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 545 546 NTSTATUS status = Irp->IoStatus.Status; 547 BOOLEAN completeRequest = TRUE; 548 BOOLEAN lockReleased = FALSE; 549 550 PAGED_CODE(); 551 552 // 553 // Extract all the useful information out of the driver object 554 // extension 555 // 556 557 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, 558 CLASS_DRIVER_EXTENSION_KEY); 559 if (driverExtension){ 560 561 initData = &(driverExtension->InitData); 562 563 if(isFdo) { 564 devInfo = &(initData->FdoData); 565 } else { 566 devInfo = &(initData->PdoData); 567 } 568 569 ClassAcquireRemoveLock(DeviceObject, Irp); 570 571 DebugPrint((2, "ClassDispatchPnp (%p,%p): minor code %#x for %s %p\n", 572 DeviceObject, Irp, 573 irpStack->MinorFunction, 574 isFdo ? "fdo" : "pdo", 575 DeviceObject)); 576 DebugPrint((2, "ClassDispatchPnp (%p,%p): previous %#x, current %#x\n", 577 DeviceObject, Irp, 578 commonExtension->PreviousState, 579 commonExtension->CurrentState)); 580 581 switch(irpStack->MinorFunction) { 582 583 case IRP_MN_START_DEVICE: { 584 585 // 586 // if this is sent to the FDO we should forward it down the 587 // attachment chain before we start the FDO. 588 // 589 590 if (isFdo) { 591 status = ClassForwardIrpSynchronous(commonExtension, Irp); 592 } 593 else { 594 status = STATUS_SUCCESS; 595 } 596 597 if (NT_SUCCESS(status)){ 598 status = Irp->IoStatus.Status = ClassPnpStartDevice(DeviceObject); 599 } 600 601 break; 602 } 603 604 605 case IRP_MN_QUERY_DEVICE_RELATIONS: { 606 607 DEVICE_RELATION_TYPE type = 608 irpStack->Parameters.QueryDeviceRelations.Type; 609 610 PDEVICE_RELATIONS deviceRelations = NULL; 611 612 if(!isFdo) { 613 614 if(type == TargetDeviceRelation) { 615 616 // 617 // Device relations has one entry built in to it's size. 618 // 619 620 status = STATUS_INSUFFICIENT_RESOURCES; 621 622 deviceRelations = ExAllocatePoolWithTag(PagedPool, 623 sizeof(DEVICE_RELATIONS), 624 '2CcS'); 625 626 if(deviceRelations != NULL) { 627 628 RtlZeroMemory(deviceRelations, 629 sizeof(DEVICE_RELATIONS)); 630 631 Irp->IoStatus.Information = (ULONG_PTR) deviceRelations; 632 633 deviceRelations->Count = 1; 634 deviceRelations->Objects[0] = DeviceObject; 635 ObReferenceObject(deviceRelations->Objects[0]); 636 637 status = STATUS_SUCCESS; 638 } 639 640 } else { 641 // 642 // PDO's just complete enumeration requests without altering 643 // the status. 644 // 645 646 status = Irp->IoStatus.Status; 647 } 648 649 break; 650 651 } else if (type == BusRelations) { 652 653 ASSERT(commonExtension->IsInitialized); 654 655 // 656 // Make sure we support enumeration 657 // 658 659 if(initData->ClassEnumerateDevice == NULL) { 660 661 // 662 // Just send the request down to the lower driver. Perhaps 663 // It can enumerate children. 664 // 665 666 } else { 667 668 // 669 // Re-enumerate the device 670 // 671 672 status = ClassPnpQueryFdoRelations(DeviceObject, Irp); 673 674 if(!NT_SUCCESS(status)) { 675 completeRequest = TRUE; 676 break; 677 } 678 } 679 } 680 681 IoCopyCurrentIrpStackLocationToNext(Irp); 682 ClassReleaseRemoveLock(DeviceObject, Irp); 683 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 684 completeRequest = FALSE; 685 686 break; 687 } 688 689 case IRP_MN_QUERY_ID: { 690 691 BUS_QUERY_ID_TYPE idType = irpStack->Parameters.QueryId.IdType; 692 UNICODE_STRING unicodeString; 693 694 if(isFdo) { 695 696 // 697 // FDO's should just forward the query down to the lower 698 // device objects 699 // 700 701 IoCopyCurrentIrpStackLocationToNext(Irp); 702 ClassReleaseRemoveLock(DeviceObject, Irp); 703 704 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 705 completeRequest = FALSE; 706 break; 707 } 708 709 // 710 // PDO's need to give an answer - this is easy for now 711 // 712 713 RtlInitUnicodeString(&unicodeString, NULL); 714 715 status = ClassGetPdoId(DeviceObject, 716 idType, 717 &unicodeString); 718 719 if(status == STATUS_NOT_IMPLEMENTED) { 720 // 721 // The driver doesn't implement this ID (whatever it is). 722 // Use the status out of the IRP so that we don't mangle a 723 // response from someone else. 724 // 725 726 status = Irp->IoStatus.Status; 727 } else if(NT_SUCCESS(status)) { 728 Irp->IoStatus.Information = (ULONG_PTR) unicodeString.Buffer; 729 } else { 730 Irp->IoStatus.Information = (ULONG_PTR) NULL; 731 } 732 733 break; 734 } 735 736 case IRP_MN_QUERY_STOP_DEVICE: 737 case IRP_MN_QUERY_REMOVE_DEVICE: { 738 739 DebugPrint((2, "ClassDispatchPnp (%p,%p): Processing QUERY_%s irp\n", 740 DeviceObject, Irp, 741 ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ? 742 "STOP" : "REMOVE"))); 743 744 // 745 // If this device is in use for some reason (paging, etc...) 746 // then we need to fail the request. 747 // 748 749 if(commonExtension->PagingPathCount != 0) { 750 751 DebugPrint((1, "ClassDispatchPnp (%p,%p): device is in paging " 752 "path and cannot be removed\n", 753 DeviceObject, Irp)); 754 status = STATUS_DEVICE_BUSY; 755 break; 756 } 757 758 // 759 // Check with the class driver to see if the query operation 760 // can succeed. 761 // 762 763 if(irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) { 764 status = devInfo->ClassStopDevice(DeviceObject, 765 irpStack->MinorFunction); 766 } else { 767 status = devInfo->ClassRemoveDevice(DeviceObject, 768 irpStack->MinorFunction); 769 } 770 771 if(NT_SUCCESS(status)) { 772 773 // 774 // ASSERT that we never get two queries in a row, as 775 // this will severely mess up the state machine 776 // 777 ASSERT(commonExtension->CurrentState != irpStack->MinorFunction); 778 commonExtension->PreviousState = commonExtension->CurrentState; 779 commonExtension->CurrentState = irpStack->MinorFunction; 780 781 if(isFdo) { 782 DebugPrint((2, "ClassDispatchPnp (%p,%p): Forwarding QUERY_" 783 "%s irp\n", DeviceObject, Irp, 784 ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ? 785 "STOP" : "REMOVE"))); 786 status = ClassForwardIrpSynchronous(commonExtension, Irp); 787 } 788 } 789 DebugPrint((2, "ClassDispatchPnp (%p,%p): Final status == %x\n", 790 DeviceObject, Irp, status)); 791 792 break; 793 } 794 795 case IRP_MN_CANCEL_STOP_DEVICE: 796 case IRP_MN_CANCEL_REMOVE_DEVICE: { 797 798 // 799 // Check with the class driver to see if the query or cancel 800 // operation can succeed. 801 // 802 803 if(irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) { 804 status = devInfo->ClassStopDevice(DeviceObject, 805 irpStack->MinorFunction); 806 NT_ASSERTMSGW(L"ClassDispatchPnp !! CANCEL_STOP_DEVICE should " 807 L"never be failed\n", NT_SUCCESS(status)); 808 } else { 809 status = devInfo->ClassRemoveDevice(DeviceObject, 810 irpStack->MinorFunction); 811 NT_ASSERTMSGW(L"ClassDispatchPnp !! CANCEL_REMOVE_DEVICE should " 812 L"never be failed\n", NT_SUCCESS(status)); 813 } 814 815 Irp->IoStatus.Status = status; 816 817 // 818 // We got a CANCEL - roll back to the previous state only 819 // if the current state is the respective QUERY state. 820 // 821 822 if(((irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) && 823 (commonExtension->CurrentState == IRP_MN_QUERY_STOP_DEVICE) 824 ) || 825 ((irpStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE) && 826 (commonExtension->CurrentState == IRP_MN_QUERY_REMOVE_DEVICE) 827 ) 828 ) { 829 830 commonExtension->CurrentState = 831 commonExtension->PreviousState; 832 commonExtension->PreviousState = 0xff; 833 834 } 835 836 if(isFdo) { 837 IoCopyCurrentIrpStackLocationToNext(Irp); 838 ClassReleaseRemoveLock(DeviceObject, Irp); 839 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 840 completeRequest = FALSE; 841 } else { 842 status = STATUS_SUCCESS; 843 } 844 845 break; 846 } 847 848 case IRP_MN_STOP_DEVICE: { 849 850 // 851 // These all mean nothing to the class driver currently. The 852 // port driver will handle all queueing when necessary. 853 // 854 855 DebugPrint((2, "ClassDispatchPnp (%p,%p): got stop request for %s\n", 856 DeviceObject, Irp, 857 (isFdo ? "fdo" : "pdo") 858 )); 859 860 ASSERT(commonExtension->PagingPathCount == 0); 861 862 // 863 // ISSUE-2000/02/03-peterwie 864 // if we stop the timer here then it means no class driver can 865 // do i/o in its ClassStopDevice routine. This is because the 866 // retry (among other things) is tied into the tick handler 867 // and disabling retries could cause the class driver to deadlock. 868 // Currently no class driver we're aware of issues i/o in its 869 // Stop routine but this is a case we may want to defend ourself 870 // against. 871 // 872 873 if (DeviceObject->Timer) { 874 IoStopTimer(DeviceObject); 875 } 876 877 status = devInfo->ClassStopDevice(DeviceObject, IRP_MN_STOP_DEVICE); 878 879 NT_ASSERTMSGW(L"ClassDispatchPnp !! STOP_DEVICE should " 880 L"never be failed\n", NT_SUCCESS(status)); 881 882 if(isFdo) { 883 status = ClassForwardIrpSynchronous(commonExtension, Irp); 884 } 885 886 if(NT_SUCCESS(status)) { 887 commonExtension->CurrentState = irpStack->MinorFunction; 888 commonExtension->PreviousState = 0xff; 889 } 890 891 break; 892 } 893 894 case IRP_MN_REMOVE_DEVICE: 895 case IRP_MN_SURPRISE_REMOVAL: { 896 897 UCHAR removeType = irpStack->MinorFunction; 898 899 if (commonExtension->PagingPathCount != 0) { 900 DBGTRACE(ClassDebugWarning, ("ClassDispatchPnp (%p,%p): paging device is getting removed!", DeviceObject, Irp)); 901 } 902 903 // 904 // Release the lock for this IRP before calling in. 905 // 906 ClassReleaseRemoveLock(DeviceObject, Irp); 907 lockReleased = TRUE; 908 909 /* 910 * If a timer was started on the device, stop it. 911 */ 912 if (DeviceObject->Timer) { 913 IoStopTimer(DeviceObject); 914 } 915 916 /* 917 * "Fire-and-forget" the remove irp to the lower stack. 918 * Don't touch the irp (or the irp stack!) after this. 919 */ 920 if (isFdo) { 921 IoCopyCurrentIrpStackLocationToNext(Irp); 922 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 923 ASSERT(NT_SUCCESS(status)); 924 completeRequest = FALSE; 925 } 926 else { 927 status = STATUS_SUCCESS; 928 } 929 930 /* 931 * Do our own cleanup and call the class driver's remove 932 * cleanup routine. 933 * For IRP_MN_REMOVE_DEVICE, this also deletes our device object, 934 * so don't touch the extension after this. 935 */ 936 commonExtension->PreviousState = commonExtension->CurrentState; 937 commonExtension->CurrentState = removeType; 938 ClassRemoveDevice(DeviceObject, removeType); 939 940 break; 941 } 942 943 case IRP_MN_DEVICE_USAGE_NOTIFICATION: { 944 945 switch(irpStack->Parameters.UsageNotification.Type) { 946 947 case DeviceUsageTypePaging: { 948 949 BOOLEAN setPagable; 950 951 if((irpStack->Parameters.UsageNotification.InPath) && 952 (commonExtension->CurrentState != IRP_MN_START_DEVICE)) { 953 954 // 955 // Device isn't started. Don't allow adding a 956 // paging file, but allow a removal of one. 957 // 958 959 status = STATUS_DEVICE_NOT_READY; 960 break; 961 } 962 963 ASSERT(commonExtension->IsInitialized); 964 965 // 966 // need to synchronize this now... 967 // 968 969 KeEnterCriticalRegion(); 970 status = KeWaitForSingleObject(&commonExtension->PathCountEvent, 971 Executive, KernelMode, 972 FALSE, NULL); 973 ASSERT(NT_SUCCESS(status)); 974 status = STATUS_SUCCESS; 975 976 // 977 // If the volume is removable we should try to lock it in 978 // place or unlock it once per paging path count 979 // 980 981 if (commonExtension->IsFdo){ 982 status = ClasspEjectionControl( 983 DeviceObject, 984 Irp, 985 InternalMediaLock, 986 (BOOLEAN)irpStack->Parameters.UsageNotification.InPath); 987 } 988 989 if (!NT_SUCCESS(status)){ 990 KeSetEvent(&commonExtension->PathCountEvent, IO_NO_INCREMENT, FALSE); 991 KeLeaveCriticalRegion(); 992 break; 993 } 994 995 // 996 // if removing last paging device, need to set DO_POWER_PAGABLE 997 // bit here, and possible re-set it below on failure. 998 // 999 1000 setPagable = FALSE; 1001 1002 if (!irpStack->Parameters.UsageNotification.InPath && 1003 commonExtension->PagingPathCount == 1 1004 ) { 1005 1006 // 1007 // removing last paging file 1008 // must have DO_POWER_PAGABLE bits set, but only 1009 // if noone set the DO_POWER_INRUSH bit 1010 // 1011 1012 1013 if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) { 1014 DebugPrint((2, "ClassDispatchPnp (%p,%p): Last " 1015 "paging file removed, but " 1016 "DO_POWER_INRUSH was set, so NOT " 1017 "setting DO_POWER_PAGABLE\n", 1018 DeviceObject, Irp)); 1019 } else { 1020 DebugPrint((2, "ClassDispatchPnp (%p,%p): Last " 1021 "paging file removed, " 1022 "setting DO_POWER_PAGABLE\n", 1023 DeviceObject, Irp)); 1024 SET_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 1025 setPagable = TRUE; 1026 } 1027 1028 } 1029 1030 // 1031 // forward the irp before finishing handling the 1032 // special cases 1033 // 1034 1035 status = ClassForwardIrpSynchronous(commonExtension, Irp); 1036 1037 // 1038 // now deal with the failure and success cases. 1039 // note that we are not allowed to fail the irp 1040 // once it is sent to the lower drivers. 1041 // 1042 1043 if (NT_SUCCESS(status)) { 1044 1045 IoAdjustPagingPathCount( 1046 (PLONG)&commonExtension->PagingPathCount, 1047 irpStack->Parameters.UsageNotification.InPath); 1048 1049 if (irpStack->Parameters.UsageNotification.InPath) { 1050 if (commonExtension->PagingPathCount == 1) { 1051 DebugPrint((2, "ClassDispatchPnp (%p,%p): " 1052 "Clearing PAGABLE bit\n", 1053 DeviceObject, Irp)); 1054 CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 1055 } 1056 } 1057 1058 } else { 1059 1060 // 1061 // cleanup the changes done above 1062 // 1063 1064 if (setPagable != FALSE) { 1065 DebugPrint((2, "ClassDispatchPnp (%p,%p): Unsetting " 1066 "PAGABLE bit due to irp failure\n", 1067 DeviceObject, Irp)); 1068 CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 1069 setPagable = FALSE; 1070 } 1071 1072 // 1073 // relock or unlock the media if needed. 1074 // 1075 1076 if (commonExtension->IsFdo) { 1077 1078 ClasspEjectionControl( 1079 DeviceObject, 1080 Irp, 1081 InternalMediaLock, 1082 (BOOLEAN)!irpStack->Parameters.UsageNotification.InPath); 1083 } 1084 } 1085 1086 // 1087 // set the event so the next one can occur. 1088 // 1089 1090 KeSetEvent(&commonExtension->PathCountEvent, 1091 IO_NO_INCREMENT, FALSE); 1092 KeLeaveCriticalRegion(); 1093 break; 1094 } 1095 1096 case DeviceUsageTypeHibernation: { 1097 1098 IoAdjustPagingPathCount( 1099 (PLONG)&commonExtension->HibernationPathCount, 1100 irpStack->Parameters.UsageNotification.InPath 1101 ); 1102 status = ClassForwardIrpSynchronous(commonExtension, Irp); 1103 if (!NT_SUCCESS(status)) { 1104 IoAdjustPagingPathCount( 1105 (PLONG)&commonExtension->HibernationPathCount, 1106 !irpStack->Parameters.UsageNotification.InPath 1107 ); 1108 } 1109 1110 break; 1111 } 1112 1113 case DeviceUsageTypeDumpFile: { 1114 IoAdjustPagingPathCount( 1115 (PLONG)&commonExtension->DumpPathCount, 1116 irpStack->Parameters.UsageNotification.InPath 1117 ); 1118 status = ClassForwardIrpSynchronous(commonExtension, Irp); 1119 if (!NT_SUCCESS(status)) { 1120 IoAdjustPagingPathCount( 1121 (PLONG)&commonExtension->DumpPathCount, 1122 !irpStack->Parameters.UsageNotification.InPath 1123 ); 1124 } 1125 1126 break; 1127 } 1128 1129 default: { 1130 status = STATUS_INVALID_PARAMETER; 1131 break; 1132 } 1133 } 1134 break; 1135 } 1136 1137 case IRP_MN_QUERY_CAPABILITIES: { 1138 1139 DebugPrint((2, "ClassDispatchPnp (%p,%p): QueryCapabilities\n", 1140 DeviceObject, Irp)); 1141 1142 if(!isFdo) { 1143 1144 status = ClassQueryPnpCapabilities( 1145 DeviceObject, 1146 irpStack->Parameters.DeviceCapabilities.Capabilities 1147 ); 1148 1149 break; 1150 1151 } else { 1152 1153 PDEVICE_CAPABILITIES deviceCapabilities; 1154 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 1155 PCLASS_PRIVATE_FDO_DATA fdoData; 1156 1157 fdoExtension = DeviceObject->DeviceExtension; 1158 fdoData = fdoExtension->PrivateFdoData; 1159 deviceCapabilities = 1160 irpStack->Parameters.DeviceCapabilities.Capabilities; 1161 1162 // 1163 // forward the irp before handling the special cases 1164 // 1165 1166 status = ClassForwardIrpSynchronous(commonExtension, Irp); 1167 if (!NT_SUCCESS(status)) { 1168 break; 1169 } 1170 1171 // 1172 // we generally want to remove the device from the hotplug 1173 // applet, which requires the SR-OK bit to be set. 1174 // only when the user specifies that they are capable of 1175 // safely removing things do we want to clear this bit 1176 // (saved in WriteCacheEnableOverride) 1177 // 1178 // setting of this bit is done either above, or by the 1179 // lower driver. 1180 // 1181 // note: may not be started, so check we have FDO data first. 1182 // 1183 1184 if (fdoData && 1185 fdoData->HotplugInfo.WriteCacheEnableOverride) { 1186 if (deviceCapabilities->SurpriseRemovalOK) { 1187 DebugPrint((1, "Classpnp: Clearing SR-OK bit in " 1188 "device capabilities due to hotplug " 1189 "device or media\n")); 1190 } 1191 deviceCapabilities->SurpriseRemovalOK = FALSE; 1192 } 1193 break; 1194 1195 } // end QUERY_CAPABILITIES for FDOs 1196 1197 ASSERT(FALSE); 1198 break; 1199 1200 1201 } // end QUERY_CAPABILITIES 1202 1203 default: { 1204 1205 if (isFdo){ 1206 IoCopyCurrentIrpStackLocationToNext(Irp); 1207 1208 ClassReleaseRemoveLock(DeviceObject, Irp); 1209 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 1210 1211 completeRequest = FALSE; 1212 } 1213 1214 break; 1215 } 1216 } 1217 } 1218 else { 1219 ASSERT(driverExtension); 1220 status = STATUS_INTERNAL_ERROR; 1221 } 1222 1223 if (completeRequest){ 1224 Irp->IoStatus.Status = status; 1225 1226 if (!lockReleased){ 1227 ClassReleaseRemoveLock(DeviceObject, Irp); 1228 } 1229 1230 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 1231 1232 DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving with previous %#x, current %#x.", DeviceObject, Irp, commonExtension->PreviousState, commonExtension->CurrentState)); 1233 } 1234 else { 1235 /* 1236 * The irp is already completed so don't touch it. 1237 * This may be a remove so don't touch the device extension. 1238 */ 1239 DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving.", DeviceObject, Irp)); 1240 } 1241 1242 return status; 1243 } // end ClassDispatchPnp() 1244 1245 /*++//////////////////////////////////////////////////////////////////////////// 1246 1247 ClassPnpStartDevice() 1248 1249 Routine Description: 1250 1251 Storage class driver routine for IRP_MN_START_DEVICE requests. 1252 This routine kicks off any device specific initialization 1253 1254 Arguments: 1255 1256 DeviceObject - a pointer to the device object 1257 1258 Irp - a pointer to the io request packet 1259 1260 Return Value: 1261 1262 none 1263 1264 --*/ 1265 NTSTATUS NTAPI ClassPnpStartDevice(IN PDEVICE_OBJECT DeviceObject) 1266 { 1267 PCLASS_DRIVER_EXTENSION driverExtension; 1268 PCLASS_INIT_DATA initData; 1269 1270 PCLASS_DEV_INFO devInfo; 1271 1272 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 1273 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 1274 BOOLEAN isFdo = commonExtension->IsFdo; 1275 1276 BOOLEAN isMountedDevice = TRUE; 1277 //UNICODE_STRING interfaceName; 1278 1279 BOOLEAN timerStarted; 1280 1281 NTSTATUS status = STATUS_SUCCESS; 1282 1283 PAGED_CODE(); 1284 1285 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, 1286 CLASS_DRIVER_EXTENSION_KEY); 1287 1288 initData = &(driverExtension->InitData); 1289 if(isFdo) { 1290 devInfo = &(initData->FdoData); 1291 } else { 1292 devInfo = &(initData->PdoData); 1293 } 1294 1295 ASSERT(devInfo->ClassInitDevice != NULL); 1296 ASSERT(devInfo->ClassStartDevice != NULL); 1297 1298 if (!commonExtension->IsInitialized){ 1299 1300 // 1301 // perform FDO/PDO specific initialization 1302 // 1303 1304 if (isFdo){ 1305 STORAGE_PROPERTY_ID propertyId; 1306 1307 // 1308 // allocate a private extension for class data 1309 // 1310 1311 if (fdoExtension->PrivateFdoData == NULL) { 1312 fdoExtension->PrivateFdoData = 1313 ExAllocatePoolWithTag(NonPagedPool, 1314 sizeof(CLASS_PRIVATE_FDO_DATA), 1315 CLASS_TAG_PRIVATE_DATA 1316 ); 1317 } 1318 1319 if (fdoExtension->PrivateFdoData == NULL) { 1320 DebugPrint((0, "ClassPnpStartDevice: Cannot allocate for " 1321 "private fdo data\n")); 1322 return STATUS_INSUFFICIENT_RESOURCES; 1323 } 1324 1325 // 1326 // initialize the struct's various fields. 1327 // 1328 1329 RtlZeroMemory(fdoExtension->PrivateFdoData, 1330 sizeof(CLASS_PRIVATE_FDO_DATA) 1331 ); 1332 KeInitializeTimer(&fdoExtension->PrivateFdoData->Retry.Timer); 1333 KeInitializeDpc(&fdoExtension->PrivateFdoData->Retry.Dpc, 1334 ClasspRetryRequestDpc, 1335 DeviceObject); 1336 KeInitializeSpinLock(&fdoExtension->PrivateFdoData->Retry.Lock); 1337 fdoExtension->PrivateFdoData->Retry.Granularity = 1338 KeQueryTimeIncrement(); 1339 commonExtension->Reserved4 = (ULONG_PTR)(' GPH'); // debug aid 1340 1341 // 1342 // NOTE: the old interface allowed the class driver to allocate 1343 // this. this was unsafe for low-memory conditions. allocate one 1344 // unconditionally now, and modify our internal functions to use 1345 // our own exclusively as it is the only safe way to do this. 1346 // 1347 1348 status = ClasspAllocateReleaseQueueIrp(fdoExtension); 1349 if (!NT_SUCCESS(status)) { 1350 DebugPrint((0, "ClassPnpStartDevice: Cannot allocate the " 1351 "private release queue irp\n")); 1352 return status; 1353 } 1354 1355 // 1356 // Call port driver to get adapter capabilities. 1357 // 1358 1359 propertyId = StorageAdapterProperty; 1360 1361 status = ClassGetDescriptor( 1362 commonExtension->LowerDeviceObject, 1363 &propertyId, 1364 (PSTORAGE_DESCRIPTOR_HEADER *)&fdoExtension->AdapterDescriptor); 1365 1366 if(!NT_SUCCESS(status)) { 1367 1368 // 1369 // This DebugPrint is to help third-party driver writers 1370 // 1371 1372 DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor " 1373 "[ADAPTER] failed %lx\n", status)); 1374 return status; 1375 } 1376 1377 // 1378 // Call port driver to get device descriptor. 1379 // 1380 1381 propertyId = StorageDeviceProperty; 1382 1383 status = ClassGetDescriptor( 1384 commonExtension->LowerDeviceObject, 1385 &propertyId, 1386 (PSTORAGE_DESCRIPTOR_HEADER *)&fdoExtension->DeviceDescriptor); 1387 1388 if(!NT_SUCCESS(status)) { 1389 1390 // 1391 // This DebugPrint is to help third-party driver writers 1392 // 1393 1394 DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor " 1395 "[DEVICE] failed %lx\n", status)); 1396 return status; 1397 } 1398 1399 ClasspScanForSpecialInRegistry(fdoExtension); 1400 ClassScanForSpecial(fdoExtension, 1401 ClassBadItems, 1402 ClasspScanForClassHacks); 1403 1404 // 1405 // allow perf to be re-enabled after a given number of failed IOs 1406 // require this number to be at least CLASS_PERF_RESTORE_MINIMUM 1407 // 1408 1409 { 1410 ULONG t = 0; 1411 ClassGetDeviceParameter(fdoExtension, 1412 CLASSP_REG_SUBKEY_NAME, 1413 CLASSP_REG_PERF_RESTORE_VALUE_NAME, 1414 &t); 1415 if (t >= CLASS_PERF_RESTORE_MINIMUM) { 1416 fdoExtension->PrivateFdoData->Perf.ReEnableThreshold = t; 1417 } 1418 } 1419 1420 1421 // 1422 // compatibility comes first. writable cd media will not 1423 // get a SYNCH_CACHE on power down. 1424 // 1425 1426 if (fdoExtension->DeviceObject->DeviceType != FILE_DEVICE_DISK) { 1427 SET_FLAG(fdoExtension->PrivateFdoData->HackFlags, 1428 FDO_HACK_NO_SYNC_CACHE); 1429 } 1430 1431 // 1432 // initialize the hotplug information only after the ScanForSpecial 1433 // routines, as it relies upon the hack flags. 1434 // 1435 1436 status = ClasspInitializeHotplugInfo(fdoExtension); 1437 1438 if (!NT_SUCCESS(status)) { 1439 DebugPrint((1, "ClassPnpStartDevice: Could not initialize " 1440 "hotplug information %lx\n", status)); 1441 return status; 1442 } 1443 1444 /* 1445 * Allocate/initialize TRANSFER_PACKETs and related resources. 1446 */ 1447 status = InitializeTransferPackets(DeviceObject); 1448 } 1449 1450 // 1451 // ISSUE - drivers need to disable write caching on the media 1452 // if hotplug and !useroverride. perhaps we should 1453 // allow registration of a callback to enable/disable 1454 // write cache instead. 1455 // 1456 1457 if (NT_SUCCESS(status)){ 1458 status = devInfo->ClassInitDevice(DeviceObject); 1459 } 1460 1461 } 1462 1463 if (!NT_SUCCESS(status)){ 1464 1465 // 1466 // Just bail out - the remove that comes down will clean up the 1467 // initialized scraps. 1468 // 1469 1470 return status; 1471 } else { 1472 commonExtension->IsInitialized = TRUE; 1473 1474 if (commonExtension->IsFdo) { 1475 fdoExtension->PrivateFdoData->Perf.OriginalSrbFlags = fdoExtension->SrbFlags; 1476 } 1477 1478 } 1479 1480 // 1481 // If device requests autorun functionality or a once a second callback 1482 // then enable the once per second timer. 1483 // 1484 // NOTE: This assumes that ClassInitializeMediaChangeDetection is always 1485 // called in the context of the ClassInitDevice callback. If called 1486 // after then this check will have already been made and the 1487 // once a second timer will not have been enabled. 1488 // 1489 if ((isFdo) && 1490 ((initData->ClassTick != NULL) || 1491 (fdoExtension->MediaChangeDetectionInfo != NULL) || 1492 ((fdoExtension->FailurePredictionInfo != NULL) && 1493 (fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone)))) 1494 { 1495 ClasspEnableTimer(DeviceObject); 1496 timerStarted = TRUE; 1497 } else { 1498 timerStarted = FALSE; 1499 } 1500 1501 // 1502 // NOTE: the timer looks at commonExtension->CurrentState now 1503 // to prevent Media Change Notification code from running 1504 // until the device is started, but allows the device 1505 // specific tick handler to run. therefore it is imperative 1506 // that commonExtension->CurrentState not be updated until 1507 // the device specific startdevice handler has finished. 1508 // 1509 1510 status = devInfo->ClassStartDevice(DeviceObject); 1511 1512 if(NT_SUCCESS(status)) { 1513 commonExtension->CurrentState = IRP_MN_START_DEVICE; 1514 1515 if((isFdo) && (initData->ClassEnumerateDevice != NULL)) { 1516 isMountedDevice = FALSE; 1517 } 1518 1519 if((DeviceObject->DeviceType != FILE_DEVICE_DISK) && 1520 (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)) { 1521 1522 isMountedDevice = FALSE; 1523 } 1524 1525 1526 if(isMountedDevice) { 1527 ClasspRegisterMountedDeviceInterface(DeviceObject); 1528 } 1529 1530 if((commonExtension->IsFdo) && 1531 (devInfo->ClassWmiInfo.GuidRegInfo != NULL)) { 1532 1533 IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_REGISTER); 1534 } 1535 } else { 1536 1537 if (timerStarted) { 1538 ClasspDisableTimer(DeviceObject); 1539 } 1540 } 1541 1542 return status; 1543 } 1544 1545 1546 /*++//////////////////////////////////////////////////////////////////////////// 1547 1548 ClassReadWrite() 1549 1550 Routine Description: 1551 1552 This is the system entry point for read and write requests. The 1553 device-specific handler is invoked to perform any validation necessary. 1554 1555 If the device object is a PDO (partition object) then the request will 1556 simply be adjusted for Partition0 and issued to the lower device driver. 1557 1558 IF the device object is an FDO (partition 0 object), the number of bytes 1559 in the request are checked against the maximum byte counts that the adapter 1560 supports and requests are broken up into 1561 smaller sizes if necessary. 1562 1563 Arguments: 1564 1565 DeviceObject - a pointer to the device object for this request 1566 1567 Irp - IO request 1568 1569 Return Value: 1570 1571 NT Status 1572 1573 --*/ 1574 NTSTATUS NTAPI ClassReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 1575 { 1576 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 1577 PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject; 1578 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 1579 //LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset; 1580 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; 1581 ULONG isRemoved; 1582 NTSTATUS status; 1583 1584 /* 1585 * Grab the remove lock. If we can't acquire it, bail out. 1586 */ 1587 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 1588 if (isRemoved) { 1589 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 1590 ClassReleaseRemoveLock(DeviceObject, Irp); 1591 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 1592 status = STATUS_DEVICE_DOES_NOT_EXIST; 1593 } 1594 else if (TEST_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME) && 1595 (currentIrpStack->MinorFunction != CLASSP_VOLUME_VERIFY_CHECKED) && 1596 !TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)){ 1597 1598 /* 1599 * DO_VERIFY_VOLUME is set for the device object, 1600 * but this request is not itself a verify request. 1601 * So fail this request. 1602 */ 1603 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 1604 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED; 1605 Irp->IoStatus.Information = 0; 1606 ClassReleaseRemoveLock(DeviceObject, Irp); 1607 ClassCompleteRequest(DeviceObject, Irp, 0); 1608 status = STATUS_VERIFY_REQUIRED; 1609 } 1610 else { 1611 1612 /* 1613 * Since we've bypassed the verify-required tests we don't need to repeat 1614 * them with this IRP - in particular we don't want to worry about 1615 * hitting them at the partition 0 level if the request has come through 1616 * a non-zero partition. 1617 */ 1618 currentIrpStack->MinorFunction = CLASSP_VOLUME_VERIFY_CHECKED; 1619 1620 /* 1621 * Call the miniport driver's pre-pass filter to check if we 1622 * should continue with this transfer. 1623 */ 1624 ASSERT(commonExtension->DevInfo->ClassReadWriteVerification); 1625 status = commonExtension->DevInfo->ClassReadWriteVerification(DeviceObject, Irp); 1626 if (!NT_SUCCESS(status)){ 1627 ASSERT(Irp->IoStatus.Status == status); 1628 ClassReleaseRemoveLock(DeviceObject, Irp); 1629 ClassCompleteRequest (DeviceObject, Irp, IO_NO_INCREMENT); 1630 } 1631 else if (status == STATUS_PENDING){ 1632 /* 1633 * ClassReadWriteVerification queued this request. 1634 * So don't touch the irp anymore. 1635 */ 1636 } 1637 else { 1638 1639 if (transferByteCount == 0) { 1640 /* 1641 * Several parts of the code turn 0 into 0xffffffff, 1642 * so don't process a zero-length request any further. 1643 */ 1644 Irp->IoStatus.Status = STATUS_SUCCESS; 1645 Irp->IoStatus.Information = 0; 1646 ClassReleaseRemoveLock(DeviceObject, Irp); 1647 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 1648 status = STATUS_SUCCESS; 1649 } 1650 else { 1651 /* 1652 * If the driver has its own StartIo routine, call it. 1653 */ 1654 if (commonExtension->DriverExtension->InitData.ClassStartIo) { 1655 IoMarkIrpPending(Irp); 1656 IoStartPacket(DeviceObject, Irp, NULL, NULL); 1657 status = STATUS_PENDING; 1658 } 1659 else { 1660 /* 1661 * The driver does not have its own StartIo routine. 1662 * So process this request ourselves. 1663 */ 1664 1665 /* 1666 * Add partition byte offset to make starting byte relative to 1667 * beginning of disk. 1668 */ 1669 currentIrpStack->Parameters.Read.ByteOffset.QuadPart += 1670 commonExtension->StartingOffset.QuadPart; 1671 1672 if (commonExtension->IsFdo){ 1673 1674 /* 1675 * Add in any skew for the disk manager software. 1676 */ 1677 currentIrpStack->Parameters.Read.ByteOffset.QuadPart += 1678 commonExtension->PartitionZeroExtension->DMByteSkew; 1679 1680 /* 1681 * Perform the actual transfer(s) on the hardware 1682 * to service this request. 1683 */ 1684 ServiceTransferRequest(DeviceObject, Irp); 1685 status = STATUS_PENDING; 1686 } 1687 else { 1688 /* 1689 * This is a child PDO enumerated for our FDO by e.g. disk.sys 1690 * and owned by e.g. partmgr. Send it down to the next device 1691 * and the same irp will come back to us for the FDO. 1692 */ 1693 IoCopyCurrentIrpStackLocationToNext(Irp); 1694 ClassReleaseRemoveLock(DeviceObject, Irp); 1695 status = IoCallDriver(lowerDeviceObject, Irp); 1696 } 1697 } 1698 } 1699 } 1700 } 1701 1702 return status; 1703 } 1704 1705 1706 /*++//////////////////////////////////////////////////////////////////////////// 1707 1708 ClassReadDriveCapacity() 1709 1710 Routine Description: 1711 1712 This routine sends a READ CAPACITY to the requested device, updates 1713 the geometry information in the device object and returns 1714 when it is complete. This routine is synchronous. 1715 1716 This routine must be called with the remove lock held or some other 1717 assurance that the Fdo will not be removed while processing. 1718 1719 Arguments: 1720 1721 DeviceObject - Supplies a pointer to the device object that represents 1722 the device whose capacity is to be read. 1723 1724 Return Value: 1725 1726 Status is returned. 1727 1728 --*/ 1729 NTSTATUS NTAPI ClassReadDriveCapacity(IN PDEVICE_OBJECT Fdo) 1730 { 1731 READ_CAPACITY_DATA readCapacityBuffer = {0}; 1732 NTSTATUS status; 1733 PMDL driveCapMdl; 1734 1735 driveCapMdl = BuildDeviceInputMdl(&readCapacityBuffer, sizeof(READ_CAPACITY_DATA)); 1736 if (driveCapMdl){ 1737 1738 TRANSFER_PACKET *pkt = DequeueFreeTransferPacket(Fdo, TRUE); 1739 if (pkt){ 1740 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 1741 KEVENT event; 1742 //NTSTATUS pktStatus; 1743 IRP pseudoIrp = {0}; 1744 1745 /* 1746 * Our engine needs an "original irp" to write the status back to 1747 * and to count down packets (one in this case). 1748 * Just use a pretend irp for this. 1749 */ 1750 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1); 1751 pseudoIrp.IoStatus.Status = STATUS_SUCCESS; 1752 pseudoIrp.IoStatus.Information = 0; 1753 pseudoIrp.MdlAddress = driveCapMdl; 1754 1755 /* 1756 * Set this up as a SYNCHRONOUS transfer, submit it, 1757 * and wait for the packet to complete. The result 1758 * status will be written to the original irp. 1759 */ 1760 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 1761 SetupDriveCapacityTransferPacket( pkt, 1762 &readCapacityBuffer, 1763 sizeof(READ_CAPACITY_DATA), 1764 &event, 1765 &pseudoIrp); 1766 SubmitTransferPacket(pkt); 1767 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 1768 1769 status = pseudoIrp.IoStatus.Status; 1770 1771 /* 1772 * If we got an UNDERRUN, retry exactly once. 1773 * (The transfer_packet engine didn't retry because the result 1774 * status was success). 1775 */ 1776 if (NT_SUCCESS(status) && 1777 (pseudoIrp.IoStatus.Information < sizeof(READ_CAPACITY_DATA))){ 1778 DBGERR(("ClassReadDriveCapacity: read len (%xh) < %xh, retrying ...", (ULONG)pseudoIrp.IoStatus.Information, sizeof(READ_CAPACITY_DATA))); 1779 1780 pkt = DequeueFreeTransferPacket(Fdo, TRUE); 1781 if (pkt){ 1782 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1); 1783 pseudoIrp.IoStatus.Status = STATUS_SUCCESS; 1784 pseudoIrp.IoStatus.Information = 0; 1785 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 1786 SetupDriveCapacityTransferPacket( pkt, 1787 &readCapacityBuffer, 1788 sizeof(READ_CAPACITY_DATA), 1789 &event, 1790 &pseudoIrp); 1791 SubmitTransferPacket(pkt); 1792 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 1793 status = pseudoIrp.IoStatus.Status; 1794 if (pseudoIrp.IoStatus.Information < sizeof(READ_CAPACITY_DATA)){ 1795 status = STATUS_DEVICE_BUSY; 1796 } 1797 } 1798 else { 1799 status = STATUS_INSUFFICIENT_RESOURCES; 1800 } 1801 } 1802 1803 1804 if (NT_SUCCESS(status)){ 1805 /* 1806 * The request succeeded. 1807 * Read out and store the drive information. 1808 */ 1809 ULONG cylinderSize; 1810 ULONG bytesPerSector; 1811 ULONG tmp; 1812 ULONG lastSector; 1813 1814 /* 1815 * Read the bytesPerSector value, 1816 * which is big-endian in the returned buffer. 1817 * Default to the standard 512 bytes. 1818 */ 1819 tmp = readCapacityBuffer.BytesPerBlock; 1820 ((PFOUR_BYTE)&bytesPerSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3; 1821 ((PFOUR_BYTE)&bytesPerSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2; 1822 ((PFOUR_BYTE)&bytesPerSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1; 1823 ((PFOUR_BYTE)&bytesPerSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0; 1824 if (bytesPerSector == 0) { 1825 bytesPerSector = 512; 1826 } 1827 else { 1828 /* 1829 * Clear all but the highest set bit. 1830 * That will give us a bytesPerSector value that is a power of 2. 1831 */ 1832 while (bytesPerSector & (bytesPerSector-1)) { 1833 bytesPerSector &= bytesPerSector-1; 1834 } 1835 } 1836 fdoExt->DiskGeometry.BytesPerSector = bytesPerSector; 1837 1838 // 1839 // Copy last sector in reverse byte order. 1840 // 1841 1842 tmp = readCapacityBuffer.LogicalBlockAddress; 1843 ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3; 1844 ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2; 1845 ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1; 1846 ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0; 1847 1848 // 1849 // Calculate sector to byte shift. 1850 // 1851 1852 WHICH_BIT(fdoExt->DiskGeometry.BytesPerSector, fdoExt->SectorShift); 1853 1854 DebugPrint((2,"SCSI ClassReadDriveCapacity: Sector size is %d\n", 1855 fdoExt->DiskGeometry.BytesPerSector)); 1856 1857 DebugPrint((2,"SCSI ClassReadDriveCapacity: Number of Sectors is %d\n", 1858 lastSector + 1)); 1859 1860 if (fdoExt->DMActive){ 1861 DebugPrint((1, "SCSI ClassReadDriveCapacity: reducing number of sectors by %d\n", 1862 fdoExt->DMSkew)); 1863 lastSector -= fdoExt->DMSkew; 1864 } 1865 1866 /* 1867 * Check to see if we have a geometry we should be using already. 1868 */ 1869 cylinderSize = (fdoExt->DiskGeometry.TracksPerCylinder * 1870 fdoExt->DiskGeometry.SectorsPerTrack); 1871 if (cylinderSize == 0){ 1872 DebugPrint((1, "ClassReadDriveCapacity: resetting H & S geometry " 1873 "values from %#x/%#x to %#x/%#x\n", 1874 fdoExt->DiskGeometry.TracksPerCylinder, 1875 fdoExt->DiskGeometry.SectorsPerTrack, 1876 0xff, 1877 0x3f)); 1878 1879 fdoExt->DiskGeometry.TracksPerCylinder = 0xff; 1880 fdoExt->DiskGeometry.SectorsPerTrack = 0x3f; 1881 1882 1883 cylinderSize = (fdoExt->DiskGeometry.TracksPerCylinder * 1884 fdoExt->DiskGeometry.SectorsPerTrack); 1885 } 1886 1887 // 1888 // Calculate number of cylinders. 1889 // 1890 1891 fdoExt->DiskGeometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/cylinderSize); 1892 1893 // 1894 // if there are zero cylinders, then the device lied AND it's 1895 // smaller than 0xff*0x3f (about 16k sectors, usually 8 meg) 1896 // this can fit into a single LONGLONG, so create another usable 1897 // geometry, even if it's unusual looking. This allows small, 1898 // non-standard devices, such as Sony's Memory Stick, to show 1899 // up as having a partition. 1900 // 1901 1902 if (fdoExt->DiskGeometry.Cylinders.QuadPart == (LONGLONG)0) { 1903 fdoExt->DiskGeometry.SectorsPerTrack = 1; 1904 fdoExt->DiskGeometry.TracksPerCylinder = 1; 1905 fdoExt->DiskGeometry.Cylinders.QuadPart = lastSector; 1906 } 1907 1908 1909 // 1910 // Calculate media capacity in bytes. 1911 // 1912 1913 fdoExt->CommonExtension.PartitionLength.QuadPart = 1914 ((LONGLONG)(lastSector + 1)) << fdoExt->SectorShift; 1915 1916 /* 1917 * Is this removable or fixed media 1918 */ 1919 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){ 1920 fdoExt->DiskGeometry.MediaType = RemovableMedia; 1921 } 1922 else { 1923 fdoExt->DiskGeometry.MediaType = FixedMedia; 1924 } 1925 } 1926 else { 1927 /* 1928 * The request failed. 1929 */ 1930 1931 // 1932 // ISSUE - 2000/02/04 - henrygab - non-512-byte sector sizes and failed geometry update 1933 // what happens when the disk's sector size is bigger than 1934 // 512 bytes and we hit this code path? this is untested. 1935 // 1936 // If the read capacity fails, set the geometry to reasonable parameter 1937 // so things don't fail at unexpected places. Zero the geometry 1938 // except for the bytes per sector and sector shift. 1939 // 1940 1941 /* 1942 * This request can sometimes fail legitimately 1943 * (e.g. when a SCSI device is attached but turned off) 1944 * so this is not necessarily a device/driver bug. 1945 */ 1946 DBGTRACE(ClassDebugWarning, ("ClassReadDriveCapacity on Fdo %xh failed with status %xh.", Fdo, status)); 1947 1948 /* 1949 * Write in a default disk geometry which we HOPE is right (??). 1950 * BUGBUG !! 1951 */ 1952 RtlZeroMemory(&fdoExt->DiskGeometry, sizeof(DISK_GEOMETRY)); 1953 fdoExt->DiskGeometry.BytesPerSector = 512; 1954 fdoExt->SectorShift = 9; 1955 fdoExt->CommonExtension.PartitionLength.QuadPart = (LONGLONG) 0; 1956 1957 /* 1958 * Is this removable or fixed media 1959 */ 1960 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){ 1961 fdoExt->DiskGeometry.MediaType = RemovableMedia; 1962 } 1963 else { 1964 fdoExt->DiskGeometry.MediaType = FixedMedia; 1965 } 1966 } 1967 1968 } 1969 else { 1970 status = STATUS_INSUFFICIENT_RESOURCES; 1971 } 1972 1973 FreeDeviceInputMdl(driveCapMdl); 1974 } 1975 else { 1976 status = STATUS_INSUFFICIENT_RESOURCES; 1977 } 1978 1979 return status; 1980 } 1981 1982 1983 /*++//////////////////////////////////////////////////////////////////////////// 1984 1985 ClassSendStartUnit() 1986 1987 Routine Description: 1988 1989 Send command to SCSI unit to start or power up. 1990 Because this command is issued asynchronously, that is, without 1991 waiting on it to complete, the IMMEDIATE flag is not set. This 1992 means that the CDB will not return until the drive has powered up. 1993 This should keep subsequent requests from being submitted to the 1994 device before it has completely spun up. 1995 1996 This routine is called from the InterpretSense routine, when a 1997 request sense returns data indicating that a drive must be 1998 powered up. 1999 2000 This routine may also be called from a class driver's error handler, 2001 or anytime a non-critical start device should be sent to the device. 2002 2003 Arguments: 2004 2005 Fdo - The functional device object for the stopped device. 2006 2007 Return Value: 2008 2009 None. 2010 2011 --*/ 2012 VOID 2013 NTAPI 2014 ClassSendStartUnit( 2015 IN PDEVICE_OBJECT Fdo 2016 ) 2017 { 2018 PIO_STACK_LOCATION irpStack; 2019 PIRP irp; 2020 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 2021 PSCSI_REQUEST_BLOCK srb; 2022 PCOMPLETION_CONTEXT context; 2023 PCDB cdb; 2024 2025 // 2026 // Allocate Srb from nonpaged pool. 2027 // 2028 2029 context = ExAllocatePoolWithTag(NonPagedPool, 2030 sizeof(COMPLETION_CONTEXT), 2031 '6CcS'); 2032 2033 if(context == NULL) { 2034 2035 // 2036 // ISSUE-2000/02/03-peterwie 2037 // This code path was inherited from the NT 4.0 class2.sys driver. 2038 // It needs to be changed to survive low-memory conditions. 2039 // 2040 2041 KeBugCheck(SCSI_DISK_DRIVER_INTERNAL); 2042 } 2043 2044 // 2045 // Save the device object in the context for use by the completion 2046 // routine. 2047 // 2048 2049 context->DeviceObject = Fdo; 2050 srb = &context->Srb; 2051 2052 // 2053 // Zero out srb. 2054 // 2055 2056 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 2057 2058 // 2059 // Write length to SRB. 2060 // 2061 2062 srb->Length = sizeof(SCSI_REQUEST_BLOCK); 2063 2064 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 2065 2066 // 2067 // Set timeout value large enough for drive to spin up. 2068 // 2069 2070 srb->TimeOutValue = START_UNIT_TIMEOUT; 2071 2072 // 2073 // Set the transfer length. 2074 // 2075 2076 srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | 2077 SRB_FLAGS_DISABLE_AUTOSENSE | 2078 SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 2079 2080 // 2081 // Build the start unit CDB. 2082 // 2083 2084 srb->CdbLength = 6; 2085 cdb = (PCDB)srb->Cdb; 2086 2087 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 2088 cdb->START_STOP.Start = 1; 2089 cdb->START_STOP.Immediate = 0; 2090 cdb->START_STOP.LogicalUnitNumber = srb->Lun; 2091 2092 // 2093 // Build the asynchronous request to be sent to the port driver. 2094 // Since this routine is called from a DPC the IRP should always be 2095 // available. 2096 // 2097 2098 irp = IoAllocateIrp(Fdo->StackSize, FALSE); 2099 2100 if(irp == NULL) { 2101 2102 // 2103 // ISSUE-2000/02/03-peterwie 2104 // This code path was inherited from the NT 4.0 class2.sys driver. 2105 // It needs to be changed to survive low-memory conditions. 2106 // 2107 2108 KeBugCheck(SCSI_DISK_DRIVER_INTERNAL); 2109 2110 } 2111 2112 ClassAcquireRemoveLock(Fdo, irp); 2113 2114 IoSetCompletionRoutine(irp, 2115 ClassAsynchronousCompletion, 2116 context, 2117 TRUE, 2118 TRUE, 2119 TRUE); 2120 2121 irpStack = IoGetNextIrpStackLocation(irp); 2122 irpStack->MajorFunction = IRP_MJ_SCSI; 2123 srb->OriginalRequest = irp; 2124 2125 // 2126 // Store the SRB address in next stack for port driver. 2127 // 2128 2129 irpStack->Parameters.Scsi.Srb = srb; 2130 2131 // 2132 // Call the port driver with the IRP. 2133 // 2134 2135 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp); 2136 2137 return; 2138 2139 } // end StartUnit() 2140 2141 /*++//////////////////////////////////////////////////////////////////////////// 2142 2143 ClassAsynchronousCompletion() ISSUE-2000/02/18-henrygab - why public?! 2144 2145 Routine Description: 2146 2147 This routine is called when an asynchronous I/O request 2148 which was issued by the class driver completes. Examples of such requests 2149 are release queue or START UNIT. This routine releases the queue if 2150 necessary. It then frees the context and the IRP. 2151 2152 Arguments: 2153 2154 DeviceObject - The device object for the logical unit; however since this 2155 is the top stack location the value is NULL. 2156 2157 Irp - Supplies a pointer to the Irp to be processed. 2158 2159 Context - Supplies the context to be used to process this request. 2160 2161 Return Value: 2162 2163 None. 2164 2165 --*/ 2166 NTSTATUS 2167 NTAPI 2168 ClassAsynchronousCompletion( 2169 PDEVICE_OBJECT DeviceObject, 2170 PIRP Irp, 2171 PVOID Context 2172 ) 2173 { 2174 PCOMPLETION_CONTEXT context = Context; 2175 PSCSI_REQUEST_BLOCK srb; 2176 2177 if(DeviceObject == NULL) { 2178 2179 DeviceObject = context->DeviceObject; 2180 } 2181 2182 srb = &context->Srb; 2183 2184 // 2185 // If this is an execute srb, then check the return status and make sure. 2186 // the queue is not frozen. 2187 // 2188 2189 if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) { 2190 2191 // 2192 // Check for a frozen queue. 2193 // 2194 2195 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 2196 2197 // 2198 // Unfreeze the queue getting the device object from the context. 2199 // 2200 2201 ClassReleaseQueue(context->DeviceObject); 2202 } 2203 } 2204 2205 { // free port-allocated sense buffer if we can detect 2206 2207 if (((PCOMMON_DEVICE_EXTENSION)(DeviceObject->DeviceExtension))->IsFdo) { 2208 2209 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 2210 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { 2211 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb); 2212 } 2213 2214 } else { 2215 2216 ASSERT(!TEST_FLAG(srb->SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 2217 2218 } 2219 } 2220 2221 2222 // 2223 // Free the context and the Irp. 2224 // 2225 2226 if (Irp->MdlAddress != NULL) { 2227 MmUnlockPages(Irp->MdlAddress); 2228 IoFreeMdl(Irp->MdlAddress); 2229 2230 Irp->MdlAddress = NULL; 2231 } 2232 2233 ClassReleaseRemoveLock(DeviceObject, Irp); 2234 2235 ExFreePool(context); 2236 IoFreeIrp(Irp); 2237 2238 // 2239 // Indicate the I/O system should stop processing the Irp completion. 2240 // 2241 2242 return STATUS_MORE_PROCESSING_REQUIRED; 2243 2244 } // end ClassAsynchronousCompletion() 2245 2246 VOID NTAPI ServiceTransferRequest(PDEVICE_OBJECT Fdo, PIRP Irp) 2247 { 2248 //PCOMMON_DEVICE_EXTENSION commonExt = Fdo->DeviceExtension; 2249 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 2250 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 2251 //PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExt->PartitionZeroExtension->AdapterDescriptor; 2252 PIO_STACK_LOCATION currentSp = IoGetCurrentIrpStackLocation(Irp); 2253 ULONG entireXferLen = currentSp->Parameters.Read.Length; 2254 PUCHAR bufPtr = MmGetMdlVirtualAddress(Irp->MdlAddress); 2255 LARGE_INTEGER targetLocation = currentSp->Parameters.Read.ByteOffset; 2256 PTRANSFER_PACKET pkt; 2257 SLIST_ENTRY pktList; 2258 PSLIST_ENTRY slistEntry; 2259 ULONG numPackets; 2260 //KIRQL oldIrql; 2261 ULONG i; 2262 2263 /* 2264 * Compute the number of hw xfers we'll have to do. 2265 * Calculate this without allowing for an overflow condition. 2266 */ 2267 ASSERT(fdoData->HwMaxXferLen >= PAGE_SIZE); 2268 numPackets = entireXferLen/fdoData->HwMaxXferLen; 2269 if (entireXferLen % fdoData->HwMaxXferLen){ 2270 numPackets++; 2271 } 2272 2273 /* 2274 * First get all the TRANSFER_PACKETs that we'll need at once. 2275 * Use our 'simple' slist functions since we don't need interlocked. 2276 */ 2277 SimpleInitSlistHdr(&pktList); 2278 for (i = 0; i < numPackets; i++){ 2279 pkt = DequeueFreeTransferPacket(Fdo, TRUE); 2280 if (pkt){ 2281 SimplePushSlist(&pktList, &pkt->SlistEntry); 2282 } 2283 else { 2284 break; 2285 } 2286 } 2287 2288 if (i == numPackets){ 2289 /* 2290 * Initialize the original IRP's status to success. 2291 * If any of the packets fail, they will set it to an error status. 2292 * The IoStatus.Information field will be incremented to the 2293 * transfer length as the pieces complete. 2294 */ 2295 Irp->IoStatus.Status = STATUS_SUCCESS; 2296 Irp->IoStatus.Information = 0; 2297 2298 /* 2299 * Store the number of transfer pieces inside the original IRP. 2300 * It will be used to count down the pieces as they complete. 2301 */ 2302 Irp->Tail.Overlay.DriverContext[0] = LongToPtr(numPackets); 2303 2304 /* 2305 * We are proceeding with the transfer. 2306 * Mark the client IRP pending since it may complete on a different thread. 2307 */ 2308 IoMarkIrpPending(Irp); 2309 2310 /* 2311 * Transmit the pieces of the transfer. 2312 */ 2313 while (entireXferLen > 0){ 2314 ULONG thisPieceLen = MIN(fdoData->HwMaxXferLen, entireXferLen); 2315 2316 /* 2317 * Set up a TRANSFER_PACKET for this piece and send it. 2318 */ 2319 slistEntry = SimplePopSlist(&pktList); 2320 ASSERT(slistEntry); 2321 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry); 2322 SetupReadWriteTransferPacket( pkt, 2323 bufPtr, 2324 thisPieceLen, 2325 targetLocation, 2326 Irp); 2327 SubmitTransferPacket(pkt); 2328 2329 entireXferLen -= thisPieceLen; 2330 bufPtr += thisPieceLen; 2331 targetLocation.QuadPart += thisPieceLen; 2332 } 2333 ASSERT(SimpleIsSlistEmpty(&pktList)); 2334 } 2335 else if (i >= 1){ 2336 /* 2337 * We were unable to get all the TRANSFER_PACKETs we need, 2338 * but we did get at least one. 2339 * That means that we are in extreme low-memory stress. 2340 * We'll try doing this transfer using a single packet. 2341 * The port driver is certainly also in stress, so use one-page 2342 * transfers. 2343 */ 2344 2345 /* 2346 * Free all but one of the TRANSFER_PACKETs. 2347 */ 2348 while (i-- > 1){ 2349 slistEntry = SimplePopSlist(&pktList); 2350 ASSERT(slistEntry); 2351 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry); 2352 EnqueueFreeTransferPacket(Fdo, pkt); 2353 } 2354 2355 /* 2356 * Get the single TRANSFER_PACKET that we'll be using. 2357 */ 2358 slistEntry = SimplePopSlist(&pktList); 2359 ASSERT(slistEntry); 2360 ASSERT(SimpleIsSlistEmpty(&pktList)); 2361 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry); 2362 DBGWARN(("Insufficient packets available in ServiceTransferRequest - entering lowMemRetry with pkt=%xh.", pkt)); 2363 2364 /* 2365 * Set default status and the number of transfer packets (one) 2366 * inside the original irp. 2367 */ 2368 Irp->IoStatus.Status = STATUS_SUCCESS; 2369 Irp->IoStatus.Information = 0; 2370 Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1); 2371 2372 /* 2373 * Mark the client irp pending since it may complete on 2374 * another thread. 2375 */ 2376 IoMarkIrpPending(Irp); 2377 2378 /* 2379 * Set up the TRANSFER_PACKET for a lowMem transfer and launch. 2380 */ 2381 SetupReadWriteTransferPacket( pkt, 2382 bufPtr, 2383 entireXferLen, 2384 targetLocation, 2385 Irp); 2386 InitLowMemRetry(pkt, bufPtr, entireXferLen, targetLocation); 2387 StepLowMemRetry(pkt); 2388 } 2389 else { 2390 /* 2391 * We were unable to get ANY TRANSFER_PACKETs. 2392 * Defer this client irp until some TRANSFER_PACKETs free up. 2393 */ 2394 DBGWARN(("No packets available in ServiceTransferRequest - deferring transfer (Irp=%xh)...", Irp)); 2395 IoMarkIrpPending(Irp); 2396 EnqueueDeferredClientIrp(fdoData, Irp); 2397 } 2398 2399 } 2400 2401 /*++//////////////////////////////////////////////////////////////////////////// 2402 2403 ClassIoComplete() 2404 2405 Routine Description: 2406 2407 This routine executes when the port driver has completed a request. 2408 It looks at the SRB status in the completing SRB and if not success 2409 it checks for valid request sense buffer information. If valid, the 2410 info is used to update status with more precise message of type of 2411 error. This routine deallocates the SRB. 2412 2413 This routine should only be placed on the stack location for a class 2414 driver FDO. 2415 2416 Arguments: 2417 2418 Fdo - Supplies the device object which represents the logical 2419 unit. 2420 2421 Irp - Supplies the Irp which has completed. 2422 2423 Context - Supplies a pointer to the SRB. 2424 2425 Return Value: 2426 2427 NT status 2428 2429 --*/ 2430 NTSTATUS 2431 NTAPI 2432 ClassIoComplete( 2433 IN PDEVICE_OBJECT Fdo, 2434 IN PIRP Irp, 2435 IN PVOID Context 2436 ) 2437 { 2438 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 2439 PSCSI_REQUEST_BLOCK srb = Context; 2440 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 2441 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 2442 NTSTATUS status; 2443 BOOLEAN retry; 2444 BOOLEAN callStartNextPacket; 2445 2446 ASSERT(fdoExtension->CommonExtension.IsFdo); 2447 2448 // 2449 // Check SRB status for success of completing request. 2450 // 2451 2452 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) { 2453 ULONG retryInterval; 2454 2455 DebugPrint((2, "ClassIoComplete: IRP %p, SRB %p\n", Irp, srb)); 2456 2457 // 2458 // Release the queue if it is frozen. 2459 // 2460 2461 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 2462 ClassReleaseQueue(Fdo); 2463 } 2464 2465 retry = ClassInterpretSenseInfo( 2466 Fdo, 2467 srb, 2468 irpStack->MajorFunction, 2469 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? 2470 irpStack->Parameters.DeviceIoControl.IoControlCode : 2471 0, 2472 MAXIMUM_RETRIES - 2473 ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4), 2474 &status, 2475 &retryInterval); 2476 2477 // 2478 // If the status is verified required and the this request 2479 // should bypass verify required then retry the request. 2480 // 2481 2482 if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) && 2483 status == STATUS_VERIFY_REQUIRED) { 2484 2485 status = STATUS_IO_DEVICE_ERROR; 2486 retry = TRUE; 2487 } 2488 2489 if (retry && ((*(PCHAR*)&irpStack->Parameters.Others.Argument4)--)) { 2490 2491 // 2492 // Retry request. 2493 // 2494 2495 DebugPrint((1, "Retry request %p\n", Irp)); 2496 2497 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { 2498 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb); 2499 } 2500 2501 RetryRequest(Fdo, Irp, srb, FALSE, retryInterval); 2502 return STATUS_MORE_PROCESSING_REQUIRED; 2503 } 2504 2505 } else { 2506 2507 // 2508 // Set status for successful request 2509 // 2510 fdoData->LoggedTURFailureSinceLastIO = FALSE; 2511 ClasspPerfIncrementSuccessfulIo(fdoExtension); 2512 status = STATUS_SUCCESS; 2513 } // end if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS) 2514 2515 2516 // 2517 // ensure we have returned some info, and it matches what the 2518 // original request wanted for PAGING operations only 2519 // 2520 2521 if ((NT_SUCCESS(status)) && TEST_FLAG(Irp->Flags, IRP_PAGING_IO)) { 2522 ASSERT(Irp->IoStatus.Information != 0); 2523 ASSERT(irpStack->Parameters.Read.Length == Irp->IoStatus.Information); 2524 } 2525 2526 // 2527 // remember if the caller wanted to skip calling IoStartNextPacket. 2528 // for legacy reasons, we cannot call IoStartNextPacket for IoDeviceControl 2529 // calls. this setting only affects device objects with StartIo routines. 2530 // 2531 2532 callStartNextPacket = !TEST_FLAG(srb->SrbFlags, SRB_FLAGS_DONT_START_NEXT_PACKET); 2533 if (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) { 2534 callStartNextPacket = FALSE; 2535 } 2536 2537 // 2538 // Free the srb 2539 // 2540 2541 if(!TEST_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT)) { 2542 2543 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { 2544 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb); 2545 } 2546 2547 if (fdoExtension->CommonExtension.IsSrbLookasideListInitialized){ 2548 ClassFreeOrReuseSrb(fdoExtension, srb); 2549 } 2550 else { 2551 DBGWARN(("ClassIoComplete is freeing an SRB (possibly) on behalf of another driver.")); 2552 ExFreePool(srb); 2553 } 2554 2555 } else { 2556 2557 DebugPrint((2, "ClassIoComplete: Not Freeing srb @ %p because " 2558 "SRB_CLASS_FLAGS_PERSISTANT set\n", srb)); 2559 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { 2560 DebugPrint((2, "ClassIoComplete: Not Freeing sensebuffer @ %p " 2561 " because SRB_CLASS_FLAGS_PERSISTANT set\n", 2562 srb->SenseInfoBuffer)); 2563 } 2564 2565 } 2566 2567 // 2568 // Set status in completing IRP. 2569 // 2570 2571 Irp->IoStatus.Status = status; 2572 2573 // 2574 // Set the hard error if necessary. 2575 // 2576 2577 if (!NT_SUCCESS(status) && 2578 IoIsErrorUserInduced(status) && 2579 (Irp->Tail.Overlay.Thread != NULL) 2580 ) { 2581 2582 // 2583 // Store DeviceObject for filesystem, and clear 2584 // in IoStatus.Information field. 2585 // 2586 2587 IoSetHardErrorOrVerifyDevice(Irp, Fdo); 2588 Irp->IoStatus.Information = 0; 2589 } 2590 2591 // 2592 // If pending has be returned for this irp then mark the current stack as 2593 // pending. 2594 // 2595 2596 if (Irp->PendingReturned) { 2597 IoMarkIrpPending(Irp); 2598 } 2599 2600 if (fdoExtension->CommonExtension.DriverExtension->InitData.ClassStartIo) { 2601 if (callStartNextPacket) { 2602 KIRQL oldIrql; 2603 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); 2604 IoStartNextPacket(Fdo, FALSE); 2605 KeLowerIrql(oldIrql); 2606 } 2607 } 2608 2609 ClassReleaseRemoveLock(Fdo, Irp); 2610 2611 return status; 2612 2613 } // end ClassIoComplete() 2614 2615 /*++//////////////////////////////////////////////////////////////////////////// 2616 2617 ClassSendSrbSynchronous() 2618 2619 Routine Description: 2620 2621 This routine is called by SCSI device controls to complete an 2622 SRB and send it to the port driver synchronously (ie wait for 2623 completion). The CDB is already completed along with the SRB CDB 2624 size and request timeout value. 2625 2626 Arguments: 2627 2628 Fdo - Supplies the functional device object which represents the target. 2629 2630 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone. 2631 2632 BufferAddress - Supplies the address of the buffer. 2633 2634 BufferLength - Supplies the length in bytes of the buffer. 2635 2636 WriteToDevice - Indicates the data should be transfer to the device. 2637 2638 Return Value: 2639 2640 NTSTATUS indicating the final results of the operation. 2641 2642 If NT_SUCCESS(), then the amount of usable data is contained in the field 2643 Srb->DataTransferLength 2644 2645 --*/ 2646 NTSTATUS 2647 NTAPI 2648 ClassSendSrbSynchronous( 2649 PDEVICE_OBJECT Fdo, 2650 PSCSI_REQUEST_BLOCK Srb, 2651 PVOID BufferAddress, 2652 ULONG BufferLength, 2653 BOOLEAN WriteToDevice 2654 ) 2655 { 2656 2657 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 2658 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 2659 IO_STATUS_BLOCK ioStatus; 2660 //ULONG controlType; 2661 PIRP irp; 2662 PIO_STACK_LOCATION irpStack; 2663 KEVENT event; 2664 PUCHAR senseInfoBuffer; 2665 ULONG retryCount = MAXIMUM_RETRIES; 2666 NTSTATUS status; 2667 BOOLEAN retry; 2668 2669 // 2670 // NOTE: This code is only pageable because we are not freezing 2671 // the queue. Allowing the queue to be frozen from a pageable 2672 // routine could leave the queue frozen as we try to page in 2673 // the code to unfreeze the queue. The result would be a nice 2674 // case of deadlock. Therefore, since we are unfreezing the 2675 // queue regardless of the result, just set the NO_FREEZE_QUEUE 2676 // flag in the SRB. 2677 // 2678 2679 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); 2680 ASSERT(fdoExtension->CommonExtension.IsFdo); 2681 2682 // 2683 // Write length to SRB. 2684 // 2685 2686 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); 2687 2688 // 2689 // Set SCSI bus address. 2690 // 2691 2692 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 2693 2694 // 2695 // Enable auto request sense. 2696 // 2697 2698 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 2699 2700 // 2701 // Sense buffer is in aligned nonpaged pool. 2702 // 2703 // 2704 senseInfoBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, 2705 SENSE_BUFFER_SIZE, 2706 '7CcS'); 2707 2708 if (senseInfoBuffer == NULL) { 2709 2710 DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate request sense " 2711 "buffer\n")); 2712 return(STATUS_INSUFFICIENT_RESOURCES); 2713 } 2714 2715 Srb->SenseInfoBuffer = senseInfoBuffer; 2716 Srb->DataBuffer = BufferAddress; 2717 2718 // 2719 // Start retries here. 2720 // 2721 2722 retry: 2723 2724 // 2725 // use fdoextension's flags by default. 2726 // do not move out of loop, as the flag may change due to errors 2727 // sending this command. 2728 // 2729 2730 Srb->SrbFlags = fdoExtension->SrbFlags; 2731 2732 if(BufferAddress != NULL) { 2733 if(WriteToDevice) { 2734 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_OUT); 2735 } else { 2736 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN); 2737 } 2738 } 2739 2740 // 2741 // Initialize the QueueAction field. 2742 // 2743 2744 Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 2745 2746 // 2747 // Disable synchronous transfer for these requests. 2748 // Disable freezing the queue, since all we do is unfreeze it anyways. 2749 // 2750 2751 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); 2752 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); 2753 2754 // 2755 // Set the event object to the unsignaled state. 2756 // It will be used to signal request completion. 2757 // 2758 2759 KeInitializeEvent(&event, NotificationEvent, FALSE); 2760 2761 // 2762 // Build device I/O control request with METHOD_NEITHER data transfer. 2763 // We'll queue a completion routine to cleanup the MDL's and such ourself. 2764 // 2765 2766 irp = IoAllocateIrp( 2767 (CCHAR) (fdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1), 2768 FALSE); 2769 2770 if(irp == NULL) { 2771 ExFreePool(senseInfoBuffer); 2772 DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate Irp\n")); 2773 return(STATUS_INSUFFICIENT_RESOURCES); 2774 } 2775 2776 // 2777 // Get next stack location. 2778 // 2779 2780 irpStack = IoGetNextIrpStackLocation(irp); 2781 2782 // 2783 // Set up SRB for execute scsi request. Save SRB address in next stack 2784 // for the port driver. 2785 // 2786 2787 irpStack->MajorFunction = IRP_MJ_SCSI; 2788 irpStack->Parameters.Scsi.Srb = Srb; 2789 2790 IoSetCompletionRoutine(irp, 2791 ClasspSendSynchronousCompletion, 2792 Srb, 2793 TRUE, 2794 TRUE, 2795 TRUE); 2796 2797 irp->UserIosb = &ioStatus; 2798 irp->UserEvent = &event; 2799 2800 if(BufferAddress) { 2801 // 2802 // Build an MDL for the data buffer and stick it into the irp. The 2803 // completion routine will unlock the pages and free the MDL. 2804 // 2805 2806 irp->MdlAddress = IoAllocateMdl( BufferAddress, 2807 BufferLength, 2808 FALSE, 2809 FALSE, 2810 irp ); 2811 if (irp->MdlAddress == NULL) { 2812 ExFreePool(senseInfoBuffer); 2813 Srb->SenseInfoBuffer = NULL; 2814 IoFreeIrp( irp ); 2815 DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate MDL\n")); 2816 return STATUS_INSUFFICIENT_RESOURCES; 2817 } 2818 2819 _SEH2_TRY { 2820 2821 // 2822 // the io manager unlocks these pages upon completion 2823 // 2824 2825 MmProbeAndLockPages( irp->MdlAddress, 2826 KernelMode, 2827 (WriteToDevice ? IoReadAccess : 2828 IoWriteAccess)); 2829 2830 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 2831 status = _SEH2_GetExceptionCode(); 2832 2833 ExFreePool(senseInfoBuffer); 2834 Srb->SenseInfoBuffer = NULL; 2835 IoFreeMdl(irp->MdlAddress); 2836 IoFreeIrp(irp); 2837 2838 DebugPrint((1, "ClassSendSrbSynchronous: Exception %lx " 2839 "locking buffer\n", status)); 2840 _SEH2_YIELD(return status); 2841 } _SEH2_END; 2842 } 2843 2844 // 2845 // Set the transfer length. 2846 // 2847 2848 Srb->DataTransferLength = BufferLength; 2849 2850 // 2851 // Zero out status. 2852 // 2853 2854 Srb->ScsiStatus = Srb->SrbStatus = 0; 2855 Srb->NextSrb = 0; 2856 2857 // 2858 // Set up IRP Address. 2859 // 2860 2861 Srb->OriginalRequest = irp; 2862 2863 // 2864 // Call the port driver with the request and wait for it to complete. 2865 // 2866 2867 status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp); 2868 2869 if (status == STATUS_PENDING) { 2870 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 2871 status = ioStatus.Status; 2872 } 2873 2874 // 2875 // Check that request completed without error. 2876 // 2877 2878 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) { 2879 2880 ULONG retryInterval; 2881 2882 DBGTRACE(ClassDebugWarning, ("ClassSendSrbSynchronous - srb %ph failed (op=%s srbstat=%s(%xh), irpstat=%xh, sense=%s/%s/%s)", Srb, DBGGETSCSIOPSTR(Srb), DBGGETSRBSTATUSSTR(Srb), (ULONG)Srb->SrbStatus, status, DBGGETSENSECODESTR(Srb), DBGGETADSENSECODESTR(Srb), DBGGETADSENSEQUALIFIERSTR(Srb))); 2883 2884 // 2885 // assert that the queue is not frozen 2886 // 2887 2888 ASSERT(!TEST_FLAG(Srb->SrbStatus, SRB_STATUS_QUEUE_FROZEN)); 2889 2890 // 2891 // Update status and determine if request should be retried. 2892 // 2893 2894 retry = ClassInterpretSenseInfo(Fdo, 2895 Srb, 2896 IRP_MJ_SCSI, 2897 0, 2898 MAXIMUM_RETRIES - retryCount, 2899 &status, 2900 &retryInterval); 2901 2902 2903 if (retry) { 2904 2905 if ((status == STATUS_DEVICE_NOT_READY && 2906 ((PSENSE_DATA) senseInfoBuffer)->AdditionalSenseCode == 2907 SCSI_ADSENSE_LUN_NOT_READY) || 2908 (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)) { 2909 2910 LARGE_INTEGER delay; 2911 2912 // 2913 // Delay for at least 2 seconds. 2914 // 2915 2916 if(retryInterval < 2) { 2917 retryInterval = 2; 2918 } 2919 2920 delay.QuadPart = (LONGLONG)( - 10 * 1000 * (LONGLONG)1000 * retryInterval); 2921 2922 // 2923 // Stall for a while to let the device become ready 2924 // 2925 2926 KeDelayExecutionThread(KernelMode, FALSE, &delay); 2927 2928 } 2929 2930 // 2931 // If retries are not exhausted then retry this operation. 2932 // 2933 2934 if (retryCount--) { 2935 2936 if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) { 2937 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb); 2938 } 2939 2940 goto retry; 2941 } 2942 } 2943 2944 } else { 2945 fdoData->LoggedTURFailureSinceLastIO = FALSE; 2946 status = STATUS_SUCCESS; 2947 } 2948 2949 // 2950 // required even though we allocated our own, since the port driver may 2951 // have allocated one also 2952 // 2953 2954 if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) { 2955 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb); 2956 } 2957 2958 Srb->SenseInfoBuffer = NULL; 2959 ExFreePool(senseInfoBuffer); 2960 2961 return status; 2962 } 2963 2964 /*++//////////////////////////////////////////////////////////////////////////// 2965 2966 ClassInterpretSenseInfo() 2967 2968 Routine Description: 2969 2970 This routine interprets the data returned from the SCSI 2971 request sense. It determines the status to return in the 2972 IRP and whether this request can be retried. 2973 2974 Arguments: 2975 2976 DeviceObject - Supplies the device object associated with this request. 2977 2978 Srb - Supplies the scsi request block which failed. 2979 2980 MajorFunctionCode - Supplies the function code to be used for logging. 2981 2982 IoDeviceCode - Supplies the device code to be used for logging. 2983 2984 Status - Returns the status for the request. 2985 2986 Return Value: 2987 2988 BOOLEAN TRUE: Drivers should retry this request. 2989 FALSE: Drivers should not retry this request. 2990 2991 --*/ 2992 BOOLEAN 2993 NTAPI 2994 ClassInterpretSenseInfo( 2995 IN PDEVICE_OBJECT Fdo, 2996 IN PSCSI_REQUEST_BLOCK Srb, 2997 IN UCHAR MajorFunctionCode, 2998 IN ULONG IoDeviceCode, 2999 IN ULONG RetryCount, 3000 OUT NTSTATUS *Status, 3001 OUT OPTIONAL ULONG *RetryInterval 3002 ) 3003 { 3004 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 3005 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 3006 3007 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; 3008 3009 BOOLEAN retry = TRUE; 3010 BOOLEAN logError = FALSE; 3011 BOOLEAN unhandledError = FALSE; 3012 BOOLEAN incrementErrorCount = FALSE; 3013 3014 ULONG badSector = 0; 3015 ULONG uniqueId = 0; 3016 3017 NTSTATUS logStatus; 3018 3019 ULONG readSector; 3020 ULONG index; 3021 3022 ULONG retryInterval = 0; 3023 KIRQL oldIrql; 3024 3025 3026 logStatus = -1; 3027 3028 if(TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) { 3029 3030 // 3031 // Log anything remotely incorrect about paging i/o 3032 // 3033 3034 logError = TRUE; 3035 uniqueId = 301; 3036 logStatus = IO_WARNING_PAGING_FAILURE; 3037 } 3038 3039 // 3040 // Check that request sense buffer is valid. 3041 // 3042 3043 ASSERT(fdoExtension->CommonExtension.IsFdo); 3044 3045 3046 // 3047 // must handle the SRB_STATUS_INTERNAL_ERROR case first, 3048 // as it has all the flags set. 3049 // 3050 3051 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_INTERNAL_ERROR) { 3052 3053 DebugPrint((ClassDebugSenseInfo, 3054 "ClassInterpretSenseInfo: Internal Error code is %x\n", 3055 Srb->InternalStatus)); 3056 3057 retry = FALSE; 3058 *Status = Srb->InternalStatus; 3059 3060 } else if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && 3061 (Srb->SenseInfoBufferLength >= 3062 offsetof(SENSE_DATA, CommandSpecificInformation))) { 3063 3064 // 3065 // Zero the additional sense code and additional sense code qualifier 3066 // if they were not returned by the device. 3067 // 3068 3069 readSector = senseBuffer->AdditionalSenseLength + 3070 offsetof(SENSE_DATA, AdditionalSenseLength); 3071 3072 if (readSector > Srb->SenseInfoBufferLength) { 3073 readSector = Srb->SenseInfoBufferLength; 3074 } 3075 3076 if (readSector <= offsetof(SENSE_DATA, AdditionalSenseCode)) { 3077 senseBuffer->AdditionalSenseCode = 0; 3078 } 3079 3080 if (readSector <= offsetof(SENSE_DATA, AdditionalSenseCodeQualifier)) { 3081 senseBuffer->AdditionalSenseCodeQualifier = 0; 3082 } 3083 3084 DebugPrint((ClassDebugSenseInfo, 3085 "ClassInterpretSenseInfo: Error code is %x\n", 3086 senseBuffer->ErrorCode)); 3087 DebugPrint((ClassDebugSenseInfo, 3088 "ClassInterpretSenseInfo: Sense key is %x\n", 3089 senseBuffer->SenseKey)); 3090 DebugPrint((ClassDebugSenseInfo, 3091 "ClassInterpretSenseInfo: Additional sense code is %x\n", 3092 senseBuffer->AdditionalSenseCode)); 3093 DebugPrint((ClassDebugSenseInfo, 3094 "ClassInterpretSenseInfo: Additional sense code qualifier " 3095 "is %x\n", 3096 senseBuffer->AdditionalSenseCodeQualifier)); 3097 3098 3099 switch (senseBuffer->SenseKey & 0xf) { 3100 3101 case SCSI_SENSE_NOT_READY: { 3102 3103 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3104 "Device not ready\n")); 3105 *Status = STATUS_DEVICE_NOT_READY; 3106 3107 switch (senseBuffer->AdditionalSenseCode) { 3108 3109 case SCSI_ADSENSE_LUN_NOT_READY: { 3110 3111 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3112 "Lun not ready\n")); 3113 3114 switch (senseBuffer->AdditionalSenseCodeQualifier) { 3115 3116 case SCSI_SENSEQ_OPERATION_IN_PROGRESS: { 3117 DEVICE_EVENT_BECOMING_READY notReady; 3118 3119 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3120 "Operation In Progress\n")); 3121 retryInterval = NOT_READY_RETRY_INTERVAL; 3122 3123 RtlZeroMemory(¬Ready, sizeof(DEVICE_EVENT_BECOMING_READY)); 3124 notReady.Version = 1; 3125 notReady.Reason = 2; 3126 notReady.Estimated100msToReady = retryInterval * 10; 3127 ClasspSendNotification(fdoExtension, 3128 &GUID_IO_DEVICE_BECOMING_READY, 3129 sizeof(DEVICE_EVENT_BECOMING_READY), 3130 ¬Ready); 3131 3132 break; 3133 } 3134 3135 case SCSI_SENSEQ_BECOMING_READY: { 3136 DEVICE_EVENT_BECOMING_READY notReady; 3137 3138 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3139 "In process of becoming ready\n")); 3140 retryInterval = NOT_READY_RETRY_INTERVAL; 3141 3142 RtlZeroMemory(¬Ready, sizeof(DEVICE_EVENT_BECOMING_READY)); 3143 notReady.Version = 1; 3144 notReady.Reason = 1; 3145 notReady.Estimated100msToReady = retryInterval * 10; 3146 ClasspSendNotification(fdoExtension, 3147 &GUID_IO_DEVICE_BECOMING_READY, 3148 sizeof(DEVICE_EVENT_BECOMING_READY), 3149 ¬Ready); 3150 break; 3151 } 3152 3153 case SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS: { 3154 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3155 "Long write in progress\n")); 3156 retry = FALSE; 3157 break; 3158 } 3159 3160 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: { 3161 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3162 "Manual intervention required\n")); 3163 *Status = STATUS_NO_MEDIA_IN_DEVICE; 3164 retry = FALSE; 3165 break; 3166 } 3167 3168 case SCSI_SENSEQ_FORMAT_IN_PROGRESS: { 3169 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3170 "Format in progress\n")); 3171 retry = FALSE; 3172 break; 3173 } 3174 3175 case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: { 3176 3177 if(!TEST_FLAG(fdoExtension->ScanForSpecialFlags, 3178 CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK)) { 3179 3180 DebugPrint((ClassDebugSenseInfo, 3181 "ClassInterpretSenseInfo: " 3182 "not ready, cause unknown\n")); 3183 /* 3184 Many non-WHQL certified drives (mostly CD-RW) return 3185 this when they have no media instead of the obvious 3186 choice of: 3187 3188 SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 3189 3190 These drives should not pass WHQL certification due 3191 to this discrepancy. 3192 3193 */ 3194 retry = FALSE; 3195 break; 3196 3197 } else { 3198 3199 // 3200 // Treat this as init command required and fall through. 3201 // 3202 } 3203 } 3204 3205 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED: 3206 default: { 3207 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3208 "Initializing command required\n")); 3209 3210 // 3211 // This sense code/additional sense code 3212 // combination may indicate that the device 3213 // needs to be started. Send an start unit if this 3214 // is a disk device. 3215 // 3216 3217 if(TEST_FLAG(fdoExtension->DeviceFlags, 3218 DEV_SAFE_START_UNIT) && 3219 !TEST_FLAG(Srb->SrbFlags, 3220 SRB_CLASS_FLAGS_LOW_PRIORITY)) { 3221 ClassSendStartUnit(Fdo); 3222 } 3223 break; 3224 } 3225 3226 3227 } // end switch (senseBuffer->AdditionalSenseCodeQualifier) 3228 break; 3229 } 3230 3231 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: { 3232 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3233 "No Media in device.\n")); 3234 *Status = STATUS_NO_MEDIA_IN_DEVICE; 3235 retry = FALSE; 3236 3237 // 3238 // signal MCN that there isn't any media in the device 3239 // 3240 if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { 3241 DebugPrint((ClassDebugError, "ClassInterpretSenseInfo: " 3242 "No Media in a non-removable device %p\n", 3243 Fdo)); 3244 } 3245 ClassSetMediaChangeState(fdoExtension, MediaNotPresent, FALSE); 3246 3247 break; 3248 } 3249 } // end switch (senseBuffer->AdditionalSenseCode) 3250 3251 break; 3252 } // end SCSI_SENSE_NOT_READY 3253 3254 case SCSI_SENSE_DATA_PROTECT: { 3255 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3256 "Media write protected\n")); 3257 *Status = STATUS_MEDIA_WRITE_PROTECTED; 3258 retry = FALSE; 3259 break; 3260 } // end SCSI_SENSE_DATA_PROTECT 3261 3262 case SCSI_SENSE_MEDIUM_ERROR: { 3263 DebugPrint((ClassDebugSenseInfo,"ClassInterpretSenseInfo: " 3264 "Medium Error (bad block)\n")); 3265 *Status = STATUS_DEVICE_DATA_ERROR; 3266 3267 retry = FALSE; 3268 logError = TRUE; 3269 uniqueId = 256; 3270 logStatus = IO_ERR_BAD_BLOCK; 3271 3272 // 3273 // Check if this error is due to unknown format 3274 // 3275 if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_INVALID_MEDIA){ 3276 3277 switch (senseBuffer->AdditionalSenseCodeQualifier) { 3278 3279 case SCSI_SENSEQ_UNKNOWN_FORMAT: { 3280 3281 *Status = STATUS_UNRECOGNIZED_MEDIA; 3282 3283 // 3284 // Log error only if this is a paging request 3285 // 3286 if(!TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) { 3287 logError = FALSE; 3288 } 3289 break; 3290 } 3291 3292 case SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED: { 3293 3294 *Status = STATUS_CLEANER_CARTRIDGE_INSTALLED; 3295 logError = FALSE; 3296 break; 3297 3298 } 3299 default: { 3300 break; 3301 } 3302 } // end switch AdditionalSenseCodeQualifier 3303 3304 } // end SCSI_ADSENSE_INVALID_MEDIA 3305 3306 break; 3307 3308 } // end SCSI_SENSE_MEDIUM_ERROR 3309 3310 case SCSI_SENSE_HARDWARE_ERROR: { 3311 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3312 "Hardware error\n")); 3313 *Status = STATUS_IO_DEVICE_ERROR; 3314 logError = TRUE; 3315 uniqueId = 257; 3316 logStatus = IO_ERR_CONTROLLER_ERROR; 3317 break; 3318 } // end SCSI_SENSE_HARDWARE_ERROR 3319 3320 case SCSI_SENSE_ILLEGAL_REQUEST: { 3321 3322 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3323 "Illegal SCSI request\n")); 3324 *Status = STATUS_INVALID_DEVICE_REQUEST; 3325 retry = FALSE; 3326 3327 switch (senseBuffer->AdditionalSenseCode) { 3328 3329 case SCSI_ADSENSE_ILLEGAL_COMMAND: { 3330 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3331 "Illegal command\n")); 3332 break; 3333 } 3334 3335 case SCSI_ADSENSE_ILLEGAL_BLOCK: { 3336 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3337 "Illegal block address\n")); 3338 *Status = STATUS_NONEXISTENT_SECTOR; 3339 break; 3340 } 3341 3342 case SCSI_ADSENSE_INVALID_LUN: { 3343 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3344 "Invalid LUN\n")); 3345 *Status = STATUS_NO_SUCH_DEVICE; 3346 break; 3347 } 3348 3349 case SCSI_ADSENSE_MUSIC_AREA: { 3350 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3351 "Music area\n")); 3352 break; 3353 } 3354 3355 case SCSI_ADSENSE_DATA_AREA: { 3356 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3357 "Data area\n")); 3358 break; 3359 } 3360 3361 case SCSI_ADSENSE_VOLUME_OVERFLOW: { 3362 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3363 "Volume overflow\n")); 3364 break; 3365 } 3366 3367 case SCSI_ADSENSE_COPY_PROTECTION_FAILURE: { 3368 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3369 "Copy protection failure\n")); 3370 3371 *Status = STATUS_COPY_PROTECTION_FAILURE; 3372 3373 switch (senseBuffer->AdditionalSenseCodeQualifier) { 3374 case SCSI_SENSEQ_AUTHENTICATION_FAILURE: 3375 DebugPrint((ClassDebugSenseInfo, 3376 "ClassInterpretSenseInfo: " 3377 "Authentication failure\n")); 3378 *Status = STATUS_CSS_AUTHENTICATION_FAILURE; 3379 break; 3380 case SCSI_SENSEQ_KEY_NOT_PRESENT: 3381 DebugPrint((ClassDebugSenseInfo, 3382 "ClassInterpretSenseInfo: " 3383 "Key not present\n")); 3384 *Status = STATUS_CSS_KEY_NOT_PRESENT; 3385 break; 3386 case SCSI_SENSEQ_KEY_NOT_ESTABLISHED: 3387 DebugPrint((ClassDebugSenseInfo, 3388 "ClassInterpretSenseInfo: " 3389 "Key not established\n")); 3390 *Status = STATUS_CSS_KEY_NOT_ESTABLISHED; 3391 break; 3392 case SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION: 3393 DebugPrint((ClassDebugSenseInfo, 3394 "ClassInterpretSenseInfo: " 3395 "Read of scrambled sector w/o " 3396 "authentication\n")); 3397 *Status = STATUS_CSS_SCRAMBLED_SECTOR; 3398 break; 3399 case SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT: 3400 DebugPrint((ClassDebugSenseInfo, 3401 "ClassInterpretSenseInfo: " 3402 "Media region does not logical unit " 3403 "region\n")); 3404 *Status = STATUS_CSS_REGION_MISMATCH; 3405 break; 3406 case SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR: 3407 DebugPrint((ClassDebugSenseInfo, 3408 "ClassInterpretSenseInfo: " 3409 "Region set error -- region may " 3410 "be permanent\n")); 3411 *Status = STATUS_CSS_RESETS_EXHAUSTED; 3412 break; 3413 } // end switch of ASCQ for COPY_PROTECTION_FAILURE 3414 3415 break; 3416 } 3417 3418 3419 case SCSI_ADSENSE_INVALID_CDB: { 3420 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3421 "Invalid CDB\n")); 3422 3423 // 3424 // Note: the retry interval is not typically used. 3425 // it is set here only because a ClassErrorHandler 3426 // cannot set the retryInterval, and the error may 3427 // require a few commands to be sent to clear whatever 3428 // caused this condition (i.e. disk clears the write 3429 // cache, requiring at least two commands) 3430 // 3431 // hopefully, this shortcoming can be changed for 3432 // blackcomb. 3433 // 3434 3435 retryInterval = 3; 3436 break; 3437 } 3438 3439 } // end switch (senseBuffer->AdditionalSenseCode) 3440 3441 break; 3442 } // end SCSI_SENSE_ILLEGAL_REQUEST 3443 3444 case SCSI_SENSE_UNIT_ATTENTION: { 3445 3446 //PVPB vpb; 3447 ULONG count; 3448 3449 // 3450 // A media change may have occured so increment the change 3451 // count for the physical device 3452 // 3453 3454 count = InterlockedIncrement((PLONG)&fdoExtension->MediaChangeCount); 3455 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3456 "Media change count for device %d incremented to %#lx\n", 3457 fdoExtension->DeviceNumber, count)); 3458 3459 3460 switch (senseBuffer->AdditionalSenseCode) { 3461 case SCSI_ADSENSE_MEDIUM_CHANGED: { 3462 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3463 "Media changed\n")); 3464 3465 if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { 3466 DebugPrint((ClassDebugError, "ClassInterpretSenseInfo: " 3467 "Media Changed on non-removable device %p\n", 3468 Fdo)); 3469 } 3470 ClassSetMediaChangeState(fdoExtension, MediaPresent, FALSE); 3471 break; 3472 } 3473 3474 case SCSI_ADSENSE_BUS_RESET: { 3475 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3476 "Bus reset\n")); 3477 break; 3478 } 3479 3480 case SCSI_ADSENSE_OPERATOR_REQUEST: { 3481 switch (senseBuffer->AdditionalSenseCodeQualifier) { 3482 3483 case SCSI_SENSEQ_MEDIUM_REMOVAL: { 3484 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3485 "Ejection request received!\n")); 3486 ClassSendEjectionNotification(fdoExtension); 3487 break; 3488 } 3489 3490 case SCSI_SENSEQ_WRITE_PROTECT_ENABLE: { 3491 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3492 "Operator selected write permit?! " 3493 "(unsupported!)\n")); 3494 break; 3495 } 3496 3497 case SCSI_SENSEQ_WRITE_PROTECT_DISABLE: { 3498 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3499 "Operator selected write protect?! " 3500 "(unsupported!)\n")); 3501 break; 3502 } 3503 3504 } 3505 break; 3506 } 3507 3508 default: { 3509 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3510 "Unit attention\n")); 3511 break; 3512 } 3513 3514 } // end switch (senseBuffer->AdditionalSenseCode) 3515 3516 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) 3517 { 3518 // 3519 // TODO : Is the media lockable? 3520 // 3521 3522 if ((ClassGetVpb(Fdo) != NULL) && (ClassGetVpb(Fdo)->Flags & VPB_MOUNTED)) 3523 { 3524 // 3525 // Set bit to indicate that media may have changed 3526 // and volume needs verification. 3527 // 3528 3529 SET_FLAG(Fdo->Flags, DO_VERIFY_VOLUME); 3530 3531 *Status = STATUS_VERIFY_REQUIRED; 3532 retry = FALSE; 3533 } 3534 } 3535 else 3536 { 3537 *Status = STATUS_IO_DEVICE_ERROR; 3538 } 3539 3540 break; 3541 3542 } // end SCSI_SENSE_UNIT_ATTENTION 3543 3544 case SCSI_SENSE_ABORTED_COMMAND: { 3545 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3546 "Command aborted\n")); 3547 *Status = STATUS_IO_DEVICE_ERROR; 3548 retryInterval = 1; 3549 break; 3550 } // end SCSI_SENSE_ABORTED_COMMAND 3551 3552 case SCSI_SENSE_BLANK_CHECK: { 3553 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3554 "Media blank check\n")); 3555 retry = FALSE; 3556 *Status = STATUS_NO_DATA_DETECTED; 3557 break; 3558 } // end SCSI_SENSE_BLANK_CHECK 3559 3560 case SCSI_SENSE_RECOVERED_ERROR: { 3561 3562 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3563 "Recovered error\n")); 3564 *Status = STATUS_SUCCESS; 3565 retry = FALSE; 3566 logError = TRUE; 3567 uniqueId = 258; 3568 3569 switch(senseBuffer->AdditionalSenseCode) { 3570 case SCSI_ADSENSE_SEEK_ERROR: 3571 case SCSI_ADSENSE_TRACK_ERROR: { 3572 logStatus = IO_ERR_SEEK_ERROR; 3573 break; 3574 } 3575 3576 case SCSI_ADSENSE_REC_DATA_NOECC: 3577 case SCSI_ADSENSE_REC_DATA_ECC: { 3578 logStatus = IO_RECOVERED_VIA_ECC; 3579 break; 3580 } 3581 3582 case SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED: { 3583 UCHAR wmiEventData[5]; 3584 3585 *((PULONG)wmiEventData) = sizeof(UCHAR); 3586 wmiEventData[sizeof(ULONG)] = senseBuffer->AdditionalSenseCodeQualifier; 3587 3588 // 3589 // Don't log another eventlog if we have already logged once 3590 // NOTE: this should have been interlocked, but the structure 3591 // was publicly defined to use a BOOLEAN (char). Since 3592 // media only reports these errors once per X minutes, 3593 // the potential race condition is nearly non-existant. 3594 // the worst case is duplicate log entries, so ignore. 3595 // 3596 3597 if (fdoExtension->FailurePredicted == 0) { 3598 logError = TRUE; 3599 } 3600 fdoExtension->FailurePredicted = TRUE; 3601 fdoExtension->FailureReason = senseBuffer->AdditionalSenseCodeQualifier; 3602 logStatus = IO_WRN_FAILURE_PREDICTED; 3603 3604 ClassNotifyFailurePredicted(fdoExtension, 3605 (PUCHAR)&wmiEventData, 3606 sizeof(wmiEventData), 3607 0, 3608 4, 3609 Srb->PathId, 3610 Srb->TargetId, 3611 Srb->Lun); 3612 break; 3613 } 3614 3615 default: { 3616 logStatus = IO_ERR_CONTROLLER_ERROR; 3617 break; 3618 } 3619 3620 } // end switch(senseBuffer->AdditionalSenseCode) 3621 3622 if (senseBuffer->IncorrectLength) { 3623 3624 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3625 "Incorrect length detected.\n")); 3626 *Status = STATUS_INVALID_BLOCK_LENGTH ; 3627 } 3628 3629 break; 3630 } // end SCSI_SENSE_RECOVERED_ERROR 3631 3632 case SCSI_SENSE_NO_SENSE: { 3633 3634 // 3635 // Check other indicators. 3636 // 3637 3638 if (senseBuffer->IncorrectLength) { 3639 3640 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3641 "Incorrect length detected.\n")); 3642 *Status = STATUS_INVALID_BLOCK_LENGTH ; 3643 retry = FALSE; 3644 3645 } else { 3646 3647 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3648 "No specific sense key\n")); 3649 *Status = STATUS_IO_DEVICE_ERROR; 3650 retry = TRUE; 3651 } 3652 3653 break; 3654 } // end SCSI_SENSE_NO_SENSE 3655 3656 default: { 3657 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3658 "Unrecognized sense code\n")); 3659 *Status = STATUS_IO_DEVICE_ERROR; 3660 break; 3661 } 3662 3663 } // end switch (senseBuffer->SenseKey & 0xf) 3664 3665 // 3666 // Try to determine the bad sector from the inquiry data. 3667 // 3668 3669 if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_READ || 3670 ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY || 3671 ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_WRITE)) { 3672 3673 for (index = 0; index < 4; index++) { 3674 badSector = (badSector << 8) | senseBuffer->Information[index]; 3675 } 3676 3677 readSector = 0; 3678 for (index = 0; index < 4; index++) { 3679 readSector = (readSector << 8) | Srb->Cdb[index+2]; 3680 } 3681 3682 index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) | 3683 ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb; 3684 3685 // 3686 // Make sure the bad sector is within the read sectors. 3687 // 3688 3689 if (!(badSector >= readSector && badSector < readSector + index)) { 3690 badSector = readSector; 3691 } 3692 } 3693 3694 } else { 3695 3696 // 3697 // Request sense buffer not valid. No sense information 3698 // to pinpoint the error. Return general request fail. 3699 // 3700 3701 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 3702 "Request sense info not valid. SrbStatus %2x\n", 3703 SRB_STATUS(Srb->SrbStatus))); 3704 retry = TRUE; 3705 3706 switch (SRB_STATUS(Srb->SrbStatus)) { 3707 case SRB_STATUS_INVALID_LUN: 3708 case SRB_STATUS_INVALID_TARGET_ID: 3709 case SRB_STATUS_NO_DEVICE: 3710 case SRB_STATUS_NO_HBA: 3711 case SRB_STATUS_INVALID_PATH_ID: { 3712 *Status = STATUS_NO_SUCH_DEVICE; 3713 retry = FALSE; 3714 break; 3715 } 3716 3717 case SRB_STATUS_COMMAND_TIMEOUT: 3718 case SRB_STATUS_TIMEOUT: { 3719 3720 // 3721 // Update the error count for the device. 3722 // 3723 3724 incrementErrorCount = TRUE; 3725 *Status = STATUS_IO_TIMEOUT; 3726 break; 3727 } 3728 3729 case SRB_STATUS_ABORTED: { 3730 3731 // 3732 // Update the error count for the device. 3733 // 3734 3735 incrementErrorCount = TRUE; 3736 *Status = STATUS_IO_TIMEOUT; 3737 retryInterval = 1; 3738 break; 3739 } 3740 3741 3742 case SRB_STATUS_SELECTION_TIMEOUT: { 3743 logError = TRUE; 3744 logStatus = IO_ERR_NOT_READY; 3745 uniqueId = 260; 3746 *Status = STATUS_DEVICE_NOT_CONNECTED; 3747 retry = FALSE; 3748 break; 3749 } 3750 3751 case SRB_STATUS_DATA_OVERRUN: { 3752 *Status = STATUS_DATA_OVERRUN; 3753 retry = FALSE; 3754 break; 3755 } 3756 3757 case SRB_STATUS_PHASE_SEQUENCE_FAILURE: { 3758 3759 // 3760 // Update the error count for the device. 3761 // 3762 3763 incrementErrorCount = TRUE; 3764 *Status = STATUS_IO_DEVICE_ERROR; 3765 3766 // 3767 // If there was phase sequence error then limit the number of 3768 // retries. 3769 // 3770 3771 if (RetryCount > 1 ) { 3772 retry = FALSE; 3773 } 3774 3775 break; 3776 } 3777 3778 case SRB_STATUS_REQUEST_FLUSHED: { 3779 3780 // 3781 // If the status needs verification bit is set. Then set 3782 // the status to need verification and no retry; otherwise, 3783 // just retry the request. 3784 // 3785 3786 if (TEST_FLAG(Fdo->Flags, DO_VERIFY_VOLUME)) { 3787 3788 *Status = STATUS_VERIFY_REQUIRED; 3789 retry = FALSE; 3790 3791 } else { 3792 *Status = STATUS_IO_DEVICE_ERROR; 3793 } 3794 3795 break; 3796 } 3797 3798 case SRB_STATUS_INVALID_REQUEST: { 3799 *Status = STATUS_INVALID_DEVICE_REQUEST; 3800 retry = FALSE; 3801 break; 3802 } 3803 3804 case SRB_STATUS_UNEXPECTED_BUS_FREE: 3805 case SRB_STATUS_PARITY_ERROR: 3806 3807 // 3808 // Update the error count for the device 3809 // and fall through to below 3810 // 3811 3812 incrementErrorCount = TRUE; 3813 3814 case SRB_STATUS_BUS_RESET: { 3815 *Status = STATUS_IO_DEVICE_ERROR; 3816 break; 3817 } 3818 3819 case SRB_STATUS_ERROR: { 3820 3821 *Status = STATUS_IO_DEVICE_ERROR; 3822 if (Srb->ScsiStatus == 0) { 3823 3824 // 3825 // This is some strange return code. Update the error 3826 // count for the device. 3827 // 3828 3829 incrementErrorCount = TRUE; 3830 3831 } if (Srb->ScsiStatus == SCSISTAT_BUSY) { 3832 3833 *Status = STATUS_DEVICE_NOT_READY; 3834 3835 } if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) { 3836 3837 *Status = STATUS_DEVICE_BUSY; 3838 retry = FALSE; 3839 logError = FALSE; 3840 3841 } 3842 3843 break; 3844 } 3845 3846 default: { 3847 logError = TRUE; 3848 logStatus = IO_ERR_CONTROLLER_ERROR; 3849 uniqueId = 259; 3850 *Status = STATUS_IO_DEVICE_ERROR; 3851 unhandledError = TRUE; 3852 break; 3853 } 3854 3855 } 3856 3857 // 3858 // NTRAID #183546 - if we support GESN subtype NOT_READY events, and 3859 // we know from a previous poll when the device will be ready (ETA) 3860 // we should delay the retry more appropriately than just guessing. 3861 // 3862 /* 3863 if (fdoExtension->MediaChangeDetectionInfo && 3864 fdoExtension->MediaChangeDetectionInfo->Gesn.Supported && 3865 TEST_FLAG(fdoExtension->MediaChangeDetectionInfo->Gesn.EventMask, 3866 NOTIFICATION_DEVICE_BUSY_CLASS_MASK) 3867 ) { 3868 // check if Gesn.ReadyTime if greater than current tick count 3869 // if so, delay that long (from 1 to 30 seconds max?) 3870 // else, leave the guess of time alone. 3871 } 3872 */ 3873 3874 } 3875 3876 if (incrementErrorCount) { 3877 3878 // 3879 // if any error count occurred, delay the retry of this io by 3880 // at least one second, if caller supports it. 3881 // 3882 3883 if (retryInterval == 0) { 3884 retryInterval = 1; 3885 } 3886 ClasspPerfIncrementErrorCount(fdoExtension); 3887 } 3888 3889 // 3890 // If there is a class specific error handler call it. 3891 // 3892 3893 if (fdoExtension->CommonExtension.DevInfo->ClassError != NULL) { 3894 3895 fdoExtension->CommonExtension.DevInfo->ClassError(Fdo, 3896 Srb, 3897 Status, 3898 &retry); 3899 } 3900 3901 // 3902 // If the caller wants to know the suggested retry interval tell them. 3903 // 3904 3905 if(ARGUMENT_PRESENT(RetryInterval)) { 3906 *RetryInterval = retryInterval; 3907 } 3908 3909 3910 /* 3911 * LOG the error: 3912 * Always log the error in our internal log. 3913 * If logError is set, also log the error in the system log. 3914 */ 3915 { 3916 ULONG totalSize; 3917 ULONG senseBufferSize = 0; 3918 IO_ERROR_LOG_PACKET staticErrLogEntry = {0}; 3919 CLASS_ERROR_LOG_DATA staticErrLogData = { { { 0 } } }; 3920 3921 // 3922 // Calculate the total size of the error log entry. 3923 // add to totalSize in the order that they are used. 3924 // the advantage to calculating all the sizes here is 3925 // that we don't have to do a bunch of extraneous checks 3926 // later on in this code path. 3927 // 3928 totalSize = sizeof(IO_ERROR_LOG_PACKET) // required 3929 - sizeof(ULONG) // struct includes one ULONG 3930 + sizeof(CLASS_ERROR_LOG_DATA);// struct for ease 3931 3932 // 3933 // also save any available extra sense data, up to the maximum errlog 3934 // packet size . WMI should be used for real-time analysis. 3935 // the event log should only be used for post-mortem debugging. 3936 // 3937 if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) { 3938 ULONG validSenseBytes; 3939 BOOLEAN validSense; 3940 3941 // 3942 // make sure we can at least access the AdditionalSenseLength field 3943 // 3944 validSense = RTL_CONTAINS_FIELD(senseBuffer, 3945 Srb->SenseInfoBufferLength, 3946 AdditionalSenseLength); 3947 if (validSense) { 3948 3949 // 3950 // if extra info exists, copy the maximum amount of available 3951 // sense data that is safe into the the errlog. 3952 // 3953 validSenseBytes = senseBuffer->AdditionalSenseLength 3954 + offsetof(SENSE_DATA, AdditionalSenseLength); 3955 3956 // 3957 // this is invalid because it causes overflow! 3958 // whoever sent this type of request would cause 3959 // a system crash. 3960 // 3961 ASSERT(validSenseBytes < MAX_ADDITIONAL_SENSE_BYTES); 3962 3963 // 3964 // set to save the most sense buffer possible 3965 // 3966 senseBufferSize = max(validSenseBytes, sizeof(SENSE_DATA)); 3967 senseBufferSize = min(senseBufferSize, Srb->SenseInfoBufferLength); 3968 } else { 3969 // 3970 // it's smaller than required to read the total number of 3971 // valid bytes, so just use the SenseInfoBufferLength field. 3972 // 3973 senseBufferSize = Srb->SenseInfoBufferLength; 3974 } 3975 3976 /* 3977 * Bump totalSize by the number of extra senseBuffer bytes 3978 * (beyond the default sense buffer within CLASS_ERROR_LOG_DATA). 3979 * Make sure to never allocate more than ERROR_LOG_MAXIMUM_SIZE. 3980 */ 3981 if (senseBufferSize > sizeof(SENSE_DATA)){ 3982 totalSize += senseBufferSize-sizeof(SENSE_DATA); 3983 if (totalSize > ERROR_LOG_MAXIMUM_SIZE){ 3984 senseBufferSize -= totalSize-ERROR_LOG_MAXIMUM_SIZE; 3985 totalSize = ERROR_LOG_MAXIMUM_SIZE; 3986 } 3987 } 3988 } 3989 3990 // 3991 // If we've used up all of our retry attempts, set the final status to 3992 // reflect the appropriate result. 3993 // 3994 if (retry && RetryCount < MAXIMUM_RETRIES) { 3995 staticErrLogEntry.FinalStatus = STATUS_SUCCESS; 3996 staticErrLogData.ErrorRetried = TRUE; 3997 } else { 3998 staticErrLogEntry.FinalStatus = *Status; 3999 } 4000 if (TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) { 4001 staticErrLogData.ErrorPaging = TRUE; 4002 } 4003 if (unhandledError) { 4004 staticErrLogData.ErrorUnhandled = TRUE; 4005 } 4006 4007 // 4008 // Calculate the device offset if there is a geometry. 4009 // 4010 staticErrLogEntry.DeviceOffset.QuadPart = (LONGLONG)badSector; 4011 staticErrLogEntry.DeviceOffset.QuadPart *= (LONGLONG)fdoExtension->DiskGeometry.BytesPerSector; 4012 if (logStatus == -1){ 4013 staticErrLogEntry.ErrorCode = STATUS_IO_DEVICE_ERROR; 4014 } else { 4015 staticErrLogEntry.ErrorCode = logStatus; 4016 } 4017 4018 /* 4019 * The dump data follows the IO_ERROR_LOG_PACKET, 4020 * with the first ULONG of dump data inside the packet. 4021 */ 4022 staticErrLogEntry.DumpDataSize = (USHORT)totalSize - sizeof(IO_ERROR_LOG_PACKET) + sizeof(ULONG); 4023 4024 staticErrLogEntry.SequenceNumber = 0; 4025 staticErrLogEntry.MajorFunctionCode = MajorFunctionCode; 4026 staticErrLogEntry.IoControlCode = IoDeviceCode; 4027 staticErrLogEntry.RetryCount = (UCHAR) RetryCount; 4028 staticErrLogEntry.UniqueErrorValue = uniqueId; 4029 4030 KeQueryTickCount(&staticErrLogData.TickCount); 4031 staticErrLogData.PortNumber = (ULONG)-1; 4032 4033 /* 4034 * Save the entire contents of the SRB. 4035 */ 4036 staticErrLogData.Srb = *Srb; 4037 4038 /* 4039 * For our private log, save just the default length of the SENSE_DATA. 4040 */ 4041 if (senseBufferSize != 0){ 4042 RtlCopyMemory(&staticErrLogData.SenseData, senseBuffer, min(senseBufferSize, sizeof(SENSE_DATA))); 4043 } 4044 4045 /* 4046 * Save the error log in our context. 4047 * We only save the default sense buffer length. 4048 */ 4049 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 4050 fdoData->ErrorLogs[fdoData->ErrorLogNextIndex] = staticErrLogData; 4051 fdoData->ErrorLogNextIndex++; 4052 fdoData->ErrorLogNextIndex %= NUM_ERROR_LOG_ENTRIES; 4053 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 4054 4055 /* 4056 * If logError is set, also save this log in the system's error log. 4057 * But make sure we don't log TUR failures over and over 4058 * (e.g. if an external drive was switched off and we're still sending TUR's to it every second). 4059 */ 4060 if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_TEST_UNIT_READY) && logError){ 4061 if (fdoData->LoggedTURFailureSinceLastIO){ 4062 logError = FALSE; 4063 } 4064 else { 4065 fdoData->LoggedTURFailureSinceLastIO = TRUE; 4066 } 4067 } 4068 if (logError){ 4069 PIO_ERROR_LOG_PACKET errorLogEntry; 4070 PCLASS_ERROR_LOG_DATA errlogData; 4071 4072 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(Fdo, (UCHAR)totalSize); 4073 if (errorLogEntry){ 4074 errlogData = (PCLASS_ERROR_LOG_DATA)errorLogEntry->DumpData; 4075 4076 *errorLogEntry = staticErrLogEntry; 4077 *errlogData = staticErrLogData; 4078 4079 /* 4080 * For the system log, copy as much of the sense buffer as possible. 4081 */ 4082 if (senseBufferSize != 0) { 4083 RtlCopyMemory(&errlogData->SenseData, senseBuffer, senseBufferSize); 4084 } 4085 4086 /* 4087 * Write the error log packet to the system error logging thread. 4088 */ 4089 IoWriteErrorLogEntry(errorLogEntry); 4090 } 4091 } 4092 } 4093 4094 return retry; 4095 4096 } // end ClassInterpretSenseInfo() 4097 4098 /*++//////////////////////////////////////////////////////////////////////////// 4099 4100 ClassModeSense() 4101 4102 Routine Description: 4103 4104 This routine sends a mode sense command to a target ID and returns 4105 when it is complete. 4106 4107 Arguments: 4108 4109 Fdo - Supplies the functional device object associated with this request. 4110 4111 ModeSenseBuffer - Supplies a buffer to store the sense data. 4112 4113 Length - Supplies the length in bytes of the mode sense buffer. 4114 4115 PageMode - Supplies the page or pages of mode sense data to be retrieved. 4116 4117 Return Value: 4118 4119 Length of the transferred data is returned. 4120 4121 --*/ 4122 ULONG NTAPI ClassModeSense( IN PDEVICE_OBJECT Fdo, 4123 IN PCHAR ModeSenseBuffer, 4124 IN ULONG Length, 4125 IN UCHAR PageMode) 4126 { 4127 ULONG lengthTransferred = 0; 4128 PMDL senseBufferMdl; 4129 4130 PAGED_CODE(); 4131 4132 senseBufferMdl = BuildDeviceInputMdl(ModeSenseBuffer, Length); 4133 if (senseBufferMdl){ 4134 4135 TRANSFER_PACKET *pkt = DequeueFreeTransferPacket(Fdo, TRUE); 4136 if (pkt){ 4137 KEVENT event; 4138 //NTSTATUS pktStatus; 4139 IRP pseudoIrp = {0}; 4140 4141 /* 4142 * Store the number of packets servicing the irp (one) 4143 * inside the original IRP. It will be used to counted down 4144 * to zero when the packet completes. 4145 * Initialize the original IRP's status to success. 4146 * If the packet fails, we will set it to the error status. 4147 */ 4148 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1); 4149 pseudoIrp.IoStatus.Status = STATUS_SUCCESS; 4150 pseudoIrp.IoStatus.Information = 0; 4151 pseudoIrp.MdlAddress = senseBufferMdl; 4152 4153 /* 4154 * Set this up as a SYNCHRONOUS transfer, submit it, 4155 * and wait for the packet to complete. The result 4156 * status will be written to the original irp. 4157 */ 4158 ASSERT(Length <= 0x0ff); 4159 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 4160 SetupModeSenseTransferPacket(pkt, &event, ModeSenseBuffer, (UCHAR)Length, PageMode, &pseudoIrp); 4161 SubmitTransferPacket(pkt); 4162 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 4163 4164 if (NT_SUCCESS(pseudoIrp.IoStatus.Status)){ 4165 lengthTransferred = (ULONG)pseudoIrp.IoStatus.Information; 4166 } 4167 else { 4168 /* 4169 * This request can sometimes fail legitimately 4170 * (e.g. when a SCSI device is attached but turned off) 4171 * so this is not necessarily a device/driver bug. 4172 */ 4173 DBGTRACE(ClassDebugWarning, ("ClassModeSense on Fdo %ph failed with status %xh.", Fdo, pseudoIrp.IoStatus.Status)); 4174 } 4175 } 4176 4177 FreeDeviceInputMdl(senseBufferMdl); 4178 } 4179 4180 return lengthTransferred; 4181 } 4182 4183 /*++//////////////////////////////////////////////////////////////////////////// 4184 4185 ClassFindModePage() 4186 4187 Routine Description: 4188 4189 This routine scans through the mode sense data and finds the requested 4190 mode sense page code. 4191 4192 Arguments: 4193 ModeSenseBuffer - Supplies a pointer to the mode sense data. 4194 4195 Length - Indicates the length of valid data. 4196 4197 PageMode - Supplies the page mode to be searched for. 4198 4199 Use6Byte - Indicates whether 6 or 10 byte mode sense was used. 4200 4201 Return Value: 4202 4203 A pointer to the the requested mode page. If the mode page was not found 4204 then NULL is return. 4205 4206 --*/ 4207 PVOID 4208 NTAPI 4209 ClassFindModePage( 4210 IN PCHAR ModeSenseBuffer, 4211 IN ULONG Length, 4212 IN UCHAR PageMode, 4213 IN BOOLEAN Use6Byte 4214 ) 4215 { 4216 PCHAR limit; 4217 ULONG parameterHeaderLength; 4218 PVOID result = NULL; 4219 4220 limit = ModeSenseBuffer + Length; 4221 parameterHeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10); 4222 4223 if (Length >= parameterHeaderLength) { 4224 4225 PMODE_PARAMETER_HEADER10 modeParam10; 4226 ULONG blockDescriptorLength; 4227 4228 /* 4229 * Skip the mode select header and block descriptors. 4230 */ 4231 if (Use6Byte){ 4232 blockDescriptorLength = ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength; 4233 } 4234 else { 4235 modeParam10 = (PMODE_PARAMETER_HEADER10) ModeSenseBuffer; 4236 blockDescriptorLength = modeParam10->BlockDescriptorLength[1]; 4237 } 4238 4239 ModeSenseBuffer += parameterHeaderLength + blockDescriptorLength; 4240 4241 // 4242 // ModeSenseBuffer now points at pages. Walk the pages looking for the 4243 // requested page until the limit is reached. 4244 // 4245 4246 while (ModeSenseBuffer + 4247 RTL_SIZEOF_THROUGH_FIELD(MODE_DISCONNECT_PAGE, PageLength) < limit) { 4248 4249 if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) { 4250 4251 /* 4252 * found the mode page. make sure it's safe to touch it all 4253 * before returning the pointer to caller 4254 */ 4255 4256 if (ModeSenseBuffer + ((PMODE_DISCONNECT_PAGE)ModeSenseBuffer)->PageLength > limit) { 4257 /* 4258 * Return NULL since the page is not safe to access in full 4259 */ 4260 result = NULL; 4261 } 4262 else { 4263 result = ModeSenseBuffer; 4264 } 4265 break; 4266 } 4267 4268 // 4269 // Advance to the next page which is 4-byte-aligned offset after this page. 4270 // 4271 ModeSenseBuffer += 4272 ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + 4273 RTL_SIZEOF_THROUGH_FIELD(MODE_DISCONNECT_PAGE, PageLength); 4274 4275 } 4276 } 4277 4278 return result; 4279 } // end ClassFindModePage() 4280 4281 /*++//////////////////////////////////////////////////////////////////////////// 4282 4283 ClassSendSrbAsynchronous() 4284 4285 Routine Description: 4286 4287 This routine takes a partially built Srb and an Irp and sends it down to 4288 the port driver. 4289 4290 This routine must be called with the remove lock held for the specified 4291 Irp. 4292 4293 Arguments: 4294 4295 Fdo - Supplies the functional device object for the original request. 4296 4297 Srb - Supplies a partially built ScsiRequestBlock. In particular, the 4298 CDB and the SRB timeout value must be filled in. The SRB must not be 4299 allocated from zone. 4300 4301 Irp - Supplies the requesting Irp. 4302 4303 BufferAddress - Supplies a pointer to the buffer to be transfered. 4304 4305 BufferLength - Supplies the length of data transfer. 4306 4307 WriteToDevice - Indicates the data transfer will be from system memory to 4308 device. 4309 4310 Return Value: 4311 4312 Returns STATUS_PENDING if the request is dispatched (since the 4313 completion routine may change the irp's status value we cannot simply 4314 return the value of the dispatch) 4315 4316 or returns a status value to indicate why it failed. 4317 4318 --*/ 4319 NTSTATUS 4320 NTAPI 4321 ClassSendSrbAsynchronous( 4322 PDEVICE_OBJECT Fdo, 4323 PSCSI_REQUEST_BLOCK Srb, 4324 PIRP Irp, 4325 PVOID BufferAddress, 4326 ULONG BufferLength, 4327 BOOLEAN WriteToDevice 4328 ) 4329 { 4330 4331 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 4332 PIO_STACK_LOCATION irpStack; 4333 4334 ULONG savedFlags; 4335 4336 // 4337 // Write length to SRB. 4338 // 4339 4340 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); 4341 4342 // 4343 // Set SCSI bus address. 4344 // 4345 4346 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 4347 4348 // 4349 // This is a violation of the SCSI spec but it is required for 4350 // some targets. 4351 // 4352 4353 // Srb->Cdb[1] |= deviceExtension->Lun << 5; 4354 4355 // 4356 // Indicate auto request sense by specifying buffer and size. 4357 // 4358 4359 Srb->SenseInfoBuffer = fdoExtension->SenseData; 4360 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 4361 Srb->DataBuffer = BufferAddress; 4362 4363 // 4364 // Save the class driver specific flags away. 4365 // 4366 4367 savedFlags = Srb->SrbFlags & SRB_FLAGS_CLASS_DRIVER_RESERVED; 4368 4369 // 4370 // Allow the caller to specify that they do not wish 4371 // IoStartNextPacket() to be called in the completion routine. 4372 // 4373 4374 SET_FLAG(savedFlags, (Srb->SrbFlags & SRB_FLAGS_DONT_START_NEXT_PACKET)); 4375 4376 if (BufferAddress != NULL) { 4377 4378 // 4379 // Build Mdl if necessary. 4380 // 4381 4382 if (Irp->MdlAddress == NULL) { 4383 4384 if (IoAllocateMdl(BufferAddress, 4385 BufferLength, 4386 FALSE, 4387 FALSE, 4388 Irp) == NULL) { 4389 4390 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 4391 4392 // 4393 // ClassIoComplete() would have free'd the srb 4394 // 4395 4396 if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) { 4397 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb); 4398 } 4399 ClassFreeOrReuseSrb(fdoExtension, Srb); 4400 ClassReleaseRemoveLock(Fdo, Irp); 4401 ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT); 4402 4403 return STATUS_INSUFFICIENT_RESOURCES; 4404 } 4405 4406 MmBuildMdlForNonPagedPool(Irp->MdlAddress); 4407 4408 } else { 4409 4410 // 4411 // Make sure the buffer requested matches the MDL. 4412 // 4413 4414 ASSERT(BufferAddress == MmGetMdlVirtualAddress(Irp->MdlAddress)); 4415 } 4416 4417 // 4418 // Set read flag. 4419 // 4420 4421 Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN; 4422 4423 } else { 4424 4425 // 4426 // Clear flags. 4427 // 4428 4429 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER; 4430 } 4431 4432 // 4433 // Restore saved flags. 4434 // 4435 4436 SET_FLAG(Srb->SrbFlags, savedFlags); 4437 4438 // 4439 // Disable synchronous transfer for these requests. 4440 // 4441 4442 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); 4443 4444 // 4445 // Set the transfer length. 4446 // 4447 4448 Srb->DataTransferLength = BufferLength; 4449 4450 // 4451 // Zero out status. 4452 // 4453 4454 Srb->ScsiStatus = Srb->SrbStatus = 0; 4455 4456 Srb->NextSrb = 0; 4457 4458 // 4459 // Save a few parameters in the current stack location. 4460 // 4461 4462 irpStack = IoGetCurrentIrpStackLocation(Irp); 4463 4464 // 4465 // Save retry count in current Irp stack. 4466 // 4467 4468 irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES; 4469 4470 // 4471 // Set up IoCompletion routine address. 4472 // 4473 4474 IoSetCompletionRoutine(Irp, ClassIoComplete, Srb, TRUE, TRUE, TRUE); 4475 4476 // 4477 // Get next stack location and 4478 // set major function code. 4479 // 4480 4481 irpStack = IoGetNextIrpStackLocation(Irp); 4482 4483 irpStack->MajorFunction = IRP_MJ_SCSI; 4484 4485 // 4486 // Save SRB address in next stack for port driver. 4487 // 4488 4489 irpStack->Parameters.Scsi.Srb = Srb; 4490 4491 // 4492 // Set up Irp Address. 4493 // 4494 4495 Srb->OriginalRequest = Irp; 4496 4497 // 4498 // Call the port driver to process the request. 4499 // 4500 4501 IoMarkIrpPending(Irp); 4502 4503 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp); 4504 4505 return STATUS_PENDING; 4506 4507 } // end ClassSendSrbAsynchronous() 4508 4509 /*++//////////////////////////////////////////////////////////////////////////// 4510 4511 ClassDeviceControlDispatch() 4512 4513 Routine Description: 4514 4515 The routine is the common class driver device control dispatch entry point. 4516 This routine is invokes the device-specific drivers DeviceControl routine, 4517 (which may call the Class driver's common DeviceControl routine). 4518 4519 Arguments: 4520 4521 DeviceObject - Supplies a pointer to the device object for this request. 4522 4523 Irp - Supplies the Irp making the request. 4524 4525 Return Value: 4526 4527 Returns the status returned from the device-specific driver. 4528 4529 --*/ 4530 NTSTATUS 4531 NTAPI 4532 ClassDeviceControlDispatch( 4533 PDEVICE_OBJECT DeviceObject, 4534 PIRP Irp 4535 ) 4536 { 4537 4538 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 4539 ULONG isRemoved; 4540 4541 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 4542 4543 if(isRemoved) { 4544 4545 ClassReleaseRemoveLock(DeviceObject, Irp); 4546 4547 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 4548 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 4549 return STATUS_DEVICE_DOES_NOT_EXIST; 4550 } 4551 4552 // 4553 // Call the class specific driver DeviceControl routine. 4554 // If it doesn't handle it, it will call back into ClassDeviceControl. 4555 // 4556 4557 ASSERT(commonExtension->DevInfo->ClassDeviceControl); 4558 4559 return commonExtension->DevInfo->ClassDeviceControl(DeviceObject,Irp); 4560 } // end ClassDeviceControlDispatch() 4561 4562 /*++//////////////////////////////////////////////////////////////////////////// 4563 4564 ClassDeviceControl() 4565 4566 Routine Description: 4567 4568 The routine is the common class driver device control dispatch function. 4569 This routine is called by a class driver when it get an unrecognized 4570 device control request. This routine will perform the correct action for 4571 common requests such as lock media. If the device request is unknown it 4572 passed down to the next level. 4573 4574 This routine must be called with the remove lock held for the specified 4575 irp. 4576 4577 Arguments: 4578 4579 DeviceObject - Supplies a pointer to the device object for this request. 4580 4581 Irp - Supplies the Irp making the request. 4582 4583 Return Value: 4584 4585 Returns back a STATUS_PENDING or a completion status. 4586 4587 --*/ 4588 NTSTATUS 4589 NTAPI 4590 ClassDeviceControl( 4591 PDEVICE_OBJECT DeviceObject, 4592 PIRP Irp 4593 ) 4594 { 4595 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 4596 4597 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 4598 PIO_STACK_LOCATION nextStack = NULL; 4599 4600 ULONG controlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; 4601 4602 PSCSI_REQUEST_BLOCK srb = NULL; 4603 PCDB cdb = NULL; 4604 4605 NTSTATUS status; 4606 ULONG modifiedIoControlCode; 4607 4608 // 4609 // If this is a pass through I/O control, set the minor function code 4610 // and device address and pass it to the port driver. 4611 // 4612 4613 if ((controlCode == IOCTL_SCSI_PASS_THROUGH) || 4614 (controlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)) { 4615 4616 //PSCSI_PASS_THROUGH scsiPass; 4617 4618 // 4619 // Validate the user buffer. 4620 // 4621 #if defined (_WIN64) 4622 4623 if (IoIs32bitProcess(Irp)) { 4624 4625 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32)){ 4626 4627 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 4628 4629 ClassReleaseRemoveLock(DeviceObject, Irp); 4630 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 4631 4632 status = STATUS_INVALID_PARAMETER; 4633 goto SetStatusAndReturn; 4634 } 4635 } 4636 else 4637 #endif 4638 { 4639 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 4640 sizeof(SCSI_PASS_THROUGH)) { 4641 4642 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 4643 4644 ClassReleaseRemoveLock(DeviceObject, Irp); 4645 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 4646 4647 status = STATUS_INVALID_PARAMETER; 4648 goto SetStatusAndReturn; 4649 } 4650 } 4651 4652 IoCopyCurrentIrpStackLocationToNext(Irp); 4653 4654 nextStack = IoGetNextIrpStackLocation(Irp); 4655 nextStack->MinorFunction = 1; 4656 4657 ClassReleaseRemoveLock(DeviceObject, Irp); 4658 4659 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 4660 goto SetStatusAndReturn; 4661 } 4662 4663 Irp->IoStatus.Information = 0; 4664 4665 switch (controlCode) { 4666 4667 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: { 4668 4669 PMOUNTDEV_UNIQUE_ID uniqueId; 4670 4671 if (!commonExtension->MountedDeviceInterfaceName.Buffer) { 4672 status = STATUS_INVALID_PARAMETER; 4673 break; 4674 } 4675 4676 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 4677 sizeof(MOUNTDEV_UNIQUE_ID)) { 4678 4679 status = STATUS_BUFFER_TOO_SMALL; 4680 Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID); 4681 break; 4682 } 4683 4684 uniqueId = Irp->AssociatedIrp.SystemBuffer; 4685 uniqueId->UniqueIdLength = 4686 commonExtension->MountedDeviceInterfaceName.Length; 4687 4688 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 4689 sizeof(USHORT) + uniqueId->UniqueIdLength) { 4690 4691 status = STATUS_BUFFER_OVERFLOW; 4692 Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID); 4693 break; 4694 } 4695 4696 RtlCopyMemory(uniqueId->UniqueId, 4697 commonExtension->MountedDeviceInterfaceName.Buffer, 4698 uniqueId->UniqueIdLength); 4699 4700 status = STATUS_SUCCESS; 4701 Irp->IoStatus.Information = sizeof(USHORT) + 4702 uniqueId->UniqueIdLength; 4703 break; 4704 } 4705 4706 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: { 4707 4708 PMOUNTDEV_NAME name; 4709 4710 ASSERT(commonExtension->DeviceName.Buffer); 4711 4712 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 4713 sizeof(MOUNTDEV_NAME)) { 4714 4715 status = STATUS_BUFFER_TOO_SMALL; 4716 Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME); 4717 break; 4718 } 4719 4720 name = Irp->AssociatedIrp.SystemBuffer; 4721 name->NameLength = commonExtension->DeviceName.Length; 4722 4723 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 4724 sizeof(USHORT) + name->NameLength) { 4725 4726 status = STATUS_BUFFER_OVERFLOW; 4727 Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME); 4728 break; 4729 } 4730 4731 RtlCopyMemory(name->Name, commonExtension->DeviceName.Buffer, 4732 name->NameLength); 4733 4734 status = STATUS_SUCCESS; 4735 Irp->IoStatus.Information = sizeof(USHORT) + name->NameLength; 4736 break; 4737 } 4738 4739 case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: { 4740 4741 PMOUNTDEV_SUGGESTED_LINK_NAME suggestedName; 4742 WCHAR driveLetterNameBuffer[10]; 4743 RTL_QUERY_REGISTRY_TABLE queryTable[2]; 4744 PWSTR valueName; 4745 UNICODE_STRING driveLetterName; 4746 4747 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 4748 sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) { 4749 4750 status = STATUS_BUFFER_TOO_SMALL; 4751 Irp->IoStatus.Information = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME); 4752 break; 4753 } 4754 4755 valueName = ExAllocatePoolWithTag( 4756 PagedPool, 4757 commonExtension->DeviceName.Length + sizeof(WCHAR), 4758 '8CcS'); 4759 4760 if (!valueName) { 4761 status = STATUS_INSUFFICIENT_RESOURCES; 4762 break; 4763 } 4764 4765 RtlCopyMemory(valueName, commonExtension->DeviceName.Buffer, 4766 commonExtension->DeviceName.Length); 4767 valueName[commonExtension->DeviceName.Length/sizeof(WCHAR)] = 0; 4768 4769 driveLetterName.Buffer = driveLetterNameBuffer; 4770 driveLetterName.MaximumLength = 20; 4771 driveLetterName.Length = 0; 4772 4773 RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE)); 4774 queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | 4775 RTL_QUERY_REGISTRY_DIRECT; 4776 queryTable[0].Name = valueName; 4777 queryTable[0].EntryContext = &driveLetterName; 4778 4779 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 4780 L"\\Registry\\Machine\\System\\DISK", 4781 queryTable, NULL, NULL); 4782 4783 if (!NT_SUCCESS(status)) { 4784 ExFreePool(valueName); 4785 break; 4786 } 4787 4788 if (driveLetterName.Length == 4 && 4789 driveLetterName.Buffer[0] == '%' && 4790 driveLetterName.Buffer[1] == ':') { 4791 4792 driveLetterName.Buffer[0] = 0xFF; 4793 4794 } else if (driveLetterName.Length != 4 || 4795 driveLetterName.Buffer[0] < FirstDriveLetter || 4796 driveLetterName.Buffer[0] > LastDriveLetter || 4797 driveLetterName.Buffer[1] != ':') { 4798 4799 status = STATUS_NOT_FOUND; 4800 ExFreePool(valueName); 4801 break; 4802 } 4803 4804 suggestedName = Irp->AssociatedIrp.SystemBuffer; 4805 suggestedName->UseOnlyIfThereAreNoOtherLinks = TRUE; 4806 suggestedName->NameLength = 28; 4807 4808 Irp->IoStatus.Information = 4809 FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME, Name) + 28; 4810 4811 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 4812 Irp->IoStatus.Information) { 4813 4814 Irp->IoStatus.Information = 4815 sizeof(MOUNTDEV_SUGGESTED_LINK_NAME); 4816 status = STATUS_BUFFER_OVERFLOW; 4817 ExFreePool(valueName); 4818 break; 4819 } 4820 4821 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, 4822 L"\\Registry\\Machine\\System\\DISK", 4823 valueName); 4824 4825 ExFreePool(valueName); 4826 4827 RtlCopyMemory(suggestedName->Name, L"\\DosDevices\\", 24); 4828 suggestedName->Name[12] = driveLetterName.Buffer[0]; 4829 suggestedName->Name[13] = ':'; 4830 4831 // 4832 // NT_SUCCESS(status) based on RtlQueryRegistryValues 4833 // 4834 status = STATUS_SUCCESS; 4835 4836 break; 4837 } 4838 4839 default: 4840 status = STATUS_PENDING; 4841 break; 4842 } 4843 4844 if (status != STATUS_PENDING) { 4845 ClassReleaseRemoveLock(DeviceObject, Irp); 4846 Irp->IoStatus.Status = status; 4847 IoCompleteRequest(Irp, IO_NO_INCREMENT); 4848 return status; 4849 } 4850 4851 if (commonExtension->IsFdo){ 4852 4853 PULONG_PTR function; 4854 4855 srb = ExAllocatePoolWithTag(NonPagedPool, 4856 sizeof(SCSI_REQUEST_BLOCK) + 4857 (sizeof(ULONG_PTR) * 2), 4858 '9CcS'); 4859 4860 if (srb == NULL) { 4861 4862 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 4863 ClassReleaseRemoveLock(DeviceObject, Irp); 4864 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 4865 status = STATUS_INSUFFICIENT_RESOURCES; 4866 goto SetStatusAndReturn; 4867 } 4868 4869 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 4870 4871 cdb = (PCDB)srb->Cdb; 4872 4873 // 4874 // Save the function code and the device object in the memory after 4875 // the SRB. 4876 // 4877 4878 function = (PULONG_PTR) ((PSCSI_REQUEST_BLOCK) (srb + 1)); 4879 *function = (ULONG_PTR) DeviceObject; 4880 function++; 4881 *function = (ULONG_PTR) controlCode; 4882 4883 } else { 4884 srb = NULL; 4885 } 4886 4887 // 4888 // Change the device type to storage for the switch statement, but only 4889 // if from a legacy device type 4890 // 4891 4892 if (((controlCode & 0xffff0000) == (IOCTL_DISK_BASE << 16)) || 4893 ((controlCode & 0xffff0000) == (IOCTL_TAPE_BASE << 16)) || 4894 ((controlCode & 0xffff0000) == (IOCTL_CDROM_BASE << 16)) 4895 ) { 4896 4897 modifiedIoControlCode = (controlCode & ~0xffff0000); 4898 modifiedIoControlCode |= (IOCTL_STORAGE_BASE << 16); 4899 4900 } else { 4901 4902 modifiedIoControlCode = controlCode; 4903 4904 } 4905 4906 DBGTRACE(ClassDebugTrace, ("> ioctl %xh (%s)", modifiedIoControlCode, DBGGETIOCTLSTR(modifiedIoControlCode))); 4907 4908 switch (modifiedIoControlCode) { 4909 4910 case IOCTL_STORAGE_GET_HOTPLUG_INFO: { 4911 4912 if (srb) { 4913 ExFreePool(srb); 4914 srb = NULL; 4915 } 4916 4917 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength < 4918 sizeof(STORAGE_HOTPLUG_INFO)) { 4919 4920 // 4921 // Indicate unsuccessful status and no data transferred. 4922 // 4923 4924 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 4925 Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO); 4926 4927 ClassReleaseRemoveLock(DeviceObject, Irp); 4928 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 4929 status = STATUS_BUFFER_TOO_SMALL; 4930 4931 } else if(!commonExtension->IsFdo) { 4932 4933 // 4934 // Just forward this down and return 4935 // 4936 4937 IoCopyCurrentIrpStackLocationToNext(Irp); 4938 4939 ClassReleaseRemoveLock(DeviceObject, Irp); 4940 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 4941 4942 } else { 4943 4944 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 4945 PSTORAGE_HOTPLUG_INFO info; 4946 4947 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)commonExtension; 4948 info = Irp->AssociatedIrp.SystemBuffer; 4949 4950 *info = fdoExtension->PrivateFdoData->HotplugInfo; 4951 Irp->IoStatus.Status = STATUS_SUCCESS; 4952 Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO); 4953 ClassReleaseRemoveLock(DeviceObject, Irp); 4954 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 4955 status = STATUS_SUCCESS; 4956 4957 } 4958 break; 4959 } 4960 4961 case IOCTL_STORAGE_SET_HOTPLUG_INFO: { 4962 4963 if (srb) 4964 { 4965 ExFreePool(srb); 4966 srb = NULL; 4967 } 4968 4969 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 4970 sizeof(STORAGE_HOTPLUG_INFO)) { 4971 4972 // 4973 // Indicate unsuccessful status and no data transferred. 4974 // 4975 4976 Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH; 4977 4978 ClassReleaseRemoveLock(DeviceObject, Irp); 4979 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 4980 status = STATUS_INFO_LENGTH_MISMATCH; 4981 goto SetStatusAndReturn; 4982 4983 } 4984 4985 if(!commonExtension->IsFdo) { 4986 4987 // 4988 // Just forward this down and return 4989 // 4990 4991 IoCopyCurrentIrpStackLocationToNext(Irp); 4992 4993 ClassReleaseRemoveLock(DeviceObject, Irp); 4994 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 4995 4996 } else { 4997 4998 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)commonExtension; 4999 PSTORAGE_HOTPLUG_INFO info = Irp->AssociatedIrp.SystemBuffer; 5000 5001 status = STATUS_SUCCESS; 5002 5003 if (info->Size != fdoExtension->PrivateFdoData->HotplugInfo.Size) 5004 { 5005 status = STATUS_INVALID_PARAMETER_1; 5006 } 5007 5008 if (info->MediaRemovable != fdoExtension->PrivateFdoData->HotplugInfo.MediaRemovable) 5009 { 5010 status = STATUS_INVALID_PARAMETER_2; 5011 } 5012 5013 if (info->MediaHotplug != fdoExtension->PrivateFdoData->HotplugInfo.MediaHotplug) 5014 { 5015 status = STATUS_INVALID_PARAMETER_3; 5016 } 5017 5018 if (info->WriteCacheEnableOverride != fdoExtension->PrivateFdoData->HotplugInfo.WriteCacheEnableOverride) 5019 { 5020 status = STATUS_INVALID_PARAMETER_5; 5021 } 5022 5023 if (NT_SUCCESS(status)) 5024 { 5025 fdoExtension->PrivateFdoData->HotplugInfo.DeviceHotplug = info->DeviceHotplug; 5026 5027 // 5028 // Store the user-defined override in the registry 5029 // 5030 5031 ClassSetDeviceParameter(fdoExtension, 5032 CLASSP_REG_SUBKEY_NAME, 5033 CLASSP_REG_REMOVAL_POLICY_VALUE_NAME, 5034 (info->DeviceHotplug) ? RemovalPolicyExpectSurpriseRemoval : RemovalPolicyExpectOrderlyRemoval); 5035 } 5036 5037 Irp->IoStatus.Status = status; 5038 5039 ClassReleaseRemoveLock(DeviceObject, Irp); 5040 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 5041 } 5042 5043 break; 5044 } 5045 5046 case IOCTL_STORAGE_CHECK_VERIFY: 5047 case IOCTL_STORAGE_CHECK_VERIFY2: { 5048 5049 PIRP irp2 = NULL; 5050 PIO_STACK_LOCATION newStack; 5051 5052 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL; 5053 5054 DebugPrint((1,"DeviceIoControl: Check verify\n")); 5055 5056 // 5057 // If a buffer for a media change count was provided, make sure it's 5058 // big enough to hold the result 5059 // 5060 5061 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) { 5062 5063 // 5064 // If the buffer is too small to hold the media change count 5065 // then return an error to the caller 5066 // 5067 5068 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength < 5069 sizeof(ULONG)) { 5070 5071 DebugPrint((3,"DeviceIoControl: media count " 5072 "buffer too small\n")); 5073 5074 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 5075 Irp->IoStatus.Information = sizeof(ULONG); 5076 5077 if(srb != NULL) { 5078 ExFreePool(srb); 5079 } 5080 5081 ClassReleaseRemoveLock(DeviceObject, Irp); 5082 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 5083 5084 status = STATUS_BUFFER_TOO_SMALL; 5085 goto SetStatusAndReturn; 5086 5087 } 5088 } 5089 5090 if(!commonExtension->IsFdo) { 5091 5092 // 5093 // If this is a PDO then we should just forward the request down 5094 // 5095 ASSERT(!srb); 5096 5097 IoCopyCurrentIrpStackLocationToNext(Irp); 5098 5099 ClassReleaseRemoveLock(DeviceObject, Irp); 5100 5101 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 5102 5103 goto SetStatusAndReturn; 5104 5105 } else { 5106 5107 fdoExtension = DeviceObject->DeviceExtension; 5108 5109 } 5110 5111 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) { 5112 5113 // 5114 // The caller has provided a valid buffer. Allocate an additional 5115 // irp and stick the CheckVerify completion routine on it. We will 5116 // then send this down to the port driver instead of the irp the 5117 // caller sent in 5118 // 5119 5120 DebugPrint((2,"DeviceIoControl: Check verify wants " 5121 "media count\n")); 5122 5123 // 5124 // Allocate a new irp to send the TestUnitReady to the port driver 5125 // 5126 5127 irp2 = IoAllocateIrp((CCHAR) (DeviceObject->StackSize + 3), FALSE); 5128 5129 if(irp2 == NULL) { 5130 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 5131 Irp->IoStatus.Information = 0; 5132 ASSERT(srb); 5133 ExFreePool(srb); 5134 ClassReleaseRemoveLock(DeviceObject, Irp); 5135 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 5136 status = STATUS_INSUFFICIENT_RESOURCES; 5137 goto SetStatusAndReturn; 5138 5139 break; 5140 } 5141 5142 // 5143 // Make sure to acquire the lock for the new irp. 5144 // 5145 5146 ClassAcquireRemoveLock(DeviceObject, irp2); 5147 5148 irp2->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread; 5149 IoSetNextIrpStackLocation(irp2); 5150 5151 // 5152 // Set the top stack location and shove the master Irp into the 5153 // top location 5154 // 5155 5156 newStack = IoGetCurrentIrpStackLocation(irp2); 5157 newStack->Parameters.Others.Argument1 = Irp; 5158 newStack->DeviceObject = DeviceObject; 5159 5160 // 5161 // Stick the check verify completion routine onto the stack 5162 // and prepare the irp for the port driver 5163 // 5164 5165 IoSetCompletionRoutine(irp2, 5166 ClassCheckVerifyComplete, 5167 NULL, 5168 TRUE, 5169 TRUE, 5170 TRUE); 5171 5172 IoSetNextIrpStackLocation(irp2); 5173 newStack = IoGetCurrentIrpStackLocation(irp2); 5174 newStack->DeviceObject = DeviceObject; 5175 newStack->MajorFunction = irpStack->MajorFunction; 5176 newStack->MinorFunction = irpStack->MinorFunction; 5177 5178 // 5179 // Mark the master irp as pending - whether the lower level 5180 // driver completes it immediately or not this should allow it 5181 // to go all the way back up. 5182 // 5183 5184 IoMarkIrpPending(Irp); 5185 5186 Irp = irp2; 5187 5188 } 5189 5190 // 5191 // Test Unit Ready 5192 // 5193 5194 srb->CdbLength = 6; 5195 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; 5196 5197 // 5198 // Set timeout value. 5199 // 5200 5201 srb->TimeOutValue = fdoExtension->TimeOutValue; 5202 5203 // 5204 // If this was a CV2 then mark the request as low-priority so we don't 5205 // spin up the drive just to satisfy it. 5206 // 5207 5208 if(controlCode == IOCTL_STORAGE_CHECK_VERIFY2) { 5209 SET_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY); 5210 } 5211 5212 // 5213 // Since this routine will always hand the request to the 5214 // port driver if there isn't a data transfer to be done 5215 // we don't have to worry about completing the request here 5216 // on an error 5217 // 5218 5219 // 5220 // This routine uses a completion routine so we don't want to release 5221 // the remove lock until then. 5222 // 5223 5224 status = ClassSendSrbAsynchronous(DeviceObject, 5225 srb, 5226 Irp, 5227 NULL, 5228 0, 5229 FALSE); 5230 5231 break; 5232 } 5233 5234 case IOCTL_STORAGE_MEDIA_REMOVAL: 5235 case IOCTL_STORAGE_EJECTION_CONTROL: { 5236 5237 PPREVENT_MEDIA_REMOVAL mediaRemoval = Irp->AssociatedIrp.SystemBuffer; 5238 5239 DebugPrint((3, "DiskIoControl: ejection control\n")); 5240 5241 if(srb) { 5242 ExFreePool(srb); 5243 } 5244 5245 if(irpStack->Parameters.DeviceIoControl.InputBufferLength < 5246 sizeof(PREVENT_MEDIA_REMOVAL)) { 5247 5248 // 5249 // Indicate unsuccessful status and no data transferred. 5250 // 5251 5252 Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH; 5253 5254 ClassReleaseRemoveLock(DeviceObject, Irp); 5255 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 5256 status = STATUS_INFO_LENGTH_MISMATCH; 5257 goto SetStatusAndReturn; 5258 } 5259 5260 if(!commonExtension->IsFdo) { 5261 5262 // 5263 // Just forward this down and return 5264 // 5265 5266 IoCopyCurrentIrpStackLocationToNext(Irp); 5267 5268 ClassReleaseRemoveLock(DeviceObject, Irp); 5269 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 5270 } 5271 else { 5272 5273 // i don't believe this assertion is valid. this is a request 5274 // from user-mode, so they could request this for any device 5275 // they want? also, we handle it properly. 5276 // ASSERT(TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)); 5277 status = ClasspEjectionControl( 5278 DeviceObject, 5279 Irp, 5280 ((modifiedIoControlCode == 5281 IOCTL_STORAGE_EJECTION_CONTROL) ? SecureMediaLock : 5282 SimpleMediaLock), 5283 mediaRemoval->PreventMediaRemoval); 5284 5285 Irp->IoStatus.Status = status; 5286 ClassReleaseRemoveLock(DeviceObject, Irp); 5287 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 5288 } 5289 5290 break; 5291 } 5292 5293 case IOCTL_STORAGE_MCN_CONTROL: { 5294 5295 DebugPrint((3, "DiskIoControl: MCN control\n")); 5296 5297 if(irpStack->Parameters.DeviceIoControl.InputBufferLength < 5298 sizeof(PREVENT_MEDIA_REMOVAL)) { 5299 5300 // 5301 // Indicate unsuccessful status and no data transferred. 5302 // 5303 5304 Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH; 5305 Irp->IoStatus.Information = 0; 5306 5307 if(srb) { 5308 ExFreePool(srb); 5309 } 5310 5311 ClassReleaseRemoveLock(DeviceObject, Irp); 5312 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 5313 status = STATUS_INFO_LENGTH_MISMATCH; 5314 goto SetStatusAndReturn; 5315 } 5316 5317 if(!commonExtension->IsFdo) { 5318 5319 // 5320 // Just forward this down and return 5321 // 5322 5323 if(srb) { 5324 ExFreePool(srb); 5325 } 5326 5327 IoCopyCurrentIrpStackLocationToNext(Irp); 5328 5329 ClassReleaseRemoveLock(DeviceObject, Irp); 5330 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 5331 5332 } else { 5333 5334 // 5335 // Call to the FDO - handle the ejection control. 5336 // 5337 5338 status = ClasspMcnControl(DeviceObject->DeviceExtension, 5339 Irp, 5340 srb); 5341 } 5342 goto SetStatusAndReturn; 5343 } 5344 5345 case IOCTL_STORAGE_RESERVE: 5346 case IOCTL_STORAGE_RELEASE: { 5347 5348 // 5349 // Reserve logical unit. 5350 // 5351 5352 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL; 5353 5354 if(!commonExtension->IsFdo) { 5355 5356 IoCopyCurrentIrpStackLocationToNext(Irp); 5357 5358 ClassReleaseRemoveLock(DeviceObject, Irp); 5359 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 5360 goto SetStatusAndReturn; 5361 } else { 5362 fdoExtension = DeviceObject->DeviceExtension; 5363 } 5364 5365 srb->CdbLength = 6; 5366 5367 if(modifiedIoControlCode == IOCTL_STORAGE_RESERVE) { 5368 cdb->CDB6GENERIC.OperationCode = SCSIOP_RESERVE_UNIT; 5369 } else { 5370 cdb->CDB6GENERIC.OperationCode = SCSIOP_RELEASE_UNIT; 5371 } 5372 5373 // 5374 // Set timeout value. 5375 // 5376 5377 srb->TimeOutValue = fdoExtension->TimeOutValue; 5378 5379 status = ClassSendSrbAsynchronous(DeviceObject, 5380 srb, 5381 Irp, 5382 NULL, 5383 0, 5384 FALSE); 5385 5386 break; 5387 } 5388 5389 case IOCTL_STORAGE_EJECT_MEDIA: 5390 case IOCTL_STORAGE_LOAD_MEDIA: 5391 case IOCTL_STORAGE_LOAD_MEDIA2:{ 5392 5393 // 5394 // Eject media. 5395 // 5396 5397 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL; 5398 5399 if(!commonExtension->IsFdo) { 5400 5401 IoCopyCurrentIrpStackLocationToNext(Irp); 5402 5403 ClassReleaseRemoveLock(DeviceObject, Irp); 5404 5405 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 5406 goto SetStatusAndReturn; 5407 } else { 5408 fdoExtension = DeviceObject->DeviceExtension; 5409 } 5410 5411 if(commonExtension->PagingPathCount != 0) { 5412 5413 DebugPrint((1, "ClassDeviceControl: call to eject paging device - " 5414 "failure\n")); 5415 5416 status = STATUS_FILES_OPEN; 5417 Irp->IoStatus.Status = status; 5418 5419 Irp->IoStatus.Information = 0; 5420 5421 if(srb) { 5422 ExFreePool(srb); 5423 } 5424 5425 ClassReleaseRemoveLock(DeviceObject, Irp); 5426 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 5427 goto SetStatusAndReturn; 5428 } 5429 5430 // 5431 // Synchronize with ejection control and ejection cleanup code as 5432 // well as other eject/load requests. 5433 // 5434 5435 KeEnterCriticalRegion(); 5436 KeWaitForSingleObject(&(fdoExtension->EjectSynchronizationEvent), 5437 UserRequest, 5438 UserMode, 5439 FALSE, 5440 NULL); 5441 5442 if(fdoExtension->ProtectedLockCount != 0) { 5443 5444 DebugPrint((1, "ClassDeviceControl: call to eject protected locked " 5445 "device - failure\n")); 5446 5447 status = STATUS_DEVICE_BUSY; 5448 Irp->IoStatus.Status = status; 5449 Irp->IoStatus.Information = 0; 5450 5451 if(srb) { 5452 ExFreePool(srb); 5453 } 5454 5455 ClassReleaseRemoveLock(DeviceObject, Irp); 5456 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 5457 5458 KeSetEvent(&fdoExtension->EjectSynchronizationEvent, 5459 IO_NO_INCREMENT, 5460 FALSE); 5461 KeLeaveCriticalRegion(); 5462 5463 goto SetStatusAndReturn; 5464 } 5465 5466 srb->CdbLength = 6; 5467 5468 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 5469 cdb->START_STOP.LoadEject = 1; 5470 5471 if(modifiedIoControlCode == IOCTL_STORAGE_EJECT_MEDIA) { 5472 cdb->START_STOP.Start = 0; 5473 } else { 5474 cdb->START_STOP.Start = 1; 5475 } 5476 5477 // 5478 // Set timeout value. 5479 // 5480 5481 srb->TimeOutValue = fdoExtension->TimeOutValue; 5482 status = ClassSendSrbAsynchronous(DeviceObject, 5483 srb, 5484 Irp, 5485 NULL, 5486 0, 5487 FALSE); 5488 5489 KeSetEvent(&fdoExtension->EjectSynchronizationEvent, IO_NO_INCREMENT, FALSE); 5490 KeLeaveCriticalRegion(); 5491 5492 break; 5493 } 5494 5495 case IOCTL_STORAGE_FIND_NEW_DEVICES: { 5496 5497 if(srb) { 5498 ExFreePool(srb); 5499 } 5500 5501 if(commonExtension->IsFdo) { 5502 5503 IoInvalidateDeviceRelations( 5504 ((PFUNCTIONAL_DEVICE_EXTENSION) commonExtension)->LowerPdo, 5505 BusRelations); 5506 5507 status = STATUS_SUCCESS; 5508 Irp->IoStatus.Status = status; 5509 5510 ClassReleaseRemoveLock(DeviceObject, Irp); 5511 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 5512 } 5513 else { 5514 5515 IoCopyCurrentIrpStackLocationToNext(Irp); 5516 5517 ClassReleaseRemoveLock(DeviceObject, Irp); 5518 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 5519 } 5520 break; 5521 } 5522 5523 case IOCTL_STORAGE_GET_DEVICE_NUMBER: { 5524 5525 if(srb) { 5526 ExFreePool(srb); 5527 } 5528 5529 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength >= 5530 sizeof(STORAGE_DEVICE_NUMBER)) { 5531 5532 PSTORAGE_DEVICE_NUMBER deviceNumber = 5533 Irp->AssociatedIrp.SystemBuffer; 5534 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = 5535 commonExtension->PartitionZeroExtension; 5536 5537 deviceNumber->DeviceType = fdoExtension->CommonExtension.DeviceObject->DeviceType; 5538 deviceNumber->DeviceNumber = fdoExtension->DeviceNumber; 5539 deviceNumber->PartitionNumber = commonExtension->PartitionNumber; 5540 5541 status = STATUS_SUCCESS; 5542 Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER); 5543 5544 } else { 5545 status = STATUS_BUFFER_TOO_SMALL; 5546 Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER); 5547 } 5548 5549 Irp->IoStatus.Status = status; 5550 ClassReleaseRemoveLock(DeviceObject, Irp); 5551 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 5552 5553 break; 5554 } 5555 5556 default: { 5557 5558 DebugPrint((4, "IoDeviceControl: Unsupported device IOCTL %x for %p\n", 5559 controlCode, DeviceObject)); 5560 5561 // 5562 // Pass the device control to the next driver. 5563 // 5564 5565 if(srb) { 5566 ExFreePool(srb); 5567 } 5568 5569 // 5570 // Copy the Irp stack parameters to the next stack location. 5571 // 5572 5573 IoCopyCurrentIrpStackLocationToNext(Irp); 5574 5575 ClassReleaseRemoveLock(DeviceObject, Irp); 5576 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 5577 break; 5578 } 5579 5580 } // end switch( ... 5581 5582 SetStatusAndReturn: 5583 5584 DBGTRACE(ClassDebugTrace, ("< ioctl %xh (%s): status %xh.", modifiedIoControlCode, DBGGETIOCTLSTR(modifiedIoControlCode), status)); 5585 5586 return status; 5587 } // end ClassDeviceControl() 5588 5589 /*++//////////////////////////////////////////////////////////////////////////// 5590 5591 ClassShutdownFlush() 5592 5593 Routine Description: 5594 5595 This routine is called for a shutdown and flush IRPs. These are sent by the 5596 system before it actually shuts down or when the file system does a flush. 5597 If it exists, the device-specific driver's routine will be invoked. If there 5598 wasn't one specified, the Irp will be completed with an Invalid device request. 5599 5600 Arguments: 5601 5602 DriverObject - Pointer to device object to being shutdown by system. 5603 5604 Irp - IRP involved. 5605 5606 Return Value: 5607 5608 NT Status 5609 5610 --*/ 5611 NTSTATUS 5612 NTAPI 5613 ClassShutdownFlush( 5614 IN PDEVICE_OBJECT DeviceObject, 5615 IN PIRP Irp 5616 ) 5617 { 5618 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 5619 5620 ULONG isRemoved; 5621 5622 //NTSTATUS status; 5623 5624 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 5625 5626 if(isRemoved) { 5627 5628 ClassReleaseRemoveLock(DeviceObject, Irp); 5629 5630 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 5631 5632 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 5633 5634 return STATUS_DEVICE_DOES_NOT_EXIST; 5635 } 5636 5637 if (commonExtension->DevInfo->ClassShutdownFlush) { 5638 5639 // 5640 // Call the device-specific driver's routine. 5641 // 5642 5643 return commonExtension->DevInfo->ClassShutdownFlush(DeviceObject, Irp); 5644 } 5645 5646 // 5647 // Device-specific driver doesn't support this. 5648 // 5649 5650 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; 5651 5652 ClassReleaseRemoveLock(DeviceObject, Irp); 5653 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 5654 5655 return STATUS_INVALID_DEVICE_REQUEST; 5656 } // end ClassShutdownFlush() 5657 5658 /*++//////////////////////////////////////////////////////////////////////////// 5659 5660 ClassCreateDeviceObject() 5661 5662 Routine Description: 5663 5664 This routine creates an object for the physical device specified and 5665 sets up the deviceExtension's function pointers for each entry point 5666 in the device-specific driver. 5667 5668 Arguments: 5669 5670 DriverObject - Pointer to driver object created by system. 5671 5672 ObjectNameBuffer - Dir. name of the object to create. 5673 5674 LowerDeviceObject - Pointer to the lower device object 5675 5676 IsFdo - should this be an fdo or a pdo 5677 5678 DeviceObject - Pointer to the device object pointer we will return. 5679 5680 Return Value: 5681 5682 NTSTATUS 5683 5684 --*/ 5685 NTSTATUS 5686 NTAPI 5687 ClassCreateDeviceObject( 5688 IN PDRIVER_OBJECT DriverObject, 5689 IN PCCHAR ObjectNameBuffer, 5690 IN PDEVICE_OBJECT LowerDevice, 5691 IN BOOLEAN IsFdo, 5692 IN OUT PDEVICE_OBJECT *DeviceObject 5693 ) 5694 { 5695 BOOLEAN isPartitionable; 5696 STRING ntNameString; 5697 UNICODE_STRING ntUnicodeString; 5698 NTSTATUS status; 5699 PDEVICE_OBJECT deviceObject = NULL; 5700 5701 ULONG characteristics; 5702 5703 PCLASS_DRIVER_EXTENSION 5704 driverExtension = IoGetDriverObjectExtension(DriverObject, 5705 CLASS_DRIVER_EXTENSION_KEY); 5706 5707 PCLASS_DEV_INFO devInfo; 5708 5709 PAGED_CODE(); 5710 5711 *DeviceObject = NULL; 5712 RtlInitUnicodeString(&ntUnicodeString, NULL); 5713 5714 DebugPrint((2, "ClassCreateFdo: Create device object\n")); 5715 5716 ASSERT(LowerDevice); 5717 5718 // 5719 // Make sure that if we're making PDO's we have an enumeration routine 5720 // 5721 5722 isPartitionable = (driverExtension->InitData.ClassEnumerateDevice != NULL); 5723 5724 ASSERT(IsFdo || isPartitionable); 5725 5726 // 5727 // Grab the correct dev-info structure out of the init data 5728 // 5729 5730 if(IsFdo) { 5731 devInfo = &(driverExtension->InitData.FdoData); 5732 } else { 5733 devInfo = &(driverExtension->InitData.PdoData); 5734 } 5735 5736 characteristics = devInfo->DeviceCharacteristics; 5737 5738 if(ARGUMENT_PRESENT(ObjectNameBuffer)) { 5739 DebugPrint((2, "ClassCreateFdo: Name is %s\n", ObjectNameBuffer)); 5740 5741 RtlInitString(&ntNameString, ObjectNameBuffer); 5742 5743 status = RtlAnsiStringToUnicodeString(&ntUnicodeString, &ntNameString, TRUE); 5744 5745 if (!NT_SUCCESS(status)) { 5746 5747 DebugPrint((1, 5748 "ClassCreateFdo: Cannot convert string %s\n", 5749 ObjectNameBuffer)); 5750 5751 ntUnicodeString.Buffer = NULL; 5752 return status; 5753 } 5754 } else { 5755 DebugPrint((2, "ClassCreateFdo: Object will be unnamed\n")); 5756 5757 if(IsFdo == FALSE) { 5758 5759 // 5760 // PDO's have to have some sort of name. 5761 // 5762 5763 SET_FLAG(characteristics, FILE_AUTOGENERATED_DEVICE_NAME); 5764 } 5765 5766 RtlInitUnicodeString(&ntUnicodeString, NULL); 5767 } 5768 5769 status = IoCreateDevice(DriverObject, 5770 devInfo->DeviceExtensionSize, 5771 &ntUnicodeString, 5772 devInfo->DeviceType, 5773 devInfo->DeviceCharacteristics, 5774 FALSE, 5775 &deviceObject); 5776 5777 if (!NT_SUCCESS(status)) { 5778 5779 DebugPrint((1, "ClassCreateFdo: Can not create device object %lx\n", 5780 status)); 5781 ASSERT(deviceObject == NULL); 5782 5783 // 5784 // buffer is not used any longer here. 5785 // 5786 5787 if (ntUnicodeString.Buffer != NULL) { 5788 DebugPrint((1, "ClassCreateFdo: Freeing unicode name buffer\n")); 5789 ExFreePool(ntUnicodeString.Buffer); 5790 RtlInitUnicodeString(&ntUnicodeString, NULL); 5791 } 5792 5793 } else { 5794 5795 PCOMMON_DEVICE_EXTENSION commonExtension = deviceObject->DeviceExtension; 5796 5797 RtlZeroMemory( 5798 deviceObject->DeviceExtension, 5799 devInfo->DeviceExtensionSize); 5800 5801 // 5802 // Setup version code 5803 // 5804 5805 commonExtension->Version = 0x03; 5806 5807 // 5808 // Setup the remove lock and event 5809 // 5810 5811 commonExtension->IsRemoved = NO_REMOVE; 5812 commonExtension->RemoveLock = 0; 5813 KeInitializeEvent(&commonExtension->RemoveEvent, 5814 SynchronizationEvent, 5815 FALSE); 5816 5817 #if DBG 5818 KeInitializeSpinLock(&commonExtension->RemoveTrackingSpinlock); 5819 commonExtension->RemoveTrackingList = NULL; 5820 #else 5821 commonExtension->RemoveTrackingSpinlock = (ULONG_PTR) -1; 5822 commonExtension->RemoveTrackingList = (PVOID) -1; 5823 #endif 5824 5825 // 5826 // Acquire the lock once. This reference will be released when the 5827 // remove IRP has been received. 5828 // 5829 5830 ClassAcquireRemoveLock(deviceObject, (PIRP) deviceObject); 5831 5832 // 5833 // Store a pointer to the driver extension so we don't have to do 5834 // lookups to get it. 5835 // 5836 5837 commonExtension->DriverExtension = driverExtension; 5838 5839 // 5840 // Fill in entry points 5841 // 5842 5843 commonExtension->DevInfo = devInfo; 5844 5845 // 5846 // Initialize some of the common values in the structure 5847 // 5848 5849 commonExtension->DeviceObject = deviceObject; 5850 5851 commonExtension->LowerDeviceObject = NULL; 5852 5853 if(IsFdo) { 5854 5855 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PVOID) commonExtension; 5856 5857 commonExtension->PartitionZeroExtension = deviceObject->DeviceExtension; 5858 5859 // 5860 // Set the initial device object flags. 5861 // 5862 5863 SET_FLAG(deviceObject->Flags, DO_POWER_PAGABLE); 5864 5865 // 5866 // Clear the PDO list 5867 // 5868 5869 commonExtension->ChildList = NULL; 5870 5871 commonExtension->DriverData = 5872 ((PFUNCTIONAL_DEVICE_EXTENSION) deviceObject->DeviceExtension + 1); 5873 5874 if(isPartitionable) { 5875 5876 commonExtension->PartitionNumber = 0; 5877 } else { 5878 commonExtension->PartitionNumber = (ULONG) (-1L); 5879 } 5880 5881 fdoExtension->DevicePowerState = PowerDeviceD0; 5882 5883 KeInitializeEvent(&fdoExtension->EjectSynchronizationEvent, 5884 SynchronizationEvent, 5885 TRUE); 5886 5887 KeInitializeEvent(&fdoExtension->ChildLock, 5888 SynchronizationEvent, 5889 TRUE); 5890 5891 status = ClasspAllocateReleaseRequest(deviceObject); 5892 5893 if(!NT_SUCCESS(status)) { 5894 IoDeleteDevice(deviceObject); 5895 *DeviceObject = NULL; 5896 5897 if (ntUnicodeString.Buffer != NULL) { 5898 DebugPrint((1, "ClassCreateFdo: Freeing unicode name buffer\n")); 5899 ExFreePool(ntUnicodeString.Buffer); 5900 RtlInitUnicodeString(&ntUnicodeString, NULL); 5901 } 5902 5903 return status; 5904 } 5905 5906 } else { 5907 5908 PPHYSICAL_DEVICE_EXTENSION pdoExtension = 5909 deviceObject->DeviceExtension; 5910 5911 PFUNCTIONAL_DEVICE_EXTENSION p0Extension = 5912 LowerDevice->DeviceExtension; 5913 5914 SET_FLAG(deviceObject->Flags, DO_POWER_PAGABLE); 5915 5916 commonExtension->PartitionZeroExtension = p0Extension; 5917 5918 // 5919 // Stick this onto the PDO list 5920 // 5921 5922 ClassAddChild(p0Extension, pdoExtension, TRUE); 5923 5924 commonExtension->DriverData = (PVOID) (pdoExtension + 1); 5925 5926 // 5927 // Get the top of stack for the lower device - this allows 5928 // filters to get stuck in between the partitions and the 5929 // physical disk. 5930 // 5931 5932 commonExtension->LowerDeviceObject = 5933 IoGetAttachedDeviceReference(LowerDevice); 5934 5935 // 5936 // Pnp will keep a reference to the lower device object long 5937 // after this partition has been deleted. Dereference now so 5938 // we don't have to deal with it later. 5939 // 5940 5941 ObDereferenceObject(commonExtension->LowerDeviceObject); 5942 } 5943 5944 KeInitializeEvent(&commonExtension->PathCountEvent, SynchronizationEvent, TRUE); 5945 5946 commonExtension->IsFdo = IsFdo; 5947 5948 commonExtension->DeviceName = ntUnicodeString; 5949 5950 commonExtension->PreviousState = 0xff; 5951 5952 InitializeDictionary(&(commonExtension->FileObjectDictionary)); 5953 5954 commonExtension->CurrentState = IRP_MN_STOP_DEVICE; 5955 } 5956 5957 *DeviceObject = deviceObject; 5958 5959 return status; 5960 } // end ClassCreateDeviceObject() 5961 5962 /*++//////////////////////////////////////////////////////////////////////////// 5963 5964 ClassClaimDevice() 5965 5966 Routine Description: 5967 5968 This function claims a device in the port driver. The port driver object 5969 is updated with the correct driver object if the device is successfully 5970 claimed. 5971 5972 Arguments: 5973 5974 LowerDeviceObject - Supplies the base port device object. 5975 5976 Release - Indicates the logical unit should be released rather than claimed. 5977 5978 Return Value: 5979 5980 Returns a status indicating success or failure of the operation. 5981 5982 --*/ 5983 NTSTATUS 5984 NTAPI 5985 ClassClaimDevice( 5986 IN PDEVICE_OBJECT LowerDeviceObject, 5987 IN BOOLEAN Release 5988 ) 5989 { 5990 IO_STATUS_BLOCK ioStatus; 5991 PIRP irp; 5992 PIO_STACK_LOCATION irpStack; 5993 KEVENT event; 5994 NTSTATUS status; 5995 SCSI_REQUEST_BLOCK srb; 5996 5997 PAGED_CODE(); 5998 5999 // 6000 // Clear the SRB fields. 6001 // 6002 6003 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 6004 6005 // 6006 // Write length to SRB. 6007 // 6008 6009 srb.Length = sizeof(SCSI_REQUEST_BLOCK); 6010 6011 srb.Function = Release ? SRB_FUNCTION_RELEASE_DEVICE : 6012 SRB_FUNCTION_CLAIM_DEVICE; 6013 6014 // 6015 // Set the event object to the unsignaled state. 6016 // It will be used to signal request completion 6017 // 6018 6019 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 6020 6021 // 6022 // Build synchronous request with no transfer. 6023 // 6024 6025 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE, 6026 LowerDeviceObject, 6027 NULL, 6028 0, 6029 NULL, 6030 0, 6031 TRUE, 6032 &event, 6033 &ioStatus); 6034 6035 if (irp == NULL) { 6036 DebugPrint((1, "ClassClaimDevice: Can't allocate Irp\n")); 6037 return STATUS_INSUFFICIENT_RESOURCES; 6038 } 6039 6040 irpStack = IoGetNextIrpStackLocation(irp); 6041 6042 // 6043 // Save SRB address in next stack for port driver. 6044 // 6045 6046 irpStack->Parameters.Scsi.Srb = &srb; 6047 6048 // 6049 // Set up IRP Address. 6050 // 6051 6052 srb.OriginalRequest = irp; 6053 6054 // 6055 // Call the port driver with the request and wait for it to complete. 6056 // 6057 6058 status = IoCallDriver(LowerDeviceObject, irp); 6059 if (status == STATUS_PENDING) { 6060 6061 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 6062 status = ioStatus.Status; 6063 } 6064 6065 // 6066 // If this is a release request, then just decrement the reference count 6067 // and return. The status does not matter. 6068 // 6069 6070 if (Release) { 6071 6072 // ObDereferenceObject(LowerDeviceObject); 6073 return STATUS_SUCCESS; 6074 } 6075 6076 if (!NT_SUCCESS(status)) { 6077 return status; 6078 } 6079 6080 ASSERT(srb.DataBuffer != NULL); 6081 ASSERT(!TEST_FLAG(srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 6082 6083 return status; 6084 } // end ClassClaimDevice() 6085 6086 /*++//////////////////////////////////////////////////////////////////////////// 6087 6088 ClassInternalIoControl() 6089 6090 Routine Description: 6091 6092 This routine passes internal device controls to the port driver. 6093 Internal device controls are used by higher level drivers both for ioctls 6094 and to pass through scsi requests. 6095 6096 If the IoControlCode does not match any of the handled ioctls and is 6097 a valid system address then the request will be treated as an SRB and 6098 passed down to the lower driver. If the IoControlCode is not a valid 6099 system address the ioctl will be failed. 6100 6101 Callers must therefore be extremely cautious to pass correct, initialized 6102 values to this function. 6103 6104 Arguments: 6105 6106 DeviceObject - Supplies a pointer to the device object for this request. 6107 6108 Irp - Supplies the Irp making the request. 6109 6110 Return Value: 6111 6112 Returns back a STATUS_PENDING or a completion status. 6113 6114 --*/ 6115 NTSTATUS 6116 NTAPI 6117 ClassInternalIoControl( 6118 IN PDEVICE_OBJECT DeviceObject, 6119 IN PIRP Irp 6120 ) 6121 { 6122 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 6123 6124 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 6125 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp); 6126 6127 ULONG isRemoved; 6128 6129 PSCSI_REQUEST_BLOCK srb; 6130 6131 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 6132 6133 if(isRemoved) { 6134 6135 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 6136 6137 ClassReleaseRemoveLock(DeviceObject, Irp); 6138 6139 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 6140 6141 return STATUS_DEVICE_DOES_NOT_EXIST; 6142 } 6143 6144 // 6145 // Get a pointer to the SRB. 6146 // 6147 6148 srb = irpStack->Parameters.Scsi.Srb; 6149 6150 // 6151 // Set the parameters in the next stack location. 6152 // 6153 6154 if(commonExtension->IsFdo) { 6155 nextStack->Parameters.Scsi.Srb = srb; 6156 nextStack->MajorFunction = IRP_MJ_SCSI; 6157 nextStack->MinorFunction = IRP_MN_SCSI_CLASS; 6158 6159 } else { 6160 6161 IoCopyCurrentIrpStackLocationToNext(Irp); 6162 } 6163 6164 ClassReleaseRemoveLock(DeviceObject, Irp); 6165 6166 return IoCallDriver(commonExtension->LowerDeviceObject, Irp); 6167 } // end ClassInternalIoControl() 6168 6169 /*++//////////////////////////////////////////////////////////////////////////// 6170 6171 ClassQueryTimeOutRegistryValue() 6172 6173 Routine Description: 6174 6175 This routine determines whether a reg key for a user-specified timeout 6176 value exists. This should be called at initialization time. 6177 6178 Arguments: 6179 6180 DeviceObject - Pointer to the device object we are retrieving the timeout 6181 value for 6182 6183 Return Value: 6184 6185 None, but it sets a new default timeout for a class of devices. 6186 6187 --*/ 6188 ULONG 6189 NTAPI 6190 ClassQueryTimeOutRegistryValue( 6191 IN PDEVICE_OBJECT DeviceObject 6192 ) 6193 { 6194 // 6195 // Find the appropriate reg. key 6196 // 6197 6198 PCLASS_DRIVER_EXTENSION 6199 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, 6200 CLASS_DRIVER_EXTENSION_KEY); 6201 6202 PUNICODE_STRING registryPath = &(driverExtension->RegistryPath); 6203 6204 PRTL_QUERY_REGISTRY_TABLE parameters = NULL; 6205 PWSTR path; 6206 NTSTATUS status; 6207 LONG timeOut = 0; 6208 ULONG zero = 0; 6209 ULONG size; 6210 6211 PAGED_CODE(); 6212 6213 if (!registryPath) { 6214 return 0; 6215 } 6216 6217 parameters = ExAllocatePoolWithTag(NonPagedPool, 6218 sizeof(RTL_QUERY_REGISTRY_TABLE)*2, 6219 '1BcS'); 6220 6221 if (!parameters) { 6222 return 0; 6223 } 6224 6225 size = registryPath->MaximumLength + sizeof(WCHAR); 6226 path = ExAllocatePoolWithTag(NonPagedPool, size, '2BcS'); 6227 6228 if (!path) { 6229 ExFreePool(parameters); 6230 return 0; 6231 } 6232 6233 RtlZeroMemory(path,size); 6234 RtlCopyMemory(path, registryPath->Buffer, size - sizeof(WCHAR)); 6235 6236 6237 // 6238 // Check for the Timeout value. 6239 // 6240 6241 RtlZeroMemory(parameters, 6242 (sizeof(RTL_QUERY_REGISTRY_TABLE)*2)); 6243 6244 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 6245 parameters[0].Name = L"TimeOutValue"; 6246 parameters[0].EntryContext = &timeOut; 6247 parameters[0].DefaultType = REG_DWORD; 6248 parameters[0].DefaultData = &zero; 6249 parameters[0].DefaultLength = sizeof(ULONG); 6250 6251 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, 6252 path, 6253 parameters, 6254 NULL, 6255 NULL); 6256 6257 if (!(NT_SUCCESS(status))) { 6258 timeOut = 0; 6259 } 6260 6261 ExFreePool(parameters); 6262 ExFreePool(path); 6263 6264 DebugPrint((2, 6265 "ClassQueryTimeOutRegistryValue: Timeout value %d\n", 6266 timeOut)); 6267 6268 6269 return timeOut; 6270 6271 } // end ClassQueryTimeOutRegistryValue() 6272 6273 /*++//////////////////////////////////////////////////////////////////////////// 6274 6275 ClassCheckVerifyComplete() ISSUE-2000/02/18-henrygab - why public?! 6276 6277 Routine Description: 6278 6279 This routine executes when the port driver has completed a check verify 6280 ioctl. It will set the status of the master Irp, copy the media change 6281 count and complete the request. 6282 6283 Arguments: 6284 6285 Fdo - Supplies the functional device object which represents the logical unit. 6286 6287 Irp - Supplies the Irp which has completed. 6288 6289 Context - NULL 6290 6291 Return Value: 6292 6293 NT status 6294 6295 --*/ 6296 NTSTATUS 6297 NTAPI 6298 ClassCheckVerifyComplete( 6299 IN PDEVICE_OBJECT Fdo, 6300 IN PIRP Irp, 6301 IN PVOID Context 6302 ) 6303 { 6304 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 6305 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 6306 6307 PIRP originalIrp; 6308 6309 ASSERT_FDO(Fdo); 6310 6311 originalIrp = irpStack->Parameters.Others.Argument1; 6312 6313 // 6314 // Copy the media change count and status 6315 // 6316 6317 *((PULONG) (originalIrp->AssociatedIrp.SystemBuffer)) = 6318 fdoExtension->MediaChangeCount; 6319 6320 DebugPrint((2, "ClassCheckVerifyComplete - Media change count for" 6321 "device %d is %lx - saved as %lx\n", 6322 fdoExtension->DeviceNumber, 6323 fdoExtension->MediaChangeCount, 6324 *((PULONG) originalIrp->AssociatedIrp.SystemBuffer))); 6325 6326 originalIrp->IoStatus.Status = Irp->IoStatus.Status; 6327 originalIrp->IoStatus.Information = sizeof(ULONG); 6328 6329 ClassReleaseRemoveLock(Fdo, originalIrp); 6330 ClassCompleteRequest(Fdo, originalIrp, IO_DISK_INCREMENT); 6331 6332 IoFreeIrp(Irp); 6333 6334 return STATUS_MORE_PROCESSING_REQUIRED; 6335 6336 } // end ClassCheckVerifyComplete() 6337 6338 /*++//////////////////////////////////////////////////////////////////////////// 6339 6340 ClassGetDescriptor() 6341 6342 Routine Description: 6343 6344 This routine will perform a query for the specified property id and will 6345 allocate a non-paged buffer to store the data in. It is the responsibility 6346 of the caller to ensure that this buffer is freed. 6347 6348 This routine must be run at IRQL_PASSIVE_LEVEL 6349 6350 Arguments: 6351 6352 DeviceObject - the device to query 6353 DeviceInfo - a location to store a pointer to the buffer we allocate 6354 6355 Return Value: 6356 6357 status 6358 if status is unsuccessful *DeviceInfo will be set to NULL, else the 6359 buffer allocated on behalf of the caller. 6360 6361 --*/ 6362 NTSTATUS 6363 NTAPI 6364 ClassGetDescriptor( 6365 IN PDEVICE_OBJECT DeviceObject, 6366 IN PSTORAGE_PROPERTY_ID PropertyId, 6367 OUT PSTORAGE_DESCRIPTOR_HEADER *Descriptor 6368 ) 6369 { 6370 STORAGE_PROPERTY_QUERY query; 6371 IO_STATUS_BLOCK ioStatus; 6372 6373 PSTORAGE_DESCRIPTOR_HEADER descriptor = NULL; 6374 ULONG length; 6375 6376 //UCHAR pass = 0; 6377 6378 PAGED_CODE(); 6379 6380 // 6381 // Set the passed-in descriptor pointer to NULL as default 6382 // 6383 6384 *Descriptor = NULL; 6385 6386 6387 RtlZeroMemory(&query, sizeof(STORAGE_PROPERTY_QUERY)); 6388 query.PropertyId = *PropertyId; 6389 query.QueryType = PropertyStandardQuery; 6390 6391 // 6392 // On the first pass we just want to get the first few 6393 // bytes of the descriptor so we can read it's size 6394 // 6395 6396 descriptor = (PVOID)&query; 6397 6398 ASSERT(sizeof(STORAGE_PROPERTY_QUERY) >= (sizeof(ULONG)*2)); 6399 6400 ClassSendDeviceIoControlSynchronous( 6401 IOCTL_STORAGE_QUERY_PROPERTY, 6402 DeviceObject, 6403 &query, 6404 sizeof(STORAGE_PROPERTY_QUERY), 6405 sizeof(ULONG) * 2, 6406 FALSE, 6407 &ioStatus 6408 ); 6409 6410 if(!NT_SUCCESS(ioStatus.Status)) { 6411 6412 DebugPrint((1, "ClassGetDescriptor: error %lx trying to " 6413 "query properties #1\n", ioStatus.Status)); 6414 return ioStatus.Status; 6415 } 6416 6417 if (descriptor->Size == 0) { 6418 6419 // 6420 // This DebugPrint is to help third-party driver writers 6421 // 6422 6423 DebugPrint((0, "ClassGetDescriptor: size returned was zero?! (status " 6424 "%x\n", ioStatus.Status)); 6425 return STATUS_UNSUCCESSFUL; 6426 6427 } 6428 6429 // 6430 // This time we know how much data there is so we can 6431 // allocate a buffer of the correct size 6432 // 6433 6434 length = descriptor->Size; 6435 6436 descriptor = ExAllocatePoolWithTag(NonPagedPool, length, '4BcS'); 6437 6438 if(descriptor == NULL) { 6439 6440 DebugPrint((1, "ClassGetDescriptor: unable to memory for descriptor " 6441 "(%d bytes)\n", length)); 6442 return STATUS_INSUFFICIENT_RESOURCES; 6443 } 6444 6445 // 6446 // setup the query again, as it was overwritten above 6447 // 6448 6449 RtlZeroMemory(&query, sizeof(STORAGE_PROPERTY_QUERY)); 6450 query.PropertyId = *PropertyId; 6451 query.QueryType = PropertyStandardQuery; 6452 6453 // 6454 // copy the input to the new outputbuffer 6455 // 6456 6457 RtlCopyMemory(descriptor, 6458 &query, 6459 sizeof(STORAGE_PROPERTY_QUERY) 6460 ); 6461 6462 ClassSendDeviceIoControlSynchronous( 6463 IOCTL_STORAGE_QUERY_PROPERTY, 6464 DeviceObject, 6465 descriptor, 6466 sizeof(STORAGE_PROPERTY_QUERY), 6467 length, 6468 FALSE, 6469 &ioStatus 6470 ); 6471 6472 if(!NT_SUCCESS(ioStatus.Status)) { 6473 6474 DebugPrint((1, "ClassGetDescriptor: error %lx trying to " 6475 "query properties #1\n", ioStatus.Status)); 6476 ExFreePool(descriptor); 6477 return ioStatus.Status; 6478 } 6479 6480 // 6481 // return the memory we've allocated to the caller 6482 // 6483 6484 *Descriptor = descriptor; 6485 return ioStatus.Status; 6486 } // end ClassGetDescriptor() 6487 6488 /*++//////////////////////////////////////////////////////////////////////////// 6489 6490 ClassSignalCompletion() 6491 6492 Routine Description: 6493 6494 This completion routine will signal the event given as context and then 6495 return STATUS_MORE_PROCESSING_REQUIRED to stop event completion. It is 6496 the responsibility of the routine waiting on the event to complete the 6497 request and free the event. 6498 6499 Arguments: 6500 6501 DeviceObject - a pointer to the device object 6502 6503 Irp - a pointer to the irp 6504 6505 Event - a pointer to the event to signal 6506 6507 Return Value: 6508 6509 STATUS_MORE_PROCESSING_REQUIRED 6510 6511 --*/ 6512 NTSTATUS 6513 NTAPI 6514 ClassSignalCompletion( 6515 IN PDEVICE_OBJECT DeviceObject, 6516 IN PIRP Irp, 6517 IN PVOID Context 6518 ) 6519 { 6520 PKEVENT Event = Context; 6521 6522 KeSetEvent(Event, IO_NO_INCREMENT, FALSE); 6523 6524 return STATUS_MORE_PROCESSING_REQUIRED; 6525 } // end ClassSignalCompletion() 6526 6527 /*++//////////////////////////////////////////////////////////////////////////// 6528 6529 ClassPnpQueryFdoRelations() 6530 6531 Routine Description: 6532 6533 This routine will call the driver's enumeration routine to update the 6534 list of PDO's. It will then build a response to the 6535 IRP_MN_QUERY_DEVICE_RELATIONS and place it into the information field in 6536 the irp. 6537 6538 Arguments: 6539 6540 Fdo - a pointer to the functional device object we are enumerating 6541 6542 Irp - a pointer to the enumeration request 6543 6544 Return Value: 6545 6546 status 6547 6548 --*/ 6549 NTSTATUS 6550 NTAPI 6551 ClassPnpQueryFdoRelations( 6552 IN PDEVICE_OBJECT Fdo, 6553 IN PIRP Irp 6554 ) 6555 { 6556 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 6557 PCLASS_DRIVER_EXTENSION 6558 driverExtension = IoGetDriverObjectExtension(Fdo->DriverObject, 6559 CLASS_DRIVER_EXTENSION_KEY); 6560 6561 PAGED_CODE(); 6562 6563 // 6564 // If there's already an enumeration in progress then don't start another 6565 // one. 6566 // 6567 6568 if(InterlockedIncrement((PLONG)&fdoExtension->EnumerationInterlock) == 1) { 6569 driverExtension->InitData.ClassEnumerateDevice(Fdo); 6570 } 6571 6572 Irp->IoStatus.Information = (ULONG_PTR) NULL; 6573 6574 Irp->IoStatus.Status = ClassRetrieveDeviceRelations( 6575 Fdo, 6576 BusRelations, 6577 (PDEVICE_RELATIONS*)&Irp->IoStatus.Information); 6578 InterlockedDecrement((PLONG)&fdoExtension->EnumerationInterlock); 6579 6580 return Irp->IoStatus.Status; 6581 } // end ClassPnpQueryFdoRelations() 6582 6583 /*++//////////////////////////////////////////////////////////////////////////// 6584 6585 ClassMarkChildrenMissing() 6586 6587 Routine Description: 6588 6589 This routine will call ClassMarkChildMissing() for all children. 6590 It acquires the ChildLock before calling ClassMarkChildMissing(). 6591 6592 Arguments: 6593 6594 Fdo - the "bus's" device object, such as the disk FDO for non-removable 6595 disks with multiple partitions. 6596 6597 Return Value: 6598 6599 None 6600 6601 --*/ 6602 VOID 6603 NTAPI 6604 ClassMarkChildrenMissing( 6605 IN PFUNCTIONAL_DEVICE_EXTENSION Fdo 6606 ) 6607 { 6608 PCOMMON_DEVICE_EXTENSION commonExtension = &(Fdo->CommonExtension); 6609 PPHYSICAL_DEVICE_EXTENSION nextChild = commonExtension->ChildList; 6610 6611 PAGED_CODE(); 6612 6613 ClassAcquireChildLock(Fdo); 6614 6615 while (nextChild){ 6616 PPHYSICAL_DEVICE_EXTENSION tmpChild; 6617 6618 /* 6619 * ClassMarkChildMissing will also dequeue the child extension. 6620 * So get the next pointer before calling ClassMarkChildMissing. 6621 */ 6622 tmpChild = nextChild; 6623 nextChild = tmpChild->CommonExtension.ChildList; 6624 ClassMarkChildMissing(tmpChild, FALSE); 6625 } 6626 ClassReleaseChildLock(Fdo); 6627 return; 6628 } // end ClassMarkChildrenMissing() 6629 6630 /*++//////////////////////////////////////////////////////////////////////////// 6631 6632 ClassMarkChildMissing() 6633 6634 Routine Description: 6635 6636 This routine will make an active child "missing." If the device has never 6637 been enumerated then it will be deleted on the spot. If the device has 6638 not been enumerated then it will be marked as missing so that we can 6639 not report it in the next device enumeration. 6640 6641 Arguments: 6642 6643 Child - the child device to be marked as missing. 6644 6645 AcquireChildLock - TRUE if the child lock should be acquired before removing 6646 the missing child. FALSE if the child lock is already 6647 acquired by this thread. 6648 6649 Return Value: 6650 6651 returns whether or not the child device object has previously been reported 6652 to PNP. 6653 6654 --*/ 6655 BOOLEAN 6656 NTAPI 6657 ClassMarkChildMissing( 6658 IN PPHYSICAL_DEVICE_EXTENSION Child, 6659 IN BOOLEAN AcquireChildLock 6660 ) 6661 { 6662 BOOLEAN returnValue = Child->IsEnumerated; 6663 6664 PAGED_CODE(); 6665 ASSERT_PDO(Child->DeviceObject); 6666 6667 Child->IsMissing = TRUE; 6668 6669 // 6670 // Make sure this child is not in the active list. 6671 // 6672 6673 ClassRemoveChild(Child->CommonExtension.PartitionZeroExtension, 6674 Child, 6675 AcquireChildLock); 6676 6677 if(Child->IsEnumerated == FALSE) { 6678 ClassRemoveDevice(Child->DeviceObject, IRP_MN_REMOVE_DEVICE); 6679 } 6680 6681 return returnValue; 6682 } // end ClassMarkChildMissing() 6683 6684 /*++//////////////////////////////////////////////////////////////////////////// 6685 6686 ClassRetrieveDeviceRelations() 6687 6688 Routine Description: 6689 6690 This routine will allocate a buffer to hold the specified list of 6691 relations. It will then fill in the list with referenced device pointers 6692 and will return the request. 6693 6694 Arguments: 6695 6696 Fdo - pointer to the FDO being queried 6697 6698 RelationType - what type of relations are being queried 6699 6700 DeviceRelations - a location to store a pointer to the response 6701 6702 Return Value: 6703 6704 status 6705 6706 --*/ 6707 NTSTATUS 6708 NTAPI 6709 ClassRetrieveDeviceRelations( 6710 IN PDEVICE_OBJECT Fdo, 6711 IN DEVICE_RELATION_TYPE RelationType, 6712 OUT PDEVICE_RELATIONS *DeviceRelations 6713 ) 6714 { 6715 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 6716 6717 ULONG count = 0; 6718 ULONG i; 6719 6720 PPHYSICAL_DEVICE_EXTENSION nextChild; 6721 6722 ULONG relationsSize; 6723 PDEVICE_RELATIONS deviceRelations = NULL; 6724 6725 NTSTATUS status; 6726 6727 PAGED_CODE(); 6728 6729 ClassAcquireChildLock(fdoExtension); 6730 6731 nextChild = fdoExtension->CommonExtension.ChildList; 6732 6733 // 6734 // Count the number of PDO's attached to this disk 6735 // 6736 6737 while(nextChild != NULL) { 6738 PCOMMON_DEVICE_EXTENSION commonExtension; 6739 6740 commonExtension = &(nextChild->CommonExtension); 6741 6742 ASSERTMSG("ClassPnp internal error: missing child on active list\n", 6743 (nextChild->IsMissing == FALSE)); 6744 6745 nextChild = commonExtension->ChildList; 6746 6747 count++; 6748 }; 6749 6750 relationsSize = (sizeof(DEVICE_RELATIONS) + 6751 (count * sizeof(PDEVICE_OBJECT))); 6752 6753 deviceRelations = ExAllocatePoolWithTag(PagedPool, relationsSize, '5BcS'); 6754 6755 if(deviceRelations == NULL) { 6756 6757 DebugPrint((1, "ClassRetrieveDeviceRelations: unable to allocate " 6758 "%d bytes for device relations\n", relationsSize)); 6759 6760 ClassReleaseChildLock(fdoExtension); 6761 6762 return STATUS_INSUFFICIENT_RESOURCES; 6763 } 6764 6765 RtlZeroMemory(deviceRelations, relationsSize); 6766 6767 nextChild = fdoExtension->CommonExtension.ChildList; 6768 i = count - 1; 6769 6770 while(nextChild != NULL) { 6771 PCOMMON_DEVICE_EXTENSION commonExtension; 6772 6773 commonExtension = &(nextChild->CommonExtension); 6774 6775 ASSERTMSG("ClassPnp internal error: missing child on active list\n", 6776 (nextChild->IsMissing == FALSE)); 6777 6778 deviceRelations->Objects[i--] = nextChild->DeviceObject; 6779 6780 status = ObReferenceObjectByPointer( 6781 nextChild->DeviceObject, 6782 0, 6783 NULL, 6784 KernelMode); 6785 ASSERT(NT_SUCCESS(status)); 6786 6787 nextChild->IsEnumerated = TRUE; 6788 nextChild = commonExtension->ChildList; 6789 } 6790 6791 ASSERTMSG("Child list has changed: ", i == -1); 6792 6793 deviceRelations->Count = count; 6794 *DeviceRelations = deviceRelations; 6795 ClassReleaseChildLock(fdoExtension); 6796 return STATUS_SUCCESS; 6797 } // end ClassRetrieveDeviceRelations() 6798 6799 /*++//////////////////////////////////////////////////////////////////////////// 6800 6801 ClassGetPdoId() 6802 6803 Routine Description: 6804 6805 This routine will call into the driver to retrieve a copy of one of it's 6806 id strings. 6807 6808 Arguments: 6809 6810 Pdo - a pointer to the pdo being queried 6811 6812 IdType - which type of id string is being queried 6813 6814 IdString - an allocated unicode string structure which the driver 6815 can fill in. 6816 6817 Return Value: 6818 6819 status 6820 6821 --*/ 6822 NTSTATUS 6823 NTAPI 6824 ClassGetPdoId( 6825 IN PDEVICE_OBJECT Pdo, 6826 IN BUS_QUERY_ID_TYPE IdType, 6827 IN PUNICODE_STRING IdString 6828 ) 6829 { 6830 PCLASS_DRIVER_EXTENSION 6831 driverExtension = IoGetDriverObjectExtension(Pdo->DriverObject, 6832 CLASS_DRIVER_EXTENSION_KEY); 6833 6834 ASSERT_PDO(Pdo); 6835 ASSERT(driverExtension->InitData.ClassQueryId); 6836 6837 PAGED_CODE(); 6838 6839 return driverExtension->InitData.ClassQueryId( Pdo, IdType, IdString); 6840 } // end ClassGetPdoId() 6841 6842 /*++//////////////////////////////////////////////////////////////////////////// 6843 6844 ClassQueryPnpCapabilities() 6845 6846 Routine Description: 6847 6848 This routine will call into the class driver to retrieve it's pnp 6849 capabilities. 6850 6851 Arguments: 6852 6853 PhysicalDeviceObject - The physical device object to retrieve properties 6854 for. 6855 6856 Return Value: 6857 6858 status 6859 6860 --*/ 6861 NTSTATUS 6862 NTAPI 6863 ClassQueryPnpCapabilities( 6864 IN PDEVICE_OBJECT DeviceObject, 6865 IN PDEVICE_CAPABILITIES Capabilities 6866 ) 6867 { 6868 PCLASS_DRIVER_EXTENSION driverExtension = 6869 ClassGetDriverExtension(DeviceObject->DriverObject); 6870 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 6871 6872 PCLASS_QUERY_PNP_CAPABILITIES queryRoutine = NULL; 6873 6874 PAGED_CODE(); 6875 6876 ASSERT(DeviceObject); 6877 ASSERT(Capabilities); 6878 6879 if(commonExtension->IsFdo) { 6880 queryRoutine = driverExtension->InitData.FdoData.ClassQueryPnpCapabilities; 6881 } else { 6882 queryRoutine = driverExtension->InitData.PdoData.ClassQueryPnpCapabilities; 6883 } 6884 6885 if(queryRoutine) { 6886 return queryRoutine(DeviceObject, 6887 Capabilities); 6888 } else { 6889 return STATUS_NOT_IMPLEMENTED; 6890 } 6891 } // end ClassQueryPnpCapabilities() 6892 6893 /*++//////////////////////////////////////////////////////////////////////////// 6894 6895 ClassInvalidateBusRelations() 6896 6897 Routine Description: 6898 6899 This routine re-enumerates the devices on the "bus". It will call into 6900 the driver's ClassEnumerate routine to update the device objects 6901 immediately. It will then schedule a bus re-enumeration for pnp by calling 6902 IoInvalidateDeviceRelations. 6903 6904 Arguments: 6905 6906 Fdo - a pointer to the functional device object for this bus 6907 6908 Return Value: 6909 6910 none 6911 6912 --*/ 6913 VOID 6914 NTAPI 6915 ClassInvalidateBusRelations( 6916 IN PDEVICE_OBJECT Fdo 6917 ) 6918 { 6919 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 6920 PCLASS_DRIVER_EXTENSION 6921 driverExtension = IoGetDriverObjectExtension(Fdo->DriverObject, 6922 CLASS_DRIVER_EXTENSION_KEY); 6923 6924 NTSTATUS status = STATUS_SUCCESS; 6925 6926 PAGED_CODE(); 6927 6928 ASSERT_FDO(Fdo); 6929 ASSERT(driverExtension->InitData.ClassEnumerateDevice != NULL); 6930 6931 if(InterlockedIncrement((PLONG)&fdoExtension->EnumerationInterlock) == 1) { 6932 status = driverExtension->InitData.ClassEnumerateDevice(Fdo); 6933 } 6934 InterlockedDecrement((PLONG)&fdoExtension->EnumerationInterlock); 6935 6936 if(!NT_SUCCESS(status)) { 6937 6938 DebugPrint((1, "ClassInvalidateBusRelations: EnumerateDevice routine " 6939 "returned %lx\n", status)); 6940 } 6941 6942 IoInvalidateDeviceRelations(fdoExtension->LowerPdo, BusRelations); 6943 6944 return; 6945 } // end ClassInvalidateBusRelations() 6946 6947 /*++//////////////////////////////////////////////////////////////////////////// 6948 6949 ClassRemoveDevice() ISSUE-2000/02/18-henrygab - why public?! 6950 6951 Routine Description: 6952 6953 This routine is called to handle the "removal" of a device. It will 6954 forward the request downwards if necessary, call into the driver 6955 to release any necessary resources (memory, events, etc) and then 6956 will delete the device object. 6957 6958 Arguments: 6959 6960 DeviceObject - a pointer to the device object being removed 6961 6962 RemoveType - indicates what type of remove this is (regular or surprise). 6963 6964 Return Value: 6965 6966 status 6967 6968 --*/ 6969 NTSTATUS 6970 NTAPI 6971 ClassRemoveDevice( 6972 IN PDEVICE_OBJECT DeviceObject, 6973 IN UCHAR RemoveType 6974 ) 6975 { 6976 PCLASS_DRIVER_EXTENSION 6977 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, 6978 CLASS_DRIVER_EXTENSION_KEY); 6979 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 6980 PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject; 6981 PCLASS_WMI_INFO classWmiInfo; 6982 BOOLEAN proceedWithRemove = TRUE; 6983 NTSTATUS status; 6984 6985 PAGED_CODE(); 6986 6987 commonExtension->IsRemoved = REMOVE_PENDING; 6988 6989 /* 6990 * Deregister from WMI. 6991 */ 6992 classWmiInfo = commonExtension->IsFdo ? 6993 &driverExtension->InitData.FdoData.ClassWmiInfo : 6994 &driverExtension->InitData.PdoData.ClassWmiInfo; 6995 if (classWmiInfo->GuidRegInfo){ 6996 status = IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_DEREGISTER); 6997 DBGTRACE(ClassDebugInfo, ("ClassRemoveDevice: IoWMIRegistrationControl(%p, WMI_ACTION_DEREGISTER) --> %lx", DeviceObject, status)); 6998 } 6999 7000 /* 7001 * If we exposed a "shingle" (a named device interface openable by CreateFile) 7002 * then delete it now. 7003 */ 7004 if (commonExtension->MountedDeviceInterfaceName.Buffer){ 7005 IoSetDeviceInterfaceState(&commonExtension->MountedDeviceInterfaceName, FALSE); 7006 RtlFreeUnicodeString(&commonExtension->MountedDeviceInterfaceName); 7007 RtlInitUnicodeString(&commonExtension->MountedDeviceInterfaceName, NULL); 7008 } 7009 7010 // 7011 // If this is a surprise removal we leave the device around - which means 7012 // we don't have to (or want to) drop the remove lock and wait for pending 7013 // requests to complete. 7014 // 7015 7016 if (RemoveType == IRP_MN_REMOVE_DEVICE){ 7017 7018 // 7019 // Release the lock we acquired when the device object was created. 7020 // 7021 7022 ClassReleaseRemoveLock(DeviceObject, (PIRP) DeviceObject); 7023 7024 DebugPrint((1, "ClasspRemoveDevice - Reference count is now %d\n", 7025 commonExtension->RemoveLock)); 7026 7027 KeWaitForSingleObject(&commonExtension->RemoveEvent, 7028 Executive, 7029 KernelMode, 7030 FALSE, 7031 NULL); 7032 7033 DebugPrint((1, "ClasspRemoveDevice - removing device %p\n", DeviceObject)); 7034 7035 if(commonExtension->IsFdo) { 7036 7037 DebugPrint((1, "ClasspRemoveDevice - FDO %p has received a " 7038 "remove request.\n", DeviceObject)); 7039 7040 } 7041 else { 7042 PPHYSICAL_DEVICE_EXTENSION pdoExtension = DeviceObject->DeviceExtension; 7043 7044 if (pdoExtension->IsMissing){ 7045 /* 7046 * The child partition PDO is missing, so we are going to go ahead 7047 * and delete it for the remove. 7048 */ 7049 DBGTRACE(ClassDebugWarning, ("ClasspRemoveDevice - PDO %p is missing and will be removed", DeviceObject)); 7050 } 7051 else { 7052 /* 7053 * We got a remove for a child partition PDO which is not actually missing. 7054 * So we will NOT actually delete it. 7055 */ 7056 DBGTRACE(ClassDebugWarning, ("ClasspRemoveDevice - PDO %p still exists and will be removed when it disappears", DeviceObject)); 7057 7058 // 7059 // Reacquire the remove lock for the next time this comes around. 7060 // 7061 7062 ClassAcquireRemoveLock(DeviceObject, (PIRP) DeviceObject); 7063 7064 // 7065 // the device wasn't missing so it's not really been removed. 7066 // 7067 7068 commonExtension->IsRemoved = NO_REMOVE; 7069 7070 IoInvalidateDeviceRelations( 7071 commonExtension->PartitionZeroExtension->LowerPdo, 7072 BusRelations); 7073 7074 proceedWithRemove = FALSE; 7075 } 7076 } 7077 } 7078 7079 7080 if (proceedWithRemove){ 7081 7082 /* 7083 * Call the class driver's remove handler. 7084 * All this is supposed to do is clean up its data and device interfaces. 7085 */ 7086 ASSERT(commonExtension->DevInfo->ClassRemoveDevice); 7087 status = commonExtension->DevInfo->ClassRemoveDevice(DeviceObject, RemoveType); 7088 ASSERT(NT_SUCCESS(status)); 7089 status = STATUS_SUCCESS; 7090 7091 if (commonExtension->IsFdo){ 7092 //PDEVICE_OBJECT pdo; 7093 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 7094 7095 ClasspDisableTimer(fdoExtension->DeviceObject); 7096 7097 if (RemoveType == IRP_MN_REMOVE_DEVICE){ 7098 7099 PPHYSICAL_DEVICE_EXTENSION child; 7100 7101 // 7102 // Cleanup the media detection resources now that the class driver 7103 // has stopped it's timer (if any) and we can be sure they won't 7104 // call us to do detection again. 7105 // 7106 7107 ClassCleanupMediaChangeDetection(fdoExtension); 7108 7109 // 7110 // Cleanup any Failure Prediction stuff 7111 // 7112 if (fdoExtension->FailurePredictionInfo) { 7113 ExFreePool(fdoExtension->FailurePredictionInfo); 7114 fdoExtension->FailurePredictionInfo = NULL; 7115 } 7116 7117 /* 7118 * Ordinarily all child PDOs will be removed by the time 7119 * that the parent gets the REMOVE_DEVICE. 7120 * However, if a child PDO has been created but has not 7121 * been announced in a QueryDeviceRelations, then it is 7122 * just a private data structure unknown to pnp, and we have 7123 * to delete it ourselves. 7124 */ 7125 ClassAcquireChildLock(fdoExtension); 7126 while ((child = ClassRemoveChild(fdoExtension, NULL, FALSE))){ 7127 7128 // 7129 // Yank the pdo. This routine will unlink the device from the 7130 // pdo list so NextPdo will point to the next one when it's 7131 // complete. 7132 // 7133 child->IsMissing = TRUE; 7134 ClassRemoveDevice(child->DeviceObject, IRP_MN_REMOVE_DEVICE); 7135 } 7136 ClassReleaseChildLock(fdoExtension); 7137 } 7138 else if (RemoveType == IRP_MN_SURPRISE_REMOVAL){ 7139 /* 7140 * This is a surprise-remove on the parent FDO. 7141 * We will mark the child PDOs as missing so that they 7142 * will actually get deleted when they get a REMOVE_DEVICE. 7143 */ 7144 ClassMarkChildrenMissing(fdoExtension); 7145 } 7146 7147 ClasspFreeReleaseRequest(DeviceObject); 7148 7149 if (RemoveType == IRP_MN_REMOVE_DEVICE){ 7150 7151 // 7152 // Free FDO-specific data structs 7153 // 7154 if (fdoExtension->PrivateFdoData){ 7155 7156 DestroyAllTransferPackets(DeviceObject); 7157 7158 ExFreePool(fdoExtension->PrivateFdoData); 7159 fdoExtension->PrivateFdoData = NULL; 7160 } 7161 7162 if (commonExtension->DeviceName.Buffer) { 7163 ExFreePool(commonExtension->DeviceName.Buffer); 7164 RtlInitUnicodeString(&commonExtension->DeviceName, NULL); 7165 } 7166 7167 if (fdoExtension->AdapterDescriptor) { 7168 ExFreePool(fdoExtension->AdapterDescriptor); 7169 fdoExtension->AdapterDescriptor = NULL; 7170 } 7171 7172 if (fdoExtension->DeviceDescriptor) { 7173 ExFreePool(fdoExtension->DeviceDescriptor); 7174 fdoExtension->DeviceDescriptor = NULL; 7175 } 7176 7177 // 7178 // Detach our device object from the stack - there's no reason 7179 // to hold off our cleanup any longer. 7180 // 7181 7182 IoDetachDevice(lowerDeviceObject); 7183 } 7184 } 7185 else { 7186 /* 7187 * This is a child partition PDO. 7188 * We have already determined that it was previously marked 7189 * as missing. So if this is a REMOVE_DEVICE, we will actually 7190 * delete it. 7191 */ 7192 if (RemoveType == IRP_MN_REMOVE_DEVICE){ 7193 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = 7194 commonExtension->PartitionZeroExtension; 7195 PPHYSICAL_DEVICE_EXTENSION pdoExtension = 7196 (PPHYSICAL_DEVICE_EXTENSION) commonExtension; 7197 7198 // 7199 // See if this device is in the child list (if this was a surprise 7200 // removal it might be) and remove it. 7201 // 7202 7203 ClassRemoveChild(fdoExtension, pdoExtension, TRUE); 7204 } 7205 } 7206 7207 commonExtension->PartitionLength.QuadPart = 0; 7208 7209 if (RemoveType == IRP_MN_REMOVE_DEVICE){ 7210 IoDeleteDevice(DeviceObject); 7211 } 7212 } 7213 7214 return STATUS_SUCCESS; 7215 } // end ClassRemoveDevice() 7216 7217 /*++//////////////////////////////////////////////////////////////////////////// 7218 7219 ClassGetDriverExtension() 7220 7221 Routine Description: 7222 7223 This routine will return the classpnp's driver extension. 7224 7225 Arguments: 7226 7227 DriverObject - the driver object for which to get classpnp's extension 7228 7229 Return Value: 7230 7231 Either NULL if none, or a pointer to the driver extension 7232 7233 --*/ 7234 PCLASS_DRIVER_EXTENSION 7235 NTAPI 7236 ClassGetDriverExtension( 7237 IN PDRIVER_OBJECT DriverObject 7238 ) 7239 { 7240 return IoGetDriverObjectExtension(DriverObject, CLASS_DRIVER_EXTENSION_KEY); 7241 } // end ClassGetDriverExtension() 7242 7243 /*++//////////////////////////////////////////////////////////////////////////// 7244 7245 ClasspStartIo() 7246 7247 Routine Description: 7248 7249 This routine wraps the class driver's start io routine. If the device 7250 is being removed it will complete any requests with 7251 STATUS_DEVICE_DOES_NOT_EXIST and fire up the next packet. 7252 7253 Arguments: 7254 7255 Return Value: 7256 7257 none 7258 7259 --*/ 7260 VOID 7261 NTAPI 7262 ClasspStartIo( 7263 IN PDEVICE_OBJECT DeviceObject, 7264 IN PIRP Irp 7265 ) 7266 { 7267 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 7268 7269 // 7270 // We're already holding the remove lock so just check the variable and 7271 // see what's going on. 7272 // 7273 7274 if(commonExtension->IsRemoved) { 7275 7276 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 7277 7278 ClassAcquireRemoveLock(DeviceObject, (PIRP) ClasspStartIo); 7279 ClassReleaseRemoveLock(DeviceObject, Irp); 7280 ClassCompleteRequest(DeviceObject, Irp, IO_DISK_INCREMENT); 7281 IoStartNextPacket(DeviceObject, FALSE); 7282 ClassReleaseRemoveLock(DeviceObject, (PIRP) ClasspStartIo); 7283 return; 7284 } 7285 7286 commonExtension->DriverExtension->InitData.ClassStartIo( 7287 DeviceObject, 7288 Irp); 7289 7290 return; 7291 } // ClasspStartIo() 7292 7293 /*++//////////////////////////////////////////////////////////////////////////// 7294 7295 ClassUpdateInformationInRegistry() 7296 7297 Routine Description: 7298 7299 This routine has knowledge about the layout of the device map information 7300 in the registry. It will update this information to include a value 7301 entry specifying the dos device name that is assumed to get assigned 7302 to this NT device name. For more information on this assigning of the 7303 dos device name look in the drive support routine in the hal that assigns 7304 all dos names. 7305 7306 Since some versions of some device's firmware did not work and some 7307 vendors did not bother to follow the specification, the entire inquiry 7308 information must also be stored in the registry so than someone can 7309 figure out the firmware version. 7310 7311 Arguments: 7312 7313 DeviceObject - A pointer to the device object for the tape device. 7314 7315 Return Value: 7316 7317 None 7318 7319 --*/ 7320 VOID 7321 NTAPI 7322 ClassUpdateInformationInRegistry( 7323 IN PDEVICE_OBJECT Fdo, 7324 IN PCHAR DeviceName, 7325 IN ULONG DeviceNumber, 7326 IN PINQUIRYDATA InquiryData, 7327 IN ULONG InquiryDataLength 7328 ) 7329 { 7330 NTSTATUS status; 7331 SCSI_ADDRESS scsiAddress; 7332 OBJECT_ATTRIBUTES objectAttributes; 7333 PSTR buffer; 7334 STRING string; 7335 UNICODE_STRING unicodeName; 7336 UNICODE_STRING unicodeRegistryPath; 7337 UNICODE_STRING unicodeData; 7338 HANDLE targetKey; 7339 IO_STATUS_BLOCK ioStatus; 7340 7341 7342 PAGED_CODE(); 7343 7344 ASSERT(DeviceName); 7345 buffer = NULL; 7346 targetKey = NULL; 7347 RtlZeroMemory(&unicodeName, sizeof(UNICODE_STRING)); 7348 RtlZeroMemory(&unicodeData, sizeof(UNICODE_STRING)); 7349 RtlZeroMemory(&unicodeRegistryPath, sizeof(UNICODE_STRING)); 7350 7351 TRY { 7352 7353 // 7354 // Issue GET_ADDRESS Ioctl to determine path, target, and lun information. 7355 // 7356 7357 ClassSendDeviceIoControlSynchronous( 7358 IOCTL_SCSI_GET_ADDRESS, 7359 Fdo, 7360 &scsiAddress, 7361 0, 7362 sizeof(SCSI_ADDRESS), 7363 FALSE, 7364 &ioStatus 7365 ); 7366 7367 if (!NT_SUCCESS(ioStatus.Status)) { 7368 7369 status = ioStatus.Status; 7370 DebugPrint((1, 7371 "UpdateInformationInRegistry: Get Address failed %lx\n", 7372 status)); 7373 LEAVE; 7374 7375 } else { 7376 7377 DebugPrint((1, 7378 "GetAddress: Port %x, Path %x, Target %x, Lun %x\n", 7379 scsiAddress.PortNumber, 7380 scsiAddress.PathId, 7381 scsiAddress.TargetId, 7382 scsiAddress.Lun)); 7383 7384 } 7385 7386 // 7387 // Allocate a buffer for the reg. spooge. 7388 // 7389 7390 buffer = ExAllocatePoolWithTag(PagedPool, 1024, '6BcS'); 7391 7392 if (buffer == NULL) { 7393 7394 // 7395 // There is not return value for this. Since this is done at 7396 // claim device time (currently only system initialization) getting 7397 // the registry information correct will be the least of the worries. 7398 // 7399 7400 LEAVE; 7401 } 7402 7403 sprintf(buffer, 7404 "\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi\\Scsi Port %d\\Scsi Bus %d\\Target Id %d\\Logical Unit Id %d", 7405 scsiAddress.PortNumber, 7406 scsiAddress.PathId, 7407 scsiAddress.TargetId, 7408 scsiAddress.Lun); 7409 7410 RtlInitString(&string, buffer); 7411 7412 status = RtlAnsiStringToUnicodeString(&unicodeRegistryPath, 7413 &string, 7414 TRUE); 7415 7416 if (!NT_SUCCESS(status)) { 7417 LEAVE; 7418 } 7419 7420 // 7421 // Open the registry key for the scsi information for this 7422 // scsibus, target, lun. 7423 // 7424 7425 InitializeObjectAttributes(&objectAttributes, 7426 &unicodeRegistryPath, 7427 OBJ_CASE_INSENSITIVE, 7428 NULL, 7429 NULL); 7430 7431 status = ZwOpenKey(&targetKey, 7432 KEY_READ | KEY_WRITE, 7433 &objectAttributes); 7434 7435 if (!NT_SUCCESS(status)) { 7436 LEAVE; 7437 } 7438 7439 // 7440 // Now construct and attempt to create the registry value 7441 // specifying the device name in the appropriate place in the 7442 // device map. 7443 // 7444 7445 RtlInitUnicodeString(&unicodeName, L"DeviceName"); 7446 7447 sprintf(buffer, "%s%lu", DeviceName, DeviceNumber); 7448 RtlInitString(&string, buffer); 7449 status = RtlAnsiStringToUnicodeString(&unicodeData, 7450 &string, 7451 TRUE); 7452 if (NT_SUCCESS(status)) { 7453 status = ZwSetValueKey(targetKey, 7454 &unicodeName, 7455 0, 7456 REG_SZ, 7457 unicodeData.Buffer, 7458 unicodeData.Length); 7459 } 7460 7461 // 7462 // if they sent in data, update the registry 7463 // 7464 7465 if (InquiryDataLength) { 7466 7467 ASSERT(InquiryData); 7468 7469 RtlInitUnicodeString(&unicodeName, L"InquiryData"); 7470 status = ZwSetValueKey(targetKey, 7471 &unicodeName, 7472 0, 7473 REG_BINARY, 7474 InquiryData, 7475 InquiryDataLength); 7476 } 7477 7478 // that's all, except to clean up. 7479 7480 } FINALLY { 7481 7482 if (unicodeData.Buffer) { 7483 RtlFreeUnicodeString(&unicodeData); 7484 } 7485 if (unicodeRegistryPath.Buffer) { 7486 RtlFreeUnicodeString(&unicodeRegistryPath); 7487 } 7488 if (targetKey) { 7489 ZwClose(targetKey); 7490 } 7491 if (buffer) { 7492 ExFreePool(buffer); 7493 } 7494 7495 } 7496 7497 } // end ClassUpdateInformationInRegistry() 7498 7499 /*++//////////////////////////////////////////////////////////////////////////// 7500 7501 ClasspSendSynchronousCompletion() 7502 7503 Routine Description: 7504 7505 This completion routine will set the user event in the irp after 7506 freeing the irp and the associated MDL (if any). 7507 7508 Arguments: 7509 7510 DeviceObject - the device object which requested the completion routine 7511 7512 Irp - the irp being completed 7513 7514 Context - unused 7515 7516 Return Value: 7517 7518 STATUS_MORE_PROCESSING_REQUIRED 7519 7520 --*/ 7521 NTSTATUS 7522 NTAPI 7523 ClasspSendSynchronousCompletion( 7524 IN PDEVICE_OBJECT DeviceObject, 7525 IN PIRP Irp, 7526 IN PVOID Context 7527 ) 7528 { 7529 DebugPrint((3, "ClasspSendSynchronousCompletion: %p %p %p\n", 7530 DeviceObject, Irp, Context)); 7531 // 7532 // First set the status and information fields in the io status block 7533 // provided by the caller. 7534 // 7535 7536 *(Irp->UserIosb) = Irp->IoStatus; 7537 7538 // 7539 // Unlock the pages for the data buffer. 7540 // 7541 7542 if(Irp->MdlAddress) { 7543 MmUnlockPages(Irp->MdlAddress); 7544 IoFreeMdl(Irp->MdlAddress); 7545 } 7546 7547 // 7548 // Signal the caller's event. 7549 // 7550 7551 KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE); 7552 7553 // 7554 // Free the MDL and the IRP. 7555 // 7556 7557 IoFreeIrp(Irp); 7558 7559 return STATUS_MORE_PROCESSING_REQUIRED; 7560 } // end ClasspSendSynchronousCompletion() 7561 7562 /*++ 7563 7564 ISSUE-2000/02/20-henrygab Not documented ClasspRegisterMountedDeviceInterface 7565 7566 --*/ 7567 VOID 7568 NTAPI 7569 ClasspRegisterMountedDeviceInterface( 7570 IN PDEVICE_OBJECT DeviceObject 7571 ) 7572 { 7573 7574 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 7575 BOOLEAN isFdo = commonExtension->IsFdo; 7576 7577 PDEVICE_OBJECT pdo; 7578 UNICODE_STRING interfaceName; 7579 7580 NTSTATUS status; 7581 7582 if(isFdo) { 7583 7584 PFUNCTIONAL_DEVICE_EXTENSION functionalExtension; 7585 7586 functionalExtension = 7587 (PFUNCTIONAL_DEVICE_EXTENSION) commonExtension; 7588 pdo = functionalExtension->LowerPdo; 7589 } else { 7590 pdo = DeviceObject; 7591 } 7592 7593 status = IoRegisterDeviceInterface( 7594 pdo, 7595 &MOUNTDEV_MOUNTED_DEVICE_GUID, 7596 NULL, 7597 &interfaceName 7598 ); 7599 7600 if(NT_SUCCESS(status)) { 7601 7602 // 7603 // Copy the interface name before setting the interface state - the 7604 // name is needed by the components we notify. 7605 // 7606 7607 commonExtension->MountedDeviceInterfaceName = interfaceName; 7608 status = IoSetDeviceInterfaceState(&interfaceName, TRUE); 7609 7610 if(!NT_SUCCESS(status)) { 7611 RtlFreeUnicodeString(&interfaceName); 7612 } 7613 } 7614 7615 if(!NT_SUCCESS(status)) { 7616 RtlInitUnicodeString(&(commonExtension->MountedDeviceInterfaceName), 7617 NULL); 7618 } 7619 return; 7620 } // end ClasspRegisterMountedDeviceInterface() 7621 7622 /*++//////////////////////////////////////////////////////////////////////////// 7623 7624 ClassSendDeviceIoControlSynchronous() 7625 7626 Routine Description: 7627 7628 This routine is based upon IoBuildDeviceIoControlRequest(). It has been 7629 modified to reduce code and memory by not double-buffering the io, using 7630 the same buffer for both input and output, allocating and deallocating 7631 the mdl on behalf of the caller, and waiting for the io to complete. 7632 7633 This routine also works around the rare cases in which APC's are disabled. 7634 Since IoBuildDeviceIoControl() used APC's to signal completion, this had 7635 led to a number of difficult-to-detect hangs, where the irp was completed, 7636 but the event passed to IoBuild..() was still being waited upon by the 7637 caller. 7638 7639 Arguments: 7640 7641 IoControlCode - the IOCTL to send 7642 7643 TargetDeviceObject - the device object that should handle the ioctl 7644 7645 Buffer - the input and output buffer, or NULL if no input/output 7646 7647 InputBufferLength - the number of bytes prepared for the IOCTL in Buffer 7648 7649 OutputBufferLength - the number of bytes to be filled in upon success 7650 7651 InternalDeviceIoControl - if TRUE, uses IRP_MJ_INTERNAL_DEVICE_CONTROL 7652 7653 IoStatus - the status block that contains the results of the operation 7654 7655 Return Value: 7656 7657 --*/ 7658 VOID 7659 NTAPI 7660 ClassSendDeviceIoControlSynchronous( 7661 IN ULONG IoControlCode, 7662 IN PDEVICE_OBJECT TargetDeviceObject, 7663 IN OUT PVOID Buffer OPTIONAL, 7664 IN ULONG InputBufferLength, 7665 IN ULONG OutputBufferLength, 7666 IN BOOLEAN InternalDeviceIoControl, 7667 OUT PIO_STATUS_BLOCK IoStatus 7668 ) 7669 { 7670 PIRP irp; 7671 PIO_STACK_LOCATION irpSp; 7672 ULONG method; 7673 7674 PAGED_CODE(); 7675 7676 irp = NULL; 7677 method = IoControlCode & 3; 7678 7679 7680 #if DBG // Begin Argument Checking (nop in fre version) 7681 7682 ASSERT(ARGUMENT_PRESENT(IoStatus)); 7683 7684 if ((InputBufferLength != 0) || (OutputBufferLength != 0)) { 7685 ASSERT(ARGUMENT_PRESENT(Buffer)); 7686 } 7687 else { 7688 ASSERT(!ARGUMENT_PRESENT(Buffer)); 7689 } 7690 #endif 7691 7692 // 7693 // Begin by allocating the IRP for this request. Do not charge quota to 7694 // the current process for this IRP. 7695 // 7696 7697 irp = IoAllocateIrp(TargetDeviceObject->StackSize, FALSE); 7698 if (!irp) { 7699 (*IoStatus).Information = 0; 7700 (*IoStatus).Status = STATUS_INSUFFICIENT_RESOURCES; 7701 return; 7702 } 7703 7704 // 7705 // Get a pointer to the stack location of the first driver which will be 7706 // invoked. This is where the function codes and the parameters are set. 7707 // 7708 7709 irpSp = IoGetNextIrpStackLocation(irp); 7710 7711 // 7712 // Set the major function code based on the type of device I/O control 7713 // function the caller has specified. 7714 // 7715 7716 if (InternalDeviceIoControl) { 7717 irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 7718 } else { 7719 irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL; 7720 } 7721 7722 // 7723 // Copy the caller's parameters to the service-specific portion of the 7724 // IRP for those parameters that are the same for all four methods. 7725 // 7726 7727 irpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength; 7728 irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength; 7729 irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode; 7730 7731 // 7732 // Get the method bits from the I/O control code to determine how the 7733 // buffers are to be passed to the driver. 7734 // 7735 7736 switch (method) { 7737 // case 0 7738 case METHOD_BUFFERED: { 7739 if ((InputBufferLength != 0) || (OutputBufferLength != 0)) { 7740 7741 irp->AssociatedIrp.SystemBuffer = 7742 ExAllocatePoolWithTag(NonPagedPoolCacheAligned, 7743 max(InputBufferLength, OutputBufferLength), 7744 CLASS_TAG_DEVICE_CONTROL 7745 ); 7746 7747 if (irp->AssociatedIrp.SystemBuffer == NULL) { 7748 IoFreeIrp(irp); 7749 (*IoStatus).Information = 0; 7750 (*IoStatus).Status = STATUS_INSUFFICIENT_RESOURCES; 7751 return; 7752 } 7753 7754 if (InputBufferLength != 0) { 7755 RtlCopyMemory(irp->AssociatedIrp.SystemBuffer, 7756 Buffer, 7757 InputBufferLength); 7758 } 7759 } // end of buffering 7760 7761 irp->UserBuffer = Buffer; 7762 break; 7763 } 7764 7765 // case 1, case 2 7766 case METHOD_IN_DIRECT: 7767 case METHOD_OUT_DIRECT: { 7768 7769 7770 if (InputBufferLength != 0) { 7771 irp->AssociatedIrp.SystemBuffer = Buffer; 7772 } 7773 7774 if (OutputBufferLength != 0) { 7775 7776 irp->MdlAddress = IoAllocateMdl(Buffer, 7777 OutputBufferLength, 7778 FALSE, FALSE, 7779 (PIRP) NULL); 7780 7781 if (irp->MdlAddress == NULL) { 7782 IoFreeIrp(irp); 7783 (*IoStatus).Information = 0; 7784 (*IoStatus).Status = STATUS_INSUFFICIENT_RESOURCES; 7785 return; 7786 } 7787 7788 if (method == METHOD_IN_DIRECT) { 7789 MmProbeAndLockPages(irp->MdlAddress, 7790 KernelMode, 7791 IoReadAccess); 7792 } else if (method == METHOD_OUT_DIRECT) { 7793 MmProbeAndLockPages(irp->MdlAddress, 7794 KernelMode, 7795 IoWriteAccess); 7796 } else { 7797 ASSERT(!"If other methods reach here, code is out of date"); 7798 } 7799 } 7800 break; 7801 } 7802 7803 // case 3 7804 case METHOD_NEITHER: { 7805 7806 ASSERT(!"This routine does not support METHOD_NEITHER ioctls"); 7807 IoStatus->Information = 0; 7808 IoStatus->Status = STATUS_NOT_SUPPORTED; 7809 return; 7810 break; 7811 } 7812 } // end of switch(method) 7813 7814 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 7815 7816 // 7817 // send the irp synchronously 7818 // 7819 7820 ClassSendIrpSynchronous(TargetDeviceObject, irp); 7821 7822 // 7823 // copy the iostatus block for the caller 7824 // 7825 7826 *IoStatus = irp->IoStatus; 7827 7828 // 7829 // free any allocated resources 7830 // 7831 7832 switch (method) { 7833 case METHOD_BUFFERED: { 7834 7835 ASSERT(irp->UserBuffer == Buffer); 7836 7837 // 7838 // first copy the buffered result, if any 7839 // Note that there are no security implications in 7840 // not checking for success since only drivers can 7841 // call into this routine anyways... 7842 // 7843 7844 if (OutputBufferLength != 0) { 7845 RtlCopyMemory(Buffer, // irp->UserBuffer 7846 irp->AssociatedIrp.SystemBuffer, 7847 OutputBufferLength 7848 ); 7849 } 7850 7851 // 7852 // then free the memory allocated to buffer the io 7853 // 7854 7855 if ((InputBufferLength !=0) || (OutputBufferLength != 0)) { 7856 ExFreePool(irp->AssociatedIrp.SystemBuffer); 7857 irp->AssociatedIrp.SystemBuffer = NULL; 7858 } 7859 break; 7860 } 7861 7862 case METHOD_IN_DIRECT: 7863 case METHOD_OUT_DIRECT: { 7864 7865 // 7866 // we alloc a mdl if there is an output buffer specified 7867 // free it here after unlocking the pages 7868 // 7869 7870 if (OutputBufferLength != 0) { 7871 ASSERT(irp->MdlAddress != NULL); 7872 MmUnlockPages(irp->MdlAddress); 7873 IoFreeMdl(irp->MdlAddress); 7874 irp->MdlAddress = (PMDL) NULL; 7875 } 7876 break; 7877 } 7878 7879 case METHOD_NEITHER: { 7880 ASSERT(!"Code is out of date"); 7881 break; 7882 } 7883 } 7884 7885 // 7886 // we always have allocated an irp. free it here. 7887 // 7888 7889 IoFreeIrp(irp); 7890 irp = (PIRP) NULL; 7891 7892 // 7893 // return the io status block's status to the caller 7894 // 7895 7896 return; 7897 } // end ClassSendDeviceIoControlSynchronous() 7898 7899 /*++//////////////////////////////////////////////////////////////////////////// 7900 7901 ClassForwardIrpSynchronous() 7902 7903 Routine Description: 7904 7905 Forwards a given irp to the next lower device object. 7906 7907 Arguments: 7908 7909 CommonExtension - the common class extension 7910 7911 Irp - the request to forward down the stack 7912 7913 Return Value: 7914 7915 --*/ 7916 NTSTATUS 7917 NTAPI 7918 ClassForwardIrpSynchronous( 7919 IN PCOMMON_DEVICE_EXTENSION CommonExtension, 7920 IN PIRP Irp 7921 ) 7922 { 7923 IoCopyCurrentIrpStackLocationToNext(Irp); 7924 return ClassSendIrpSynchronous(CommonExtension->LowerDeviceObject, Irp); 7925 } // end ClassForwardIrpSynchronous() 7926 7927 /*++//////////////////////////////////////////////////////////////////////////// 7928 7929 ClassSendIrpSynchronous() 7930 7931 Routine Description: 7932 7933 This routine sends the given irp to the given device object, and waits for 7934 it to complete. On debug versions, will print out a debug message and 7935 optionally assert for "lost" irps based upon classpnp's globals 7936 7937 Arguments: 7938 7939 TargetDeviceObject - the device object to handle this irp 7940 7941 Irp - the request to be sent 7942 7943 Return Value: 7944 7945 --*/ 7946 NTSTATUS 7947 NTAPI 7948 ClassSendIrpSynchronous( 7949 IN PDEVICE_OBJECT TargetDeviceObject, 7950 IN PIRP Irp 7951 ) 7952 { 7953 KEVENT event; 7954 NTSTATUS status; 7955 7956 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); 7957 ASSERT(TargetDeviceObject != NULL); 7958 ASSERT(Irp != NULL); 7959 ASSERT(Irp->StackCount >= TargetDeviceObject->StackSize); 7960 7961 // 7962 // ISSUE-2000/02/20-henrygab What if APCs are disabled? 7963 // May need to enter critical section before IoCallDriver() 7964 // until the event is hit? 7965 // 7966 7967 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 7968 IoSetCompletionRoutine(Irp, ClassSignalCompletion, &event, 7969 TRUE, TRUE, TRUE); 7970 7971 status = IoCallDriver(TargetDeviceObject, Irp); 7972 7973 if (status == STATUS_PENDING) { 7974 7975 #if DBG 7976 LARGE_INTEGER timeout; 7977 7978 timeout.QuadPart = (LONGLONG)(-1 * 10 * 1000 * (LONGLONG)1000 * 7979 ClasspnpGlobals.SecondsToWaitForIrps); 7980 7981 do { 7982 status = KeWaitForSingleObject(&event, 7983 Executive, 7984 KernelMode, 7985 FALSE, 7986 &timeout); 7987 7988 7989 if (status == STATUS_TIMEOUT) { 7990 7991 // 7992 // This DebugPrint should almost always be investigated by the 7993 // party who sent the irp and/or the current owner of the irp. 7994 // Synchronous Irps should not take this long (currently 30 7995 // seconds) without good reason. This points to a potentially 7996 // serious problem in the underlying device stack. 7997 // 7998 7999 DebugPrint((0, "ClassSendIrpSynchronous: (%p) irp %p did not " 8000 "complete within %x seconds\n", 8001 TargetDeviceObject, Irp, 8002 ClasspnpGlobals.SecondsToWaitForIrps 8003 )); 8004 8005 if (ClasspnpGlobals.BreakOnLostIrps != 0) { 8006 ASSERT(!" - Irp failed to complete within 30 seconds - "); 8007 } 8008 } 8009 8010 8011 } while (status==STATUS_TIMEOUT); 8012 #else 8013 KeWaitForSingleObject(&event, 8014 Executive, 8015 KernelMode, 8016 FALSE, 8017 NULL); 8018 #endif 8019 8020 status = Irp->IoStatus.Status; 8021 } 8022 8023 return status; 8024 } // end ClassSendIrpSynchronous() 8025 8026 /*++//////////////////////////////////////////////////////////////////////////// 8027 8028 ClassGetVpb() 8029 8030 Routine Description: 8031 8032 This routine returns the current VPB (Volume Parameter Block) for the 8033 given device object. 8034 The Vpb field is only visible in the ntddk.h (not the wdm.h) definition 8035 of DEVICE_OBJECT; hence this exported function. 8036 8037 Arguments: 8038 8039 DeviceObject - the device to get the VPB for 8040 8041 Return Value: 8042 8043 the VPB, or NULL if none. 8044 8045 --*/ 8046 PVPB 8047 NTAPI 8048 ClassGetVpb( 8049 IN PDEVICE_OBJECT DeviceObject 8050 ) 8051 { 8052 return DeviceObject->Vpb; 8053 } // end ClassGetVpb() 8054 8055 /*++ 8056 8057 ISSUE-2000/02/20-henrygab Not documented ClasspAllocateReleaseRequest 8058 8059 --*/ 8060 NTSTATUS 8061 NTAPI 8062 ClasspAllocateReleaseRequest( 8063 IN PDEVICE_OBJECT Fdo 8064 ) 8065 { 8066 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 8067 //PIO_STACK_LOCATION irpStack; 8068 8069 KeInitializeSpinLock(&(fdoExtension->ReleaseQueueSpinLock)); 8070 8071 fdoExtension->ReleaseQueueNeeded = FALSE; 8072 fdoExtension->ReleaseQueueInProgress = FALSE; 8073 fdoExtension->ReleaseQueueIrpFromPool = FALSE; 8074 8075 // 8076 // The class driver is responsible for allocating a properly sized irp, 8077 // or ClassReleaseQueue will attempt to do it on the first error. 8078 // 8079 8080 fdoExtension->ReleaseQueueIrp = NULL; 8081 8082 // 8083 // Write length to SRB. 8084 // 8085 8086 fdoExtension->ReleaseQueueSrb.Length = sizeof(SCSI_REQUEST_BLOCK); 8087 8088 return STATUS_SUCCESS; 8089 } // end ClasspAllocateReleaseRequest() 8090 8091 /*++ 8092 8093 ISSUE-2000/02/20-henrygab Not documented ClasspFreeReleaseRequest 8094 8095 --*/ 8096 VOID 8097 NTAPI 8098 ClasspFreeReleaseRequest( 8099 IN PDEVICE_OBJECT Fdo 8100 ) 8101 { 8102 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 8103 //KIRQL oldIrql; 8104 8105 ASSERT(fdoExtension->CommonExtension.IsRemoved != NO_REMOVE); 8106 8107 // 8108 // free anything the driver allocated 8109 // 8110 8111 if (fdoExtension->ReleaseQueueIrp) { 8112 if (fdoExtension->ReleaseQueueIrpFromPool) { 8113 ExFreePool(fdoExtension->ReleaseQueueIrp); 8114 } else { 8115 IoFreeIrp(fdoExtension->ReleaseQueueIrp); 8116 } 8117 fdoExtension->ReleaseQueueIrp = NULL; 8118 } 8119 8120 // 8121 // free anything that we allocated 8122 // 8123 8124 if ((fdoExtension->PrivateFdoData) && 8125 (fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated)) { 8126 8127 ExFreePool(fdoExtension->PrivateFdoData->ReleaseQueueIrp); 8128 fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated = FALSE; 8129 fdoExtension->PrivateFdoData->ReleaseQueueIrp = NULL; 8130 } 8131 8132 return; 8133 } // end ClasspFreeReleaseRequest() 8134 8135 /*++//////////////////////////////////////////////////////////////////////////// 8136 8137 ClassReleaseQueue() 8138 8139 Routine Description: 8140 8141 This routine issues an internal device control command 8142 to the port driver to release a frozen queue. The call 8143 is issued asynchronously as ClassReleaseQueue will be invoked 8144 from the IO completion DPC (and will have no context to 8145 wait for a synchronous call to complete). 8146 8147 This routine must be called with the remove lock held. 8148 8149 Arguments: 8150 8151 Fdo - The functional device object for the device with the frozen queue. 8152 8153 Return Value: 8154 8155 None. 8156 8157 --*/ 8158 VOID 8159 NTAPI 8160 ClassReleaseQueue( 8161 IN PDEVICE_OBJECT Fdo 8162 ) 8163 { 8164 ClasspReleaseQueue(Fdo, NULL); 8165 return; 8166 } // end ClassReleaseQueue() 8167 8168 /*++//////////////////////////////////////////////////////////////////////////// 8169 8170 ClasspAllocateReleaseQueueIrp() 8171 8172 Routine Description: 8173 8174 This routine allocates the release queue irp held in classpnp's private 8175 extension. This was added to allow no-memory conditions to be more 8176 survivable. 8177 8178 Return Value: 8179 8180 NT_SUCCESS value. 8181 8182 Notes: 8183 8184 Does not grab the spinlock. Should only be called from StartDevice() 8185 routine. May be called elsewhere for poorly-behaved drivers that cause 8186 the queue to lockup before the device is started. This should *never* 8187 occur, since it's illegal to send a request to a non-started PDO. This 8188 condition is checked for in ClasspReleaseQueue(). 8189 8190 --*/ 8191 NTSTATUS 8192 NTAPI 8193 ClasspAllocateReleaseQueueIrp( 8194 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 8195 ) 8196 { 8197 //KIRQL oldIrql; 8198 UCHAR lowerStackSize; 8199 8200 // 8201 // do an initial check w/o the spinlock 8202 // 8203 8204 if (FdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) { 8205 return STATUS_SUCCESS; 8206 } 8207 8208 8209 lowerStackSize = FdoExtension->CommonExtension.LowerDeviceObject->StackSize; 8210 8211 // 8212 // don't allocate one if one is in progress! this means whoever called 8213 // this routine didn't check if one was in progress. 8214 // 8215 8216 ASSERT(!(FdoExtension->ReleaseQueueInProgress)); 8217 8218 FdoExtension->PrivateFdoData->ReleaseQueueIrp = 8219 ExAllocatePoolWithTag(NonPagedPool, 8220 IoSizeOfIrp(lowerStackSize), 8221 CLASS_TAG_RELEASE_QUEUE 8222 ); 8223 8224 if (FdoExtension->PrivateFdoData->ReleaseQueueIrp == NULL) { 8225 DebugPrint((0, "ClassPnpStartDevice: Cannot allocate for " 8226 "release queue irp\n")); 8227 return STATUS_INSUFFICIENT_RESOURCES; 8228 } 8229 IoInitializeIrp(FdoExtension->PrivateFdoData->ReleaseQueueIrp, 8230 IoSizeOfIrp(lowerStackSize), 8231 lowerStackSize); 8232 FdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated = TRUE; 8233 8234 return STATUS_SUCCESS; 8235 } 8236 8237 /*++//////////////////////////////////////////////////////////////////////////// 8238 8239 ClasspReleaseQueue() 8240 8241 Routine Description: 8242 8243 This routine issues an internal device control command 8244 to the port driver to release a frozen queue. The call 8245 is issued asynchronously as ClassReleaseQueue will be invoked 8246 from the IO completion DPC (and will have no context to 8247 wait for a synchronous call to complete). 8248 8249 This routine must be called with the remove lock held. 8250 8251 Arguments: 8252 8253 Fdo - The functional device object for the device with the frozen queue. 8254 8255 ReleaseQueueIrp - If this irp is supplied then the test to determine whether 8256 a release queue request is in progress will be ignored. 8257 The irp provided must be the IRP originally allocated 8258 for release queue requests (so this parameter can only 8259 really be provided by the release queue completion 8260 routine.) 8261 8262 Return Value: 8263 8264 None. 8265 8266 --*/ 8267 VOID 8268 NTAPI 8269 ClasspReleaseQueue( 8270 IN PDEVICE_OBJECT Fdo, 8271 IN PIRP ReleaseQueueIrp OPTIONAL 8272 ) 8273 { 8274 PIO_STACK_LOCATION irpStack; 8275 PIRP irp; 8276 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 8277 PDEVICE_OBJECT lowerDevice; 8278 PSCSI_REQUEST_BLOCK srb; 8279 KIRQL currentIrql; 8280 8281 lowerDevice = fdoExtension->CommonExtension.LowerDeviceObject; 8282 8283 // 8284 // we raise irql separately so we're not swapped out or suspended 8285 // while holding the release queue irp in this routine. this lets 8286 // us release the spin lock before lowering irql. 8287 // 8288 8289 KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql); 8290 8291 KeAcquireSpinLockAtDpcLevel(&(fdoExtension->ReleaseQueueSpinLock)); 8292 8293 // 8294 // make sure that if they passed us an irp, it matches our allocated irp. 8295 // 8296 8297 ASSERT((ReleaseQueueIrp == NULL) || 8298 (ReleaseQueueIrp == fdoExtension->PrivateFdoData->ReleaseQueueIrp)); 8299 8300 // 8301 // ASSERT that we've already allocated this. (should not occur) 8302 // try to allocate it anyways, then finally bugcheck if 8303 // there's still no memory... 8304 // 8305 8306 ASSERT(fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated); 8307 if (!fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) { 8308 ClasspAllocateReleaseQueueIrp(fdoExtension); 8309 } 8310 if (!fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) { 8311 KeBugCheckEx(SCSI_DISK_DRIVER_INTERNAL, 0x12, (ULONG_PTR)Fdo, 0x0, 0x0); 8312 } 8313 8314 if ((fdoExtension->ReleaseQueueInProgress) && (ReleaseQueueIrp == NULL)) { 8315 8316 // 8317 // Someone is already using the irp - just set the flag to indicate that 8318 // we need to release the queue again. 8319 // 8320 8321 fdoExtension->ReleaseQueueNeeded = TRUE; 8322 KeReleaseSpinLockFromDpcLevel(&(fdoExtension->ReleaseQueueSpinLock)); 8323 KeLowerIrql(currentIrql); 8324 return; 8325 8326 } 8327 8328 // 8329 // Mark that there is a release queue in progress and drop the spinlock. 8330 // 8331 8332 fdoExtension->ReleaseQueueInProgress = TRUE; 8333 if (ReleaseQueueIrp) { 8334 irp = ReleaseQueueIrp; 8335 } else { 8336 irp = fdoExtension->PrivateFdoData->ReleaseQueueIrp; 8337 } 8338 srb = &(fdoExtension->ReleaseQueueSrb); 8339 8340 KeReleaseSpinLockFromDpcLevel(&(fdoExtension->ReleaseQueueSpinLock)); 8341 8342 ASSERT(irp != NULL); 8343 8344 irpStack = IoGetNextIrpStackLocation(irp); 8345 8346 irpStack->MajorFunction = IRP_MJ_SCSI; 8347 8348 srb->OriginalRequest = irp; 8349 8350 // 8351 // Store the SRB address in next stack for port driver. 8352 // 8353 8354 irpStack->Parameters.Scsi.Srb = srb; 8355 8356 // 8357 // If this device is removable then flush the queue. This will also 8358 // release it. 8359 // 8360 8361 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){ 8362 srb->Function = SRB_FUNCTION_FLUSH_QUEUE; 8363 } 8364 else { 8365 srb->Function = SRB_FUNCTION_RELEASE_QUEUE; 8366 } 8367 8368 ClassAcquireRemoveLock(Fdo, irp); 8369 8370 IoSetCompletionRoutine(irp, 8371 ClassReleaseQueueCompletion, 8372 Fdo, 8373 TRUE, 8374 TRUE, 8375 TRUE); 8376 8377 IoCallDriver(lowerDevice, irp); 8378 8379 KeLowerIrql(currentIrql); 8380 8381 return; 8382 8383 } // end ClassReleaseQueue() 8384 8385 /*++//////////////////////////////////////////////////////////////////////////// 8386 8387 ClassReleaseQueueCompletion() 8388 8389 Routine Description: 8390 8391 This routine is called when an asynchronous I/O request 8392 which was issued by the class driver completes. Examples of such requests 8393 are release queue or START UNIT. This routine releases the queue if 8394 necessary. It then frees the context and the IRP. 8395 8396 Arguments: 8397 8398 DeviceObject - The device object for the logical unit; however since this 8399 is the top stack location the value is NULL. 8400 8401 Irp - Supplies a pointer to the Irp to be processed. 8402 8403 Context - Supplies the context to be used to process this request. 8404 8405 Return Value: 8406 8407 None. 8408 8409 --*/ 8410 NTSTATUS 8411 NTAPI 8412 ClassReleaseQueueCompletion( 8413 PDEVICE_OBJECT DeviceObject, 8414 PIRP Irp, 8415 PVOID Context 8416 ) 8417 { 8418 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 8419 KIRQL oldIrql; 8420 8421 BOOLEAN releaseQueueNeeded; 8422 8423 DeviceObject = Context; 8424 8425 fdoExtension = DeviceObject->DeviceExtension; 8426 8427 ClassReleaseRemoveLock(DeviceObject, Irp); 8428 8429 // 8430 // Grab the spinlock and clear the release queue in progress flag so others 8431 // can run. Save (and clear) the state of the release queue needed flag 8432 // so that we can issue a new release queue outside the spinlock. 8433 // 8434 8435 KeAcquireSpinLock(&(fdoExtension->ReleaseQueueSpinLock), &oldIrql); 8436 8437 releaseQueueNeeded = fdoExtension->ReleaseQueueNeeded; 8438 8439 fdoExtension->ReleaseQueueNeeded = FALSE; 8440 fdoExtension->ReleaseQueueInProgress = FALSE; 8441 8442 KeReleaseSpinLock(&(fdoExtension->ReleaseQueueSpinLock), oldIrql); 8443 8444 // 8445 // If we need a release queue then issue one now. Another processor may 8446 // have already started one in which case we'll try to issue this one after 8447 // it is done - but we should never recurse more than one deep. 8448 // 8449 8450 if(releaseQueueNeeded) { 8451 ClasspReleaseQueue(DeviceObject, Irp); 8452 } 8453 8454 // 8455 // Indicate the I/O system should stop processing the Irp completion. 8456 // 8457 8458 return STATUS_MORE_PROCESSING_REQUIRED; 8459 8460 } // ClassAsynchronousCompletion() 8461 8462 /*++//////////////////////////////////////////////////////////////////////////// 8463 8464 ClassAcquireChildLock() 8465 8466 Routine Description: 8467 8468 This routine acquires the lock protecting children PDOs. It may be 8469 acquired recursively by the same thread, but must be release by the 8470 thread once for each acquisition. 8471 8472 Arguments: 8473 8474 FdoExtension - the device whose child list is protected. 8475 8476 Return Value: 8477 8478 None 8479 8480 --*/ 8481 VOID 8482 NTAPI 8483 ClassAcquireChildLock( 8484 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 8485 ) 8486 { 8487 PAGED_CODE(); 8488 8489 if(FdoExtension->ChildLockOwner != KeGetCurrentThread()) { 8490 KeWaitForSingleObject(&FdoExtension->ChildLock, 8491 Executive, KernelMode, 8492 FALSE, NULL); 8493 8494 ASSERT(FdoExtension->ChildLockOwner == NULL); 8495 ASSERT(FdoExtension->ChildLockAcquisitionCount == 0); 8496 8497 FdoExtension->ChildLockOwner = KeGetCurrentThread(); 8498 } else { 8499 ASSERT(FdoExtension->ChildLockAcquisitionCount != 0); 8500 } 8501 8502 FdoExtension->ChildLockAcquisitionCount++; 8503 return; 8504 } 8505 8506 /*++//////////////////////////////////////////////////////////////////////////// 8507 8508 ClassReleaseChildLock() ISSUE-2000/02/18-henrygab - not documented 8509 8510 Routine Description: 8511 8512 This routine releases the lock protecting children PDOs. It must be 8513 called once for each time ClassAcquireChildLock was called. 8514 8515 Arguments: 8516 8517 FdoExtension - the device whose child list is protected 8518 8519 Return Value: 8520 8521 None. 8522 8523 --*/ 8524 VOID 8525 NTAPI 8526 ClassReleaseChildLock( 8527 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 8528 ) 8529 { 8530 ASSERT(FdoExtension->ChildLockOwner == KeGetCurrentThread()); 8531 ASSERT(FdoExtension->ChildLockAcquisitionCount != 0); 8532 8533 FdoExtension->ChildLockAcquisitionCount -= 1; 8534 8535 if(FdoExtension->ChildLockAcquisitionCount == 0) { 8536 FdoExtension->ChildLockOwner = NULL; 8537 KeSetEvent(&FdoExtension->ChildLock, IO_NO_INCREMENT, FALSE); 8538 } 8539 8540 return; 8541 } // end ClassReleaseChildLock( 8542 8543 /*++//////////////////////////////////////////////////////////////////////////// 8544 8545 ClassAddChild() 8546 8547 Routine Description: 8548 8549 This routine will insert a new child into the head of the child list. 8550 8551 Arguments: 8552 8553 Parent - the child's parent (contains the head of the list) 8554 Child - the child to be inserted. 8555 AcquireLock - whether the child lock should be acquired (TRUE) or whether 8556 it's already been acquired by or on behalf of the caller 8557 (FALSE). 8558 8559 Return Value: 8560 8561 None. 8562 8563 --*/ 8564 VOID 8565 NTAPI 8566 ClassAddChild( 8567 IN PFUNCTIONAL_DEVICE_EXTENSION Parent, 8568 IN PPHYSICAL_DEVICE_EXTENSION Child, 8569 IN BOOLEAN AcquireLock 8570 ) 8571 { 8572 if(AcquireLock) { 8573 ClassAcquireChildLock(Parent); 8574 } 8575 8576 #if DBG 8577 // 8578 // Make sure this child's not already in the list. 8579 // 8580 { 8581 PPHYSICAL_DEVICE_EXTENSION testChild; 8582 8583 for (testChild = Parent->CommonExtension.ChildList; 8584 testChild != NULL; 8585 testChild = testChild->CommonExtension.ChildList) { 8586 8587 ASSERT(testChild != Child); 8588 } 8589 } 8590 #endif 8591 8592 Child->CommonExtension.ChildList = Parent->CommonExtension.ChildList; 8593 Parent->CommonExtension.ChildList = Child; 8594 8595 if(AcquireLock) { 8596 ClassReleaseChildLock(Parent); 8597 } 8598 return; 8599 } // end ClassAddChild() 8600 8601 /*++//////////////////////////////////////////////////////////////////////////// 8602 8603 ClassRemoveChild() 8604 8605 Routine Description: 8606 8607 This routine will remove a child from the child list. 8608 8609 Arguments: 8610 8611 Parent - the parent to be removed from. 8612 8613 Child - the child to be removed or NULL if the first child should be 8614 removed. 8615 8616 AcquireLock - whether the child lock should be acquired (TRUE) or whether 8617 it's already been acquired by or on behalf of the caller 8618 (FALSE). 8619 8620 Return Value: 8621 8622 A pointer to the child which was removed or NULL if no such child could 8623 be found in the list (or if Child was NULL but the list is empty). 8624 8625 --*/ 8626 PPHYSICAL_DEVICE_EXTENSION 8627 NTAPI 8628 ClassRemoveChild( 8629 IN PFUNCTIONAL_DEVICE_EXTENSION Parent, 8630 IN PPHYSICAL_DEVICE_EXTENSION Child, 8631 IN BOOLEAN AcquireLock 8632 ) 8633 { 8634 if(AcquireLock) { 8635 ClassAcquireChildLock(Parent); 8636 } 8637 8638 TRY { 8639 PCOMMON_DEVICE_EXTENSION previousChild = &Parent->CommonExtension; 8640 8641 // 8642 // If the list is empty then bail out now. 8643 // 8644 8645 if(Parent->CommonExtension.ChildList == NULL) { 8646 Child = NULL; 8647 LEAVE; 8648 } 8649 8650 // 8651 // If the caller specified a child then find the child object before 8652 // it. If none was specified then the FDO is the child object before 8653 // the one we want to remove. 8654 // 8655 8656 if(Child != NULL) { 8657 8658 // 8659 // Scan through the child list to find the entry which points to 8660 // this one. 8661 // 8662 8663 do { 8664 ASSERT(previousChild != &Child->CommonExtension); 8665 8666 if(previousChild->ChildList == Child) { 8667 break; 8668 } 8669 8670 previousChild = &previousChild->ChildList->CommonExtension; 8671 } while(previousChild != NULL); 8672 8673 if(previousChild == NULL) { 8674 Child = NULL; 8675 LEAVE; 8676 } 8677 } 8678 8679 // 8680 // Save the next child away then unlink it from the list. 8681 // 8682 8683 Child = previousChild->ChildList; 8684 previousChild->ChildList = Child->CommonExtension.ChildList; 8685 Child->CommonExtension.ChildList = NULL; 8686 8687 } FINALLY { 8688 if(AcquireLock) { 8689 ClassReleaseChildLock(Parent); 8690 } 8691 } 8692 return Child; 8693 } // end ClassRemoveChild() 8694 8695 /*++ 8696 8697 ISSUE-2000/02/20-henrygab Not documented ClasspRetryRequestDpc 8698 8699 --*/ 8700 VOID 8701 NTAPI 8702 ClasspRetryRequestDpc( 8703 IN PKDPC Dpc, 8704 IN PVOID Context, 8705 IN PVOID Arg1, 8706 IN PVOID Arg2 8707 ) 8708 { 8709 PDEVICE_OBJECT deviceObject = Context; 8710 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 8711 PCOMMON_DEVICE_EXTENSION commonExtension; 8712 PCLASS_PRIVATE_FDO_DATA fdoData; 8713 PCLASS_RETRY_INFO retryList; 8714 KIRQL irql; 8715 8716 8717 commonExtension = deviceObject->DeviceExtension; 8718 ASSERT(commonExtension->IsFdo); 8719 fdoExtension = deviceObject->DeviceExtension; 8720 fdoData = fdoExtension->PrivateFdoData; 8721 8722 8723 KeAcquireSpinLock(&fdoData->Retry.Lock, &irql); 8724 { 8725 LARGE_INTEGER now; 8726 KeQueryTickCount(&now); 8727 8728 // 8729 // if CurrentTick is less than now 8730 // fire another DPC 8731 // else 8732 // retry entire list 8733 // endif 8734 // 8735 8736 if (now.QuadPart < fdoData->Retry.Tick.QuadPart) { 8737 8738 ClasspRetryDpcTimer(fdoData); 8739 retryList = NULL; 8740 8741 } else { 8742 8743 retryList = fdoData->Retry.ListHead; 8744 fdoData->Retry.ListHead = NULL; 8745 fdoData->Retry.Delta.QuadPart = (LONGLONG)0; 8746 fdoData->Retry.Tick.QuadPart = (LONGLONG)0; 8747 8748 } 8749 } 8750 KeReleaseSpinLock(&fdoData->Retry.Lock, irql); 8751 8752 while (retryList != NULL) { 8753 8754 PIRP irp; 8755 8756 irp = CONTAINING_RECORD(retryList, IRP, Tail.Overlay.DriverContext[0]); 8757 DebugPrint((ClassDebugDelayedRetry, "ClassRetry: -- %p\n", irp)); 8758 retryList = retryList->Next; 8759 #if DBG 8760 irp->Tail.Overlay.DriverContext[0] = ULongToPtr(0xdddddddd); // invalidate data 8761 irp->Tail.Overlay.DriverContext[1] = ULongToPtr(0xdddddddd); // invalidate data 8762 irp->Tail.Overlay.DriverContext[2] = ULongToPtr(0xdddddddd); // invalidate data 8763 irp->Tail.Overlay.DriverContext[3] = ULongToPtr(0xdddddddd); // invalidate data 8764 #endif 8765 8766 IoCallDriver(commonExtension->LowerDeviceObject, irp); 8767 8768 } 8769 return; 8770 8771 } // end ClasspRetryRequestDpc() 8772 8773 /*++ 8774 8775 ISSUE-2000/02/20-henrygab Not documented ClassRetryRequest 8776 8777 --*/ 8778 VOID 8779 NTAPI 8780 ClassRetryRequest( 8781 IN PDEVICE_OBJECT SelfDeviceObject, 8782 IN PIRP Irp, 8783 IN LARGE_INTEGER TimeDelta100ns // in 100ns units 8784 ) 8785 { 8786 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 8787 PCLASS_PRIVATE_FDO_DATA fdoData; 8788 PCLASS_RETRY_INFO retryInfo; 8789 //PCLASS_RETRY_INFO *previousNext; 8790 LARGE_INTEGER delta; 8791 KIRQL irql; 8792 8793 // 8794 // this checks we aren't destroying irps 8795 // 8796 ASSERT(sizeof(CLASS_RETRY_INFO) <= (4*sizeof(PVOID))); 8797 8798 fdoExtension = SelfDeviceObject->DeviceExtension; 8799 fdoData = fdoExtension->PrivateFdoData; 8800 8801 if (!fdoExtension->CommonExtension.IsFdo) { 8802 8803 // 8804 // this debug print/assertion should ALWAYS be investigated. 8805 // ClassRetryRequest can currently only be used by FDO's 8806 // 8807 8808 DebugPrint((ClassDebugError, "ClassRetryRequestEx: LOST IRP %p\n", Irp)); 8809 ASSERT(!"ClassRetryRequestEx Called From PDO? LOST IRP"); 8810 return; 8811 8812 } 8813 8814 if (TimeDelta100ns.QuadPart < 0) { 8815 ASSERT(!"ClassRetryRequest - must use positive delay"); 8816 TimeDelta100ns.QuadPart *= -1; 8817 } 8818 8819 // 8820 // prepare what we can out of the loop 8821 // 8822 8823 retryInfo = (PCLASS_RETRY_INFO)(&Irp->Tail.Overlay.DriverContext[0]); 8824 RtlZeroMemory(retryInfo, sizeof(CLASS_RETRY_INFO)); 8825 8826 delta.QuadPart = (TimeDelta100ns.QuadPart / fdoData->Retry.Granularity); 8827 if (TimeDelta100ns.QuadPart % fdoData->Retry.Granularity) { 8828 delta.QuadPart ++; // round up to next tick 8829 } 8830 if (delta.QuadPart == (LONGLONG)0) { 8831 delta.QuadPart = MINIMUM_RETRY_UNITS; 8832 } 8833 8834 // 8835 // now determine if we should fire another DPC or not 8836 // 8837 8838 KeAcquireSpinLock(&fdoData->Retry.Lock, &irql); 8839 8840 // 8841 // always add request to the list 8842 // 8843 8844 retryInfo->Next = fdoData->Retry.ListHead; 8845 fdoData->Retry.ListHead = retryInfo; 8846 8847 if (fdoData->Retry.Delta.QuadPart == (LONGLONG)0) { 8848 8849 DebugPrint((ClassDebugDelayedRetry, "ClassRetry: +++ %p\n", Irp)); 8850 8851 // 8852 // must be exactly one item on list 8853 // 8854 8855 ASSERT(fdoData->Retry.ListHead != NULL); 8856 ASSERT(fdoData->Retry.ListHead->Next == NULL); 8857 8858 // 8859 // if currentDelta is zero, always fire a DPC 8860 // 8861 8862 KeQueryTickCount(&fdoData->Retry.Tick); 8863 fdoData->Retry.Tick.QuadPart += delta.QuadPart; 8864 fdoData->Retry.Delta.QuadPart = delta.QuadPart; 8865 ClasspRetryDpcTimer(fdoData); 8866 8867 } else if (delta.QuadPart > fdoData->Retry.Delta.QuadPart) { 8868 8869 // 8870 // if delta is greater than the list's current delta, 8871 // increase the DPC handling time by difference 8872 // and update the delta to new larger value 8873 // allow the DPC to re-fire itself if needed 8874 // 8875 8876 DebugPrint((ClassDebugDelayedRetry, "ClassRetry: ++ %p\n", Irp)); 8877 8878 // 8879 // must be at least two items on list 8880 // 8881 8882 ASSERT(fdoData->Retry.ListHead != NULL); 8883 ASSERT(fdoData->Retry.ListHead->Next != NULL); 8884 8885 fdoData->Retry.Tick.QuadPart -= fdoData->Retry.Delta.QuadPart; 8886 fdoData->Retry.Tick.QuadPart += delta.QuadPart; 8887 8888 fdoData->Retry.Delta.QuadPart = delta.QuadPart; 8889 8890 } else { 8891 8892 // 8893 // just inserting it on the list was enough 8894 // 8895 8896 DebugPrint((ClassDebugDelayedRetry, "ClassRetry: ++ %p\n", Irp)); 8897 8898 } 8899 8900 8901 KeReleaseSpinLock(&fdoData->Retry.Lock, irql); 8902 8903 8904 } // end ClassRetryRequest() 8905 8906 /*++ 8907 8908 ISSUE-2000/02/20-henrygab Not documented ClasspRetryDpcTimer 8909 8910 --*/ 8911 VOID 8912 NTAPI 8913 ClasspRetryDpcTimer( 8914 IN PCLASS_PRIVATE_FDO_DATA FdoData 8915 ) 8916 { 8917 LARGE_INTEGER fire; 8918 8919 ASSERT(FdoData->Retry.Tick.QuadPart != (LONGLONG)0); 8920 ASSERT(FdoData->Retry.ListHead != NULL); // never fire an empty list 8921 8922 // 8923 // fire == (CurrentTick - now) * (100ns per tick) 8924 // 8925 // NOTE: Overflow is nearly impossible and is ignored here 8926 // 8927 8928 KeQueryTickCount(&fire); 8929 fire.QuadPart = FdoData->Retry.Tick.QuadPart - fire.QuadPart; 8930 fire.QuadPart *= FdoData->Retry.Granularity; 8931 8932 // 8933 // fire is now multiples of 100ns until should fire the timer. 8934 // if timer should already have expired, or would fire too quickly, 8935 // fire it in some arbitrary number of ticks to prevent infinitely 8936 // recursing. 8937 // 8938 8939 if (fire.QuadPart < MINIMUM_RETRY_UNITS) { 8940 fire.QuadPart = MINIMUM_RETRY_UNITS; 8941 } 8942 8943 DebugPrint((ClassDebugDelayedRetry, 8944 "ClassRetry: ======= %I64x ticks\n", 8945 fire.QuadPart)); 8946 8947 // 8948 // must use negative to specify relative time to fire 8949 // 8950 8951 fire.QuadPart = fire.QuadPart * ((LONGLONG)-1); 8952 8953 // 8954 // set the timer, since this is the first addition 8955 // 8956 8957 KeSetTimerEx(&FdoData->Retry.Timer, fire, 0, &FdoData->Retry.Dpc); 8958 8959 return; 8960 } // end ClasspRetryDpcTimer() 8961 8962 NTSTATUS 8963 NTAPI 8964 ClasspInitializeHotplugInfo( 8965 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 8966 ) 8967 { 8968 PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData; 8969 DEVICE_REMOVAL_POLICY deviceRemovalPolicy; 8970 NTSTATUS status; 8971 ULONG resultLength = 0; 8972 ULONG writeCacheOverride; 8973 8974 PAGED_CODE(); 8975 8976 // 8977 // start with some default settings 8978 // 8979 RtlZeroMemory(&(fdoData->HotplugInfo), sizeof(STORAGE_HOTPLUG_INFO)); 8980 8981 // 8982 // set the size (aka version) 8983 // 8984 8985 fdoData->HotplugInfo.Size = sizeof(STORAGE_HOTPLUG_INFO); 8986 8987 // 8988 // set if the device has removable media 8989 // 8990 8991 if (FdoExtension->DeviceDescriptor->RemovableMedia) { 8992 fdoData->HotplugInfo.MediaRemovable = TRUE; 8993 } else { 8994 fdoData->HotplugInfo.MediaRemovable = FALSE; 8995 } 8996 8997 // 8998 // this refers to devices which, for reasons not yet understood, 8999 // do not fail PREVENT_MEDIA_REMOVAL requests even though they 9000 // have no way to lock the media into the drive. this allows 9001 // the filesystems to turn off delayed-write caching for these 9002 // devices as well. 9003 // 9004 9005 if (TEST_FLAG(FdoExtension->PrivateFdoData->HackFlags, 9006 FDO_HACK_CANNOT_LOCK_MEDIA)) { 9007 fdoData->HotplugInfo.MediaHotplug = TRUE; 9008 } else { 9009 fdoData->HotplugInfo.MediaHotplug = FALSE; 9010 } 9011 9012 9013 // 9014 // Look into the registry to see if the user has chosen 9015 // to override the default setting for the removal policy 9016 // 9017 9018 RtlZeroMemory(&deviceRemovalPolicy, sizeof(DEVICE_REMOVAL_POLICY)); 9019 9020 ClassGetDeviceParameter(FdoExtension, 9021 CLASSP_REG_SUBKEY_NAME, 9022 CLASSP_REG_REMOVAL_POLICY_VALUE_NAME, 9023 (PULONG)&deviceRemovalPolicy); 9024 9025 if (deviceRemovalPolicy == 0) 9026 { 9027 // 9028 // Query the default removal policy from the kernel 9029 // 9030 9031 status = IoGetDeviceProperty(FdoExtension->LowerPdo, 9032 DevicePropertyRemovalPolicy, 9033 sizeof(DEVICE_REMOVAL_POLICY), 9034 (PVOID)&deviceRemovalPolicy, 9035 &resultLength); 9036 if (!NT_SUCCESS(status)) 9037 { 9038 return status; 9039 } 9040 9041 if (resultLength != sizeof(DEVICE_REMOVAL_POLICY)) 9042 { 9043 return STATUS_UNSUCCESSFUL; 9044 } 9045 } 9046 9047 // 9048 // use this info to set the DeviceHotplug setting 9049 // don't rely on DeviceCapabilities, since it can't properly 9050 // determine device relations, etc. let the kernel figure this 9051 // stuff out instead. 9052 // 9053 9054 if (deviceRemovalPolicy == RemovalPolicyExpectSurpriseRemoval) { 9055 fdoData->HotplugInfo.DeviceHotplug = TRUE; 9056 } else { 9057 fdoData->HotplugInfo.DeviceHotplug = FALSE; 9058 } 9059 9060 // 9061 // this refers to the *filesystem* caching, but has to be included 9062 // here since it's a per-device setting. this may change to be 9063 // stored by the system in the future. 9064 // 9065 9066 writeCacheOverride = FALSE; 9067 ClassGetDeviceParameter(FdoExtension, 9068 CLASSP_REG_SUBKEY_NAME, 9069 CLASSP_REG_WRITE_CACHE_VALUE_NAME, 9070 &writeCacheOverride); 9071 9072 if (writeCacheOverride) { 9073 fdoData->HotplugInfo.WriteCacheEnableOverride = TRUE; 9074 } else { 9075 fdoData->HotplugInfo.WriteCacheEnableOverride = FALSE; 9076 } 9077 9078 return STATUS_SUCCESS; 9079 } 9080 9081 VOID 9082 NTAPI 9083 ClasspScanForClassHacks( 9084 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 9085 IN ULONG_PTR Data 9086 ) 9087 { 9088 PAGED_CODE(); 9089 9090 // 9091 // remove invalid flags and save 9092 // 9093 9094 CLEAR_FLAG(Data, FDO_HACK_INVALID_FLAGS); 9095 SET_FLAG(FdoExtension->PrivateFdoData->HackFlags, Data); 9096 return; 9097 } 9098 9099 VOID 9100 NTAPI 9101 ClasspScanForSpecialInRegistry( 9102 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 9103 ) 9104 { 9105 HANDLE deviceParameterHandle; // device instance key 9106 HANDLE classParameterHandle; // classpnp subkey 9107 OBJECT_ATTRIBUTES objectAttributes; 9108 UNICODE_STRING subkeyName; 9109 NTSTATUS status; 9110 9111 // 9112 // seeded in the ENUM tree by ClassInstaller 9113 // 9114 ULONG deviceHacks; 9115 RTL_QUERY_REGISTRY_TABLE queryTable[2]; // null terminated array 9116 9117 PAGED_CODE(); 9118 9119 deviceParameterHandle = NULL; 9120 classParameterHandle = NULL; 9121 deviceHacks = 0; 9122 9123 status = IoOpenDeviceRegistryKey(FdoExtension->LowerPdo, 9124 PLUGPLAY_REGKEY_DEVICE, 9125 KEY_WRITE, 9126 &deviceParameterHandle 9127 ); 9128 9129 if (!NT_SUCCESS(status)) { 9130 goto cleanupScanForSpecial; 9131 } 9132 9133 RtlInitUnicodeString(&subkeyName, CLASSP_REG_SUBKEY_NAME); 9134 InitializeObjectAttributes(&objectAttributes, 9135 &subkeyName, 9136 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 9137 deviceParameterHandle, 9138 NULL 9139 ); 9140 9141 status = ZwOpenKey( &classParameterHandle, 9142 KEY_READ, 9143 &objectAttributes 9144 ); 9145 9146 if (!NT_SUCCESS(status)) { 9147 goto cleanupScanForSpecial; 9148 } 9149 9150 // 9151 // Zero out the memory 9152 // 9153 9154 RtlZeroMemory(&queryTable[0], 2*sizeof(RTL_QUERY_REGISTRY_TABLE)); 9155 9156 // 9157 // Setup the structure to read 9158 // 9159 9160 queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 9161 queryTable[0].Name = CLASSP_REG_HACK_VALUE_NAME; 9162 queryTable[0].EntryContext = &deviceHacks; 9163 queryTable[0].DefaultType = REG_DWORD; 9164 queryTable[0].DefaultData = &deviceHacks; 9165 queryTable[0].DefaultLength = 0; 9166 9167 // 9168 // read values 9169 // 9170 9171 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 9172 (PWSTR)classParameterHandle, 9173 &queryTable[0], 9174 NULL, 9175 NULL 9176 ); 9177 if (!NT_SUCCESS(status)) { 9178 goto cleanupScanForSpecial; 9179 } 9180 9181 // 9182 // remove unknown values and save... 9183 // 9184 9185 KdPrintEx((DPFLTR_CLASSPNP_ID, DPFLTR_ERROR_LEVEL, 9186 "Classpnp => ScanForSpecial: HackFlags %#08x\n", 9187 deviceHacks)); 9188 9189 CLEAR_FLAG(deviceHacks, FDO_HACK_INVALID_FLAGS); 9190 SET_FLAG(FdoExtension->PrivateFdoData->HackFlags, deviceHacks); 9191 9192 9193 cleanupScanForSpecial: 9194 9195 if (deviceParameterHandle) { 9196 ZwClose(deviceParameterHandle); 9197 } 9198 9199 if (classParameterHandle) { 9200 ZwClose(classParameterHandle); 9201 } 9202 9203 // 9204 // we should modify the system hive to include another key for us to grab 9205 // settings from. in this case: Classpnp\HackFlags 9206 // 9207 // the use of a DWORD value for the HackFlags allows 32 hacks w/o 9208 // significant use of the registry, and also reduces OEM exposure. 9209 // 9210 // definition of bit flags: 9211 // 0x00000001 -- Device succeeds PREVENT_MEDIUM_REMOVAL, but 9212 // cannot actually prevent removal. 9213 // 0x00000002 -- Device hard-hangs or times out for GESN requests. 9214 // 0xfffffffc -- Currently reserved, may be used later. 9215 // 9216 9217 return; 9218 } 9219