Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenclass.c
Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (C) Microsoft Corporation, 1991 - 1999 00004 00005 Module Name: 00006 00007 class.c 00008 00009 Abstract: 00010 00011 SCSI class driver routines 00012 00013 Environment: 00014 00015 kernel mode only 00016 00017 Notes: 00018 00019 00020 Revision History: 00021 00022 --*/ 00023 00024 #define CLASS_INIT_GUID 1 00025 #include "classp.h" 00026 #include "debug.h" 00027 00028 #ifdef ALLOC_PRAGMA 00029 #pragma alloc_text(INIT, DriverEntry) 00030 #pragma alloc_text(PAGE, ClassAddDevice) 00031 #pragma alloc_text(PAGE, ClassClaimDevice) 00032 #pragma alloc_text(PAGE, ClassCreateDeviceObject) 00033 #pragma alloc_text(PAGE, ClassDispatchPnp) 00034 #pragma alloc_text(PAGE, ClassGetDescriptor) 00035 #pragma alloc_text(PAGE, ClassGetPdoId) 00036 #pragma alloc_text(PAGE, ClassInitialize) 00037 #pragma alloc_text(PAGE, ClassInitializeEx) 00038 #pragma alloc_text(PAGE, ClassInvalidateBusRelations) 00039 #pragma alloc_text(PAGE, ClassMarkChildMissing) 00040 #pragma alloc_text(PAGE, ClassMarkChildrenMissing) 00041 #pragma alloc_text(PAGE, ClassModeSense) 00042 #pragma alloc_text(PAGE, ClassPnpQueryFdoRelations) 00043 #pragma alloc_text(PAGE, ClassPnpStartDevice) 00044 #pragma alloc_text(PAGE, ClassQueryPnpCapabilities) 00045 #pragma alloc_text(PAGE, ClassQueryTimeOutRegistryValue) 00046 #pragma alloc_text(PAGE, ClassRemoveDevice) 00047 #pragma alloc_text(PAGE, ClassRetrieveDeviceRelations) 00048 #pragma alloc_text(PAGE, ClassUpdateInformationInRegistry) 00049 #pragma alloc_text(PAGE, ClassSendDeviceIoControlSynchronous) 00050 #pragma alloc_text(PAGE, ClassUnload) 00051 #pragma alloc_text(PAGE, ClasspAllocateReleaseRequest) 00052 #pragma alloc_text(PAGE, ClasspFreeReleaseRequest) 00053 #pragma alloc_text(PAGE, ClasspInitializeHotplugInfo) 00054 #pragma alloc_text(PAGE, ClasspRegisterMountedDeviceInterface) 00055 #pragma alloc_text(PAGE, ClasspScanForClassHacks) 00056 #pragma alloc_text(PAGE, ClasspScanForSpecialInRegistry) 00057 #endif 00058 00059 ULONG ClassPnpAllowUnload = TRUE; 00060 00061 00062 #define FirstDriveLetter 'C' 00063 #define LastDriveLetter 'Z' 00064 00065 00066 00067 /*++//////////////////////////////////////////////////////////////////////////// 00068 00069 DriverEntry() 00070 00071 Routine Description: 00072 00073 Temporary entry point needed to initialize the class system dll. 00074 It doesn't do anything. 00075 00076 Arguments: 00077 00078 DriverObject - Pointer to the driver object created by the system. 00079 00080 Return Value: 00081 00082 STATUS_SUCCESS 00083 00084 --*/ 00085 NTSTATUS 00086 NTAPI 00087 DriverEntry( 00088 IN PDRIVER_OBJECT DriverObject, 00089 IN PUNICODE_STRING RegistryPath 00090 ) 00091 { 00092 return STATUS_SUCCESS; 00093 } 00094 00095 00096 00097 00098 /*++//////////////////////////////////////////////////////////////////////////// 00099 00100 ClassInitialize() 00101 00102 Routine Description: 00103 00104 This routine is called by a class driver during its 00105 DriverEntry routine to initialize the driver. 00106 00107 Arguments: 00108 00109 Argument1 - Driver Object. 00110 Argument2 - Registry Path. 00111 InitializationData - Device-specific driver's initialization data. 00112 00113 Return Value: 00114 00115 A valid return code for a DriverEntry routine. 00116 00117 --*/ 00118 ULONG 00119 ClassInitialize( 00120 IN PVOID Argument1, 00121 IN PVOID Argument2, 00122 IN PCLASS_INIT_DATA InitializationData 00123 ) 00124 { 00125 PDRIVER_OBJECT DriverObject = Argument1; 00126 PUNICODE_STRING RegistryPath = Argument2; 00127 00128 PCLASS_DRIVER_EXTENSION driverExtension; 00129 00130 NTSTATUS status; 00131 00132 PAGED_CODE(); 00133 00134 DebugPrint((3,"\n\nSCSI Class Driver\n")); 00135 00136 ClasspInitializeDebugGlobals(); 00137 00138 // 00139 // Validate the length of this structure. This is effectively a 00140 // version check. 00141 // 00142 00143 if (InitializationData->InitializationDataSize != sizeof(CLASS_INIT_DATA)) { 00144 00145 // 00146 // This DebugPrint is to help third-party driver writers 00147 // 00148 00149 DebugPrint((0,"ClassInitialize: Class driver wrong version\n")); 00150 return (ULONG) STATUS_REVISION_MISMATCH; 00151 } 00152 00153 // 00154 // Check that each required entry is not NULL. Note that Shutdown, Flush and Error 00155 // are not required entry points. 00156 // 00157 00158 if ((!InitializationData->FdoData.ClassDeviceControl) || 00159 (!((InitializationData->FdoData.ClassReadWriteVerification) || 00160 (InitializationData->ClassStartIo))) || 00161 (!InitializationData->ClassAddDevice) || 00162 (!InitializationData->FdoData.ClassStartDevice)) { 00163 00164 // 00165 // This DebugPrint is to help third-party driver writers 00166 // 00167 00168 DebugPrint((0, 00169 "ClassInitialize: Class device-specific driver missing required " 00170 "FDO entry\n")); 00171 00172 return (ULONG) STATUS_REVISION_MISMATCH; 00173 } 00174 00175 if ((InitializationData->ClassEnumerateDevice) && 00176 ((!InitializationData->PdoData.ClassDeviceControl) || 00177 (!InitializationData->PdoData.ClassStartDevice) || 00178 (!((InitializationData->PdoData.ClassReadWriteVerification) || 00179 (InitializationData->ClassStartIo))))) { 00180 00181 // 00182 // This DebugPrint is to help third-party driver writers 00183 // 00184 00185 DebugPrint((0, "ClassInitialize: Class device-specific missing " 00186 "required PDO entry\n")); 00187 00188 return (ULONG) STATUS_REVISION_MISMATCH; 00189 } 00190 00191 if((InitializationData->FdoData.ClassStopDevice == NULL) || 00192 ((InitializationData->ClassEnumerateDevice != NULL) && 00193 (InitializationData->PdoData.ClassStopDevice == NULL))) { 00194 00195 // 00196 // This DebugPrint is to help third-party driver writers 00197 // 00198 00199 DebugPrint((0, "ClassInitialize: Class device-specific missing " 00200 "required PDO entry\n")); 00201 ASSERT(FALSE); 00202 return (ULONG) STATUS_REVISION_MISMATCH; 00203 } 00204 00205 // 00206 // Setup the default power handlers if the class driver didn't provide 00207 // any. 00208 // 00209 00210 if(InitializationData->FdoData.ClassPowerDevice == NULL) { 00211 InitializationData->FdoData.ClassPowerDevice = ClassMinimalPowerHandler; 00212 } 00213 00214 if((InitializationData->ClassEnumerateDevice != NULL) && 00215 (InitializationData->PdoData.ClassPowerDevice == NULL)) { 00216 InitializationData->PdoData.ClassPowerDevice = ClassMinimalPowerHandler; 00217 } 00218 00219 // 00220 // warn that unload is not supported 00221 // 00222 // ISSUE-2000/02/03-peterwie 00223 // We should think about making this a fatal error. 00224 // 00225 00226 if(InitializationData->ClassUnload == NULL) { 00227 00228 // 00229 // This DebugPrint is to help third-party driver writers 00230 // 00231 00232 DebugPrint((0, "ClassInitialize: driver does not support unload %wZ\n", 00233 RegistryPath)); 00234 } 00235 00236 // 00237 // Create an extension for the driver object 00238 // 00239 00240 status = IoAllocateDriverObjectExtension(DriverObject, 00241 CLASS_DRIVER_EXTENSION_KEY, 00242 sizeof(CLASS_DRIVER_EXTENSION), 00243 &driverExtension); 00244 00245 if(NT_SUCCESS(status)) { 00246 00247 // 00248 // Copy the registry path into the driver extension so we can use it later 00249 // 00250 00251 driverExtension->RegistryPath.Length = RegistryPath->Length; 00252 driverExtension->RegistryPath.MaximumLength = RegistryPath->MaximumLength; 00253 00254 driverExtension->RegistryPath.Buffer = 00255 ExAllocatePoolWithTag(PagedPool, 00256 RegistryPath->MaximumLength, 00257 '1CcS'); 00258 00259 if(driverExtension->RegistryPath.Buffer == NULL) { 00260 00261 status = STATUS_INSUFFICIENT_RESOURCES; 00262 return status; 00263 } 00264 00265 RtlCopyUnicodeString( 00266 &(driverExtension->RegistryPath), 00267 RegistryPath); 00268 00269 // 00270 // Copy the initialization data into the driver extension so we can reuse 00271 // it during our add device routine 00272 // 00273 00274 RtlCopyMemory( 00275 &(driverExtension->InitData), 00276 InitializationData, 00277 sizeof(CLASS_INIT_DATA)); 00278 00279 driverExtension->DeviceCount = 0; 00280 00281 } else if (status == STATUS_OBJECT_NAME_COLLISION) { 00282 00283 // 00284 // The extension already exists - get a pointer to it 00285 // 00286 00287 driverExtension = IoGetDriverObjectExtension(DriverObject, 00288 CLASS_DRIVER_EXTENSION_KEY); 00289 00290 ASSERT(driverExtension != NULL); 00291 00292 } else { 00293 00294 DebugPrint((1, "ClassInitialize: Class driver extension could not be " 00295 "allocated %lx\n", status)); 00296 return status; 00297 } 00298 00299 // 00300 // Update driver object with entry points. 00301 // 00302 00303 DriverObject->MajorFunction[IRP_MJ_CREATE] = ClassCreateClose; 00304 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ClassCreateClose; 00305 DriverObject->MajorFunction[IRP_MJ_READ] = ClassReadWrite; 00306 DriverObject->MajorFunction[IRP_MJ_WRITE] = ClassReadWrite; 00307 DriverObject->MajorFunction[IRP_MJ_SCSI] = ClassInternalIoControl; 00308 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControlDispatch; 00309 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = ClassShutdownFlush; 00310 DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = ClassShutdownFlush; 00311 DriverObject->MajorFunction[IRP_MJ_PNP] = ClassDispatchPnp; 00312 DriverObject->MajorFunction[IRP_MJ_POWER] = ClassDispatchPower; 00313 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ClassSystemControl; 00314 00315 if (InitializationData->ClassStartIo) { 00316 DriverObject->DriverStartIo = ClasspStartIo; 00317 } 00318 00319 if ((InitializationData->ClassUnload) && (ClassPnpAllowUnload == TRUE)) { 00320 DriverObject->DriverUnload = ClassUnload; 00321 } else { 00322 DriverObject->DriverUnload = NULL; 00323 } 00324 00325 DriverObject->DriverExtension->AddDevice = ClassAddDevice; 00326 00327 DbgPrint("Driver is ready to go\n"); 00328 status = STATUS_SUCCESS; 00329 return status; 00330 } // end ClassInitialize() 00331 00332 /*++//////////////////////////////////////////////////////////////////////////// 00333 00334 ClassInitializeEx() 00335 00336 Routine Description: 00337 00338 This routine is allows the caller to do any extra initialization or 00339 setup that is not done in ClassInitialize. The operation is 00340 controlled by the GUID that is passed and the contents of the Data 00341 parameter is dependent upon the GUID. 00342 00343 This is the list of supported operations: 00344 00345 Guid - GUID_CLASSPNP_QUERY_REGINFOEX 00346 Data - A PCLASS_QUERY_WMI_REGINFO_EX callback function pointer 00347 00348 Initialized classpnp to callback a PCLASS_QUERY_WMI_REGINFO_EX 00349 callback instead of a PCLASS_QUERY_WMI_REGINFO callback. The 00350 former callback allows the driver to specify the name of the 00351 mof resource. 00352 00353 Arguments: 00354 00355 DriverObject 00356 Guid 00357 Data 00358 00359 Return Value: 00360 00361 Status Code 00362 00363 --*/ 00364 ULONG 00365 ClassInitializeEx( 00366 IN PDRIVER_OBJECT DriverObject, 00367 IN LPGUID Guid, 00368 IN PVOID Data 00369 ) 00370 { 00371 PCLASS_DRIVER_EXTENSION driverExtension; 00372 00373 NTSTATUS status; 00374 00375 PAGED_CODE(); 00376 00377 driverExtension = IoGetDriverObjectExtension( DriverObject, 00378 CLASS_DRIVER_EXTENSION_KEY 00379 ); 00380 if (IsEqualGUID(Guid, &ClassGuidQueryRegInfoEx)) 00381 { 00382 PCLASS_QUERY_WMI_REGINFO_EX_LIST List; 00383 00384 // 00385 // Indicate the device supports PCLASS_QUERY_REGINFO_EX 00386 // callback instead of PCLASS_QUERY_REGINFO callback. 00387 // 00388 List = (PCLASS_QUERY_WMI_REGINFO_EX_LIST)Data; 00389 00390 if (List->Size == sizeof(CLASS_QUERY_WMI_REGINFO_EX_LIST)) 00391 { 00392 driverExtension->ClassFdoQueryWmiRegInfoEx = List->ClassFdoQueryWmiRegInfoEx; 00393 driverExtension->ClassPdoQueryWmiRegInfoEx = List->ClassPdoQueryWmiRegInfoEx; 00394 status = STATUS_SUCCESS; 00395 } else { 00396 status = STATUS_INVALID_PARAMETER; 00397 } 00398 } else { 00399 status = STATUS_NOT_SUPPORTED; 00400 } 00401 00402 return(status); 00403 00404 } // end ClassInitializeEx() 00405 00406 /*++//////////////////////////////////////////////////////////////////////////// 00407 00408 ClassUnload() 00409 00410 Routine Description: 00411 00412 called when there are no more references to the driver. this allows 00413 drivers to be updated without rebooting. 00414 00415 Arguments: 00416 00417 DriverObject - a pointer to the driver object that is being unloaded 00418 00419 Status: 00420 00421 --*/ 00422 VOID 00423 ClassUnload( 00424 IN PDRIVER_OBJECT DriverObject 00425 ) 00426 { 00427 PCLASS_DRIVER_EXTENSION driverExtension; 00428 NTSTATUS status; 00429 00430 PAGED_CODE(); 00431 00432 ASSERT( DriverObject->DeviceObject == NULL ); 00433 00434 driverExtension = IoGetDriverObjectExtension( DriverObject, 00435 CLASS_DRIVER_EXTENSION_KEY 00436 ); 00437 00438 ASSERT(driverExtension != NULL); 00439 ASSERT(driverExtension->RegistryPath.Buffer != NULL); 00440 ASSERT(driverExtension->InitData.ClassUnload != NULL); 00441 00442 DebugPrint((1, "ClassUnload: driver unloading %wZ\n", 00443 &driverExtension->RegistryPath)); 00444 00445 // 00446 // attempt to process the driver's unload routine first. 00447 // 00448 00449 driverExtension->InitData.ClassUnload(DriverObject); 00450 00451 // 00452 // free own allocated resources and return 00453 // 00454 00455 ExFreePool( driverExtension->RegistryPath.Buffer ); 00456 driverExtension->RegistryPath.Buffer = NULL; 00457 driverExtension->RegistryPath.Length = 0; 00458 driverExtension->RegistryPath.MaximumLength = 0; 00459 00460 return; 00461 } // end ClassUnload() 00462 00463 /*++//////////////////////////////////////////////////////////////////////////// 00464 00465 ClassAddDevice() 00466 00467 Routine Description: 00468 00469 SCSI class driver add device routine. This is called by pnp when a new 00470 physical device come into being. 00471 00472 This routine will call out to the class driver to verify that it should 00473 own this device then will create and attach a device object and then hand 00474 it to the driver to initialize and create symbolic links 00475 00476 Arguments: 00477 00478 DriverObject - a pointer to the driver object that this is being created for 00479 PhysicalDeviceObject - a pointer to the physical device object 00480 00481 Status: STATUS_NO_SUCH_DEVICE if the class driver did not want this device 00482 STATUS_SUCCESS if the creation and attachment was successful 00483 status of device creation and initialization 00484 00485 --*/ 00486 NTSTATUS 00487 ClassAddDevice( 00488 IN PDRIVER_OBJECT DriverObject, 00489 IN PDEVICE_OBJECT PhysicalDeviceObject 00490 ) 00491 { 00492 PCLASS_DRIVER_EXTENSION driverExtension = 00493 IoGetDriverObjectExtension(DriverObject, 00494 CLASS_DRIVER_EXTENSION_KEY); 00495 00496 NTSTATUS status; 00497 00498 PAGED_CODE(); 00499 00500 DbgPrint("got a device\n"); 00501 status = driverExtension->InitData.ClassAddDevice(DriverObject, 00502 PhysicalDeviceObject); 00503 return status; 00504 } // end ClassAddDevice() 00505 00506 /*++//////////////////////////////////////////////////////////////////////////// 00507 00508 ClassDispatchPnp() 00509 00510 Routine Description: 00511 00512 Storage class driver pnp routine. This is called by the io system when 00513 a PNP request is sent to the device. 00514 00515 Arguments: 00516 00517 DeviceObject - pointer to the device object 00518 00519 Irp - pointer to the io request packet 00520 00521 Return Value: 00522 00523 status 00524 00525 --*/ 00526 NTSTATUS 00527 ClassDispatchPnp( 00528 IN PDEVICE_OBJECT DeviceObject, 00529 IN PIRP Irp 00530 ) 00531 { 00532 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 00533 BOOLEAN isFdo = commonExtension->IsFdo; 00534 00535 PCLASS_DRIVER_EXTENSION driverExtension; 00536 PCLASS_INIT_DATA initData; 00537 PCLASS_DEV_INFO devInfo; 00538 00539 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 00540 PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); 00541 00542 NTSTATUS status = Irp->IoStatus.Status; 00543 BOOLEAN completeRequest = TRUE; 00544 BOOLEAN lockReleased = FALSE; 00545 00546 ULONG isRemoved; 00547 00548 PAGED_CODE(); 00549 00550 // 00551 // Extract all the useful information out of the driver object 00552 // extension 00553 // 00554 00555 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, 00556 CLASS_DRIVER_EXTENSION_KEY); 00557 if (driverExtension){ 00558 00559 initData = &(driverExtension->InitData); 00560 00561 if(isFdo) { 00562 devInfo = &(initData->FdoData); 00563 } else { 00564 devInfo = &(initData->PdoData); 00565 } 00566 00567 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 00568 00569 DebugPrint((2, "ClassDispatchPnp (%p,%p): minor code %#x for %s %p\n", 00570 DeviceObject, Irp, 00571 irpStack->MinorFunction, 00572 isFdo ? "fdo" : "pdo", 00573 DeviceObject)); 00574 DebugPrint((2, "ClassDispatchPnp (%p,%p): previous %#x, current %#x\n", 00575 DeviceObject, Irp, 00576 commonExtension->PreviousState, 00577 commonExtension->CurrentState)); 00578 00579 switch(irpStack->MinorFunction) { 00580 00581 case IRP_MN_START_DEVICE: { 00582 00583 // 00584 // if this is sent to the FDO we should forward it down the 00585 // attachment chain before we start the FDO. 00586 // 00587 00588 if (isFdo) { 00589 status = ClassForwardIrpSynchronous(commonExtension, Irp); 00590 } 00591 else { 00592 status = STATUS_SUCCESS; 00593 } 00594 00595 if (NT_SUCCESS(status)){ 00596 status = Irp->IoStatus.Status = ClassPnpStartDevice(DeviceObject); 00597 } 00598 00599 break; 00600 } 00601 00602 00603 case IRP_MN_QUERY_DEVICE_RELATIONS: { 00604 00605 DEVICE_RELATION_TYPE type = 00606 irpStack->Parameters.QueryDeviceRelations.Type; 00607 00608 PDEVICE_RELATIONS deviceRelations = NULL; 00609 00610 if(!isFdo) { 00611 00612 if(type == TargetDeviceRelation) { 00613 00614 // 00615 // Device relations has one entry built in to it's size. 00616 // 00617 00618 status = STATUS_INSUFFICIENT_RESOURCES; 00619 00620 deviceRelations = ExAllocatePoolWithTag(PagedPool, 00621 sizeof(DEVICE_RELATIONS), 00622 '2CcS'); 00623 00624 if(deviceRelations != NULL) { 00625 00626 RtlZeroMemory(deviceRelations, 00627 sizeof(DEVICE_RELATIONS)); 00628 00629 Irp->IoStatus.Information = (ULONG_PTR) deviceRelations; 00630 00631 deviceRelations->Count = 1; 00632 deviceRelations->Objects[0] = DeviceObject; 00633 ObReferenceObject(deviceRelations->Objects[0]); 00634 00635 status = STATUS_SUCCESS; 00636 } 00637 00638 } else { 00639 // 00640 // PDO's just complete enumeration requests without altering 00641 // the status. 00642 // 00643 00644 status = Irp->IoStatus.Status; 00645 } 00646 00647 break; 00648 00649 } else if (type == BusRelations) { 00650 00651 ASSERT(commonExtension->IsInitialized); 00652 00653 // 00654 // Make sure we support enumeration 00655 // 00656 00657 if(initData->ClassEnumerateDevice == NULL) { 00658 00659 // 00660 // Just send the request down to the lower driver. Perhaps 00661 // It can enumerate children. 00662 // 00663 00664 } else { 00665 00666 // 00667 // Re-enumerate the device 00668 // 00669 00670 status = ClassPnpQueryFdoRelations(DeviceObject, Irp); 00671 00672 if(!NT_SUCCESS(status)) { 00673 completeRequest = TRUE; 00674 break; 00675 } 00676 } 00677 } 00678 00679 IoCopyCurrentIrpStackLocationToNext(Irp); 00680 ClassReleaseRemoveLock(DeviceObject, Irp); 00681 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 00682 completeRequest = FALSE; 00683 00684 break; 00685 } 00686 00687 case IRP_MN_QUERY_ID: { 00688 00689 BUS_QUERY_ID_TYPE idType = irpStack->Parameters.QueryId.IdType; 00690 UNICODE_STRING unicodeString; 00691 00692 if(isFdo) { 00693 00694 // 00695 // FDO's should just forward the query down to the lower 00696 // device objects 00697 // 00698 00699 IoCopyCurrentIrpStackLocationToNext(Irp); 00700 ClassReleaseRemoveLock(DeviceObject, Irp); 00701 00702 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 00703 completeRequest = FALSE; 00704 break; 00705 } 00706 00707 // 00708 // PDO's need to give an answer - this is easy for now 00709 // 00710 00711 RtlInitUnicodeString(&unicodeString, NULL); 00712 00713 status = ClassGetPdoId(DeviceObject, 00714 idType, 00715 &unicodeString); 00716 00717 if(status == STATUS_NOT_IMPLEMENTED) { 00718 // 00719 // The driver doesn't implement this ID (whatever it is). 00720 // Use the status out of the IRP so that we don't mangle a 00721 // response from someone else. 00722 // 00723 00724 status = Irp->IoStatus.Status; 00725 } else if(NT_SUCCESS(status)) { 00726 Irp->IoStatus.Information = (ULONG_PTR) unicodeString.Buffer; 00727 } else { 00728 Irp->IoStatus.Information = (ULONG_PTR) NULL; 00729 } 00730 00731 break; 00732 } 00733 00734 case IRP_MN_QUERY_STOP_DEVICE: 00735 case IRP_MN_QUERY_REMOVE_DEVICE: { 00736 00737 DebugPrint((2, "ClassDispatchPnp (%p,%p): Processing QUERY_%s irp\n", 00738 DeviceObject, Irp, 00739 ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ? 00740 "STOP" : "REMOVE"))); 00741 00742 // 00743 // If this device is in use for some reason (paging, etc...) 00744 // then we need to fail the request. 00745 // 00746 00747 if(commonExtension->PagingPathCount != 0) { 00748 00749 DebugPrint((1, "ClassDispatchPnp (%p,%p): device is in paging " 00750 "path and cannot be removed\n", 00751 DeviceObject, Irp)); 00752 status = STATUS_DEVICE_BUSY; 00753 break; 00754 } 00755 00756 // 00757 // Check with the class driver to see if the query operation 00758 // can succeed. 00759 // 00760 00761 if(irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) { 00762 status = devInfo->ClassStopDevice(DeviceObject, 00763 irpStack->MinorFunction); 00764 } else { 00765 status = devInfo->ClassRemoveDevice(DeviceObject, 00766 irpStack->MinorFunction); 00767 } 00768 00769 if(NT_SUCCESS(status)) { 00770 00771 // 00772 // ASSERT that we never get two queries in a row, as 00773 // this will severly mess up the state machine 00774 // 00775 ASSERT(commonExtension->CurrentState != irpStack->MinorFunction); 00776 commonExtension->PreviousState = commonExtension->CurrentState; 00777 commonExtension->CurrentState = irpStack->MinorFunction; 00778 00779 if(isFdo) { 00780 DebugPrint((2, "ClassDispatchPnp (%p,%p): Forwarding QUERY_" 00781 "%s irp\n", DeviceObject, Irp, 00782 ((irpStack->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ? 00783 "STOP" : "REMOVE"))); 00784 status = ClassForwardIrpSynchronous(commonExtension, Irp); 00785 } 00786 } 00787 DebugPrint((2, "ClassDispatchPnp (%p,%p): Final status == %x\n", 00788 DeviceObject, Irp, status)); 00789 00790 break; 00791 } 00792 00793 case IRP_MN_CANCEL_STOP_DEVICE: 00794 case IRP_MN_CANCEL_REMOVE_DEVICE: { 00795 00796 // 00797 // Check with the class driver to see if the query or cancel 00798 // operation can succeed. 00799 // 00800 00801 if(irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) { 00802 status = devInfo->ClassStopDevice(DeviceObject, 00803 irpStack->MinorFunction); 00804 ASSERTMSG("ClassDispatchPnp !! CANCEL_STOP_DEVICE should " 00805 "never be failed\n", NT_SUCCESS(status)); 00806 } else { 00807 status = devInfo->ClassRemoveDevice(DeviceObject, 00808 irpStack->MinorFunction); 00809 ASSERTMSG("ClassDispatchPnp !! CANCEL_REMOVE_DEVICE should " 00810 "never be failed\n", NT_SUCCESS(status)); 00811 } 00812 00813 Irp->IoStatus.Status = status; 00814 00815 // 00816 // We got a CANCEL - roll back to the previous state only 00817 // if the current state is the respective QUERY state. 00818 // 00819 00820 if(((irpStack->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) && 00821 (commonExtension->CurrentState == IRP_MN_QUERY_STOP_DEVICE) 00822 ) || 00823 ((irpStack->MinorFunction == IRP_MN_CANCEL_REMOVE_DEVICE) && 00824 (commonExtension->CurrentState == IRP_MN_QUERY_REMOVE_DEVICE) 00825 ) 00826 ) { 00827 00828 commonExtension->CurrentState = 00829 commonExtension->PreviousState; 00830 commonExtension->PreviousState = 0xff; 00831 00832 } 00833 00834 if(isFdo) { 00835 IoCopyCurrentIrpStackLocationToNext(Irp); 00836 ClassReleaseRemoveLock(DeviceObject, Irp); 00837 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 00838 completeRequest = FALSE; 00839 } else { 00840 status = STATUS_SUCCESS; 00841 } 00842 00843 break; 00844 } 00845 00846 case IRP_MN_STOP_DEVICE: { 00847 00848 // 00849 // These all mean nothing to the class driver currently. The 00850 // port driver will handle all queueing when necessary. 00851 // 00852 00853 DebugPrint((2, "ClassDispatchPnp (%p,%p): got stop request for %s\n", 00854 DeviceObject, Irp, 00855 (isFdo ? "fdo" : "pdo") 00856 )); 00857 00858 ASSERT(commonExtension->PagingPathCount == 0); 00859 00860 // 00861 // ISSUE-2000/02/03-peterwie 00862 // if we stop the timer here then it means no class driver can 00863 // do i/o in its ClassStopDevice routine. This is because the 00864 // retry (among other things) is tied into the tick handler 00865 // and disabling retries could cause the class driver to deadlock. 00866 // Currently no class driver we're aware of issues i/o in its 00867 // Stop routine but this is a case we may want to defend ourself 00868 // against. 00869 // 00870 00871 if (DeviceObject->Timer) { 00872 IoStopTimer(DeviceObject); 00873 } 00874 00875 status = devInfo->ClassStopDevice(DeviceObject, IRP_MN_STOP_DEVICE); 00876 00877 ASSERTMSG("ClassDispatchPnp !! STOP_DEVICE should " 00878 "never be failed\n", NT_SUCCESS(status)); 00879 00880 if(isFdo) { 00881 status = ClassForwardIrpSynchronous(commonExtension, Irp); 00882 } 00883 00884 if(NT_SUCCESS(status)) { 00885 commonExtension->CurrentState = irpStack->MinorFunction; 00886 commonExtension->PreviousState = 0xff; 00887 } 00888 00889 break; 00890 } 00891 00892 case IRP_MN_REMOVE_DEVICE: 00893 case IRP_MN_SURPRISE_REMOVAL: { 00894 00895 PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject; 00896 UCHAR removeType = irpStack->MinorFunction; 00897 00898 if (commonExtension->PagingPathCount != 0) { 00899 DBGTRACE(ClassDebugWarning, ("ClassDispatchPnp (%p,%p): paging device is getting removed!", DeviceObject, Irp)); 00900 } 00901 00902 // 00903 // Release the lock for this IRP before calling in. 00904 // 00905 ClassReleaseRemoveLock(DeviceObject, Irp); 00906 lockReleased = TRUE; 00907 00908 /* 00909 * If a timer was started on the device, stop it. 00910 */ 00911 if (DeviceObject->Timer) { 00912 IoStopTimer(DeviceObject); 00913 } 00914 00915 /* 00916 * "Fire-and-forget" the remove irp to the lower stack. 00917 * Don't touch the irp (or the irp stack!) after this. 00918 */ 00919 if (isFdo) { 00920 IoCopyCurrentIrpStackLocationToNext(Irp); 00921 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 00922 ASSERT(NT_SUCCESS(status)); 00923 completeRequest = FALSE; 00924 } 00925 else { 00926 status = STATUS_SUCCESS; 00927 } 00928 00929 /* 00930 * Do our own cleanup and call the class driver's remove 00931 * cleanup routine. 00932 * For IRP_MN_REMOVE_DEVICE, this also deletes our device object, 00933 * so don't touch the extension after this. 00934 */ 00935 commonExtension->PreviousState = commonExtension->CurrentState; 00936 commonExtension->CurrentState = removeType; 00937 ClassRemoveDevice(DeviceObject, removeType); 00938 00939 break; 00940 } 00941 00942 case IRP_MN_DEVICE_USAGE_NOTIFICATION: { 00943 00944 switch(irpStack->Parameters.UsageNotification.Type) { 00945 00946 case DeviceUsageTypePaging: { 00947 00948 BOOLEAN setPagable; 00949 00950 if((irpStack->Parameters.UsageNotification.InPath) && 00951 (commonExtension->CurrentState != IRP_MN_START_DEVICE)) { 00952 00953 // 00954 // Device isn't started. Don't allow adding a 00955 // paging file, but allow a removal of one. 00956 // 00957 00958 status = STATUS_DEVICE_NOT_READY; 00959 break; 00960 } 00961 00962 ASSERT(commonExtension->IsInitialized); 00963 00964 // 00965 // need to synchronize this now... 00966 // 00967 00968 KeEnterCriticalRegion(); 00969 status = KeWaitForSingleObject(&commonExtension->PathCountEvent, 00970 Executive, KernelMode, 00971 FALSE, NULL); 00972 ASSERT(NT_SUCCESS(status)); 00973 status = STATUS_SUCCESS; 00974 00975 // 00976 // If the volume is removable we should try to lock it in 00977 // place or unlock it once per paging path count 00978 // 00979 00980 if (commonExtension->IsFdo){ 00981 status = ClasspEjectionControl( 00982 DeviceObject, 00983 Irp, 00984 InternalMediaLock, 00985 (BOOLEAN)irpStack->Parameters.UsageNotification.InPath); 00986 } 00987 00988 if (!NT_SUCCESS(status)){ 00989 KeSetEvent(&commonExtension->PathCountEvent, IO_NO_INCREMENT, FALSE); 00990 KeLeaveCriticalRegion(); 00991 break; 00992 } 00993 00994 // 00995 // if removing last paging device, need to set DO_POWER_PAGABLE 00996 // bit here, and possible re-set it below on failure. 00997 // 00998 00999 setPagable = FALSE; 01000 01001 if (!irpStack->Parameters.UsageNotification.InPath && 01002 commonExtension->PagingPathCount == 1 01003 ) { 01004 01005 // 01006 // removing last paging file 01007 // must have DO_POWER_PAGABLE bits set, but only 01008 // if noone set the DO_POWER_INRUSH bit 01009 // 01010 01011 01012 if (TEST_FLAG(DeviceObject->Flags, DO_POWER_INRUSH)) { 01013 DebugPrint((2, "ClassDispatchPnp (%p,%p): Last " 01014 "paging file removed, but " 01015 "DO_POWER_INRUSH was set, so NOT " 01016 "setting DO_POWER_PAGABLE\n", 01017 DeviceObject, Irp)); 01018 } else { 01019 DebugPrint((2, "ClassDispatchPnp (%p,%p): Last " 01020 "paging file removed, " 01021 "setting DO_POWER_PAGABLE\n", 01022 DeviceObject, Irp)); 01023 SET_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 01024 setPagable = TRUE; 01025 } 01026 01027 } 01028 01029 // 01030 // forward the irp before finishing handling the 01031 // special cases 01032 // 01033 01034 status = ClassForwardIrpSynchronous(commonExtension, Irp); 01035 01036 // 01037 // now deal with the failure and success cases. 01038 // note that we are not allowed to fail the irp 01039 // once it is sent to the lower drivers. 01040 // 01041 01042 if (NT_SUCCESS(status)) { 01043 01044 IoAdjustPagingPathCount( 01045 &commonExtension->PagingPathCount, 01046 irpStack->Parameters.UsageNotification.InPath); 01047 01048 if (irpStack->Parameters.UsageNotification.InPath) { 01049 if (commonExtension->PagingPathCount == 1) { 01050 DebugPrint((2, "ClassDispatchPnp (%p,%p): " 01051 "Clearing PAGABLE bit\n", 01052 DeviceObject, Irp)); 01053 CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 01054 } 01055 } 01056 01057 } else { 01058 01059 // 01060 // cleanup the changes done above 01061 // 01062 01063 if (setPagable == TRUE) { 01064 DebugPrint((2, "ClassDispatchPnp (%p,%p): Unsetting " 01065 "PAGABLE bit due to irp failure\n", 01066 DeviceObject, Irp)); 01067 CLEAR_FLAG(DeviceObject->Flags, DO_POWER_PAGABLE); 01068 setPagable = FALSE; 01069 } 01070 01071 // 01072 // relock or unlock the media if needed. 01073 // 01074 01075 if (commonExtension->IsFdo) { 01076 01077 ClasspEjectionControl( 01078 DeviceObject, 01079 Irp, 01080 InternalMediaLock, 01081 (BOOLEAN)!irpStack->Parameters.UsageNotification.InPath); 01082 } 01083 } 01084 01085 // 01086 // set the event so the next one can occur. 01087 // 01088 01089 KeSetEvent(&commonExtension->PathCountEvent, 01090 IO_NO_INCREMENT, FALSE); 01091 KeLeaveCriticalRegion(); 01092 break; 01093 } 01094 01095 case DeviceUsageTypeHibernation: { 01096 01097 IoAdjustPagingPathCount( 01098 &commonExtension->HibernationPathCount, 01099 irpStack->Parameters.UsageNotification.InPath 01100 ); 01101 status = ClassForwardIrpSynchronous(commonExtension, Irp); 01102 if (!NT_SUCCESS(status)) { 01103 IoAdjustPagingPathCount( 01104 &commonExtension->HibernationPathCount, 01105 !irpStack->Parameters.UsageNotification.InPath 01106 ); 01107 } 01108 01109 break; 01110 } 01111 01112 case DeviceUsageTypeDumpFile: { 01113 IoAdjustPagingPathCount( 01114 &commonExtension->DumpPathCount, 01115 irpStack->Parameters.UsageNotification.InPath 01116 ); 01117 status = ClassForwardIrpSynchronous(commonExtension, Irp); 01118 if (!NT_SUCCESS(status)) { 01119 IoAdjustPagingPathCount( 01120 &commonExtension->DumpPathCount, 01121 !irpStack->Parameters.UsageNotification.InPath 01122 ); 01123 } 01124 01125 break; 01126 } 01127 01128 default: { 01129 status = STATUS_INVALID_PARAMETER; 01130 break; 01131 } 01132 } 01133 break; 01134 } 01135 01136 case IRP_MN_QUERY_CAPABILITIES: { 01137 01138 DebugPrint((2, "ClassDispatchPnp (%p,%p): QueryCapabilities\n", 01139 DeviceObject, Irp)); 01140 01141 if(!isFdo) { 01142 01143 status = ClassQueryPnpCapabilities( 01144 DeviceObject, 01145 irpStack->Parameters.DeviceCapabilities.Capabilities 01146 ); 01147 01148 break; 01149 01150 } else { 01151 01152 PDEVICE_CAPABILITIES deviceCapabilities; 01153 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 01154 PCLASS_PRIVATE_FDO_DATA fdoData; 01155 01156 fdoExtension = DeviceObject->DeviceExtension; 01157 fdoData = fdoExtension->PrivateFdoData; 01158 deviceCapabilities = 01159 irpStack->Parameters.DeviceCapabilities.Capabilities; 01160 01161 // 01162 // forward the irp before handling the special cases 01163 // 01164 01165 status = ClassForwardIrpSynchronous(commonExtension, Irp); 01166 if (!NT_SUCCESS(status)) { 01167 break; 01168 } 01169 01170 // 01171 // we generally want to remove the device from the hotplug 01172 // applet, which requires the SR-OK bit to be set. 01173 // only when the user specifies that they are capable of 01174 // safely removing things do we want to clear this bit 01175 // (saved in WriteCacheEnableOverride) 01176 // 01177 // setting of this bit is done either above, or by the 01178 // lower driver. 01179 // 01180 // note: may not be started, so check we have FDO data first. 01181 // 01182 01183 if (fdoData && 01184 fdoData->HotplugInfo.WriteCacheEnableOverride) { 01185 if (deviceCapabilities->SurpriseRemovalOK) { 01186 DebugPrint((1, "Classpnp: Clearing SR-OK bit in " 01187 "device capabilities due to hotplug " 01188 "device or media\n")); 01189 } 01190 deviceCapabilities->SurpriseRemovalOK = FALSE; 01191 } 01192 break; 01193 01194 } // end QUERY_CAPABILITIES for FDOs 01195 01196 ASSERT(FALSE); 01197 break; 01198 01199 01200 } // end QUERY_CAPABILITIES 01201 01202 default: { 01203 01204 if (isFdo){ 01205 IoCopyCurrentIrpStackLocationToNext(Irp); 01206 01207 ClassReleaseRemoveLock(DeviceObject, Irp); 01208 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 01209 01210 completeRequest = FALSE; 01211 } 01212 01213 break; 01214 } 01215 } 01216 } 01217 else { 01218 ASSERT(driverExtension); 01219 status = STATUS_INTERNAL_ERROR; 01220 } 01221 01222 if (completeRequest){ 01223 Irp->IoStatus.Status = status; 01224 01225 if (!lockReleased){ 01226 ClassReleaseRemoveLock(DeviceObject, Irp); 01227 } 01228 01229 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 01230 01231 DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving with previous %#x, current %#x.", DeviceObject, Irp, commonExtension->PreviousState, commonExtension->CurrentState)); 01232 } 01233 else { 01234 /* 01235 * The irp is already completed so don't touch it. 01236 * This may be a remove so don't touch the device extension. 01237 */ 01238 DBGTRACE(ClassDebugTrace, ("ClassDispatchPnp (%p,%p): leaving.", DeviceObject, Irp)); 01239 } 01240 01241 return status; 01242 } // end ClassDispatchPnp() 01243 01244 /*++//////////////////////////////////////////////////////////////////////////// 01245 01246 ClassPnpStartDevice() 01247 01248 Routine Description: 01249 01250 Storage class driver routine for IRP_MN_START_DEVICE requests. 01251 This routine kicks off any device specific initialization 01252 01253 Arguments: 01254 01255 DeviceObject - a pointer to the device object 01256 01257 Irp - a pointer to the io request packet 01258 01259 Return Value: 01260 01261 none 01262 01263 --*/ 01264 NTSTATUS ClassPnpStartDevice(IN PDEVICE_OBJECT DeviceObject) 01265 { 01266 PCLASS_DRIVER_EXTENSION driverExtension; 01267 PCLASS_INIT_DATA initData; 01268 01269 PCLASS_DEV_INFO devInfo; 01270 01271 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 01272 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 01273 BOOLEAN isFdo = commonExtension->IsFdo; 01274 01275 BOOLEAN isMountedDevice = TRUE; 01276 UNICODE_STRING interfaceName; 01277 01278 BOOLEAN timerStarted; 01279 01280 NTSTATUS status = STATUS_SUCCESS; 01281 01282 PAGED_CODE(); 01283 01284 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, 01285 CLASS_DRIVER_EXTENSION_KEY); 01286 01287 initData = &(driverExtension->InitData); 01288 if(isFdo) { 01289 devInfo = &(initData->FdoData); 01290 } else { 01291 devInfo = &(initData->PdoData); 01292 } 01293 01294 ASSERT(devInfo->ClassInitDevice != NULL); 01295 ASSERT(devInfo->ClassStartDevice != NULL); 01296 01297 if (!commonExtension->IsInitialized){ 01298 01299 // 01300 // perform FDO/PDO specific initialization 01301 // 01302 01303 if (isFdo){ 01304 STORAGE_PROPERTY_ID propertyId; 01305 01306 // 01307 // allocate a private extension for class data 01308 // 01309 01310 if (fdoExtension->PrivateFdoData == NULL) { 01311 fdoExtension->PrivateFdoData = 01312 ExAllocatePoolWithTag(NonPagedPool, 01313 sizeof(CLASS_PRIVATE_FDO_DATA), 01314 CLASS_TAG_PRIVATE_DATA 01315 ); 01316 } 01317 01318 if (fdoExtension->PrivateFdoData == NULL) { 01319 DebugPrint((0, "ClassPnpStartDevice: Cannot allocate for " 01320 "private fdo data\n")); 01321 return STATUS_INSUFFICIENT_RESOURCES; 01322 } 01323 01324 // 01325 // initialize the struct's various fields. 01326 // 01327 01328 RtlZeroMemory(fdoExtension->PrivateFdoData, 01329 sizeof(CLASS_PRIVATE_FDO_DATA) 01330 ); 01331 KeInitializeTimer(&fdoExtension->PrivateFdoData->Retry.Timer); 01332 KeInitializeDpc(&fdoExtension->PrivateFdoData->Retry.Dpc, 01333 ClasspRetryRequestDpc, 01334 DeviceObject); 01335 KeInitializeSpinLock(&fdoExtension->PrivateFdoData->Retry.Lock); 01336 fdoExtension->PrivateFdoData->Retry.Granularity = 01337 KeQueryTimeIncrement(); 01338 commonExtension->Reserved4 = (ULONG_PTR)(' GPH'); // debug aid 01339 01340 // 01341 // NOTE: the old interface allowed the class driver to allocate 01342 // this. this was unsafe for low-memory conditions. allocate one 01343 // unconditionally now, and modify our internal functions to use 01344 // our own exclusively as it is the only safe way to do this. 01345 // 01346 01347 status = ClasspAllocateReleaseQueueIrp(fdoExtension); 01348 if (!NT_SUCCESS(status)) { 01349 DebugPrint((0, "ClassPnpStartDevice: Cannot allocate the " 01350 "private release queue irp\n")); 01351 return status; 01352 } 01353 01354 // 01355 // Call port driver to get adapter capabilities. 01356 // 01357 01358 propertyId = StorageAdapterProperty; 01359 01360 status = ClassGetDescriptor( 01361 commonExtension->LowerDeviceObject, 01362 &propertyId, 01363 &fdoExtension->AdapterDescriptor); 01364 01365 if(!NT_SUCCESS(status)) { 01366 01367 // 01368 // This DebugPrint is to help third-party driver writers 01369 // 01370 01371 DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor " 01372 "[ADAPTER] failed %lx\n", status)); 01373 return status; 01374 } 01375 01376 // 01377 // Call port driver to get device descriptor. 01378 // 01379 01380 propertyId = StorageDeviceProperty; 01381 01382 status = ClassGetDescriptor( 01383 commonExtension->LowerDeviceObject, 01384 &propertyId, 01385 &fdoExtension->DeviceDescriptor); 01386 01387 if(!NT_SUCCESS(status)) { 01388 01389 // 01390 // This DebugPrint is to help third-party driver writers 01391 // 01392 01393 DebugPrint((0, "ClassPnpStartDevice: ClassGetDescriptor " 01394 "[DEVICE] failed %lx\n", status)); 01395 return status; 01396 } 01397 01398 ClasspScanForSpecialInRegistry(fdoExtension); 01399 ClassScanForSpecial(fdoExtension, 01400 ClassBadItems, 01401 ClasspScanForClassHacks); 01402 01403 // 01404 // allow perf to be re-enabled after a given number of failed IOs 01405 // require this number to be at least CLASS_PERF_RESTORE_MINIMUM 01406 // 01407 01408 { 01409 ULONG t = 0; 01410 ClassGetDeviceParameter(fdoExtension, 01411 CLASSP_REG_SUBKEY_NAME, 01412 CLASSP_REG_PERF_RESTORE_VALUE_NAME, 01413 &t); 01414 if (t >= CLASS_PERF_RESTORE_MINIMUM) { 01415 fdoExtension->PrivateFdoData->Perf.ReEnableThreshhold = t; 01416 } 01417 } 01418 01419 01420 // 01421 // compatibility comes first. writable cd media will not 01422 // get a SYNCH_CACHE on power down. 01423 // 01424 01425 if (fdoExtension->DeviceObject->DeviceType != FILE_DEVICE_DISK) { 01426 SET_FLAG(fdoExtension->PrivateFdoData->HackFlags, 01427 FDO_HACK_NO_SYNC_CACHE); 01428 } 01429 01430 // 01431 // initialize the hotplug information only after the ScanForSpecial 01432 // routines, as it relies upon the hack flags. 01433 // 01434 01435 status = ClasspInitializeHotplugInfo(fdoExtension); 01436 01437 if (!NT_SUCCESS(status)) { 01438 DebugPrint((1, "ClassPnpStartDevice: Could not initialize " 01439 "hotplug information %lx\n", status)); 01440 return status; 01441 } 01442 01443 /* 01444 * Allocate/initialize TRANSFER_PACKETs and related resources. 01445 */ 01446 status = InitializeTransferPackets(DeviceObject); 01447 } 01448 01449 // 01450 // ISSUE - drivers need to disable write caching on the media 01451 // if hotplug and !useroverride. perhaps we should 01452 // allow registration of a callback to enable/disable 01453 // write cache instead. 01454 // 01455 01456 if (NT_SUCCESS(status)){ 01457 status = devInfo->ClassInitDevice(DeviceObject); 01458 } 01459 01460 } 01461 01462 if (!NT_SUCCESS(status)){ 01463 01464 // 01465 // Just bail out - the remove that comes down will clean up the 01466 // initialized scraps. 01467 // 01468 01469 return status; 01470 } else { 01471 commonExtension->IsInitialized = TRUE; 01472 01473 if (commonExtension->IsFdo) { 01474 fdoExtension->PrivateFdoData->Perf.OriginalSrbFlags = fdoExtension->SrbFlags; 01475 } 01476 01477 } 01478 01479 // 01480 // If device requests autorun functionality or a once a second callback 01481 // then enable the once per second timer. 01482 // 01483 // NOTE: This assumes that ClassInitializeMediaChangeDetection is always 01484 // called in the context of the ClassInitDevice callback. If called 01485 // after then this check will have already been made and the 01486 // once a second timer will not have been enabled. 01487 // 01488 if ((isFdo) && 01489 ((initData->ClassTick != NULL) || 01490 (fdoExtension->MediaChangeDetectionInfo != NULL) || 01491 ((fdoExtension->FailurePredictionInfo != NULL) && 01492 (fdoExtension->FailurePredictionInfo->Method != FailurePredictionNone)))) 01493 { 01494 ClasspEnableTimer(DeviceObject); 01495 timerStarted = TRUE; 01496 } else { 01497 timerStarted = FALSE; 01498 } 01499 01500 // 01501 // NOTE: the timer looks at commonExtension->CurrentState now 01502 // to prevent Media Change Notification code from running 01503 // until the device is started, but allows the device 01504 // specific tick handler to run. therefore it is imperative 01505 // that commonExtension->CurrentState not be updated until 01506 // the device specific startdevice handler has finished. 01507 // 01508 01509 status = devInfo->ClassStartDevice(DeviceObject); 01510 01511 if(NT_SUCCESS(status)) { 01512 commonExtension->CurrentState = IRP_MN_START_DEVICE; 01513 01514 if((isFdo) && (initData->ClassEnumerateDevice != NULL)) { 01515 isMountedDevice = FALSE; 01516 } 01517 01518 if((DeviceObject->DeviceType != FILE_DEVICE_DISK) && 01519 (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)) { 01520 01521 isMountedDevice = FALSE; 01522 } 01523 01524 01525 if(isMountedDevice) { 01526 ClasspRegisterMountedDeviceInterface(DeviceObject); 01527 } 01528 01529 if((commonExtension->IsFdo) && 01530 (devInfo->ClassWmiInfo.GuidRegInfo != NULL)) { 01531 01532 IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_REGISTER); 01533 } 01534 } else { 01535 01536 if (timerStarted) { 01537 ClasspDisableTimer(DeviceObject); 01538 } 01539 } 01540 01541 return status; 01542 } 01543 01544 01545 /*++//////////////////////////////////////////////////////////////////////////// 01546 01547 ClassReadWrite() 01548 01549 Routine Description: 01550 01551 This is the system entry point for read and write requests. The 01552 device-specific handler is invoked to perform any validation necessary. 01553 01554 If the device object is a PDO (partition object) then the request will 01555 simply be adjusted for Partition0 and issued to the lower device driver. 01556 01557 IF the device object is an FDO (paritition 0 object), the number of bytes 01558 in the request are checked against the maximum byte counts that the adapter 01559 supports and requests are broken up into 01560 smaller sizes if necessary. 01561 01562 Arguments: 01563 01564 DeviceObject - a pointer to the device object for this request 01565 01566 Irp - IO request 01567 01568 Return Value: 01569 01570 NT Status 01571 01572 --*/ 01573 NTSTATUS ClassReadWrite(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) 01574 { 01575 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 01576 PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject; 01577 PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); 01578 LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset; 01579 ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; 01580 ULONG isRemoved; 01581 NTSTATUS status; 01582 01583 /* 01584 * Grab the remove lock. If we can't acquire it, bail out. 01585 */ 01586 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 01587 if (isRemoved) { 01588 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 01589 ClassReleaseRemoveLock(DeviceObject, Irp); 01590 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 01591 status = STATUS_DEVICE_DOES_NOT_EXIST; 01592 } 01593 else if (TEST_FLAG(DeviceObject->Flags, DO_VERIFY_VOLUME) && 01594 (currentIrpStack->MinorFunction != CLASSP_VOLUME_VERIFY_CHECKED) && 01595 !TEST_FLAG(currentIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME)){ 01596 01597 /* 01598 * DO_VERIFY_VOLUME is set for the device object, 01599 * but this request is not itself a verify request. 01600 * So fail this request. 01601 */ 01602 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 01603 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED; 01604 Irp->IoStatus.Information = 0; 01605 ClassReleaseRemoveLock(DeviceObject, Irp); 01606 ClassCompleteRequest(DeviceObject, Irp, 0); 01607 status = STATUS_VERIFY_REQUIRED; 01608 } 01609 else { 01610 01611 /* 01612 * Since we've bypassed the verify-required tests we don't need to repeat 01613 * them with this IRP - in particular we don't want to worry about 01614 * hitting them at the partition 0 level if the request has come through 01615 * a non-zero partition. 01616 */ 01617 currentIrpStack->MinorFunction = CLASSP_VOLUME_VERIFY_CHECKED; 01618 01619 /* 01620 * Call the miniport driver's pre-pass filter to check if we 01621 * should continue with this transfer. 01622 */ 01623 ASSERT(commonExtension->DevInfo->ClassReadWriteVerification); 01624 status = commonExtension->DevInfo->ClassReadWriteVerification(DeviceObject, Irp); 01625 if (!NT_SUCCESS(status)){ 01626 ASSERT(Irp->IoStatus.Status == status); 01627 ClassReleaseRemoveLock(DeviceObject, Irp); 01628 ClassCompleteRequest (DeviceObject, Irp, IO_NO_INCREMENT); 01629 } 01630 else if (status == STATUS_PENDING){ 01631 /* 01632 * ClassReadWriteVerification queued this request. 01633 * So don't touch the irp anymore. 01634 */ 01635 } 01636 else { 01637 01638 if (transferByteCount == 0) { 01639 /* 01640 * Several parts of the code turn 0 into 0xffffffff, 01641 * so don't process a zero-length request any further. 01642 */ 01643 Irp->IoStatus.Status = STATUS_SUCCESS; 01644 Irp->IoStatus.Information = 0; 01645 ClassReleaseRemoveLock(DeviceObject, Irp); 01646 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 01647 status = STATUS_SUCCESS; 01648 } 01649 else { 01650 /* 01651 * If the driver has its own StartIo routine, call it. 01652 */ 01653 if (commonExtension->DriverExtension->InitData.ClassStartIo) { 01654 IoMarkIrpPending(Irp); 01655 IoStartPacket(DeviceObject, Irp, NULL, NULL); 01656 status = STATUS_PENDING; 01657 } 01658 else { 01659 /* 01660 * The driver does not have its own StartIo routine. 01661 * So process this request ourselves. 01662 */ 01663 01664 /* 01665 * Add partition byte offset to make starting byte relative to 01666 * beginning of disk. 01667 */ 01668 currentIrpStack->Parameters.Read.ByteOffset.QuadPart += 01669 commonExtension->StartingOffset.QuadPart; 01670 01671 if (commonExtension->IsFdo){ 01672 01673 /* 01674 * Add in any skew for the disk manager software. 01675 */ 01676 currentIrpStack->Parameters.Read.ByteOffset.QuadPart += 01677 commonExtension->PartitionZeroExtension->DMByteSkew; 01678 01679 /* 01680 * Perform the actual transfer(s) on the hardware 01681 * to service this request. 01682 */ 01683 ServiceTransferRequest(DeviceObject, Irp); 01684 status = STATUS_PENDING; 01685 } 01686 else { 01687 /* 01688 * This is a child PDO enumerated for our FDO by e.g. disk.sys 01689 * and owned by e.g. partmgr. Send it down to the next device 01690 * and the same irp will come back to us for the FDO. 01691 */ 01692 IoCopyCurrentIrpStackLocationToNext(Irp); 01693 ClassReleaseRemoveLock(DeviceObject, Irp); 01694 status = IoCallDriver(lowerDeviceObject, Irp); 01695 } 01696 } 01697 } 01698 } 01699 } 01700 01701 return status; 01702 } 01703 01704 01705 /*++//////////////////////////////////////////////////////////////////////////// 01706 01707 ClassReadDriveCapacity() 01708 01709 Routine Description: 01710 01711 This routine sends a READ CAPACITY to the requested device, updates 01712 the geometry information in the device object and returns 01713 when it is complete. This routine is synchronous. 01714 01715 This routine must be called with the remove lock held or some other 01716 assurance that the Fdo will not be removed while processing. 01717 01718 Arguments: 01719 01720 DeviceObject - Supplies a pointer to the device object that represents 01721 the device whose capacity is to be read. 01722 01723 Return Value: 01724 01725 Status is returned. 01726 01727 --*/ 01728 NTSTATUS ClassReadDriveCapacity(IN PDEVICE_OBJECT Fdo) 01729 { 01730 READ_CAPACITY_DATA readCapacityBuffer = {0}; 01731 NTSTATUS status; 01732 PMDL driveCapMdl; 01733 01734 driveCapMdl = BuildDeviceInputMdl(&readCapacityBuffer, sizeof(READ_CAPACITY_DATA)); 01735 if (driveCapMdl){ 01736 01737 TRANSFER_PACKET *pkt = DequeueFreeTransferPacket(Fdo, TRUE); 01738 if (pkt){ 01739 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 01740 KEVENT event; 01741 NTSTATUS pktStatus; 01742 IRP pseudoIrp = {0}; 01743 01744 /* 01745 * Our engine needs an "original irp" to write the status back to 01746 * and to count down packets (one in this case). 01747 * Just use a pretend irp for this. 01748 */ 01749 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1); 01750 pseudoIrp.IoStatus.Status = STATUS_SUCCESS; 01751 pseudoIrp.IoStatus.Information = 0; 01752 pseudoIrp.MdlAddress = driveCapMdl; 01753 01754 /* 01755 * Set this up as a SYNCHRONOUS transfer, submit it, 01756 * and wait for the packet to complete. The result 01757 * status will be written to the original irp. 01758 */ 01759 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 01760 SetupDriveCapacityTransferPacket( pkt, 01761 &readCapacityBuffer, 01762 sizeof(READ_CAPACITY_DATA), 01763 &event, 01764 &pseudoIrp); 01765 SubmitTransferPacket(pkt); 01766 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 01767 01768 status = pseudoIrp.IoStatus.Status; 01769 01770 /* 01771 * If we got an UNDERRUN, retry exactly once. 01772 * (The transfer_packet engine didn't retry because the result 01773 * status was success). 01774 */ 01775 if (NT_SUCCESS(status) && 01776 (pseudoIrp.IoStatus.Information < sizeof(READ_CAPACITY_DATA))){ 01777 DBGERR(("ClassReadDriveCapacity: read len (%xh) < %xh, retrying ...", (ULONG)pseudoIrp.IoStatus.Information, sizeof(READ_CAPACITY_DATA))); 01778 01779 pkt = DequeueFreeTransferPacket(Fdo, TRUE); 01780 if (pkt){ 01781 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1); 01782 pseudoIrp.IoStatus.Status = STATUS_SUCCESS; 01783 pseudoIrp.IoStatus.Information = 0; 01784 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 01785 SetupDriveCapacityTransferPacket( pkt, 01786 &readCapacityBuffer, 01787 sizeof(READ_CAPACITY_DATA), 01788 &event, 01789 &pseudoIrp); 01790 SubmitTransferPacket(pkt); 01791 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 01792 status = pseudoIrp.IoStatus.Status; 01793 if (pseudoIrp.IoStatus.Information < sizeof(READ_CAPACITY_DATA)){ 01794 status = STATUS_DEVICE_BUSY; 01795 } 01796 } 01797 else { 01798 status = STATUS_INSUFFICIENT_RESOURCES; 01799 } 01800 } 01801 01802 01803 if (NT_SUCCESS(status)){ 01804 /* 01805 * The request succeeded. 01806 * Read out and store the drive information. 01807 */ 01808 ULONG cylinderSize; 01809 ULONG bytesPerSector; 01810 ULONG tmp; 01811 ULONG lastSector; 01812 01813 /* 01814 * Read the bytesPerSector value, 01815 * which is big-endian in the returned buffer. 01816 * Default to the standard 512 bytes. 01817 */ 01818 tmp = readCapacityBuffer.BytesPerBlock; 01819 ((PFOUR_BYTE)&bytesPerSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3; 01820 ((PFOUR_BYTE)&bytesPerSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2; 01821 ((PFOUR_BYTE)&bytesPerSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1; 01822 ((PFOUR_BYTE)&bytesPerSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0; 01823 if (bytesPerSector == 0) { 01824 bytesPerSector = 512; 01825 } 01826 else { 01827 /* 01828 * Clear all but the highest set bit. 01829 * That will give us a bytesPerSector value that is a power of 2. 01830 */ 01831 while (bytesPerSector & (bytesPerSector-1)) { 01832 bytesPerSector &= bytesPerSector-1; 01833 } 01834 } 01835 fdoExt->DiskGeometry.BytesPerSector = bytesPerSector; 01836 01837 // 01838 // Copy last sector in reverse byte order. 01839 // 01840 01841 tmp = readCapacityBuffer.LogicalBlockAddress; 01842 ((PFOUR_BYTE)&lastSector)->Byte0 = ((PFOUR_BYTE)&tmp)->Byte3; 01843 ((PFOUR_BYTE)&lastSector)->Byte1 = ((PFOUR_BYTE)&tmp)->Byte2; 01844 ((PFOUR_BYTE)&lastSector)->Byte2 = ((PFOUR_BYTE)&tmp)->Byte1; 01845 ((PFOUR_BYTE)&lastSector)->Byte3 = ((PFOUR_BYTE)&tmp)->Byte0; 01846 01847 // 01848 // Calculate sector to byte shift. 01849 // 01850 01851 WHICH_BIT(fdoExt->DiskGeometry.BytesPerSector, fdoExt->SectorShift); 01852 01853 DebugPrint((2,"SCSI ClassReadDriveCapacity: Sector size is %d\n", 01854 fdoExt->DiskGeometry.BytesPerSector)); 01855 01856 DebugPrint((2,"SCSI ClassReadDriveCapacity: Number of Sectors is %d\n", 01857 lastSector + 1)); 01858 01859 if (fdoExt->DMActive){ 01860 DebugPrint((1, "SCSI ClassReadDriveCapacity: reducing number of sectors by %d\n", 01861 fdoExt->DMSkew)); 01862 lastSector -= fdoExt->DMSkew; 01863 } 01864 01865 /* 01866 * Check to see if we have a geometry we should be using already. 01867 */ 01868 cylinderSize = (fdoExt->DiskGeometry.TracksPerCylinder * 01869 fdoExt->DiskGeometry.SectorsPerTrack); 01870 if (cylinderSize == 0){ 01871 DebugPrint((1, "ClassReadDriveCapacity: resetting H & S geometry " 01872 "values from %#x/%#x to %#x/%#x\n", 01873 fdoExt->DiskGeometry.TracksPerCylinder, 01874 fdoExt->DiskGeometry.SectorsPerTrack, 01875 0xff, 01876 0x3f)); 01877 01878 fdoExt->DiskGeometry.TracksPerCylinder = 0xff; 01879 fdoExt->DiskGeometry.SectorsPerTrack = 0x3f; 01880 01881 01882 cylinderSize = (fdoExt->DiskGeometry.TracksPerCylinder * 01883 fdoExt->DiskGeometry.SectorsPerTrack); 01884 } 01885 01886 // 01887 // Calculate number of cylinders. 01888 // 01889 01890 fdoExt->DiskGeometry.Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/cylinderSize); 01891 01892 // 01893 // if there are zero cylinders, then the device lied AND it's 01894 // smaller than 0xff*0x3f (about 16k sectors, usually 8 meg) 01895 // this can fit into a single LONGLONG, so create another usable 01896 // geometry, even if it's unusual looking. This allows small, 01897 // non-standard devices, such as Sony's Memory Stick, to show 01898 // up as having a partition. 01899 // 01900 01901 if (fdoExt->DiskGeometry.Cylinders.QuadPart == (LONGLONG)0) { 01902 fdoExt->DiskGeometry.SectorsPerTrack = 1; 01903 fdoExt->DiskGeometry.TracksPerCylinder = 1; 01904 fdoExt->DiskGeometry.Cylinders.QuadPart = lastSector; 01905 } 01906 01907 01908 // 01909 // Calculate media capacity in bytes. 01910 // 01911 01912 fdoExt->CommonExtension.PartitionLength.QuadPart = 01913 ((LONGLONG)(lastSector + 1)) << fdoExt->SectorShift; 01914 01915 /* 01916 * Is this removable or fixed media 01917 */ 01918 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){ 01919 fdoExt->DiskGeometry.MediaType = RemovableMedia; 01920 } 01921 else { 01922 fdoExt->DiskGeometry.MediaType = FixedMedia; 01923 } 01924 } 01925 else { 01926 /* 01927 * The request failed. 01928 */ 01929 01930 // 01931 // ISSUE - 2000/02/04 - henrygab - non-512-byte sector sizes and failed geometry update 01932 // what happens when the disk's sector size is bigger than 01933 // 512 bytes and we hit this code path? this is untested. 01934 // 01935 // If the read capacity fails, set the geometry to reasonable parameter 01936 // so things don't fail at unexpected places. Zero the geometry 01937 // except for the bytes per sector and sector shift. 01938 // 01939 01940 /* 01941 * This request can sometimes fail legitimately 01942 * (e.g. when a SCSI device is attached but turned off) 01943 * so this is not necessarily a device/driver bug. 01944 */ 01945 DBGTRACE(ClassDebugWarning, ("ClassReadDriveCapacity on Fdo %xh failed with status %xh.", Fdo, status)); 01946 01947 /* 01948 * Write in a default disk geometry which we HOPE is right (??). 01949 * BUGBUG !! 01950 */ 01951 RtlZeroMemory(&fdoExt->DiskGeometry, sizeof(DISK_GEOMETRY)); 01952 fdoExt->DiskGeometry.BytesPerSector = 512; 01953 fdoExt->SectorShift = 9; 01954 fdoExt->CommonExtension.PartitionLength.QuadPart = (LONGLONG) 0; 01955 01956 /* 01957 * Is this removable or fixed media 01958 */ 01959 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){ 01960 fdoExt->DiskGeometry.MediaType = RemovableMedia; 01961 } 01962 else { 01963 fdoExt->DiskGeometry.MediaType = FixedMedia; 01964 } 01965 } 01966 01967 } 01968 else { 01969 status = STATUS_INSUFFICIENT_RESOURCES; 01970 } 01971 01972 FreeDeviceInputMdl(driveCapMdl); 01973 } 01974 else { 01975 status = STATUS_INSUFFICIENT_RESOURCES; 01976 } 01977 01978 return status; 01979 } 01980 01981 01982 /*++//////////////////////////////////////////////////////////////////////////// 01983 01984 ClassSendStartUnit() 01985 01986 Routine Description: 01987 01988 Send command to SCSI unit to start or power up. 01989 Because this command is issued asynchronounsly, that is, without 01990 waiting on it to complete, the IMMEDIATE flag is not set. This 01991 means that the CDB will not return until the drive has powered up. 01992 This should keep subsequent requests from being submitted to the 01993 device before it has completely spun up. 01994 01995 This routine is called from the InterpretSense routine, when a 01996 request sense returns data indicating that a drive must be 01997 powered up. 01998 01999 This routine may also be called from a class driver's error handler, 02000 or anytime a non-critical start device should be sent to the device. 02001 02002 Arguments: 02003 02004 Fdo - The functional device object for the stopped device. 02005 02006 Return Value: 02007 02008 None. 02009 02010 --*/ 02011 VOID 02012 ClassSendStartUnit( 02013 IN PDEVICE_OBJECT Fdo 02014 ) 02015 { 02016 PIO_STACK_LOCATION irpStack; 02017 PIRP irp; 02018 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 02019 PSCSI_REQUEST_BLOCK srb; 02020 PCOMPLETION_CONTEXT context; 02021 PCDB cdb; 02022 02023 // 02024 // Allocate Srb from nonpaged pool. 02025 // 02026 02027 context = ExAllocatePoolWithTag(NonPagedPool, 02028 sizeof(COMPLETION_CONTEXT), 02029 '6CcS'); 02030 02031 if(context == NULL) { 02032 02033 // 02034 // ISSUE-2000/02/03-peterwie 02035 // This code path was inheritted from the NT 4.0 class2.sys driver. 02036 // It needs to be changed to survive low-memory conditions. 02037 // 02038 02039 KeBugCheck(SCSI_DISK_DRIVER_INTERNAL); 02040 } 02041 02042 // 02043 // Save the device object in the context for use by the completion 02044 // routine. 02045 // 02046 02047 context->DeviceObject = Fdo; 02048 srb = &context->Srb; 02049 02050 // 02051 // Zero out srb. 02052 // 02053 02054 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 02055 02056 // 02057 // Write length to SRB. 02058 // 02059 02060 srb->Length = sizeof(SCSI_REQUEST_BLOCK); 02061 02062 srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 02063 02064 // 02065 // Set timeout value large enough for drive to spin up. 02066 // 02067 02068 srb->TimeOutValue = START_UNIT_TIMEOUT; 02069 02070 // 02071 // Set the transfer length. 02072 // 02073 02074 srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER | 02075 SRB_FLAGS_DISABLE_AUTOSENSE | 02076 SRB_FLAGS_DISABLE_SYNCH_TRANSFER; 02077 02078 // 02079 // Build the start unit CDB. 02080 // 02081 02082 srb->CdbLength = 6; 02083 cdb = (PCDB)srb->Cdb; 02084 02085 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 02086 cdb->START_STOP.Start = 1; 02087 cdb->START_STOP.Immediate = 0; 02088 cdb->START_STOP.LogicalUnitNumber = srb->Lun; 02089 02090 // 02091 // Build the asynchronous request to be sent to the port driver. 02092 // Since this routine is called from a DPC the IRP should always be 02093 // available. 02094 // 02095 02096 irp = IoAllocateIrp(Fdo->StackSize, FALSE); 02097 02098 if(irp == NULL) { 02099 02100 // 02101 // ISSUE-2000/02/03-peterwie 02102 // This code path was inheritted from the NT 4.0 class2.sys driver. 02103 // It needs to be changed to survive low-memory conditions. 02104 // 02105 02106 KeBugCheck(SCSI_DISK_DRIVER_INTERNAL); 02107 02108 } 02109 02110 ClassAcquireRemoveLock(Fdo, irp); 02111 02112 IoSetCompletionRoutine(irp, 02113 (PIO_COMPLETION_ROUTINE)ClassAsynchronousCompletion, 02114 context, 02115 TRUE, 02116 TRUE, 02117 TRUE); 02118 02119 irpStack = IoGetNextIrpStackLocation(irp); 02120 irpStack->MajorFunction = IRP_MJ_SCSI; 02121 srb->OriginalRequest = irp; 02122 02123 // 02124 // Store the SRB address in next stack for port driver. 02125 // 02126 02127 irpStack->Parameters.Scsi.Srb = srb; 02128 02129 // 02130 // Call the port driver with the IRP. 02131 // 02132 02133 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp); 02134 02135 return; 02136 02137 } // end StartUnit() 02138 02139 /*++//////////////////////////////////////////////////////////////////////////// 02140 02141 ClassAsynchronousCompletion() ISSUE-2000/02/18-henrygab - why public?! 02142 02143 Routine Description: 02144 02145 This routine is called when an asynchronous I/O request 02146 which was issused by the class driver completes. Examples of such requests 02147 are release queue or START UNIT. This routine releases the queue if 02148 necessary. It then frees the context and the IRP. 02149 02150 Arguments: 02151 02152 DeviceObject - The device object for the logical unit; however since this 02153 is the top stack location the value is NULL. 02154 02155 Irp - Supplies a pointer to the Irp to be processed. 02156 02157 Context - Supplies the context to be used to process this request. 02158 02159 Return Value: 02160 02161 None. 02162 02163 --*/ 02164 NTSTATUS 02165 ClassAsynchronousCompletion( 02166 PDEVICE_OBJECT DeviceObject, 02167 PIRP Irp, 02168 PVOID Context 02169 ) 02170 { 02171 PCOMPLETION_CONTEXT context = Context; 02172 PSCSI_REQUEST_BLOCK srb; 02173 02174 if(DeviceObject == NULL) { 02175 02176 DeviceObject = context->DeviceObject; 02177 } 02178 02179 srb = &context->Srb; 02180 02181 // 02182 // If this is an execute srb, then check the return status and make sure. 02183 // the queue is not frozen. 02184 // 02185 02186 if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) { 02187 02188 // 02189 // Check for a frozen queue. 02190 // 02191 02192 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 02193 02194 // 02195 // Unfreeze the queue getting the device object from the context. 02196 // 02197 02198 ClassReleaseQueue(context->DeviceObject); 02199 } 02200 } 02201 02202 { // free port-allocated sense buffer if we can detect 02203 02204 if (((PCOMMON_DEVICE_EXTENSION)(DeviceObject->DeviceExtension))->IsFdo) { 02205 02206 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 02207 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { 02208 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb); 02209 } 02210 02211 } else { 02212 02213 ASSERT(!TEST_FLAG(srb->SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 02214 02215 } 02216 } 02217 02218 02219 // 02220 // Free the context and the Irp. 02221 // 02222 02223 if (Irp->MdlAddress != NULL) { 02224 MmUnlockPages(Irp->MdlAddress); 02225 IoFreeMdl(Irp->MdlAddress); 02226 02227 Irp->MdlAddress = NULL; 02228 } 02229 02230 ClassReleaseRemoveLock(DeviceObject, Irp); 02231 02232 ExFreePool(context); 02233 IoFreeIrp(Irp); 02234 02235 // 02236 // Indicate the I/O system should stop processing the Irp completion. 02237 // 02238 02239 return STATUS_MORE_PROCESSING_REQUIRED; 02240 02241 } // end ClassAsynchronousCompletion() 02242 02243 02244 02245 VOID ServiceTransferRequest(PDEVICE_OBJECT Fdo, PIRP Irp) 02246 { 02247 PCOMMON_DEVICE_EXTENSION commonExt = Fdo->DeviceExtension; 02248 PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Fdo->DeviceExtension; 02249 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData; 02250 PSTORAGE_ADAPTER_DESCRIPTOR adapterDesc = commonExt->PartitionZeroExtension->AdapterDescriptor; 02251 PIO_STACK_LOCATION currentSp = IoGetCurrentIrpStackLocation(Irp); 02252 ULONG entireXferLen = currentSp->Parameters.Read.Length; 02253 PUCHAR bufPtr = MmGetMdlVirtualAddress(Irp->MdlAddress); 02254 LARGE_INTEGER targetLocation = currentSp->Parameters.Read.ByteOffset; 02255 PTRANSFER_PACKET pkt; 02256 SINGLE_LIST_ENTRY pktList; 02257 PSINGLE_LIST_ENTRY slistEntry; 02258 ULONG numPackets; 02259 KIRQL oldIrql; 02260 ULONG i; 02261 02262 /* 02263 * Compute the number of hw xfers we'll have to do. 02264 * Calculate this without allowing for an overflow condition. 02265 */ 02266 ASSERT(fdoData->HwMaxXferLen >= PAGE_SIZE); 02267 numPackets = entireXferLen/fdoData->HwMaxXferLen; 02268 if (entireXferLen % fdoData->HwMaxXferLen){ 02269 numPackets++; 02270 } 02271 02272 /* 02273 * First get all the TRANSFER_PACKETs that we'll need at once. 02274 * Use our 'simple' slist functions since we don't need interlocked. 02275 */ 02276 SimpleInitSlistHdr(&pktList); 02277 for (i = 0; i < numPackets; i++){ 02278 pkt = DequeueFreeTransferPacket(Fdo, TRUE); 02279 if (pkt){ 02280 SimplePushSlist(&pktList, &pkt->SlistEntry); 02281 } 02282 else { 02283 break; 02284 } 02285 } 02286 02287 if (i == numPackets){ 02288 /* 02289 * Initialize the original IRP's status to success. 02290 * If any of the packets fail, they will set it to an error status. 02291 * The IoStatus.Information field will be incremented to the 02292 * transfer length as the pieces complete. 02293 */ 02294 Irp->IoStatus.Status = STATUS_SUCCESS; 02295 Irp->IoStatus.Information = 0; 02296 02297 /* 02298 * Store the number of transfer pieces inside the original IRP. 02299 * It will be used to count down the pieces as they complete. 02300 */ 02301 Irp->Tail.Overlay.DriverContext[0] = LongToPtr(numPackets); 02302 02303 /* 02304 * We are proceeding with the transfer. 02305 * Mark the client IRP pending since it may complete on a different thread. 02306 */ 02307 IoMarkIrpPending(Irp); 02308 02309 /* 02310 * Transmit the pieces of the transfer. 02311 */ 02312 while (entireXferLen > 0){ 02313 ULONG thisPieceLen = MIN(fdoData->HwMaxXferLen, entireXferLen); 02314 02315 /* 02316 * Set up a TRANSFER_PACKET for this piece and send it. 02317 */ 02318 slistEntry = SimplePopSlist(&pktList); 02319 ASSERT(slistEntry); 02320 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry); 02321 SetupReadWriteTransferPacket( pkt, 02322 bufPtr, 02323 thisPieceLen, 02324 targetLocation, 02325 Irp); 02326 SubmitTransferPacket(pkt); 02327 02328 entireXferLen -= thisPieceLen; 02329 bufPtr += thisPieceLen; 02330 targetLocation.QuadPart += thisPieceLen; 02331 } 02332 ASSERT(SimpleIsSlistEmpty(&pktList)); 02333 } 02334 else if (i >= 1){ 02335 /* 02336 * We were unable to get all the TRANSFER_PACKETs we need, 02337 * but we did get at least one. 02338 * That means that we are in extreme low-memory stress. 02339 * We'll try doing this transfer using a single packet. 02340 * The port driver is certainly also in stress, so use one-page 02341 * transfers. 02342 */ 02343 02344 /* 02345 * Free all but one of the TRANSFER_PACKETs. 02346 */ 02347 while (i-- > 1){ 02348 slistEntry = SimplePopSlist(&pktList); 02349 ASSERT(slistEntry); 02350 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry); 02351 EnqueueFreeTransferPacket(Fdo, pkt); 02352 } 02353 02354 /* 02355 * Get the single TRANSFER_PACKET that we'll be using. 02356 */ 02357 slistEntry = SimplePopSlist(&pktList); 02358 ASSERT(slistEntry); 02359 ASSERT(SimpleIsSlistEmpty(&pktList)); 02360 pkt = CONTAINING_RECORD(slistEntry, TRANSFER_PACKET, SlistEntry); 02361 DBGWARN(("Insufficient packets available in ServiceTransferRequest - entering lowMemRetry with pkt=%xh.", pkt)); 02362 02363 /* 02364 * Set default status and the number of transfer packets (one) 02365 * inside the original irp. 02366 */ 02367 Irp->IoStatus.Status = STATUS_SUCCESS; 02368 Irp->IoStatus.Information = 0; 02369 Irp->Tail.Overlay.DriverContext[0] = LongToPtr(1); 02370 02371 /* 02372 * Mark the client irp pending since it may complete on 02373 * another thread. 02374 */ 02375 IoMarkIrpPending(Irp); 02376 02377 /* 02378 * Set up the TRANSFER_PACKET for a lowMem transfer and launch. 02379 */ 02380 SetupReadWriteTransferPacket( pkt, 02381 bufPtr, 02382 entireXferLen, 02383 targetLocation, 02384 Irp); 02385 InitLowMemRetry(pkt, bufPtr, entireXferLen, targetLocation); 02386 StepLowMemRetry(pkt); 02387 } 02388 else { 02389 /* 02390 * We were unable to get ANY TRANSFER_PACKETs. 02391 * Defer this client irp until some TRANSFER_PACKETs free up. 02392 */ 02393 DBGWARN(("No packets available in ServiceTransferRequest - deferring transfer (Irp=%xh)...", Irp)); 02394 IoMarkIrpPending(Irp); 02395 EnqueueDeferredClientIrp(fdoData, Irp); 02396 } 02397 02398 } 02399 02400 02401 /*++//////////////////////////////////////////////////////////////////////////// 02402 02403 ClassIoComplete() 02404 02405 Routine Description: 02406 02407 This routine executes when the port driver has completed a request. 02408 It looks at the SRB status in the completing SRB and if not success 02409 it checks for valid request sense buffer information. If valid, the 02410 info is used to update status with more precise message of type of 02411 error. This routine deallocates the SRB. 02412 02413 This routine should only be placed on the stack location for a class 02414 driver FDO. 02415 02416 Arguments: 02417 02418 Fdo - Supplies the device object which represents the logical 02419 unit. 02420 02421 Irp - Supplies the Irp which has completed. 02422 02423 Context - Supplies a pointer to the SRB. 02424 02425 Return Value: 02426 02427 NT status 02428 02429 --*/ 02430 NTSTATUS 02431 ClassIoComplete( 02432 IN PDEVICE_OBJECT Fdo, 02433 IN PIRP Irp, 02434 IN PVOID Context 02435 ) 02436 { 02437 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 02438 PSCSI_REQUEST_BLOCK srb = Context; 02439 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 02440 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 02441 NTSTATUS status; 02442 BOOLEAN retry; 02443 BOOLEAN callStartNextPacket; 02444 02445 ASSERT(fdoExtension->CommonExtension.IsFdo); 02446 02447 // 02448 // Check SRB status for success of completing request. 02449 // 02450 02451 if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) { 02452 ULONG retryInterval; 02453 02454 DebugPrint((2, "ClassIoComplete: IRP %p, SRB %p\n", Irp, srb)); 02455 02456 // 02457 // Release the queue if it is frozen. 02458 // 02459 02460 if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) { 02461 ClassReleaseQueue(Fdo); 02462 } 02463 02464 retry = ClassInterpretSenseInfo( 02465 Fdo, 02466 srb, 02467 irpStack->MajorFunction, 02468 irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? 02469 irpStack->Parameters.DeviceIoControl.IoControlCode : 02470 0, 02471 MAXIMUM_RETRIES - 02472 ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4), 02473 &status, 02474 &retryInterval); 02475 02476 // 02477 // If the status is verified required and the this request 02478 // should bypass verify required then retry the request. 02479 // 02480 02481 if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) && 02482 status == STATUS_VERIFY_REQUIRED) { 02483 02484 status = STATUS_IO_DEVICE_ERROR; 02485 retry = TRUE; 02486 } 02487 02488 if (retry && ((*(PCHAR*)&irpStack->Parameters.Others.Argument4)--)) { 02489 02490 // 02491 // Retry request. 02492 // 02493 02494 DebugPrint((1, "Retry request %p\n", Irp)); 02495 02496 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { 02497 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb); 02498 } 02499 02500 RetryRequest(Fdo, Irp, srb, FALSE, retryInterval); 02501 return STATUS_MORE_PROCESSING_REQUIRED; 02502 } 02503 02504 } else { 02505 02506 // 02507 // Set status for successful request 02508 // 02509 fdoData->LoggedTURFailureSinceLastIO = FALSE; 02510 ClasspPerfIncrementSuccessfulIo(fdoExtension); 02511 status = STATUS_SUCCESS; 02512 } // end if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS) 02513 02514 02515 // 02516 // ensure we have returned some info, and it matches what the 02517 // original request wanted for PAGING operations only 02518 // 02519 02520 if ((NT_SUCCESS(status)) && TEST_FLAG(Irp->Flags, IRP_PAGING_IO)) { 02521 ASSERT(Irp->IoStatus.Information != 0); 02522 ASSERT(irpStack->Parameters.Read.Length == Irp->IoStatus.Information); 02523 } 02524 02525 // 02526 // remember if the caller wanted to skip calling IoStartNextPacket. 02527 // for legacy reasons, we cannot call IoStartNextPacket for IoDeviceControl 02528 // calls. this setting only affects device objects with StartIo routines. 02529 // 02530 02531 callStartNextPacket = !TEST_FLAG(srb->SrbFlags, SRB_FLAGS_DONT_START_NEXT_PACKET); 02532 if (irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL) { 02533 callStartNextPacket = FALSE; 02534 } 02535 02536 // 02537 // Free the srb 02538 // 02539 02540 if(!TEST_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_PERSISTANT)) { 02541 02542 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { 02543 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, srb); 02544 } 02545 02546 if (fdoExtension->CommonExtension.IsSrbLookasideListInitialized){ 02547 ClassFreeOrReuseSrb(fdoExtension, srb); 02548 } 02549 else { 02550 DBGWARN(("ClassIoComplete is freeing an SRB (possibly) on behalf of another driver.")); 02551 ExFreePool(srb); 02552 } 02553 02554 } else { 02555 02556 DebugPrint((2, "ClassIoComplete: Not Freeing srb @ %p because " 02557 "SRB_CLASS_FLAGS_PERSISTANT set\n", srb)); 02558 if (PORT_ALLOCATED_SENSE(fdoExtension, srb)) { 02559 DebugPrint((2, "ClassIoComplete: Not Freeing sensebuffer @ %p " 02560 " because SRB_CLASS_FLAGS_PERSISTANT set\n", 02561 srb->SenseInfoBuffer)); 02562 } 02563 02564 } 02565 02566 // 02567 // Set status in completing IRP. 02568 // 02569 02570 Irp->IoStatus.Status = status; 02571 02572 // 02573 // Set the hard error if necessary. 02574 // 02575 02576 if (!NT_SUCCESS(status) && 02577 IoIsErrorUserInduced(status) && 02578 (Irp->Tail.Overlay.Thread != NULL) 02579 ) { 02580 02581 // 02582 // Store DeviceObject for filesystem, and clear 02583 // in IoStatus.Information field. 02584 // 02585 02586 IoSetHardErrorOrVerifyDevice(Irp, Fdo); 02587 Irp->IoStatus.Information = 0; 02588 } 02589 02590 // 02591 // If pending has be returned for this irp then mark the current stack as 02592 // pending. 02593 // 02594 02595 if (Irp->PendingReturned) { 02596 IoMarkIrpPending(Irp); 02597 } 02598 02599 if (fdoExtension->CommonExtension.DriverExtension->InitData.ClassStartIo) { 02600 if (callStartNextPacket) { 02601 KIRQL oldIrql; 02602 KeRaiseIrql(DISPATCH_LEVEL, &oldIrql); 02603 IoStartNextPacket(Fdo, FALSE); 02604 KeLowerIrql(oldIrql); 02605 } 02606 } 02607 02608 ClassReleaseRemoveLock(Fdo, Irp); 02609 02610 return status; 02611 02612 } // end ClassIoComplete() 02613 02614 02615 /*++//////////////////////////////////////////////////////////////////////////// 02616 02617 ClassSendSrbSynchronous() 02618 02619 Routine Description: 02620 02621 This routine is called by SCSI device controls to complete an 02622 SRB and send it to the port driver synchronously (ie wait for 02623 completion). The CDB is already completed along with the SRB CDB 02624 size and request timeout value. 02625 02626 Arguments: 02627 02628 Fdo - Supplies the functional device object which represents the target. 02629 02630 Srb - Supplies a partially initialized SRB. The SRB cannot come from zone. 02631 02632 BufferAddress - Supplies the address of the buffer. 02633 02634 BufferLength - Supplies the length in bytes of the buffer. 02635 02636 WriteToDevice - Indicates the data should be transfer to the device. 02637 02638 Return Value: 02639 02640 NTSTATUS indicating the final results of the operation. 02641 02642 If NT_SUCCESS(), then the amount of usable data is contained in the field 02643 Srb->DataTransferLength 02644 02645 --*/ 02646 NTSTATUS 02647 ClassSendSrbSynchronous( 02648 PDEVICE_OBJECT Fdo, 02649 PSCSI_REQUEST_BLOCK Srb, 02650 PVOID BufferAddress, 02651 ULONG BufferLength, 02652 BOOLEAN WriteToDevice 02653 ) 02654 { 02655 02656 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 02657 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 02658 IO_STATUS_BLOCK ioStatus; 02659 ULONG controlType; 02660 PIRP irp; 02661 PIO_STACK_LOCATION irpStack; 02662 KEVENT event; 02663 PUCHAR senseInfoBuffer; 02664 ULONG retryCount = MAXIMUM_RETRIES; 02665 NTSTATUS status; 02666 BOOLEAN retry; 02667 02668 // 02669 // NOTE: This code is only pagable because we are not freezing 02670 // the queue. Allowing the queue to be frozen from a pagable 02671 // routine could leave the queue frozen as we try to page in 02672 // the code to unfreeze the queue. The result would be a nice 02673 // case of deadlock. Therefore, since we are unfreezing the 02674 // queue regardless of the result, just set the NO_FREEZE_QUEUE 02675 // flag in the SRB. 02676 // 02677 02678 ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); 02679 ASSERT(fdoExtension->CommonExtension.IsFdo); 02680 02681 // 02682 // Write length to SRB. 02683 // 02684 02685 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); 02686 02687 // 02688 // Set SCSI bus address. 02689 // 02690 02691 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 02692 02693 // 02694 // Enable auto request sense. 02695 // 02696 02697 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 02698 02699 // 02700 // Sense buffer is in aligned nonpaged pool. 02701 // 02702 // 02703 senseInfoBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, 02704 SENSE_BUFFER_SIZE, 02705 '7CcS'); 02706 02707 if (senseInfoBuffer == NULL) { 02708 02709 DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate request sense " 02710 "buffer\n")); 02711 return(STATUS_INSUFFICIENT_RESOURCES); 02712 } 02713 02714 Srb->SenseInfoBuffer = senseInfoBuffer; 02715 Srb->DataBuffer = BufferAddress; 02716 02717 // 02718 // Start retries here. 02719 // 02720 02721 retry: 02722 02723 // 02724 // use fdoextension's flags by default. 02725 // do not move out of loop, as the flag may change due to errors 02726 // sending this command. 02727 // 02728 02729 Srb->SrbFlags = fdoExtension->SrbFlags; 02730 02731 if(BufferAddress != NULL) { 02732 if(WriteToDevice) { 02733 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_OUT); 02734 } else { 02735 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DATA_IN); 02736 } 02737 } 02738 02739 // 02740 // Initialize the QueueAction field. 02741 // 02742 02743 Srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; 02744 02745 // 02746 // Disable synchronous transfer for these requests. 02747 // Disable freezing the queue, since all we do is unfreeze it anyways. 02748 // 02749 02750 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); 02751 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); 02752 02753 // 02754 // Set the event object to the unsignaled state. 02755 // It will be used to signal request completion. 02756 // 02757 02758 KeInitializeEvent(&event, NotificationEvent, FALSE); 02759 02760 // 02761 // Build device I/O control request with METHOD_NEITHER data transfer. 02762 // We'll queue a completion routine to cleanup the MDL's and such ourself. 02763 // 02764 02765 irp = IoAllocateIrp( 02766 (CCHAR) (fdoExtension->CommonExtension.LowerDeviceObject->StackSize + 1), 02767 FALSE); 02768 02769 if(irp == NULL) { 02770 ExFreePool(senseInfoBuffer); 02771 DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate Irp\n")); 02772 return(STATUS_INSUFFICIENT_RESOURCES); 02773 } 02774 02775 // 02776 // Get next stack location. 02777 // 02778 02779 irpStack = IoGetNextIrpStackLocation(irp); 02780 02781 // 02782 // Set up SRB for execute scsi request. Save SRB address in next stack 02783 // for the port driver. 02784 // 02785 02786 irpStack->MajorFunction = IRP_MJ_SCSI; 02787 irpStack->Parameters.Scsi.Srb = Srb; 02788 02789 IoSetCompletionRoutine(irp, 02790 ClasspSendSynchronousCompletion, 02791 Srb, 02792 TRUE, 02793 TRUE, 02794 TRUE); 02795 02796 irp->UserIosb = &ioStatus; 02797 irp->UserEvent = &event; 02798 02799 if(BufferAddress) { 02800 // 02801 // Build an MDL for the data buffer and stick it into the irp. The 02802 // completion routine will unlock the pages and free the MDL. 02803 // 02804 02805 irp->MdlAddress = IoAllocateMdl( BufferAddress, 02806 BufferLength, 02807 FALSE, 02808 FALSE, 02809 irp ); 02810 if (irp->MdlAddress == NULL) { 02811 ExFreePool(senseInfoBuffer); 02812 Srb->SenseInfoBuffer = NULL; 02813 IoFreeIrp( irp ); 02814 DebugPrint((1, "ClassSendSrbSynchronous: Can't allocate MDL\n")); 02815 return STATUS_INSUFFICIENT_RESOURCES; 02816 } 02817 02818 _SEH2_TRY { 02819 02820 // 02821 // the io manager unlocks these pages upon completion 02822 // 02823 02824 MmProbeAndLockPages( irp->MdlAddress, 02825 KernelMode, 02826 (WriteToDevice ? IoReadAccess : 02827 IoWriteAccess)); 02828 02829 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 02830 status = _SEH2_GetExceptionCode(); 02831 02832 ExFreePool(senseInfoBuffer); 02833 Srb->SenseInfoBuffer = NULL; 02834 IoFreeMdl(irp->MdlAddress); 02835 IoFreeIrp(irp); 02836 02837 DebugPrint((1, "ClassSendSrbSynchronous: Exception %lx " 02838 "locking buffer\n", status)); 02839 return status; 02840 } _SEH2_END; 02841 } 02842 02843 // 02844 // Set the transfer length. 02845 // 02846 02847 Srb->DataTransferLength = BufferLength; 02848 02849 // 02850 // Zero out status. 02851 // 02852 02853 Srb->ScsiStatus = Srb->SrbStatus = 0; 02854 Srb->NextSrb = 0; 02855 02856 // 02857 // Set up IRP Address. 02858 // 02859 02860 Srb->OriginalRequest = irp; 02861 02862 // 02863 // Call the port driver with the request and wait for it to complete. 02864 // 02865 02866 status = IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, irp); 02867 02868 if (status == STATUS_PENDING) { 02869 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 02870 status = ioStatus.Status; 02871 } 02872 02873 // 02874 // Check that request completed without error. 02875 // 02876 02877 if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) { 02878 02879 ULONG retryInterval; 02880 02881 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))); 02882 02883 // 02884 // assert that the queue is not frozen 02885 // 02886 02887 ASSERT(!TEST_FLAG(Srb->SrbStatus, SRB_STATUS_QUEUE_FROZEN)); 02888 02889 // 02890 // Update status and determine if request should be retried. 02891 // 02892 02893 retry = ClassInterpretSenseInfo(Fdo, 02894 Srb, 02895 IRP_MJ_SCSI, 02896 0, 02897 MAXIMUM_RETRIES - retryCount, 02898 &status, 02899 &retryInterval); 02900 02901 02902 if (retry) { 02903 02904 if ((status == STATUS_DEVICE_NOT_READY && 02905 ((PSENSE_DATA) senseInfoBuffer)->AdditionalSenseCode == 02906 SCSI_ADSENSE_LUN_NOT_READY) || 02907 (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)) { 02908 02909 LARGE_INTEGER delay; 02910 02911 // 02912 // Delay for at least 2 seconds. 02913 // 02914 02915 if(retryInterval < 2) { 02916 retryInterval = 2; 02917 } 02918 02919 delay.QuadPart = (LONGLONG)( - 10 * 1000 * (LONGLONG)1000 * retryInterval); 02920 02921 // 02922 // Stall for a while to let the device become ready 02923 // 02924 02925 KeDelayExecutionThread(KernelMode, FALSE, &delay); 02926 02927 } 02928 02929 // 02930 // If retries are not exhausted then retry this operation. 02931 // 02932 02933 if (retryCount--) { 02934 02935 if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) { 02936 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb); 02937 } 02938 02939 goto retry; 02940 } 02941 } 02942 02943 } else { 02944 fdoData->LoggedTURFailureSinceLastIO = FALSE; 02945 status = STATUS_SUCCESS; 02946 } 02947 02948 // 02949 // required even though we allocated our own, since the port driver may 02950 // have allocated one also 02951 // 02952 02953 if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) { 02954 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb); 02955 } 02956 02957 Srb->SenseInfoBuffer = NULL; 02958 ExFreePool(senseInfoBuffer); 02959 02960 return status; 02961 } 02962 02963 02964 /*++//////////////////////////////////////////////////////////////////////////// 02965 02966 ClassInterpretSenseInfo() 02967 02968 Routine Description: 02969 02970 This routine interprets the data returned from the SCSI 02971 request sense. It determines the status to return in the 02972 IRP and whether this request can be retried. 02973 02974 Arguments: 02975 02976 DeviceObject - Supplies the device object associated with this request. 02977 02978 Srb - Supplies the scsi request block which failed. 02979 02980 MajorFunctionCode - Supplies the function code to be used for logging. 02981 02982 IoDeviceCode - Supplies the device code to be used for logging. 02983 02984 Status - Returns the status for the request. 02985 02986 Return Value: 02987 02988 BOOLEAN TRUE: Drivers should retry this request. 02989 FALSE: Drivers should not retry this request. 02990 02991 --*/ 02992 BOOLEAN 02993 ClassInterpretSenseInfo( 02994 IN PDEVICE_OBJECT Fdo, 02995 IN PSCSI_REQUEST_BLOCK Srb, 02996 IN UCHAR MajorFunctionCode, 02997 IN ULONG IoDeviceCode, 02998 IN ULONG RetryCount, 02999 OUT NTSTATUS *Status, 03000 OUT OPTIONAL ULONG *RetryInterval 03001 ) 03002 { 03003 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 03004 PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension; 03005 PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData; 03006 03007 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; 03008 03009 BOOLEAN retry = TRUE; 03010 BOOLEAN logError = FALSE; 03011 BOOLEAN unhandledError = FALSE; 03012 BOOLEAN incrementErrorCount = FALSE; 03013 03014 ULONG badSector = 0; 03015 ULONG uniqueId = 0; 03016 03017 NTSTATUS logStatus; 03018 03019 ULONG readSector; 03020 ULONG index; 03021 03022 ULONG retryInterval = 0; 03023 KIRQL oldIrql; 03024 03025 03026 logStatus = -1; 03027 03028 if(TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) { 03029 03030 // 03031 // Log anything remotely incorrect about paging i/o 03032 // 03033 03034 logError = TRUE; 03035 uniqueId = 301; 03036 logStatus = IO_WARNING_PAGING_FAILURE; 03037 } 03038 03039 // 03040 // Check that request sense buffer is valid. 03041 // 03042 03043 ASSERT(fdoExtension->CommonExtension.IsFdo); 03044 03045 03046 // 03047 // must handle the SRB_STATUS_INTERNAL_ERROR case first, 03048 // as it has all the flags set. 03049 // 03050 03051 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_INTERNAL_ERROR) { 03052 03053 DebugPrint((ClassDebugSenseInfo, 03054 "ClassInterpretSenseInfo: Internal Error code is %x\n", 03055 Srb->InternalStatus)); 03056 03057 retry = FALSE; 03058 *Status = Srb->InternalStatus; 03059 03060 } else if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && 03061 (Srb->SenseInfoBufferLength >= 03062 offsetof(SENSE_DATA, CommandSpecificInformation))) { 03063 03064 // 03065 // Zero the additional sense code and additional sense code qualifier 03066 // if they were not returned by the device. 03067 // 03068 03069 readSector = senseBuffer->AdditionalSenseLength + 03070 offsetof(SENSE_DATA, AdditionalSenseLength); 03071 03072 if (readSector > Srb->SenseInfoBufferLength) { 03073 readSector = Srb->SenseInfoBufferLength; 03074 } 03075 03076 if (readSector <= offsetof(SENSE_DATA, AdditionalSenseCode)) { 03077 senseBuffer->AdditionalSenseCode = 0; 03078 } 03079 03080 if (readSector <= offsetof(SENSE_DATA, AdditionalSenseCodeQualifier)) { 03081 senseBuffer->AdditionalSenseCodeQualifier = 0; 03082 } 03083 03084 DebugPrint((ClassDebugSenseInfo, 03085 "ClassInterpretSenseInfo: Error code is %x\n", 03086 senseBuffer->ErrorCode)); 03087 DebugPrint((ClassDebugSenseInfo, 03088 "ClassInterpretSenseInfo: Sense key is %x\n", 03089 senseBuffer->SenseKey)); 03090 DebugPrint((ClassDebugSenseInfo, 03091 "ClassInterpretSenseInfo: Additional sense code is %x\n", 03092 senseBuffer->AdditionalSenseCode)); 03093 DebugPrint((ClassDebugSenseInfo, 03094 "ClassInterpretSenseInfo: Additional sense code qualifier " 03095 "is %x\n", 03096 senseBuffer->AdditionalSenseCodeQualifier)); 03097 03098 03099 switch (senseBuffer->SenseKey & 0xf) { 03100 03101 case SCSI_SENSE_NOT_READY: { 03102 03103 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03104 "Device not ready\n")); 03105 *Status = STATUS_DEVICE_NOT_READY; 03106 03107 switch (senseBuffer->AdditionalSenseCode) { 03108 03109 case SCSI_ADSENSE_LUN_NOT_READY: { 03110 03111 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03112 "Lun not ready\n")); 03113 03114 switch (senseBuffer->AdditionalSenseCodeQualifier) { 03115 03116 case SCSI_SENSEQ_OPERATION_IN_PROGRESS: { 03117 DEVICE_EVENT_BECOMING_READY notReady; 03118 03119 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03120 "Operation In Progress\n")); 03121 retryInterval = NOT_READY_RETRY_INTERVAL; 03122 03123 RtlZeroMemory(¬Ready, sizeof(DEVICE_EVENT_BECOMING_READY)); 03124 notReady.Version = 1; 03125 notReady.Reason = 2; 03126 notReady.Estimated100msToReady = retryInterval * 10; 03127 ClasspSendNotification(fdoExtension, 03128 &GUID_IO_DEVICE_BECOMING_READY, 03129 sizeof(DEVICE_EVENT_BECOMING_READY), 03130 ¬Ready); 03131 03132 break; 03133 } 03134 03135 case SCSI_SENSEQ_BECOMING_READY: { 03136 DEVICE_EVENT_BECOMING_READY notReady; 03137 03138 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03139 "In process of becoming ready\n")); 03140 retryInterval = NOT_READY_RETRY_INTERVAL; 03141 03142 RtlZeroMemory(¬Ready, sizeof(DEVICE_EVENT_BECOMING_READY)); 03143 notReady.Version = 1; 03144 notReady.Reason = 1; 03145 notReady.Estimated100msToReady = retryInterval * 10; 03146 ClasspSendNotification(fdoExtension, 03147 &GUID_IO_DEVICE_BECOMING_READY, 03148 sizeof(DEVICE_EVENT_BECOMING_READY), 03149 ¬Ready); 03150 break; 03151 } 03152 03153 case SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS: { 03154 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03155 "Long write in progress\n")); 03156 retry = FALSE; 03157 break; 03158 } 03159 03160 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: { 03161 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03162 "Manual intervention required\n")); 03163 *Status = STATUS_NO_MEDIA_IN_DEVICE; 03164 retry = FALSE; 03165 break; 03166 } 03167 03168 case SCSI_SENSEQ_FORMAT_IN_PROGRESS: { 03169 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03170 "Format in progress\n")); 03171 retry = FALSE; 03172 break; 03173 } 03174 03175 case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: { 03176 03177 if(!TEST_FLAG(fdoExtension->ScanForSpecialFlags, 03178 CLASS_SPECIAL_CAUSE_NOT_REPORTABLE_HACK)) { 03179 03180 DebugPrint((ClassDebugSenseInfo, 03181 "ClassInterpretSenseInfo: " 03182 "not ready, cause unknown\n")); 03183 /* 03184 Many non-WHQL certified drives (mostly CD-RW) return 03185 this when they have no media instead of the obvious 03186 choice of: 03187 03188 SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 03189 03190 These drives should not pass WHQL certification due 03191 to this discrepency. 03192 03193 */ 03194 retry = FALSE; 03195 break; 03196 03197 } else { 03198 03199 // 03200 // Treat this as init command required and fall through. 03201 // 03202 } 03203 } 03204 03205 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED: 03206 default: { 03207 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03208 "Initializing command required\n")); 03209 03210 // 03211 // This sense code/additional sense code 03212 // combination may indicate that the device 03213 // needs to be started. Send an start unit if this 03214 // is a disk device. 03215 // 03216 03217 if(TEST_FLAG(fdoExtension->DeviceFlags, 03218 DEV_SAFE_START_UNIT) && 03219 !TEST_FLAG(Srb->SrbFlags, 03220 SRB_CLASS_FLAGS_LOW_PRIORITY)) { 03221 ClassSendStartUnit(Fdo); 03222 } 03223 break; 03224 } 03225 03226 03227 } // end switch (senseBuffer->AdditionalSenseCodeQualifier) 03228 break; 03229 } 03230 03231 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: { 03232 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03233 "No Media in device.\n")); 03234 *Status = STATUS_NO_MEDIA_IN_DEVICE; 03235 retry = FALSE; 03236 03237 // 03238 // signal MCN that there isn't any media in the device 03239 // 03240 if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { 03241 DebugPrint((ClassDebugError, "ClassInterpretSenseInfo: " 03242 "No Media in a non-removable device %p\n", 03243 Fdo)); 03244 } 03245 ClassSetMediaChangeState(fdoExtension, MediaNotPresent, FALSE); 03246 03247 break; 03248 } 03249 } // end switch (senseBuffer->AdditionalSenseCode) 03250 03251 break; 03252 } // end SCSI_SENSE_NOT_READY 03253 03254 case SCSI_SENSE_DATA_PROTECT: { 03255 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03256 "Media write protected\n")); 03257 *Status = STATUS_MEDIA_WRITE_PROTECTED; 03258 retry = FALSE; 03259 break; 03260 } // end SCSI_SENSE_DATA_PROTECT 03261 03262 case SCSI_SENSE_MEDIUM_ERROR: { 03263 DebugPrint((ClassDebugSenseInfo,"ClassInterpretSenseInfo: " 03264 "Medium Error (bad block)\n")); 03265 *Status = STATUS_DEVICE_DATA_ERROR; 03266 03267 retry = FALSE; 03268 logError = TRUE; 03269 uniqueId = 256; 03270 logStatus = IO_ERR_BAD_BLOCK; 03271 03272 // 03273 // Check if this error is due to unknown format 03274 // 03275 if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_INVALID_MEDIA){ 03276 03277 switch (senseBuffer->AdditionalSenseCodeQualifier) { 03278 03279 case SCSI_SENSEQ_UNKNOWN_FORMAT: { 03280 03281 *Status = STATUS_UNRECOGNIZED_MEDIA; 03282 03283 // 03284 // Log error only if this is a paging request 03285 // 03286 if(!TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) { 03287 logError = FALSE; 03288 } 03289 break; 03290 } 03291 03292 case SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED: { 03293 03294 *Status = STATUS_CLEANER_CARTRIDGE_INSTALLED; 03295 logError = FALSE; 03296 break; 03297 03298 } 03299 default: { 03300 break; 03301 } 03302 } // end switch AdditionalSenseCodeQualifier 03303 03304 } // end SCSI_ADSENSE_INVALID_MEDIA 03305 03306 break; 03307 03308 } // end SCSI_SENSE_MEDIUM_ERROR 03309 03310 case SCSI_SENSE_HARDWARE_ERROR: { 03311 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03312 "Hardware error\n")); 03313 *Status = STATUS_IO_DEVICE_ERROR; 03314 logError = TRUE; 03315 uniqueId = 257; 03316 logStatus = IO_ERR_CONTROLLER_ERROR; 03317 break; 03318 } // end SCSI_SENSE_HARDWARE_ERROR 03319 03320 case SCSI_SENSE_ILLEGAL_REQUEST: { 03321 03322 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03323 "Illegal SCSI request\n")); 03324 *Status = STATUS_INVALID_DEVICE_REQUEST; 03325 retry = FALSE; 03326 03327 switch (senseBuffer->AdditionalSenseCode) { 03328 03329 case SCSI_ADSENSE_ILLEGAL_COMMAND: { 03330 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03331 "Illegal command\n")); 03332 break; 03333 } 03334 03335 case SCSI_ADSENSE_ILLEGAL_BLOCK: { 03336 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03337 "Illegal block address\n")); 03338 *Status = STATUS_NONEXISTENT_SECTOR; 03339 break; 03340 } 03341 03342 case SCSI_ADSENSE_INVALID_LUN: { 03343 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03344 "Invalid LUN\n")); 03345 *Status = STATUS_NO_SUCH_DEVICE; 03346 break; 03347 } 03348 03349 case SCSI_ADSENSE_MUSIC_AREA: { 03350 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03351 "Music area\n")); 03352 break; 03353 } 03354 03355 case SCSI_ADSENSE_DATA_AREA: { 03356 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03357 "Data area\n")); 03358 break; 03359 } 03360 03361 case SCSI_ADSENSE_VOLUME_OVERFLOW: { 03362 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03363 "Volume overflow\n")); 03364 break; 03365 } 03366 03367 case SCSI_ADSENSE_COPY_PROTECTION_FAILURE: { 03368 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03369 "Copy protection failure\n")); 03370 03371 *Status = STATUS_COPY_PROTECTION_FAILURE; 03372 03373 switch (senseBuffer->AdditionalSenseCodeQualifier) { 03374 case SCSI_SENSEQ_AUTHENTICATION_FAILURE: 03375 DebugPrint((ClassDebugSenseInfo, 03376 "ClassInterpretSenseInfo: " 03377 "Authentication failure\n")); 03378 *Status = STATUS_CSS_AUTHENTICATION_FAILURE; 03379 break; 03380 case SCSI_SENSEQ_KEY_NOT_PRESENT: 03381 DebugPrint((ClassDebugSenseInfo, 03382 "ClassInterpretSenseInfo: " 03383 "Key not present\n")); 03384 *Status = STATUS_CSS_KEY_NOT_PRESENT; 03385 break; 03386 case SCSI_SENSEQ_KEY_NOT_ESTABLISHED: 03387 DebugPrint((ClassDebugSenseInfo, 03388 "ClassInterpretSenseInfo: " 03389 "Key not established\n")); 03390 *Status = STATUS_CSS_KEY_NOT_ESTABLISHED; 03391 break; 03392 case SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION: 03393 DebugPrint((ClassDebugSenseInfo, 03394 "ClassInterpretSenseInfo: " 03395 "Read of scrambled sector w/o " 03396 "authentication\n")); 03397 *Status = STATUS_CSS_SCRAMBLED_SECTOR; 03398 break; 03399 case SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT: 03400 DebugPrint((ClassDebugSenseInfo, 03401 "ClassInterpretSenseInfo: " 03402 "Media region does not logical unit " 03403 "region\n")); 03404 *Status = STATUS_CSS_REGION_MISMATCH; 03405 break; 03406 case SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR: 03407 DebugPrint((ClassDebugSenseInfo, 03408 "ClassInterpretSenseInfo: " 03409 "Region set error -- region may " 03410 "be permanent\n")); 03411 *Status = STATUS_CSS_RESETS_EXHAUSTED; 03412 break; 03413 } // end switch of ASCQ for COPY_PROTECTION_FAILURE 03414 03415 break; 03416 } 03417 03418 03419 case SCSI_ADSENSE_INVALID_CDB: { 03420 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03421 "Invalid CDB\n")); 03422 03423 // 03424 // Note: the retry interval is not typically used. 03425 // it is set here only because a ClassErrorHandler 03426 // cannot set the retryInterval, and the error may 03427 // require a few commands to be sent to clear whatever 03428 // caused this condition (i.e. disk clears the write 03429 // cache, requiring at least two commands) 03430 // 03431 // hopefully, this shortcoming can be changed for 03432 // blackcomb. 03433 // 03434 03435 retryInterval = 3; 03436 break; 03437 } 03438 03439 } // end switch (senseBuffer->AdditionalSenseCode) 03440 03441 break; 03442 } // end SCSI_SENSE_ILLEGAL_REQUEST 03443 03444 case SCSI_SENSE_UNIT_ATTENTION: { 03445 03446 PVPB vpb; 03447 ULONG count; 03448 03449 // 03450 // A media change may have occured so increment the change 03451 // count for the physical device 03452 // 03453 03454 count = InterlockedIncrement(&fdoExtension->MediaChangeCount); 03455 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03456 "Media change count for device %d incremented to %#lx\n", 03457 fdoExtension->DeviceNumber, count)); 03458 03459 03460 switch (senseBuffer->AdditionalSenseCode) { 03461 case SCSI_ADSENSE_MEDIUM_CHANGED: { 03462 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03463 "Media changed\n")); 03464 03465 if (!TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) { 03466 DebugPrint((ClassDebugError, "ClassInterpretSenseInfo: " 03467 "Media Changed on non-removable device %p\n", 03468 Fdo)); 03469 } 03470 ClassSetMediaChangeState(fdoExtension, MediaPresent, FALSE); 03471 break; 03472 } 03473 03474 case SCSI_ADSENSE_BUS_RESET: { 03475 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03476 "Bus reset\n")); 03477 break; 03478 } 03479 03480 case SCSI_ADSENSE_OPERATOR_REQUEST: { 03481 switch (senseBuffer->AdditionalSenseCodeQualifier) { 03482 03483 case SCSI_SENSEQ_MEDIUM_REMOVAL: { 03484 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03485 "Ejection request received!\n")); 03486 ClassSendEjectionNotification(fdoExtension); 03487 break; 03488 } 03489 03490 case SCSI_SENSEQ_WRITE_PROTECT_ENABLE: { 03491 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03492 "Operator selected write permit?! " 03493 "(unsupported!)\n")); 03494 break; 03495 } 03496 03497 case SCSI_SENSEQ_WRITE_PROTECT_DISABLE: { 03498 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03499 "Operator selected write protect?! " 03500 "(unsupported!)\n")); 03501 break; 03502 } 03503 03504 } 03505 break; 03506 } 03507 03508 default: { 03509 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03510 "Unit attention\n")); 03511 break; 03512 } 03513 03514 } // end switch (senseBuffer->AdditionalSenseCode) 03515 03516 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)) 03517 { 03518 // 03519 // TODO : Is the media lockable? 03520 // 03521 03522 if ((ClassGetVpb(Fdo) != NULL) && (ClassGetVpb(Fdo)->Flags & VPB_MOUNTED)) 03523 { 03524 // 03525 // Set bit to indicate that media may have changed 03526 // and volume needs verification. 03527 // 03528 03529 SET_FLAG(Fdo->Flags, DO_VERIFY_VOLUME); 03530 03531 *Status = STATUS_VERIFY_REQUIRED; 03532 retry = FALSE; 03533 } 03534 } 03535 else 03536 { 03537 *Status = STATUS_IO_DEVICE_ERROR; 03538 } 03539 03540 break; 03541 03542 } // end SCSI_SENSE_UNIT_ATTENTION 03543 03544 case SCSI_SENSE_ABORTED_COMMAND: { 03545 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03546 "Command aborted\n")); 03547 *Status = STATUS_IO_DEVICE_ERROR; 03548 retryInterval = 1; 03549 break; 03550 } // end SCSI_SENSE_ABORTED_COMMAND 03551 03552 case SCSI_SENSE_BLANK_CHECK: { 03553 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03554 "Media blank check\n")); 03555 retry = FALSE; 03556 *Status = STATUS_NO_DATA_DETECTED; 03557 break; 03558 } // end SCSI_SENSE_BLANK_CHECK 03559 03560 case SCSI_SENSE_RECOVERED_ERROR: { 03561 03562 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03563 "Recovered error\n")); 03564 *Status = STATUS_SUCCESS; 03565 retry = FALSE; 03566 logError = TRUE; 03567 uniqueId = 258; 03568 03569 switch(senseBuffer->AdditionalSenseCode) { 03570 case SCSI_ADSENSE_SEEK_ERROR: 03571 case SCSI_ADSENSE_TRACK_ERROR: { 03572 logStatus = IO_ERR_SEEK_ERROR; 03573 break; 03574 } 03575 03576 case SCSI_ADSENSE_REC_DATA_NOECC: 03577 case SCSI_ADSENSE_REC_DATA_ECC: { 03578 logStatus = IO_RECOVERED_VIA_ECC; 03579 break; 03580 } 03581 03582 case SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED: { 03583 UCHAR wmiEventData[5]; 03584 03585 *((PULONG)wmiEventData) = sizeof(UCHAR); 03586 wmiEventData[sizeof(ULONG)] = senseBuffer->AdditionalSenseCodeQualifier; 03587 03588 // 03589 // Don't log another eventlog if we have already logged once 03590 // NOTE: this should have been interlocked, but the structure 03591 // was publicly defined to use a BOOLEAN (char). Since 03592 // media only reports these errors once per X minutes, 03593 // the potential race condition is nearly non-existant. 03594 // the worst case is duplicate log entries, so ignore. 03595 // 03596 03597 if (fdoExtension->FailurePredicted == 0) { 03598 logError = TRUE; 03599 } 03600 fdoExtension->FailurePredicted = TRUE; 03601 fdoExtension->FailureReason = senseBuffer->AdditionalSenseCodeQualifier; 03602 logStatus = IO_WRN_FAILURE_PREDICTED; 03603 03604 ClassNotifyFailurePredicted(fdoExtension, 03605 (PUCHAR)&wmiEventData, 03606 sizeof(wmiEventData), 03607 0, 03608 4, 03609 Srb->PathId, 03610 Srb->TargetId, 03611 Srb->Lun); 03612 break; 03613 } 03614 03615 default: { 03616 logStatus = IO_ERR_CONTROLLER_ERROR; 03617 break; 03618 } 03619 03620 } // end switch(senseBuffer->AdditionalSenseCode) 03621 03622 if (senseBuffer->IncorrectLength) { 03623 03624 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03625 "Incorrect length detected.\n")); 03626 *Status = STATUS_INVALID_BLOCK_LENGTH ; 03627 } 03628 03629 break; 03630 } // end SCSI_SENSE_RECOVERED_ERROR 03631 03632 case SCSI_SENSE_NO_SENSE: { 03633 03634 // 03635 // Check other indicators. 03636 // 03637 03638 if (senseBuffer->IncorrectLength) { 03639 03640 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03641 "Incorrect length detected.\n")); 03642 *Status = STATUS_INVALID_BLOCK_LENGTH ; 03643 retry = FALSE; 03644 03645 } else { 03646 03647 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03648 "No specific sense key\n")); 03649 *Status = STATUS_IO_DEVICE_ERROR; 03650 retry = TRUE; 03651 } 03652 03653 break; 03654 } // end SCSI_SENSE_NO_SENSE 03655 03656 default: { 03657 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03658 "Unrecognized sense code\n")); 03659 *Status = STATUS_IO_DEVICE_ERROR; 03660 break; 03661 } 03662 03663 } // end switch (senseBuffer->SenseKey & 0xf) 03664 03665 // 03666 // Try to determine the bad sector from the inquiry data. 03667 // 03668 03669 if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_READ || 03670 ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY || 03671 ((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_WRITE)) { 03672 03673 for (index = 0; index < 4; index++) { 03674 badSector = (badSector << 8) | senseBuffer->Information[index]; 03675 } 03676 03677 readSector = 0; 03678 for (index = 0; index < 4; index++) { 03679 readSector = (readSector << 8) | Srb->Cdb[index+2]; 03680 } 03681 03682 index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) | 03683 ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb; 03684 03685 // 03686 // Make sure the bad sector is within the read sectors. 03687 // 03688 03689 if (!(badSector >= readSector && badSector < readSector + index)) { 03690 badSector = readSector; 03691 } 03692 } 03693 03694 } else { 03695 03696 // 03697 // Request sense buffer not valid. No sense information 03698 // to pinpoint the error. Return general request fail. 03699 // 03700 03701 DebugPrint((ClassDebugSenseInfo, "ClassInterpretSenseInfo: " 03702 "Request sense info not valid. SrbStatus %2x\n", 03703 SRB_STATUS(Srb->SrbStatus))); 03704 retry = TRUE; 03705 03706 switch (SRB_STATUS(Srb->SrbStatus)) { 03707 case SRB_STATUS_INVALID_LUN: 03708 case SRB_STATUS_INVALID_TARGET_ID: 03709 case SRB_STATUS_NO_DEVICE: 03710 case SRB_STATUS_NO_HBA: 03711 case SRB_STATUS_INVALID_PATH_ID: { 03712 *Status = STATUS_NO_SUCH_DEVICE; 03713 retry = FALSE; 03714 break; 03715 } 03716 03717 case SRB_STATUS_COMMAND_TIMEOUT: 03718 case SRB_STATUS_TIMEOUT: { 03719 03720 // 03721 // Update the error count for the device. 03722 // 03723 03724 incrementErrorCount = TRUE; 03725 *Status = STATUS_IO_TIMEOUT; 03726 break; 03727 } 03728 03729 case SRB_STATUS_ABORTED: { 03730 03731 // 03732 // Update the error count for the device. 03733 // 03734 03735 incrementErrorCount = TRUE; 03736 *Status = STATUS_IO_TIMEOUT; 03737 retryInterval = 1; 03738 break; 03739 } 03740 03741 03742 case SRB_STATUS_SELECTION_TIMEOUT: { 03743 logError = TRUE; 03744 logStatus = IO_ERR_NOT_READY; 03745 uniqueId = 260; 03746 *Status = STATUS_DEVICE_NOT_CONNECTED; 03747 retry = FALSE; 03748 break; 03749 } 03750 03751 case SRB_STATUS_DATA_OVERRUN: { 03752 *Status = STATUS_DATA_OVERRUN; 03753 retry = FALSE; 03754 break; 03755 } 03756 03757 case SRB_STATUS_PHASE_SEQUENCE_FAILURE: { 03758 03759 // 03760 // Update the error count for the device. 03761 // 03762 03763 incrementErrorCount = TRUE; 03764 *Status = STATUS_IO_DEVICE_ERROR; 03765 03766 // 03767 // If there was phase sequence error then limit the number of 03768 // retries. 03769 // 03770 03771 if (RetryCount > 1 ) { 03772 retry = FALSE; 03773 } 03774 03775 break; 03776 } 03777 03778 case SRB_STATUS_REQUEST_FLUSHED: { 03779 03780 // 03781 // If the status needs verification bit is set. Then set 03782 // the status to need verification and no retry; otherwise, 03783 // just retry the request. 03784 // 03785 03786 if (TEST_FLAG(Fdo->Flags, DO_VERIFY_VOLUME)) { 03787 03788 *Status = STATUS_VERIFY_REQUIRED; 03789 retry = FALSE; 03790 03791 } else { 03792 *Status = STATUS_IO_DEVICE_ERROR; 03793 } 03794 03795 break; 03796 } 03797 03798 case SRB_STATUS_INVALID_REQUEST: { 03799 *Status = STATUS_INVALID_DEVICE_REQUEST; 03800 retry = FALSE; 03801 break; 03802 } 03803 03804 case SRB_STATUS_UNEXPECTED_BUS_FREE: 03805 case SRB_STATUS_PARITY_ERROR: 03806 03807 // 03808 // Update the error count for the device 03809 // and fall through to below 03810 // 03811 03812 incrementErrorCount = TRUE; 03813 03814 case SRB_STATUS_BUS_RESET: { 03815 *Status = STATUS_IO_DEVICE_ERROR; 03816 break; 03817 } 03818 03819 case SRB_STATUS_ERROR: { 03820 03821 *Status = STATUS_IO_DEVICE_ERROR; 03822 if (Srb->ScsiStatus == 0) { 03823 03824 // 03825 // This is some strange return code. Update the error 03826 // count for the device. 03827 // 03828 03829 incrementErrorCount = TRUE; 03830 03831 } if (Srb->ScsiStatus == SCSISTAT_BUSY) { 03832 03833 *Status = STATUS_DEVICE_NOT_READY; 03834 03835 } if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) { 03836 03837 *Status = STATUS_DEVICE_BUSY; 03838 retry = FALSE; 03839 logError = FALSE; 03840 03841 } 03842 03843 break; 03844 } 03845 03846 default: { 03847 logError = TRUE; 03848 logStatus = IO_ERR_CONTROLLER_ERROR; 03849 uniqueId = 259; 03850 *Status = STATUS_IO_DEVICE_ERROR; 03851 unhandledError = TRUE; 03852 break; 03853 } 03854 03855 } 03856 03857 // 03858 // NTRAID #183546 - if we support GESN subtype NOT_READY events, and 03859 // we know from a previous poll when the device will be ready (ETA) 03860 // we should delay the retry more appropriately than just guessing. 03861 // 03862 /* 03863 if (fdoExtension->MediaChangeDetectionInfo && 03864 fdoExtension->MediaChangeDetectionInfo->Gesn.Supported && 03865 TEST_FLAG(fdoExtension->MediaChangeDetectionInfo->Gesn.EventMask, 03866 NOTIFICATION_DEVICE_BUSY_CLASS_MASK) 03867 ) { 03868 // check if Gesn.ReadyTime if greater than current tick count 03869 // if so, delay that long (from 1 to 30 seconds max?) 03870 // else, leave the guess of time alone. 03871 } 03872 */ 03873 03874 } 03875 03876 if (incrementErrorCount) { 03877 03878 // 03879 // if any error count occurred, delay the retry of this io by 03880 // at least one second, if caller supports it. 03881 // 03882 03883 if (retryInterval == 0) { 03884 retryInterval = 1; 03885 } 03886 ClasspPerfIncrementErrorCount(fdoExtension); 03887 } 03888 03889 // 03890 // If there is a class specific error handler call it. 03891 // 03892 03893 if (fdoExtension->CommonExtension.DevInfo->ClassError != NULL) { 03894 03895 fdoExtension->CommonExtension.DevInfo->ClassError(Fdo, 03896 Srb, 03897 Status, 03898 &retry); 03899 } 03900 03901 // 03902 // If the caller wants to know the suggested retry interval tell them. 03903 // 03904 03905 if(ARGUMENT_PRESENT(RetryInterval)) { 03906 *RetryInterval = retryInterval; 03907 } 03908 03909 03910 /* 03911 * LOG the error: 03912 * Always log the error in our internal log. 03913 * If logError is set, also log the error in the system log. 03914 */ 03915 { 03916 ULONG totalSize; 03917 ULONG senseBufferSize = 0; 03918 IO_ERROR_LOG_PACKET staticErrLogEntry = {0}; 03919 CLASS_ERROR_LOG_DATA staticErrLogData = {0}; 03920 03921 // 03922 // Calculate the total size of the error log entry. 03923 // add to totalSize in the order that they are used. 03924 // the advantage to calculating all the sizes here is 03925 // that we don't have to do a bunch of extraneous checks 03926 // later on in this code path. 03927 // 03928 totalSize = sizeof(IO_ERROR_LOG_PACKET) // required 03929 - sizeof(ULONG) // struct includes one ULONG 03930 + sizeof(CLASS_ERROR_LOG_DATA);// struct for ease 03931 03932 // 03933 // also save any available extra sense data, up to the maximum errlog 03934 // packet size . WMI should be used for real-time analysis. 03935 // the event log should only be used for post-mortem debugging. 03936 // 03937 if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) { 03938 ULONG validSenseBytes; 03939 BOOLEAN validSense; 03940 03941 // 03942 // make sure we can at least access the AdditionalSenseLength field 03943 // 03944 validSense = RTL_CONTAINS_FIELD(senseBuffer, 03945 Srb->SenseInfoBufferLength, 03946 AdditionalSenseLength); 03947 if (validSense) { 03948 03949 // 03950 // if extra info exists, copy the maximum amount of available 03951 // sense data that is safe into the the errlog. 03952 // 03953 validSenseBytes = senseBuffer->AdditionalSenseLength 03954 + offsetof(SENSE_DATA, AdditionalSenseLength); 03955 03956 // 03957 // this is invalid because it causes overflow! 03958 // whoever sent this type of request would cause 03959 // a system crash. 03960 // 03961 ASSERT(validSenseBytes < MAX_ADDITIONAL_SENSE_BYTES); 03962 03963 // 03964 // set to save the most sense buffer possible 03965 // 03966 senseBufferSize = max(validSenseBytes, sizeof(SENSE_DATA)); 03967 senseBufferSize = min(senseBufferSize, Srb->SenseInfoBufferLength); 03968 } else { 03969 // 03970 // it's smaller than required to read the total number of 03971 // valid bytes, so just use the SenseInfoBufferLength field. 03972 // 03973 senseBufferSize = Srb->SenseInfoBufferLength; 03974 } 03975 03976 /* 03977 * Bump totalSize by the number of extra senseBuffer bytes 03978 * (beyond the default sense buffer within CLASS_ERROR_LOG_DATA). 03979 * Make sure to never allocate more than ERROR_LOG_MAXIMUM_SIZE. 03980 */ 03981 if (senseBufferSize > sizeof(SENSE_DATA)){ 03982 totalSize += senseBufferSize-sizeof(SENSE_DATA); 03983 if (totalSize > ERROR_LOG_MAXIMUM_SIZE){ 03984 senseBufferSize -= totalSize-ERROR_LOG_MAXIMUM_SIZE; 03985 totalSize = ERROR_LOG_MAXIMUM_SIZE; 03986 } 03987 } 03988 } 03989 03990 // 03991 // If we've used up all of our retry attempts, set the final status to 03992 // reflect the appropriate result. 03993 // 03994 if (retry && RetryCount < MAXIMUM_RETRIES) { 03995 staticErrLogEntry.FinalStatus = STATUS_SUCCESS; 03996 staticErrLogData.ErrorRetried = TRUE; 03997 } else { 03998 staticErrLogEntry.FinalStatus = *Status; 03999 } 04000 if (TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) { 04001 staticErrLogData.ErrorPaging = TRUE; 04002 } 04003 if (unhandledError) { 04004 staticErrLogData.ErrorUnhandled = TRUE; 04005 } 04006 04007 // 04008 // Calculate the device offset if there is a geometry. 04009 // 04010 staticErrLogEntry.DeviceOffset.QuadPart = (LONGLONG)badSector; 04011 staticErrLogEntry.DeviceOffset.QuadPart *= (LONGLONG)fdoExtension->DiskGeometry.BytesPerSector; 04012 if (logStatus == -1){ 04013 staticErrLogEntry.ErrorCode = STATUS_IO_DEVICE_ERROR; 04014 } else { 04015 staticErrLogEntry.ErrorCode = logStatus; 04016 } 04017 04018 /* 04019 * The dump data follows the IO_ERROR_LOG_PACKET, 04020 * with the first ULONG of dump data inside the packet. 04021 */ 04022 staticErrLogEntry.DumpDataSize = (USHORT)totalSize - sizeof(IO_ERROR_LOG_PACKET) + sizeof(ULONG); 04023 04024 staticErrLogEntry.SequenceNumber = 0; 04025 staticErrLogEntry.MajorFunctionCode = MajorFunctionCode; 04026 staticErrLogEntry.IoControlCode = IoDeviceCode; 04027 staticErrLogEntry.RetryCount = (UCHAR) RetryCount; 04028 staticErrLogEntry.UniqueErrorValue = uniqueId; 04029 04030 KeQueryTickCount(&staticErrLogData.TickCount); 04031 staticErrLogData.PortNumber = (ULONG)-1; 04032 04033 /* 04034 * Save the entire contents of the SRB. 04035 */ 04036 staticErrLogData.Srb = *Srb; 04037 04038 /* 04039 * For our private log, save just the default length of the SENSE_DATA. 04040 */ 04041 if (senseBufferSize != 0){ 04042 RtlCopyMemory(&staticErrLogData.SenseData, senseBuffer, min(senseBufferSize, sizeof(SENSE_DATA))); 04043 } 04044 04045 /* 04046 * Save the error log in our context. 04047 * We only save the default sense buffer length. 04048 */ 04049 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 04050 fdoData->ErrorLogs[fdoData->ErrorLogNextIndex] = staticErrLogData; 04051 fdoData->ErrorLogNextIndex++; 04052 fdoData->ErrorLogNextIndex %= NUM_ERROR_LOG_ENTRIES; 04053 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 04054 04055 /* 04056 * If logError is set, also save this log in the system's error log. 04057 * But make sure we don't log TUR failures over and over 04058 * (e.g. if an external drive was switched off and we're still sending TUR's to it every second). 04059 */ 04060 if ((((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_TEST_UNIT_READY) && logError){ 04061 if (fdoData->LoggedTURFailureSinceLastIO){ 04062 logError = FALSE; 04063 } 04064 else { 04065 fdoData->LoggedTURFailureSinceLastIO = TRUE; 04066 } 04067 } 04068 if (logError){ 04069 PIO_ERROR_LOG_PACKET errorLogEntry; 04070 PCLASS_ERROR_LOG_DATA errlogData; 04071 04072 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(Fdo, (UCHAR)totalSize); 04073 if (errorLogEntry){ 04074 errlogData = (PCLASS_ERROR_LOG_DATA)errorLogEntry->DumpData; 04075 04076 *errorLogEntry = staticErrLogEntry; 04077 *errlogData = staticErrLogData; 04078 04079 /* 04080 * For the system log, copy as much of the sense buffer as possible. 04081 */ 04082 if (senseBufferSize != 0) { 04083 RtlCopyMemory(&errlogData->SenseData, senseBuffer, senseBufferSize); 04084 } 04085 04086 /* 04087 * Write the error log packet to the system error logging thread. 04088 */ 04089 IoWriteErrorLogEntry(errorLogEntry); 04090 } 04091 } 04092 } 04093 04094 return retry; 04095 04096 } // end ClassInterpretSenseInfo() 04097 04098 04099 04100 /*++//////////////////////////////////////////////////////////////////////////// 04101 04102 ClassModeSense() 04103 04104 Routine Description: 04105 04106 This routine sends a mode sense command to a target ID and returns 04107 when it is complete. 04108 04109 Arguments: 04110 04111 Fdo - Supplies the functional device object associated with this request. 04112 04113 ModeSenseBuffer - Supplies a buffer to store the sense data. 04114 04115 Length - Supplies the length in bytes of the mode sense buffer. 04116 04117 PageMode - Supplies the page or pages of mode sense data to be retrived. 04118 04119 Return Value: 04120 04121 Length of the transferred data is returned. 04122 04123 --*/ 04124 ULONG ClassModeSense( IN PDEVICE_OBJECT Fdo, 04125 IN PCHAR ModeSenseBuffer, 04126 IN ULONG Length, 04127 IN UCHAR PageMode) 04128 { 04129 ULONG lengthTransferred = 0; 04130 PMDL senseBufferMdl; 04131 04132 PAGED_CODE(); 04133 04134 senseBufferMdl = BuildDeviceInputMdl(ModeSenseBuffer, Length); 04135 if (senseBufferMdl){ 04136 04137 TRANSFER_PACKET *pkt = DequeueFreeTransferPacket(Fdo, TRUE); 04138 if (pkt){ 04139 KEVENT event; 04140 NTSTATUS pktStatus; 04141 IRP pseudoIrp = {0}; 04142 04143 /* 04144 * Store the number of packets servicing the irp (one) 04145 * inside the original IRP. It will be used to counted down 04146 * to zero when the packet completes. 04147 * Initialize the original IRP's status to success. 04148 * If the packet fails, we will set it to the error status. 04149 */ 04150 pseudoIrp.Tail.Overlay.DriverContext[0] = LongToPtr(1); 04151 pseudoIrp.IoStatus.Status = STATUS_SUCCESS; 04152 pseudoIrp.IoStatus.Information = 0; 04153 pseudoIrp.MdlAddress = senseBufferMdl; 04154 04155 /* 04156 * Set this up as a SYNCHRONOUS transfer, submit it, 04157 * and wait for the packet to complete. The result 04158 * status will be written to the original irp. 04159 */ 04160 ASSERT(Length <= 0x0ff); 04161 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 04162 SetupModeSenseTransferPacket(pkt, &event, ModeSenseBuffer, (UCHAR)Length, PageMode, &pseudoIrp); 04163 SubmitTransferPacket(pkt); 04164 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 04165 04166 if (NT_SUCCESS(pseudoIrp.IoStatus.Status)){ 04167 lengthTransferred = (ULONG)pseudoIrp.IoStatus.Information; 04168 } 04169 else { 04170 /* 04171 * This request can sometimes fail legitimately 04172 * (e.g. when a SCSI device is attached but turned off) 04173 * so this is not necessarily a device/driver bug. 04174 */ 04175 DBGTRACE(ClassDebugWarning, ("ClassModeSense on Fdo %ph failed with status %xh.", Fdo, pseudoIrp.IoStatus.Status)); 04176 } 04177 } 04178 04179 FreeDeviceInputMdl(senseBufferMdl); 04180 } 04181 04182 return lengthTransferred; 04183 } 04184 04185 04186 /*++//////////////////////////////////////////////////////////////////////////// 04187 04188 ClassFindModePage() 04189 04190 Routine Description: 04191 04192 This routine scans through the mode sense data and finds the requested 04193 mode sense page code. 04194 04195 Arguments: 04196 ModeSenseBuffer - Supplies a pointer to the mode sense data. 04197 04198 Length - Indicates the length of valid data. 04199 04200 PageMode - Supplies the page mode to be searched for. 04201 04202 Use6Byte - Indicates whether 6 or 10 byte mode sense was used. 04203 04204 Return Value: 04205 04206 A pointer to the the requested mode page. If the mode page was not found 04207 then NULL is return. 04208 04209 --*/ 04210 PVOID 04211 ClassFindModePage( 04212 IN PCHAR ModeSenseBuffer, 04213 IN ULONG Length, 04214 IN UCHAR PageMode, 04215 IN BOOLEAN Use6Byte 04216 ) 04217 { 04218 PUCHAR limit; 04219 ULONG parameterHeaderLength; 04220 PVOID result = NULL; 04221 04222 limit = ModeSenseBuffer + Length; 04223 parameterHeaderLength = (Use6Byte) ? sizeof(MODE_PARAMETER_HEADER) : sizeof(MODE_PARAMETER_HEADER10); 04224 04225 if (Length >= parameterHeaderLength) { 04226 04227 PMODE_PARAMETER_HEADER10 modeParam10; 04228 ULONG blockDescriptorLength; 04229 04230 /* 04231 * Skip the mode select header and block descriptors. 04232 */ 04233 if (Use6Byte){ 04234 blockDescriptorLength = ((PMODE_PARAMETER_HEADER) ModeSenseBuffer)->BlockDescriptorLength; 04235 } 04236 else { 04237 modeParam10 = (PMODE_PARAMETER_HEADER10) ModeSenseBuffer; 04238 blockDescriptorLength = modeParam10->BlockDescriptorLength[1]; 04239 } 04240 04241 ModeSenseBuffer += parameterHeaderLength + blockDescriptorLength; 04242 04243 // 04244 // ModeSenseBuffer now points at pages. Walk the pages looking for the 04245 // requested page until the limit is reached. 04246 // 04247 04248 while (ModeSenseBuffer + 04249 RTL_SIZEOF_THROUGH_FIELD(MODE_DISCONNECT_PAGE, PageLength) < limit) { 04250 04251 if (((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageCode == PageMode) { 04252 04253 /* 04254 * found the mode page. make sure it's safe to touch it all 04255 * before returning the pointer to caller 04256 */ 04257 04258 if (ModeSenseBuffer + ((PMODE_DISCONNECT_PAGE)ModeSenseBuffer)->PageLength > limit) { 04259 /* 04260 * Return NULL since the page is not safe to access in full 04261 */ 04262 result = NULL; 04263 } 04264 else { 04265 result = ModeSenseBuffer; 04266 } 04267 break; 04268 } 04269 04270 // 04271 // Advance to the next page which is 4-byte-aligned offset after this page. 04272 // 04273 ModeSenseBuffer += 04274 ((PMODE_DISCONNECT_PAGE) ModeSenseBuffer)->PageLength + 04275 RTL_SIZEOF_THROUGH_FIELD(MODE_DISCONNECT_PAGE, PageLength); 04276 04277 } 04278 } 04279 04280 return result; 04281 } // end ClassFindModePage() 04282 04283 /*++//////////////////////////////////////////////////////////////////////////// 04284 04285 ClassSendSrbAsynchronous() 04286 04287 Routine Description: 04288 04289 This routine takes a partially built Srb and an Irp and sends it down to 04290 the port driver. 04291 04292 This routine must be called with the remove lock held for the specified 04293 Irp. 04294 04295 Arguments: 04296 04297 Fdo - Supplies the functional device object for the orginal request. 04298 04299 Srb - Supplies a paritally build ScsiRequestBlock. In particular, the 04300 CDB and the SRB timeout value must be filled in. The SRB must not be 04301 allocated from zone. 04302 04303 Irp - Supplies the requesting Irp. 04304 04305 BufferAddress - Supplies a pointer to the buffer to be transfered. 04306 04307 BufferLength - Supplies the length of data transfer. 04308 04309 WriteToDevice - Indicates the data transfer will be from system memory to 04310 device. 04311 04312 Return Value: 04313 04314 Returns STATUS_PENDING if the request is dispatched (since the 04315 completion routine may change the irp's status value we cannot simply 04316 return the value of the dispatch) 04317 04318 or returns a status value to indicate why it failed. 04319 04320 --*/ 04321 NTSTATUS 04322 ClassSendSrbAsynchronous( 04323 PDEVICE_OBJECT Fdo, 04324 PSCSI_REQUEST_BLOCK Srb, 04325 PIRP Irp, 04326 PVOID BufferAddress, 04327 ULONG BufferLength, 04328 BOOLEAN WriteToDevice 04329 ) 04330 { 04331 04332 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 04333 PIO_STACK_LOCATION irpStack; 04334 04335 ULONG savedFlags; 04336 04337 // 04338 // Write length to SRB. 04339 // 04340 04341 Srb->Length = sizeof(SCSI_REQUEST_BLOCK); 04342 04343 // 04344 // Set SCSI bus address. 04345 // 04346 04347 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI; 04348 04349 // 04350 // This is a violation of the SCSI spec but it is required for 04351 // some targets. 04352 // 04353 04354 // Srb->Cdb[1] |= deviceExtension->Lun << 5; 04355 04356 // 04357 // Indicate auto request sense by specifying buffer and size. 04358 // 04359 04360 Srb->SenseInfoBuffer = fdoExtension->SenseData; 04361 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; 04362 Srb->DataBuffer = BufferAddress; 04363 04364 // 04365 // Save the class driver specific flags away. 04366 // 04367 04368 savedFlags = Srb->SrbFlags & SRB_FLAGS_CLASS_DRIVER_RESERVED; 04369 04370 // 04371 // Allow the caller to specify that they do not wish 04372 // IoStartNextPacket() to be called in the completion routine. 04373 // 04374 04375 SET_FLAG(savedFlags, (Srb->SrbFlags & SRB_FLAGS_DONT_START_NEXT_PACKET)); 04376 04377 if (BufferAddress != NULL) { 04378 04379 // 04380 // Build Mdl if necessary. 04381 // 04382 04383 if (Irp->MdlAddress == NULL) { 04384 04385 if (IoAllocateMdl(BufferAddress, 04386 BufferLength, 04387 FALSE, 04388 FALSE, 04389 Irp) == NULL) { 04390 04391 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 04392 04393 // 04394 // ClassIoComplete() would have free'd the srb 04395 // 04396 04397 if (PORT_ALLOCATED_SENSE(fdoExtension, Srb)) { 04398 FREE_PORT_ALLOCATED_SENSE_BUFFER(fdoExtension, Srb); 04399 } 04400 ClassFreeOrReuseSrb(fdoExtension, Srb); 04401 ClassReleaseRemoveLock(Fdo, Irp); 04402 ClassCompleteRequest(Fdo, Irp, IO_NO_INCREMENT); 04403 04404 return STATUS_INSUFFICIENT_RESOURCES; 04405 } 04406 04407 MmBuildMdlForNonPagedPool(Irp->MdlAddress); 04408 04409 } else { 04410 04411 // 04412 // Make sure the buffer requested matches the MDL. 04413 // 04414 04415 ASSERT(BufferAddress == MmGetMdlVirtualAddress(Irp->MdlAddress)); 04416 } 04417 04418 // 04419 // Set read flag. 04420 // 04421 04422 Srb->SrbFlags = WriteToDevice ? SRB_FLAGS_DATA_OUT : SRB_FLAGS_DATA_IN; 04423 04424 } else { 04425 04426 // 04427 // Clear flags. 04428 // 04429 04430 Srb->SrbFlags = SRB_FLAGS_NO_DATA_TRANSFER; 04431 } 04432 04433 // 04434 // Restore saved flags. 04435 // 04436 04437 SET_FLAG(Srb->SrbFlags, savedFlags); 04438 04439 // 04440 // Disable synchronous transfer for these requests. 04441 // 04442 04443 SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); 04444 04445 // 04446 // Set the transfer length. 04447 // 04448 04449 Srb->DataTransferLength = BufferLength; 04450 04451 // 04452 // Zero out status. 04453 // 04454 04455 Srb->ScsiStatus = Srb->SrbStatus = 0; 04456 04457 Srb->NextSrb = 0; 04458 04459 // 04460 // Save a few parameters in the current stack location. 04461 // 04462 04463 irpStack = IoGetCurrentIrpStackLocation(Irp); 04464 04465 // 04466 // Save retry count in current Irp stack. 04467 // 04468 04469 irpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES; 04470 04471 // 04472 // Set up IoCompletion routine address. 04473 // 04474 04475 IoSetCompletionRoutine(Irp, ClassIoComplete, Srb, TRUE, TRUE, TRUE); 04476 04477 // 04478 // Get next stack location and 04479 // set major function code. 04480 // 04481 04482 irpStack = IoGetNextIrpStackLocation(Irp); 04483 04484 irpStack->MajorFunction = IRP_MJ_SCSI; 04485 04486 // 04487 // Save SRB address in next stack for port driver. 04488 // 04489 04490 irpStack->Parameters.Scsi.Srb = Srb; 04491 04492 // 04493 // Set up Irp Address. 04494 // 04495 04496 Srb->OriginalRequest = Irp; 04497 04498 // 04499 // Call the port driver to process the request. 04500 // 04501 04502 IoMarkIrpPending(Irp); 04503 04504 IoCallDriver(fdoExtension->CommonExtension.LowerDeviceObject, Irp); 04505 04506 return STATUS_PENDING; 04507 04508 } // end ClassSendSrbAsynchronous() 04509 04510 /*++//////////////////////////////////////////////////////////////////////////// 04511 04512 ClassDeviceControlDispatch() 04513 04514 Routine Description: 04515 04516 The routine is the common class driver device control dispatch entry point. 04517 This routine is invokes the device-specific drivers DeviceControl routine, 04518 (which may call the Class driver's common DeviceControl routine). 04519 04520 Arguments: 04521 04522 DeviceObject - Supplies a pointer to the device object for this request. 04523 04524 Irp - Supplies the Irp making the request. 04525 04526 Return Value: 04527 04528 Returns the status returned from the device-specific driver. 04529 04530 --*/ 04531 NTSTATUS 04532 ClassDeviceControlDispatch( 04533 PDEVICE_OBJECT DeviceObject, 04534 PIRP Irp 04535 ) 04536 { 04537 04538 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 04539 ULONG isRemoved; 04540 04541 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 04542 04543 if(isRemoved) { 04544 04545 ClassReleaseRemoveLock(DeviceObject, Irp); 04546 04547 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 04548 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 04549 return STATUS_DEVICE_DOES_NOT_EXIST; 04550 } 04551 04552 // 04553 // Call the class specific driver DeviceControl routine. 04554 // If it doesn't handle it, it will call back into ClassDeviceControl. 04555 // 04556 04557 ASSERT(commonExtension->DevInfo->ClassDeviceControl); 04558 04559 return commonExtension->DevInfo->ClassDeviceControl(DeviceObject,Irp); 04560 } // end ClassDeviceControlDispatch() 04561 04562 04563 /*++//////////////////////////////////////////////////////////////////////////// 04564 04565 ClassDeviceControl() 04566 04567 Routine Description: 04568 04569 The routine is the common class driver device control dispatch function. 04570 This routine is called by a class driver when it get an unrecognized 04571 device control request. This routine will perform the correct action for 04572 common requests such as lock media. If the device request is unknown it 04573 passed down to the next level. 04574 04575 This routine must be called with the remove lock held for the specified 04576 irp. 04577 04578 Arguments: 04579 04580 DeviceObject - Supplies a pointer to the device object for this request. 04581 04582 Irp - Supplies the Irp making the request. 04583 04584 Return Value: 04585 04586 Returns back a STATUS_PENDING or a completion status. 04587 04588 --*/ 04589 NTSTATUS 04590 ClassDeviceControl( 04591 PDEVICE_OBJECT DeviceObject, 04592 PIRP Irp 04593 ) 04594 { 04595 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 04596 04597 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 04598 PIO_STACK_LOCATION nextStack = NULL; 04599 04600 ULONG controlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; 04601 04602 PSCSI_REQUEST_BLOCK srb = NULL; 04603 PCDB cdb = NULL; 04604 04605 NTSTATUS status; 04606 ULONG modifiedIoControlCode; 04607 04608 // 04609 // If this is a pass through I/O control, set the minor function code 04610 // and device address and pass it to the port driver. 04611 // 04612 04613 if ((controlCode == IOCTL_SCSI_PASS_THROUGH) || 04614 (controlCode == IOCTL_SCSI_PASS_THROUGH_DIRECT)) { 04615 04616 PSCSI_PASS_THROUGH scsiPass; 04617 04618 // 04619 // Validiate the user buffer. 04620 // 04621 #if defined (_WIN64) 04622 04623 if (IoIs32bitProcess(Irp)) { 04624 04625 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32)){ 04626 04627 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 04628 04629 ClassReleaseRemoveLock(DeviceObject, Irp); 04630 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 04631 04632 status = STATUS_INVALID_PARAMETER; 04633 goto SetStatusAndReturn; 04634 } 04635 } 04636 else 04637 #endif 04638 { 04639 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 04640 sizeof(SCSI_PASS_THROUGH)) { 04641 04642 Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; 04643 04644 ClassReleaseRemoveLock(DeviceObject, Irp); 04645 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 04646 04647 status = STATUS_INVALID_PARAMETER; 04648 goto SetStatusAndReturn; 04649 } 04650 } 04651 04652 IoCopyCurrentIrpStackLocationToNext(Irp); 04653 04654 nextStack = IoGetNextIrpStackLocation(Irp); 04655 nextStack->MinorFunction = 1; 04656 04657 ClassReleaseRemoveLock(DeviceObject, Irp); 04658 04659 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 04660 goto SetStatusAndReturn; 04661 } 04662 04663 Irp->IoStatus.Information = 0; 04664 04665 switch (controlCode) { 04666 04667 case IOCTL_MOUNTDEV_QUERY_UNIQUE_ID: { 04668 04669 PMOUNTDEV_UNIQUE_ID uniqueId; 04670 04671 if (!commonExtension->MountedDeviceInterfaceName.Buffer) { 04672 status = STATUS_INVALID_PARAMETER; 04673 break; 04674 } 04675 04676 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 04677 sizeof(MOUNTDEV_UNIQUE_ID)) { 04678 04679 status = STATUS_BUFFER_TOO_SMALL; 04680 Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID); 04681 break; 04682 } 04683 04684 uniqueId = Irp->AssociatedIrp.SystemBuffer; 04685 uniqueId->UniqueIdLength = 04686 commonExtension->MountedDeviceInterfaceName.Length; 04687 04688 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 04689 sizeof(USHORT) + uniqueId->UniqueIdLength) { 04690 04691 status = STATUS_BUFFER_OVERFLOW; 04692 Irp->IoStatus.Information = sizeof(MOUNTDEV_UNIQUE_ID); 04693 break; 04694 } 04695 04696 RtlCopyMemory(uniqueId->UniqueId, 04697 commonExtension->MountedDeviceInterfaceName.Buffer, 04698 uniqueId->UniqueIdLength); 04699 04700 status = STATUS_SUCCESS; 04701 Irp->IoStatus.Information = sizeof(USHORT) + 04702 uniqueId->UniqueIdLength; 04703 break; 04704 } 04705 04706 case IOCTL_MOUNTDEV_QUERY_DEVICE_NAME: { 04707 04708 PMOUNTDEV_NAME name; 04709 04710 ASSERT(commonExtension->DeviceName.Buffer); 04711 04712 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 04713 sizeof(MOUNTDEV_NAME)) { 04714 04715 status = STATUS_BUFFER_TOO_SMALL; 04716 Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME); 04717 break; 04718 } 04719 04720 name = Irp->AssociatedIrp.SystemBuffer; 04721 name->NameLength = commonExtension->DeviceName.Length; 04722 04723 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 04724 sizeof(USHORT) + name->NameLength) { 04725 04726 status = STATUS_BUFFER_OVERFLOW; 04727 Irp->IoStatus.Information = sizeof(MOUNTDEV_NAME); 04728 break; 04729 } 04730 04731 RtlCopyMemory(name->Name, commonExtension->DeviceName.Buffer, 04732 name->NameLength); 04733 04734 status = STATUS_SUCCESS; 04735 Irp->IoStatus.Information = sizeof(USHORT) + name->NameLength; 04736 break; 04737 } 04738 04739 case IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME: { 04740 04741 PMOUNTDEV_SUGGESTED_LINK_NAME suggestedName; 04742 WCHAR driveLetterNameBuffer[10]; 04743 RTL_QUERY_REGISTRY_TABLE queryTable[2]; 04744 PWSTR valueName; 04745 UNICODE_STRING driveLetterName; 04746 04747 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 04748 sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) { 04749 04750 status = STATUS_BUFFER_TOO_SMALL; 04751 Irp->IoStatus.Information = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME); 04752 break; 04753 } 04754 04755 valueName = ExAllocatePoolWithTag( 04756 PagedPool, 04757 commonExtension->DeviceName.Length + sizeof(WCHAR), 04758 '8CcS'); 04759 04760 if (!valueName) { 04761 status = STATUS_INSUFFICIENT_RESOURCES; 04762 break; 04763 } 04764 04765 RtlCopyMemory(valueName, commonExtension->DeviceName.Buffer, 04766 commonExtension->DeviceName.Length); 04767 valueName[commonExtension->DeviceName.Length/sizeof(WCHAR)] = 0; 04768 04769 driveLetterName.Buffer = driveLetterNameBuffer; 04770 driveLetterName.MaximumLength = 20; 04771 driveLetterName.Length = 0; 04772 04773 RtlZeroMemory(queryTable, 2*sizeof(RTL_QUERY_REGISTRY_TABLE)); 04774 queryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | 04775 RTL_QUERY_REGISTRY_DIRECT; 04776 queryTable[0].Name = valueName; 04777 queryTable[0].EntryContext = &driveLetterName; 04778 04779 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, 04780 L"\\Registry\\Machine\\System\\DISK", 04781 queryTable, NULL, NULL); 04782 04783 if (!NT_SUCCESS(status)) { 04784 ExFreePool(valueName); 04785 break; 04786 } 04787 04788 if (driveLetterName.Length == 4 && 04789 driveLetterName.Buffer[0] == '%' && 04790 driveLetterName.Buffer[1] == ':') { 04791 04792 driveLetterName.Buffer[0] = 0xFF; 04793 04794 } else if (driveLetterName.Length != 4 || 04795 driveLetterName.Buffer[0] < FirstDriveLetter || 04796 driveLetterName.Buffer[0] > LastDriveLetter || 04797 driveLetterName.Buffer[1] != ':') { 04798 04799 status = STATUS_NOT_FOUND; 04800 ExFreePool(valueName); 04801 break; 04802 } 04803 04804 suggestedName = Irp->AssociatedIrp.SystemBuffer; 04805 suggestedName->UseOnlyIfThereAreNoOtherLinks = TRUE; 04806 suggestedName->NameLength = 28; 04807 04808 Irp->IoStatus.Information = 04809 FIELD_OFFSET(MOUNTDEV_SUGGESTED_LINK_NAME, Name) + 28; 04810 04811 if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < 04812 Irp->IoStatus.Information) { 04813 04814 Irp->IoStatus.Information = 04815 sizeof(MOUNTDEV_SUGGESTED_LINK_NAME); 04816 status = STATUS_BUFFER_OVERFLOW; 04817 ExFreePool(valueName); 04818 break; 04819 } 04820 04821 RtlDeleteRegistryValue(RTL_REGISTRY_ABSOLUTE, 04822 L"\\Registry\\Machine\\System\\DISK", 04823 valueName); 04824 04825 ExFreePool(valueName); 04826 04827 RtlCopyMemory(suggestedName->Name, L"\\DosDevices\\", 24); 04828 suggestedName->Name[12] = driveLetterName.Buffer[0]; 04829 suggestedName->Name[13] = ':'; 04830 04831 // 04832 // NT_SUCCESS(status) based on RtlQueryRegistryValues 04833 // 04834 status = STATUS_SUCCESS; 04835 04836 break; 04837 } 04838 04839 default: 04840 status = STATUS_PENDING; 04841 break; 04842 } 04843 04844 if (status != STATUS_PENDING) { 04845 ClassReleaseRemoveLock(DeviceObject, Irp); 04846 Irp->IoStatus.Status = status; 04847 IoCompleteRequest(Irp, IO_NO_INCREMENT); 04848 return status; 04849 } 04850 04851 if (commonExtension->IsFdo){ 04852 04853 PULONG_PTR function; 04854 04855 srb = ExAllocatePoolWithTag(NonPagedPool, 04856 sizeof(SCSI_REQUEST_BLOCK) + 04857 (sizeof(ULONG_PTR) * 2), 04858 '9CcS'); 04859 04860 if (srb == NULL) { 04861 04862 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 04863 ClassReleaseRemoveLock(DeviceObject, Irp); 04864 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 04865 status = STATUS_INSUFFICIENT_RESOURCES; 04866 goto SetStatusAndReturn; 04867 } 04868 04869 RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK)); 04870 04871 cdb = (PCDB)srb->Cdb; 04872 04873 // 04874 // Save the function code and the device object in the memory after 04875 // the SRB. 04876 // 04877 04878 function = (PULONG_PTR) ((PSCSI_REQUEST_BLOCK) (srb + 1)); 04879 *function = (ULONG_PTR) DeviceObject; 04880 function++; 04881 *function = (ULONG_PTR) controlCode; 04882 04883 } else { 04884 srb = NULL; 04885 } 04886 04887 // 04888 // Change the device type to storage for the switch statement, but only 04889 // if from a legacy device type 04890 // 04891 04892 if (((controlCode & 0xffff0000) == (IOCTL_DISK_BASE << 16)) || 04893 ((controlCode & 0xffff0000) == (IOCTL_TAPE_BASE << 16)) || 04894 ((controlCode & 0xffff0000) == (IOCTL_CDROM_BASE << 16)) 04895 ) { 04896 04897 modifiedIoControlCode = (controlCode & ~0xffff0000); 04898 modifiedIoControlCode |= (IOCTL_STORAGE_BASE << 16); 04899 04900 } else { 04901 04902 modifiedIoControlCode = controlCode; 04903 04904 } 04905 04906 DBGTRACE(ClassDebugTrace, ("> ioctl %xh (%s)", modifiedIoControlCode, DBGGETIOCTLSTR(modifiedIoControlCode))); 04907 04908 switch (modifiedIoControlCode) { 04909 04910 case IOCTL_STORAGE_GET_HOTPLUG_INFO: { 04911 04912 if (srb) { 04913 ExFreePool(srb); 04914 srb = NULL; 04915 } 04916 04917 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength < 04918 sizeof(STORAGE_HOTPLUG_INFO)) { 04919 04920 // 04921 // Indicate unsuccessful status and no data transferred. 04922 // 04923 04924 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 04925 Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO); 04926 04927 ClassReleaseRemoveLock(DeviceObject, Irp); 04928 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 04929 status = STATUS_BUFFER_TOO_SMALL; 04930 04931 } else if(!commonExtension->IsFdo) { 04932 04933 // 04934 // Just forward this down and return 04935 // 04936 04937 IoCopyCurrentIrpStackLocationToNext(Irp); 04938 04939 ClassReleaseRemoveLock(DeviceObject, Irp); 04940 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 04941 04942 } else { 04943 04944 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 04945 PSTORAGE_HOTPLUG_INFO info; 04946 04947 fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)commonExtension; 04948 info = Irp->AssociatedIrp.SystemBuffer; 04949 04950 *info = fdoExtension->PrivateFdoData->HotplugInfo; 04951 Irp->IoStatus.Status = STATUS_SUCCESS; 04952 Irp->IoStatus.Information = sizeof(STORAGE_HOTPLUG_INFO); 04953 ClassReleaseRemoveLock(DeviceObject, Irp); 04954 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 04955 status = STATUS_SUCCESS; 04956 04957 } 04958 break; 04959 } 04960 04961 case IOCTL_STORAGE_SET_HOTPLUG_INFO: { 04962 04963 if (srb) 04964 { 04965 ExFreePool(srb); 04966 srb = NULL; 04967 } 04968 04969 if (irpStack->Parameters.DeviceIoControl.InputBufferLength < 04970 sizeof(STORAGE_HOTPLUG_INFO)) { 04971 04972 // 04973 // Indicate unsuccessful status and no data transferred. 04974 // 04975 04976 Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH; 04977 04978 ClassReleaseRemoveLock(DeviceObject, Irp); 04979 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 04980 status = STATUS_INFO_LENGTH_MISMATCH; 04981 goto SetStatusAndReturn; 04982 04983 } 04984 04985 if(!commonExtension->IsFdo) { 04986 04987 // 04988 // Just forward this down and return 04989 // 04990 04991 IoCopyCurrentIrpStackLocationToNext(Irp); 04992 04993 ClassReleaseRemoveLock(DeviceObject, Irp); 04994 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 04995 04996 } else { 04997 04998 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PFUNCTIONAL_DEVICE_EXTENSION)commonExtension; 04999 PSTORAGE_HOTPLUG_INFO info = Irp->AssociatedIrp.SystemBuffer; 05000 05001 status = STATUS_SUCCESS; 05002 05003 if (info->Size != fdoExtension->PrivateFdoData->HotplugInfo.Size) 05004 { 05005 status = STATUS_INVALID_PARAMETER_1; 05006 } 05007 05008 if (info->MediaRemovable != fdoExtension->PrivateFdoData->HotplugInfo.MediaRemovable) 05009 { 05010 status = STATUS_INVALID_PARAMETER_2; 05011 } 05012 05013 if (info->MediaHotplug != fdoExtension->PrivateFdoData->HotplugInfo.MediaHotplug) 05014 { 05015 status = STATUS_INVALID_PARAMETER_3; 05016 } 05017 05018 if (info->WriteCacheEnableOverride != fdoExtension->PrivateFdoData->HotplugInfo.WriteCacheEnableOverride) 05019 { 05020 status = STATUS_INVALID_PARAMETER_5; 05021 } 05022 05023 if (NT_SUCCESS(status)) 05024 { 05025 fdoExtension->PrivateFdoData->HotplugInfo.DeviceHotplug = info->DeviceHotplug; 05026 05027 // 05028 // Store the user-defined override in the registry 05029 // 05030 05031 ClassSetDeviceParameter(fdoExtension, 05032 CLASSP_REG_SUBKEY_NAME, 05033 CLASSP_REG_REMOVAL_POLICY_VALUE_NAME, 05034 (info->DeviceHotplug) ? RemovalPolicyExpectSurpriseRemoval : RemovalPolicyExpectOrderlyRemoval); 05035 } 05036 05037 Irp->IoStatus.Status = status; 05038 05039 ClassReleaseRemoveLock(DeviceObject, Irp); 05040 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 05041 } 05042 05043 break; 05044 } 05045 05046 case IOCTL_STORAGE_CHECK_VERIFY: 05047 case IOCTL_STORAGE_CHECK_VERIFY2: { 05048 05049 PIRP irp2 = NULL; 05050 PIO_STACK_LOCATION newStack; 05051 05052 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL; 05053 05054 DebugPrint((1,"DeviceIoControl: Check verify\n")); 05055 05056 // 05057 // If a buffer for a media change count was provided, make sure it's 05058 // big enough to hold the result 05059 // 05060 05061 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) { 05062 05063 // 05064 // If the buffer is too small to hold the media change count 05065 // then return an error to the caller 05066 // 05067 05068 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength < 05069 sizeof(ULONG)) { 05070 05071 DebugPrint((3,"DeviceIoControl: media count " 05072 "buffer too small\n")); 05073 05074 Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; 05075 Irp->IoStatus.Information = sizeof(ULONG); 05076 05077 if(srb != NULL) { 05078 ExFreePool(srb); 05079 } 05080 05081 ClassReleaseRemoveLock(DeviceObject, Irp); 05082 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 05083 05084 status = STATUS_BUFFER_TOO_SMALL; 05085 goto SetStatusAndReturn; 05086 05087 } 05088 } 05089 05090 if(!commonExtension->IsFdo) { 05091 05092 // 05093 // If this is a PDO then we should just forward the request down 05094 // 05095 ASSERT(!srb); 05096 05097 IoCopyCurrentIrpStackLocationToNext(Irp); 05098 05099 ClassReleaseRemoveLock(DeviceObject, Irp); 05100 05101 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 05102 05103 goto SetStatusAndReturn; 05104 05105 } else { 05106 05107 fdoExtension = DeviceObject->DeviceExtension; 05108 05109 } 05110 05111 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength) { 05112 05113 // 05114 // The caller has provided a valid buffer. Allocate an additional 05115 // irp and stick the CheckVerify completion routine on it. We will 05116 // then send this down to the port driver instead of the irp the 05117 // caller sent in 05118 // 05119 05120 DebugPrint((2,"DeviceIoControl: Check verify wants " 05121 "media count\n")); 05122 05123 // 05124 // Allocate a new irp to send the TestUnitReady to the port driver 05125 // 05126 05127 irp2 = IoAllocateIrp((CCHAR) (DeviceObject->StackSize + 3), FALSE); 05128 05129 if(irp2 == NULL) { 05130 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 05131 Irp->IoStatus.Information = 0; 05132 ASSERT(srb); 05133 ExFreePool(srb); 05134 ClassReleaseRemoveLock(DeviceObject, Irp); 05135 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 05136 status = STATUS_INSUFFICIENT_RESOURCES; 05137 goto SetStatusAndReturn; 05138 05139 break; 05140 } 05141 05142 // 05143 // Make sure to acquire the lock for the new irp. 05144 // 05145 05146 ClassAcquireRemoveLock(DeviceObject, irp2); 05147 05148 irp2->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread; 05149 IoSetNextIrpStackLocation(irp2); 05150 05151 // 05152 // Set the top stack location and shove the master Irp into the 05153 // top location 05154 // 05155 05156 newStack = IoGetCurrentIrpStackLocation(irp2); 05157 newStack->Parameters.Others.Argument1 = Irp; 05158 newStack->DeviceObject = DeviceObject; 05159 05160 // 05161 // Stick the check verify completion routine onto the stack 05162 // and prepare the irp for the port driver 05163 // 05164 05165 IoSetCompletionRoutine(irp2, 05166 ClassCheckVerifyComplete, 05167 NULL, 05168 TRUE, 05169 TRUE, 05170 TRUE); 05171 05172 IoSetNextIrpStackLocation(irp2); 05173 newStack = IoGetCurrentIrpStackLocation(irp2); 05174 newStack->DeviceObject = DeviceObject; 05175 newStack->MajorFunction = irpStack->MajorFunction; 05176 newStack->MinorFunction = irpStack->MinorFunction; 05177 05178 // 05179 // Mark the master irp as pending - whether the lower level 05180 // driver completes it immediately or not this should allow it 05181 // to go all the way back up. 05182 // 05183 05184 IoMarkIrpPending(Irp); 05185 05186 Irp = irp2; 05187 05188 } 05189 05190 // 05191 // Test Unit Ready 05192 // 05193 05194 srb->CdbLength = 6; 05195 cdb->CDB6GENERIC.OperationCode = SCSIOP_TEST_UNIT_READY; 05196 05197 // 05198 // Set timeout value. 05199 // 05200 05201 srb->TimeOutValue = fdoExtension->TimeOutValue; 05202 05203 // 05204 // If this was a CV2 then mark the request as low-priority so we don't 05205 // spin up the drive just to satisfy it. 05206 // 05207 05208 if(controlCode == IOCTL_STORAGE_CHECK_VERIFY2) { 05209 SET_FLAG(srb->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY); 05210 } 05211 05212 // 05213 // Since this routine will always hand the request to the 05214 // port driver if there isn't a data transfer to be done 05215 // we don't have to worry about completing the request here 05216 // on an error 05217 // 05218 05219 // 05220 // This routine uses a completion routine so we don't want to release 05221 // the remove lock until then. 05222 // 05223 05224 status = ClassSendSrbAsynchronous(DeviceObject, 05225 srb, 05226 Irp, 05227 NULL, 05228 0, 05229 FALSE); 05230 05231 break; 05232 } 05233 05234 case IOCTL_STORAGE_MEDIA_REMOVAL: 05235 case IOCTL_STORAGE_EJECTION_CONTROL: { 05236 05237 PPREVENT_MEDIA_REMOVAL mediaRemoval = Irp->AssociatedIrp.SystemBuffer; 05238 05239 DebugPrint((3, "DiskIoControl: ejection control\n")); 05240 05241 if(srb) { 05242 ExFreePool(srb); 05243 } 05244 05245 if(irpStack->Parameters.DeviceIoControl.InputBufferLength < 05246 sizeof(PREVENT_MEDIA_REMOVAL)) { 05247 05248 // 05249 // Indicate unsuccessful status and no data transferred. 05250 // 05251 05252 Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH; 05253 05254 ClassReleaseRemoveLock(DeviceObject, Irp); 05255 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 05256 status = STATUS_INFO_LENGTH_MISMATCH; 05257 goto SetStatusAndReturn; 05258 } 05259 05260 if(!commonExtension->IsFdo) { 05261 05262 // 05263 // Just forward this down and return 05264 // 05265 05266 IoCopyCurrentIrpStackLocationToNext(Irp); 05267 05268 ClassReleaseRemoveLock(DeviceObject, Irp); 05269 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 05270 } 05271 else { 05272 05273 // i don't believe this assertion is valid. this is a request 05274 // from user-mode, so they could request this for any device 05275 // they want? also, we handle it properly. 05276 // ASSERT(TEST_FLAG(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)); 05277 status = ClasspEjectionControl( 05278 DeviceObject, 05279 Irp, 05280 ((modifiedIoControlCode == 05281 IOCTL_STORAGE_EJECTION_CONTROL) ? SecureMediaLock : 05282 SimpleMediaLock), 05283 mediaRemoval->PreventMediaRemoval); 05284 05285 Irp->IoStatus.Status = status; 05286 ClassReleaseRemoveLock(DeviceObject, Irp); 05287 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 05288 } 05289 05290 break; 05291 } 05292 05293 case IOCTL_STORAGE_MCN_CONTROL: { 05294 05295 DebugPrint((3, "DiskIoControl: MCN control\n")); 05296 05297 if(irpStack->Parameters.DeviceIoControl.InputBufferLength < 05298 sizeof(PREVENT_MEDIA_REMOVAL)) { 05299 05300 // 05301 // Indicate unsuccessful status and no data transferred. 05302 // 05303 05304 Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH; 05305 Irp->IoStatus.Information = 0; 05306 05307 if(srb) { 05308 ExFreePool(srb); 05309 } 05310 05311 ClassReleaseRemoveLock(DeviceObject, Irp); 05312 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 05313 status = STATUS_INFO_LENGTH_MISMATCH; 05314 goto SetStatusAndReturn; 05315 } 05316 05317 if(!commonExtension->IsFdo) { 05318 05319 // 05320 // Just forward this down and return 05321 // 05322 05323 if(srb) { 05324 ExFreePool(srb); 05325 } 05326 05327 IoCopyCurrentIrpStackLocationToNext(Irp); 05328 05329 ClassReleaseRemoveLock(DeviceObject, Irp); 05330 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 05331 05332 } else { 05333 05334 // 05335 // Call to the FDO - handle the ejection control. 05336 // 05337 05338 status = ClasspMcnControl(DeviceObject->DeviceExtension, 05339 Irp, 05340 srb); 05341 } 05342 goto SetStatusAndReturn; 05343 } 05344 05345 case IOCTL_STORAGE_RESERVE: 05346 case IOCTL_STORAGE_RELEASE: { 05347 05348 // 05349 // Reserve logical unit. 05350 // 05351 05352 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL; 05353 05354 if(!commonExtension->IsFdo) { 05355 05356 IoCopyCurrentIrpStackLocationToNext(Irp); 05357 05358 ClassReleaseRemoveLock(DeviceObject, Irp); 05359 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 05360 goto SetStatusAndReturn; 05361 } else { 05362 fdoExtension = DeviceObject->DeviceExtension; 05363 } 05364 05365 srb->CdbLength = 6; 05366 05367 if(modifiedIoControlCode == IOCTL_STORAGE_RESERVE) { 05368 cdb->CDB6GENERIC.OperationCode = SCSIOP_RESERVE_UNIT; 05369 } else { 05370 cdb->CDB6GENERIC.OperationCode = SCSIOP_RELEASE_UNIT; 05371 } 05372 05373 // 05374 // Set timeout value. 05375 // 05376 05377 srb->TimeOutValue = fdoExtension->TimeOutValue; 05378 05379 status = ClassSendSrbAsynchronous(DeviceObject, 05380 srb, 05381 Irp, 05382 NULL, 05383 0, 05384 FALSE); 05385 05386 break; 05387 } 05388 05389 case IOCTL_STORAGE_EJECT_MEDIA: 05390 case IOCTL_STORAGE_LOAD_MEDIA: 05391 case IOCTL_STORAGE_LOAD_MEDIA2:{ 05392 05393 // 05394 // Eject media. 05395 // 05396 05397 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = NULL; 05398 05399 if(!commonExtension->IsFdo) { 05400 05401 IoCopyCurrentIrpStackLocationToNext(Irp); 05402 05403 ClassReleaseRemoveLock(DeviceObject, Irp); 05404 05405 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 05406 goto SetStatusAndReturn; 05407 } else { 05408 fdoExtension = DeviceObject->DeviceExtension; 05409 } 05410 05411 if(commonExtension->PagingPathCount != 0) { 05412 05413 DebugPrint((1, "ClassDeviceControl: call to eject paging device - " 05414 "failure\n")); 05415 05416 status = STATUS_FILES_OPEN; 05417 Irp->IoStatus.Status = status; 05418 05419 Irp->IoStatus.Information = 0; 05420 05421 if(srb) { 05422 ExFreePool(srb); 05423 } 05424 05425 ClassReleaseRemoveLock(DeviceObject, Irp); 05426 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 05427 goto SetStatusAndReturn; 05428 } 05429 05430 // 05431 // Synchronize with ejection control and ejection cleanup code as 05432 // well as other eject/load requests. 05433 // 05434 05435 KeEnterCriticalRegion(); 05436 KeWaitForSingleObject(&(fdoExtension->EjectSynchronizationEvent), 05437 UserRequest, 05438 UserMode, 05439 FALSE, 05440 NULL); 05441 05442 if(fdoExtension->ProtectedLockCount != 0) { 05443 05444 DebugPrint((1, "ClassDeviceControl: call to eject protected locked " 05445 "device - failure\n")); 05446 05447 status = STATUS_DEVICE_BUSY; 05448 Irp->IoStatus.Status = status; 05449 Irp->IoStatus.Information = 0; 05450 05451 if(srb) { 05452 ExFreePool(srb); 05453 } 05454 05455 ClassReleaseRemoveLock(DeviceObject, Irp); 05456 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 05457 05458 KeSetEvent(&fdoExtension->EjectSynchronizationEvent, 05459 IO_NO_INCREMENT, 05460 FALSE); 05461 KeLeaveCriticalRegion(); 05462 05463 goto SetStatusAndReturn; 05464 } 05465 05466 srb->CdbLength = 6; 05467 05468 cdb->START_STOP.OperationCode = SCSIOP_START_STOP_UNIT; 05469 cdb->START_STOP.LoadEject = 1; 05470 05471 if(modifiedIoControlCode == IOCTL_STORAGE_EJECT_MEDIA) { 05472 cdb->START_STOP.Start = 0; 05473 } else { 05474 cdb->START_STOP.Start = 1; 05475 } 05476 05477 // 05478 // Set timeout value. 05479 // 05480 05481 srb->TimeOutValue = fdoExtension->TimeOutValue; 05482 status = ClassSendSrbAsynchronous(DeviceObject, 05483 srb, 05484 Irp, 05485 NULL, 05486 0, 05487 FALSE); 05488 05489 KeSetEvent(&fdoExtension->EjectSynchronizationEvent, IO_NO_INCREMENT, FALSE); 05490 KeLeaveCriticalRegion(); 05491 05492 break; 05493 } 05494 05495 case IOCTL_STORAGE_FIND_NEW_DEVICES: { 05496 05497 if(srb) { 05498 ExFreePool(srb); 05499 } 05500 05501 if(commonExtension->IsFdo) { 05502 05503 IoInvalidateDeviceRelations( 05504 ((PFUNCTIONAL_DEVICE_EXTENSION) commonExtension)->LowerPdo, 05505 BusRelations); 05506 05507 status = STATUS_SUCCESS; 05508 Irp->IoStatus.Status = status; 05509 05510 ClassReleaseRemoveLock(DeviceObject, Irp); 05511 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 05512 } 05513 else { 05514 05515 IoCopyCurrentIrpStackLocationToNext(Irp); 05516 05517 ClassReleaseRemoveLock(DeviceObject, Irp); 05518 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 05519 } 05520 break; 05521 } 05522 05523 case IOCTL_STORAGE_GET_DEVICE_NUMBER: { 05524 05525 if(srb) { 05526 ExFreePool(srb); 05527 } 05528 05529 if(irpStack->Parameters.DeviceIoControl.OutputBufferLength >= 05530 sizeof(STORAGE_DEVICE_NUMBER)) { 05531 05532 PSTORAGE_DEVICE_NUMBER deviceNumber = 05533 Irp->AssociatedIrp.SystemBuffer; 05534 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = 05535 commonExtension->PartitionZeroExtension; 05536 05537 deviceNumber->DeviceType = fdoExtension->CommonExtension.DeviceObject->DeviceType; 05538 deviceNumber->DeviceNumber = fdoExtension->DeviceNumber; 05539 deviceNumber->PartitionNumber = commonExtension->PartitionNumber; 05540 05541 status = STATUS_SUCCESS; 05542 Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER); 05543 05544 } else { 05545 status = STATUS_BUFFER_TOO_SMALL; 05546 Irp->IoStatus.Information = sizeof(STORAGE_DEVICE_NUMBER); 05547 } 05548 05549 Irp->IoStatus.Status = status; 05550 ClassReleaseRemoveLock(DeviceObject, Irp); 05551 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 05552 05553 break; 05554 } 05555 05556 default: { 05557 05558 DebugPrint((4, "IoDeviceControl: Unsupported device IOCTL %x for %p\n", 05559 controlCode, DeviceObject)); 05560 05561 // 05562 // Pass the device control to the next driver. 05563 // 05564 05565 if(srb) { 05566 ExFreePool(srb); 05567 } 05568 05569 // 05570 // Copy the Irp stack parameters to the next stack location. 05571 // 05572 05573 IoCopyCurrentIrpStackLocationToNext(Irp); 05574 05575 ClassReleaseRemoveLock(DeviceObject, Irp); 05576 status = IoCallDriver(commonExtension->LowerDeviceObject, Irp); 05577 break; 05578 } 05579 05580 } // end switch( ... 05581 05582 SetStatusAndReturn: 05583 05584 DBGTRACE(ClassDebugTrace, ("< ioctl %xh (%s): status %xh.", modifiedIoControlCode, DBGGETIOCTLSTR(modifiedIoControlCode), status)); 05585 05586 return status; 05587 } // end ClassDeviceControl() 05588 05589 /*++//////////////////////////////////////////////////////////////////////////// 05590 05591 ClassShutdownFlush() 05592 05593 Routine Description: 05594 05595 This routine is called for a shutdown and flush IRPs. These are sent by the 05596 system before it actually shuts down or when the file system does a flush. 05597 If it exists, the device-specific driver's routine will be invoked. If there 05598 wasn't one specified, the Irp will be completed with an Invalid device request. 05599 05600 Arguments: 05601 05602 DriverObject - Pointer to device object to being shutdown by system. 05603 05604 Irp - IRP involved. 05605 05606 Return Value: 05607 05608 NT Status 05609 05610 --*/ 05611 NTSTATUS 05612 ClassShutdownFlush( 05613 IN PDEVICE_OBJECT DeviceObject, 05614 IN PIRP Irp 05615 ) 05616 { 05617 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 05618 05619 ULONG isRemoved; 05620 05621 NTSTATUS status; 05622 05623 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 05624 05625 if(isRemoved) { 05626 05627 ClassReleaseRemoveLock(DeviceObject, Irp); 05628 05629 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 05630 05631 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 05632 05633 return STATUS_DEVICE_DOES_NOT_EXIST; 05634 } 05635 05636 if (commonExtension->DevInfo->ClassShutdownFlush) { 05637 05638 // 05639 // Call the device-specific driver's routine. 05640 // 05641 05642 return commonExtension->DevInfo->ClassShutdownFlush(DeviceObject, Irp); 05643 } 05644 05645 // 05646 // Device-specific driver doesn't support this. 05647 // 05648 05649 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; 05650 05651 ClassReleaseRemoveLock(DeviceObject, Irp); 05652 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 05653 05654 return STATUS_INVALID_DEVICE_REQUEST; 05655 } // end ClassShutdownFlush() 05656 05657 /*++//////////////////////////////////////////////////////////////////////////// 05658 05659 ClassCreateDeviceObject() 05660 05661 Routine Description: 05662 05663 This routine creates an object for the physical device specified and 05664 sets up the deviceExtension's function pointers for each entry point 05665 in the device-specific driver. 05666 05667 Arguments: 05668 05669 DriverObject - Pointer to driver object created by system. 05670 05671 ObjectNameBuffer - Dir. name of the object to create. 05672 05673 LowerDeviceObject - Pointer to the lower device object 05674 05675 IsFdo - should this be an fdo or a pdo 05676 05677 DeviceObject - Pointer to the device object pointer we will return. 05678 05679 Return Value: 05680 05681 NTSTATUS 05682 05683 --*/ 05684 NTSTATUS 05685 ClassCreateDeviceObject( 05686 IN PDRIVER_OBJECT DriverObject, 05687 IN PCCHAR ObjectNameBuffer, 05688 IN PDEVICE_OBJECT LowerDevice, 05689 IN BOOLEAN IsFdo, 05690 IN OUT PDEVICE_OBJECT *DeviceObject 05691 ) 05692 { 05693 BOOLEAN isPartitionable; 05694 STRING ntNameString; 05695 UNICODE_STRING ntUnicodeString; 05696 NTSTATUS status, status2; 05697 PDEVICE_OBJECT deviceObject = NULL; 05698 05699 ULONG characteristics; 05700 05701 PCLASS_DRIVER_EXTENSION 05702 driverExtension = IoGetDriverObjectExtension(DriverObject, 05703 CLASS_DRIVER_EXTENSION_KEY); 05704 05705 PCLASS_DEV_INFO devInfo; 05706 05707 PAGED_CODE(); 05708 05709 *DeviceObject = NULL; 05710 RtlInitUnicodeString(&ntUnicodeString, NULL); 05711 05712 DebugPrint((2, "ClassCreateFdo: Create device object\n")); 05713 05714 ASSERT(LowerDevice); 05715 05716 // 05717 // Make sure that if we're making PDO's we have an enumeration routine 05718 // 05719 05720 isPartitionable = (driverExtension->InitData.ClassEnumerateDevice != NULL); 05721 05722 ASSERT(IsFdo || isPartitionable); 05723 05724 // 05725 // Grab the correct dev-info structure out of the init data 05726 // 05727 05728 if(IsFdo) { 05729 devInfo = &(driverExtension->InitData.FdoData); 05730 } else { 05731 devInfo = &(driverExtension->InitData.PdoData); 05732 } 05733 05734 characteristics = devInfo->DeviceCharacteristics; 05735 05736 if(ARGUMENT_PRESENT(ObjectNameBuffer)) { 05737 DebugPrint((2, "ClassCreateFdo: Name is %s\n", ObjectNameBuffer)); 05738 05739 RtlInitString(&ntNameString, ObjectNameBuffer); 05740 05741 status = RtlAnsiStringToUnicodeString(&ntUnicodeString, &ntNameString, TRUE); 05742 05743 if (!NT_SUCCESS(status)) { 05744 05745 DebugPrint((1, 05746 "ClassCreateFdo: Cannot convert string %s\n", 05747 ObjectNameBuffer)); 05748 05749 ntUnicodeString.Buffer = NULL; 05750 return status; 05751 } 05752 } else { 05753 DebugPrint((2, "ClassCreateFdo: Object will be unnamed\n")); 05754 05755 if(IsFdo == FALSE) { 05756 05757 // 05758 // PDO's have to have some sort of name. 05759 // 05760 05761 SET_FLAG(characteristics, FILE_AUTOGENERATED_DEVICE_NAME); 05762 } 05763 05764 RtlInitUnicodeString(&ntUnicodeString, NULL); 05765 } 05766 05767 status = IoCreateDevice(DriverObject, 05768 devInfo->DeviceExtensionSize, 05769 &ntUnicodeString, 05770 devInfo->DeviceType, 05771 devInfo->DeviceCharacteristics, 05772 FALSE, 05773 &deviceObject); 05774 05775 if (!NT_SUCCESS(status)) { 05776 05777 DebugPrint((1, "ClassCreateFdo: Can not create device object %lx\n", 05778 status)); 05779 ASSERT(deviceObject == NULL); 05780 05781 // 05782 // buffer is not used any longer here. 05783 // 05784 05785 if (ntUnicodeString.Buffer != NULL) { 05786 DebugPrint((1, "ClassCreateFdo: Freeing unicode name buffer\n")); 05787 ExFreePool(ntUnicodeString.Buffer); 05788 RtlInitUnicodeString(&ntUnicodeString, NULL); 05789 } 05790 05791 } else { 05792 05793 PCOMMON_DEVICE_EXTENSION commonExtension = deviceObject->DeviceExtension; 05794 05795 RtlZeroMemory( 05796 deviceObject->DeviceExtension, 05797 devInfo->DeviceExtensionSize); 05798 05799 // 05800 // Setup version code 05801 // 05802 05803 commonExtension->Version = 0x03; 05804 05805 // 05806 // Setup the remove lock and event 05807 // 05808 05809 commonExtension->IsRemoved = NO_REMOVE; 05810 commonExtension->RemoveLock = 0; 05811 KeInitializeEvent(&commonExtension->RemoveEvent, 05812 SynchronizationEvent, 05813 FALSE); 05814 05815 #if DBG 05816 KeInitializeSpinLock(&commonExtension->RemoveTrackingSpinlock); 05817 commonExtension->RemoveTrackingList = NULL; 05818 #else 05819 commonExtension->RemoveTrackingSpinlock = (ULONG_PTR) -1; 05820 commonExtension->RemoveTrackingList = (PVOID) -1; 05821 #endif 05822 05823 // 05824 // Acquire the lock once. This reference will be released when the 05825 // remove IRP has been received. 05826 // 05827 05828 ClassAcquireRemoveLock(deviceObject, (PIRP) deviceObject); 05829 05830 // 05831 // Store a pointer to the driver extension so we don't have to do 05832 // lookups to get it. 05833 // 05834 05835 commonExtension->DriverExtension = driverExtension; 05836 05837 // 05838 // Fill in entry points 05839 // 05840 05841 commonExtension->DevInfo = devInfo; 05842 05843 // 05844 // Initialize some of the common values in the structure 05845 // 05846 05847 commonExtension->DeviceObject = deviceObject; 05848 05849 commonExtension->LowerDeviceObject = NULL; 05850 05851 if(IsFdo) { 05852 05853 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = (PVOID) commonExtension; 05854 05855 commonExtension->PartitionZeroExtension = deviceObject->DeviceExtension; 05856 05857 // 05858 // Set the initial device object flags. 05859 // 05860 05861 SET_FLAG(deviceObject->Flags, DO_POWER_PAGABLE); 05862 05863 // 05864 // Clear the PDO list 05865 // 05866 05867 commonExtension->ChildList = NULL; 05868 05869 commonExtension->DriverData = 05870 ((PFUNCTIONAL_DEVICE_EXTENSION) deviceObject->DeviceExtension + 1); 05871 05872 if(isPartitionable) { 05873 05874 commonExtension->PartitionNumber = 0; 05875 } else { 05876 commonExtension->PartitionNumber = (ULONG) (-1L); 05877 } 05878 05879 fdoExtension->DevicePowerState = PowerDeviceD0; 05880 05881 KeInitializeEvent(&fdoExtension->EjectSynchronizationEvent, 05882 SynchronizationEvent, 05883 TRUE); 05884 05885 KeInitializeEvent(&fdoExtension->ChildLock, 05886 SynchronizationEvent, 05887 TRUE); 05888 05889 status = ClasspAllocateReleaseRequest(deviceObject); 05890 05891 if(!NT_SUCCESS(status)) { 05892 IoDeleteDevice(deviceObject); 05893 *DeviceObject = NULL; 05894 05895 if (ntUnicodeString.Buffer != NULL) { 05896 DebugPrint((1, "ClassCreateFdo: Freeing unicode name buffer\n")); 05897 ExFreePool(ntUnicodeString.Buffer); 05898 RtlInitUnicodeString(&ntUnicodeString, NULL); 05899 } 05900 05901 return status; 05902 } 05903 05904 } else { 05905 05906 PPHYSICAL_DEVICE_EXTENSION pdoExtension = 05907 deviceObject->DeviceExtension; 05908 05909 PFUNCTIONAL_DEVICE_EXTENSION p0Extension = 05910 LowerDevice->DeviceExtension; 05911 05912 SET_FLAG(deviceObject->Flags, DO_POWER_PAGABLE); 05913 05914 commonExtension->PartitionZeroExtension = p0Extension; 05915 05916 // 05917 // Stick this onto the PDO list 05918 // 05919 05920 ClassAddChild(p0Extension, pdoExtension, TRUE); 05921 05922 commonExtension->DriverData = (PVOID) (pdoExtension + 1); 05923 05924 // 05925 // Get the top of stack for the lower device - this allows 05926 // filters to get stuck in between the partitions and the 05927 // physical disk. 05928 // 05929 05930 commonExtension->LowerDeviceObject = 05931 IoGetAttachedDeviceReference(LowerDevice); 05932 05933 // 05934 // Pnp will keep a reference to the lower device object long 05935 // after this partition has been deleted. Dereference now so 05936 // we don't have to deal with it later. 05937 // 05938 05939 ObDereferenceObject(commonExtension->LowerDeviceObject); 05940 } 05941 05942 KeInitializeEvent(&commonExtension->PathCountEvent, SynchronizationEvent, TRUE); 05943 05944 commonExtension->IsFdo = IsFdo; 05945 05946 commonExtension->DeviceName = ntUnicodeString; 05947 05948 commonExtension->PreviousState = 0xff; 05949 05950 InitializeDictionary(&(commonExtension->FileObjectDictionary)); 05951 05952 commonExtension->CurrentState = IRP_MN_STOP_DEVICE; 05953 } 05954 05955 *DeviceObject = deviceObject; 05956 05957 return status; 05958 } // end ClassCreateDeviceObject() 05959 05960 /*++//////////////////////////////////////////////////////////////////////////// 05961 05962 ClassClaimDevice() 05963 05964 Routine Description: 05965 05966 This function claims a device in the port driver. The port driver object 05967 is updated with the correct driver object if the device is successfully 05968 claimed. 05969 05970 Arguments: 05971 05972 LowerDeviceObject - Supplies the base port device object. 05973 05974 Release - Indicates the logical unit should be released rather than claimed. 05975 05976 Return Value: 05977 05978 Returns a status indicating success or failure of the operation. 05979 05980 --*/ 05981 NTSTATUS 05982 ClassClaimDevice( 05983 IN PDEVICE_OBJECT LowerDeviceObject, 05984 IN BOOLEAN Release 05985 ) 05986 { 05987 IO_STATUS_BLOCK ioStatus; 05988 PIRP irp; 05989 PIO_STACK_LOCATION irpStack; 05990 KEVENT event; 05991 NTSTATUS status; 05992 SCSI_REQUEST_BLOCK srb; 05993 05994 PAGED_CODE(); 05995 05996 // 05997 // Clear the SRB fields. 05998 // 05999 06000 RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK)); 06001 06002 // 06003 // Write length to SRB. 06004 // 06005 06006 srb.Length = sizeof(SCSI_REQUEST_BLOCK); 06007 06008 srb.Function = Release ? SRB_FUNCTION_RELEASE_DEVICE : 06009 SRB_FUNCTION_CLAIM_DEVICE; 06010 06011 // 06012 // Set the event object to the unsignaled state. 06013 // It will be used to signal request completion 06014 // 06015 06016 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 06017 06018 // 06019 // Build synchronous request with no transfer. 06020 // 06021 06022 irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_EXECUTE_NONE, 06023 LowerDeviceObject, 06024 NULL, 06025 0, 06026 NULL, 06027 0, 06028 TRUE, 06029 &event, 06030 &ioStatus); 06031 06032 if (irp == NULL) { 06033 DebugPrint((1, "ClassClaimDevice: Can't allocate Irp\n")); 06034 return STATUS_INSUFFICIENT_RESOURCES; 06035 } 06036 06037 irpStack = IoGetNextIrpStackLocation(irp); 06038 06039 // 06040 // Save SRB address in next stack for port driver. 06041 // 06042 06043 irpStack->Parameters.Scsi.Srb = &srb; 06044 06045 // 06046 // Set up IRP Address. 06047 // 06048 06049 srb.OriginalRequest = irp; 06050 06051 // 06052 // Call the port driver with the request and wait for it to complete. 06053 // 06054 06055 status = IoCallDriver(LowerDeviceObject, irp); 06056 if (status == STATUS_PENDING) { 06057 06058 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 06059 status = ioStatus.Status; 06060 } 06061 06062 // 06063 // If this is a release request, then just decrement the reference count 06064 // and return. The status does not matter. 06065 // 06066 06067 if (Release) { 06068 06069 // ObDereferenceObject(LowerDeviceObject); 06070 return STATUS_SUCCESS; 06071 } 06072 06073 if (!NT_SUCCESS(status)) { 06074 return status; 06075 } 06076 06077 ASSERT(srb.DataBuffer != NULL); 06078 ASSERT(!TEST_FLAG(srb.SrbFlags, SRB_FLAGS_FREE_SENSE_BUFFER)); 06079 06080 return status; 06081 } // end ClassClaimDevice() 06082 06083 /*++//////////////////////////////////////////////////////////////////////////// 06084 06085 ClassInternalIoControl() 06086 06087 Routine Description: 06088 06089 This routine passes internal device controls to the port driver. 06090 Internal device controls are used by higher level drivers both for ioctls 06091 and to pass through scsi requests. 06092 06093 If the IoControlCode does not match any of the handled ioctls and is 06094 a valid system address then the request will be treated as an SRB and 06095 passed down to the lower driver. If the IoControlCode is not a valid 06096 system address the ioctl will be failed. 06097 06098 Callers must therefore be extremely cautious to pass correct, initialized 06099 values to this function. 06100 06101 Arguments: 06102 06103 DeviceObject - Supplies a pointer to the device object for this request. 06104 06105 Irp - Supplies the Irp making the request. 06106 06107 Return Value: 06108 06109 Returns back a STATUS_PENDING or a completion status. 06110 06111 --*/ 06112 NTSTATUS 06113 ClassInternalIoControl( 06114 IN PDEVICE_OBJECT DeviceObject, 06115 IN PIRP Irp 06116 ) 06117 { 06118 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 06119 06120 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 06121 PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp); 06122 06123 ULONG isRemoved; 06124 06125 PSCSI_REQUEST_BLOCK srb; 06126 06127 isRemoved = ClassAcquireRemoveLock(DeviceObject, Irp); 06128 06129 if(isRemoved) { 06130 06131 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 06132 06133 ClassReleaseRemoveLock(DeviceObject, Irp); 06134 06135 ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT); 06136 06137 return STATUS_DEVICE_DOES_NOT_EXIST; 06138 } 06139 06140 // 06141 // Get a pointer to the SRB. 06142 // 06143 06144 srb = irpStack->Parameters.Scsi.Srb; 06145 06146 // 06147 // Set the parameters in the next stack location. 06148 // 06149 06150 if(commonExtension->IsFdo) { 06151 nextStack->Parameters.Scsi.Srb = srb; 06152 nextStack->MajorFunction = IRP_MJ_SCSI; 06153 nextStack->MinorFunction = IRP_MN_SCSI_CLASS; 06154 06155 } else { 06156 06157 IoCopyCurrentIrpStackLocationToNext(Irp); 06158 } 06159 06160 ClassReleaseRemoveLock(DeviceObject, Irp); 06161 06162 return IoCallDriver(commonExtension->LowerDeviceObject, Irp); 06163 } // end ClassInternalIoControl() 06164 06165 /*++//////////////////////////////////////////////////////////////////////////// 06166 06167 ClassQueryTimeOutRegistryValue() 06168 06169 Routine Description: 06170 06171 This routine determines whether a reg key for a user-specified timeout 06172 value exists. This should be called at initialization time. 06173 06174 Arguments: 06175 06176 DeviceObject - Pointer to the device object we are retrieving the timeout 06177 value for 06178 06179 Return Value: 06180 06181 None, but it sets a new default timeout for a class of devices. 06182 06183 --*/ 06184 ULONG 06185 ClassQueryTimeOutRegistryValue( 06186 IN PDEVICE_OBJECT DeviceObject 06187 ) 06188 { 06189 // 06190 // Find the appropriate reg. key 06191 // 06192 06193 PCLASS_DRIVER_EXTENSION 06194 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, 06195 CLASS_DRIVER_EXTENSION_KEY); 06196 06197 PUNICODE_STRING registryPath = &(driverExtension->RegistryPath); 06198 06199 PRTL_QUERY_REGISTRY_TABLE parameters = NULL; 06200 PWSTR path; 06201 NTSTATUS status; 06202 LONG timeOut = 0; 06203 ULONG zero = 0; 06204 ULONG size; 06205 06206 PAGED_CODE(); 06207 06208 if (!registryPath) { 06209 return 0; 06210 } 06211 06212 parameters = ExAllocatePoolWithTag(NonPagedPool, 06213 sizeof(RTL_QUERY_REGISTRY_TABLE)*2, 06214 '1BcS'); 06215 06216 if (!parameters) { 06217 return 0; 06218 } 06219 06220 size = registryPath->MaximumLength + sizeof(WCHAR); 06221 path = ExAllocatePoolWithTag(NonPagedPool, size, '2BcS'); 06222 06223 if (!path) { 06224 ExFreePool(parameters); 06225 return 0; 06226 } 06227 06228 RtlZeroMemory(path,size); 06229 RtlCopyMemory(path, registryPath->Buffer, size - sizeof(WCHAR)); 06230 06231 06232 // 06233 // Check for the Timeout value. 06234 // 06235 06236 RtlZeroMemory(parameters, 06237 (sizeof(RTL_QUERY_REGISTRY_TABLE)*2)); 06238 06239 parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 06240 parameters[0].Name = L"TimeOutValue"; 06241 parameters[0].EntryContext = &timeOut; 06242 parameters[0].DefaultType = REG_DWORD; 06243 parameters[0].DefaultData = &zero; 06244 parameters[0].DefaultLength = sizeof(ULONG); 06245 06246 status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, 06247 path, 06248 parameters, 06249 NULL, 06250 NULL); 06251 06252 if (!(NT_SUCCESS(status))) { 06253 timeOut = 0; 06254 } 06255 06256 ExFreePool(parameters); 06257 ExFreePool(path); 06258 06259 DebugPrint((2, 06260 "ClassQueryTimeOutRegistryValue: Timeout value %d\n", 06261 timeOut)); 06262 06263 06264 return timeOut; 06265 06266 } // end ClassQueryTimeOutRegistryValue() 06267 06268 /*++//////////////////////////////////////////////////////////////////////////// 06269 06270 ClassCheckVerifyComplete() ISSUE-2000/02/18-henrygab - why public?! 06271 06272 Routine Description: 06273 06274 This routine executes when the port driver has completed a check verify 06275 ioctl. It will set the status of the master Irp, copy the media change 06276 count and complete the request. 06277 06278 Arguments: 06279 06280 Fdo - Supplies the functional device object which represents the logical unit. 06281 06282 Irp - Supplies the Irp which has completed. 06283 06284 Context - NULL 06285 06286 Return Value: 06287 06288 NT status 06289 06290 --*/ 06291 NTSTATUS 06292 ClassCheckVerifyComplete( 06293 IN PDEVICE_OBJECT Fdo, 06294 IN PIRP Irp, 06295 IN PVOID Context 06296 ) 06297 { 06298 PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); 06299 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 06300 06301 PIRP originalIrp; 06302 06303 ASSERT_FDO(Fdo); 06304 06305 originalIrp = irpStack->Parameters.Others.Argument1; 06306 06307 // 06308 // Copy the media change count and status 06309 // 06310 06311 *((PULONG) (originalIrp->AssociatedIrp.SystemBuffer)) = 06312 fdoExtension->MediaChangeCount; 06313 06314 DebugPrint((2, "ClassCheckVerifyComplete - Media change count for" 06315 "device %d is %lx - saved as %lx\n", 06316 fdoExtension->DeviceNumber, 06317 fdoExtension->MediaChangeCount, 06318 *((PULONG) originalIrp->AssociatedIrp.SystemBuffer))); 06319 06320 originalIrp->IoStatus.Status = Irp->IoStatus.Status; 06321 originalIrp->IoStatus.Information = sizeof(ULONG); 06322 06323 ClassReleaseRemoveLock(Fdo, originalIrp); 06324 ClassCompleteRequest(Fdo, originalIrp, IO_DISK_INCREMENT); 06325 06326 IoFreeIrp(Irp); 06327 06328 return STATUS_MORE_PROCESSING_REQUIRED; 06329 06330 } // end ClassCheckVerifyComplete() 06331 06332 /*++//////////////////////////////////////////////////////////////////////////// 06333 06334 ClassGetDescriptor() 06335 06336 Routine Description: 06337 06338 This routine will perform a query for the specified property id and will 06339 allocate a non-paged buffer to store the data in. It is the responsibility 06340 of the caller to ensure that this buffer is freed. 06341 06342 This routine must be run at IRQL_PASSIVE_LEVEL 06343 06344 Arguments: 06345 06346 DeviceObject - the device to query 06347 DeviceInfo - a location to store a pointer to the buffer we allocate 06348 06349 Return Value: 06350 06351 status 06352 if status is unsuccessful *DeviceInfo will be set to NULL, else the 06353 buffer allocated on behalf of the caller. 06354 06355 --*/ 06356 NTSTATUS 06357 ClassGetDescriptor( 06358 IN PDEVICE_OBJECT DeviceObject, 06359 IN PSTORAGE_PROPERTY_ID PropertyId, 06360 OUT PSTORAGE_DESCRIPTOR_HEADER *Descriptor 06361 ) 06362 { 06363 STORAGE_PROPERTY_QUERY query; 06364 IO_STATUS_BLOCK ioStatus; 06365 06366 PSTORAGE_DESCRIPTOR_HEADER descriptor = NULL; 06367 ULONG length; 06368 06369 UCHAR pass = 0; 06370 06371 PAGED_CODE(); 06372 06373 // 06374 // Set the passed-in descriptor pointer to NULL as default 06375 // 06376 06377 *Descriptor = NULL; 06378 06379 06380 RtlZeroMemory(&query, sizeof(STORAGE_PROPERTY_QUERY)); 06381 query.PropertyId = *PropertyId; 06382 query.QueryType = PropertyStandardQuery; 06383 06384 // 06385 // On the first pass we just want to get the first few 06386 // bytes of the descriptor so we can read it's size 06387 // 06388 06389 descriptor = (PVOID)&query; 06390 06391 ASSERT(sizeof(STORAGE_PROPERTY_QUERY) >= (sizeof(ULONG)*2)); 06392 06393 ClassSendDeviceIoControlSynchronous( 06394 IOCTL_STORAGE_QUERY_PROPERTY, 06395 DeviceObject, 06396 &query, 06397 sizeof(STORAGE_PROPERTY_QUERY), 06398 sizeof(ULONG) * 2, 06399 FALSE, 06400 &ioStatus 06401 ); 06402 06403 if(!NT_SUCCESS(ioStatus.Status)) { 06404 06405 DebugPrint((1, "ClassGetDescriptor: error %lx trying to " 06406 "query properties #1\n", ioStatus.Status)); 06407 return ioStatus.Status; 06408 } 06409 06410 if (descriptor->Size == 0) { 06411 06412 // 06413 // This DebugPrint is to help third-party driver writers 06414 // 06415 06416 DebugPrint((0, "ClassGetDescriptor: size returned was zero?! (status " 06417 "%x\n", ioStatus.Status)); 06418 return STATUS_UNSUCCESSFUL; 06419 06420 } 06421 06422 // 06423 // This time we know how much data there is so we can 06424 // allocate a buffer of the correct size 06425 // 06426 06427 length = descriptor->Size; 06428 06429 descriptor = ExAllocatePoolWithTag(NonPagedPool, length, '4BcS'); 06430 06431 if(descriptor == NULL) { 06432 06433 DebugPrint((1, "ClassGetDescriptor: unable to memory for descriptor " 06434 "(%d bytes)\n", length)); 06435 return STATUS_INSUFFICIENT_RESOURCES; 06436 } 06437 06438 // 06439 // setup the query again, as it was overwritten above 06440 // 06441 06442 RtlZeroMemory(&query, sizeof(STORAGE_PROPERTY_QUERY)); 06443 query.PropertyId = *PropertyId; 06444 query.QueryType = PropertyStandardQuery; 06445 06446 // 06447 // copy the input to the new outputbuffer 06448 // 06449 06450 RtlCopyMemory(descriptor, 06451 &query, 06452 sizeof(STORAGE_PROPERTY_QUERY) 06453 ); 06454 06455 ClassSendDeviceIoControlSynchronous( 06456 IOCTL_STORAGE_QUERY_PROPERTY, 06457 DeviceObject, 06458 descriptor, 06459 sizeof(STORAGE_PROPERTY_QUERY), 06460 length, 06461 FALSE, 06462 &ioStatus 06463 ); 06464 06465 if(!NT_SUCCESS(ioStatus.Status)) { 06466 06467 DebugPrint((1, "ClassGetDescriptor: error %lx trying to " 06468 "query properties #1\n", ioStatus.Status)); 06469 ExFreePool(descriptor); 06470 return ioStatus.Status; 06471 } 06472 06473 // 06474 // return the memory we've allocated to the caller 06475 // 06476 06477 *Descriptor = descriptor; 06478 return ioStatus.Status; 06479 } // end ClassGetDescriptor() 06480 06481 /*++//////////////////////////////////////////////////////////////////////////// 06482 06483 ClassSignalCompletion() 06484 06485 Routine Description: 06486 06487 This completion routine will signal the event given as context and then 06488 return STATUS_MORE_PROCESSING_REQUIRED to stop event completion. It is 06489 the responsibility of the routine waiting on the event to complete the 06490 request and free the event. 06491 06492 Arguments: 06493 06494 DeviceObject - a pointer to the device object 06495 06496 Irp - a pointer to the irp 06497 06498 Event - a pointer to the event to signal 06499 06500 Return Value: 06501 06502 STATUS_MORE_PROCESSING_REQUIRED 06503 06504 --*/ 06505 NTSTATUS 06506 ClassSignalCompletion( 06507 IN PDEVICE_OBJECT DeviceObject, 06508 IN PIRP Irp, 06509 IN PKEVENT Event 06510 ) 06511 { 06512 KeSetEvent(Event, IO_NO_INCREMENT, FALSE); 06513 06514 return STATUS_MORE_PROCESSING_REQUIRED; 06515 } // end ClassSignalCompletion() 06516 06517 /*++//////////////////////////////////////////////////////////////////////////// 06518 06519 ClassPnpQueryFdoRelations() 06520 06521 Routine Description: 06522 06523 This routine will call the driver's enumeration routine to update the 06524 list of PDO's. It will then build a response to the 06525 IRP_MN_QUERY_DEVICE_RELATIONS and place it into the information field in 06526 the irp. 06527 06528 Arguments: 06529 06530 Fdo - a pointer to the functional device object we are enumerating 06531 06532 Irp - a pointer to the enumeration request 06533 06534 Return Value: 06535 06536 status 06537 06538 --*/ 06539 NTSTATUS 06540 ClassPnpQueryFdoRelations( 06541 IN PDEVICE_OBJECT Fdo, 06542 IN PIRP Irp 06543 ) 06544 { 06545 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 06546 PCLASS_DRIVER_EXTENSION 06547 driverExtension = IoGetDriverObjectExtension(Fdo->DriverObject, 06548 CLASS_DRIVER_EXTENSION_KEY); 06549 NTSTATUS status; 06550 06551 PAGED_CODE(); 06552 06553 // 06554 // If there's already an enumeration in progress then don't start another 06555 // one. 06556 // 06557 06558 if(InterlockedIncrement(&(fdoExtension->EnumerationInterlock)) == 1) { 06559 status = driverExtension->InitData.ClassEnumerateDevice(Fdo); 06560 } 06561 06562 Irp->IoStatus.Information = (ULONG_PTR) NULL; 06563 06564 Irp->IoStatus.Status = ClassRetrieveDeviceRelations( 06565 Fdo, 06566 BusRelations, 06567 (PDEVICE_RELATIONS*)&Irp->IoStatus.Information); 06568 InterlockedDecrement(&(fdoExtension->EnumerationInterlock)); 06569 06570 return Irp->IoStatus.Status; 06571 } // end ClassPnpQueryFdoRelations() 06572 06573 /*++//////////////////////////////////////////////////////////////////////////// 06574 06575 ClassMarkChildrenMissing() 06576 06577 Routine Description: 06578 06579 This routine will call ClassMarkChildMissing() for all children. 06580 It acquires the ChildLock before calling ClassMarkChildMissing(). 06581 06582 Arguments: 06583 06584 Fdo - the "bus's" device object, such as the disk FDO for non-removable 06585 disks with multiple partitions. 06586 06587 Return Value: 06588 06589 None 06590 06591 --*/ 06592 VOID 06593 ClassMarkChildrenMissing( 06594 IN PFUNCTIONAL_DEVICE_EXTENSION Fdo 06595 ) 06596 { 06597 PCOMMON_DEVICE_EXTENSION commonExtension = &(Fdo->CommonExtension); 06598 PPHYSICAL_DEVICE_EXTENSION nextChild = commonExtension->ChildList; 06599 06600 PAGED_CODE(); 06601 06602 ClassAcquireChildLock(Fdo); 06603 06604 while (nextChild){ 06605 PPHYSICAL_DEVICE_EXTENSION tmpChild; 06606 06607 /* 06608 * ClassMarkChildMissing will also dequeue the child extension. 06609 * So get the next pointer before calling ClassMarkChildMissing. 06610 */ 06611 tmpChild = nextChild; 06612 nextChild = tmpChild->CommonExtension.ChildList; 06613 ClassMarkChildMissing(tmpChild, FALSE); 06614 } 06615 ClassReleaseChildLock(Fdo); 06616 return; 06617 } // end ClassMarkChildrenMissing() 06618 06619 /*++//////////////////////////////////////////////////////////////////////////// 06620 06621 ClassMarkChildMissing() 06622 06623 Routine Description: 06624 06625 This routine will make an active child "missing." If the device has never 06626 been enumerated then it will be deleted on the spot. If the device has 06627 not been enumerated then it will be marked as missing so that we can 06628 not report it in the next device enumeration. 06629 06630 Arguments: 06631 06632 Child - the child device to be marked as missing. 06633 06634 AcquireChildLock - TRUE if the child lock should be acquired before removing 06635 the missing child. FALSE if the child lock is already 06636 acquired by this thread. 06637 06638 Return Value: 06639 06640 returns whether or not the child device object has previously been reported 06641 to PNP. 06642 06643 --*/ 06644 BOOLEAN 06645 ClassMarkChildMissing( 06646 IN PPHYSICAL_DEVICE_EXTENSION Child, 06647 IN BOOLEAN AcquireChildLock 06648 ) 06649 { 06650 BOOLEAN returnValue = Child->IsEnumerated; 06651 06652 PAGED_CODE(); 06653 ASSERT_PDO(Child->DeviceObject); 06654 06655 Child->IsMissing = TRUE; 06656 06657 // 06658 // Make sure this child is not in the active list. 06659 // 06660 06661 ClassRemoveChild(Child->CommonExtension.PartitionZeroExtension, 06662 Child, 06663 AcquireChildLock); 06664 06665 if(Child->IsEnumerated == FALSE) { 06666 ClassRemoveDevice(Child->DeviceObject, IRP_MN_REMOVE_DEVICE); 06667 } 06668 06669 return returnValue; 06670 } // end ClassMarkChildMissing() 06671 06672 /*++//////////////////////////////////////////////////////////////////////////// 06673 06674 ClassRetrieveDeviceRelations() 06675 06676 Routine Description: 06677 06678 This routine will allocate a buffer to hold the specified list of 06679 relations. It will then fill in the list with referenced device pointers 06680 and will return the request. 06681 06682 Arguments: 06683 06684 Fdo - pointer to the FDO being queried 06685 06686 RelationType - what type of relations are being queried 06687 06688 DeviceRelations - a location to store a pointer to the response 06689 06690 Return Value: 06691 06692 status 06693 06694 --*/ 06695 NTSTATUS 06696 ClassRetrieveDeviceRelations( 06697 IN PDEVICE_OBJECT Fdo, 06698 IN DEVICE_RELATION_TYPE RelationType, 06699 OUT PDEVICE_RELATIONS *DeviceRelations 06700 ) 06701 { 06702 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 06703 06704 ULONG count = 0; 06705 ULONG i; 06706 06707 PPHYSICAL_DEVICE_EXTENSION nextChild; 06708 06709 ULONG relationsSize; 06710 PDEVICE_RELATIONS deviceRelations = NULL; 06711 06712 NTSTATUS status; 06713 06714 PAGED_CODE(); 06715 06716 ClassAcquireChildLock(fdoExtension); 06717 06718 nextChild = fdoExtension->CommonExtension.ChildList; 06719 06720 // 06721 // Count the number of PDO's attached to this disk 06722 // 06723 06724 while(nextChild != NULL) { 06725 PCOMMON_DEVICE_EXTENSION commonExtension; 06726 06727 commonExtension = &(nextChild->CommonExtension); 06728 06729 ASSERTMSG("ClassPnp internal error: missing child on active list\n", 06730 (nextChild->IsMissing == FALSE)); 06731 06732 nextChild = commonExtension->ChildList; 06733 06734 count++; 06735 }; 06736 06737 relationsSize = (sizeof(DEVICE_RELATIONS) + 06738 (count * sizeof(PDEVICE_OBJECT))); 06739 06740 deviceRelations = ExAllocatePoolWithTag(PagedPool, relationsSize, '5BcS'); 06741 06742 if(deviceRelations == NULL) { 06743 06744 DebugPrint((1, "ClassRetrieveDeviceRelations: unable to allocate " 06745 "%d bytes for device relations\n", relationsSize)); 06746 06747 ClassReleaseChildLock(fdoExtension); 06748 06749 return STATUS_INSUFFICIENT_RESOURCES; 06750 } 06751 06752 RtlZeroMemory(deviceRelations, relationsSize); 06753 06754 nextChild = fdoExtension->CommonExtension.ChildList; 06755 i = count - 1; 06756 06757 while(nextChild != NULL) { 06758 PCOMMON_DEVICE_EXTENSION commonExtension; 06759 06760 commonExtension = &(nextChild->CommonExtension); 06761 06762 ASSERTMSG("ClassPnp internal error: missing child on active list\n", 06763 (nextChild->IsMissing == FALSE)); 06764 06765 deviceRelations->Objects[i--] = nextChild->DeviceObject; 06766 06767 status = ObReferenceObjectByPointer( 06768 nextChild->DeviceObject, 06769 0, 06770 NULL, 06771 KernelMode); 06772 ASSERT(NT_SUCCESS(status)); 06773 06774 nextChild->IsEnumerated = TRUE; 06775 nextChild = commonExtension->ChildList; 06776 } 06777 06778 ASSERTMSG("Child list has changed: ", i == -1); 06779 06780 deviceRelations->Count = count; 06781 *DeviceRelations = deviceRelations; 06782 ClassReleaseChildLock(fdoExtension); 06783 return STATUS_SUCCESS; 06784 } // end ClassRetrieveDeviceRelations() 06785 06786 /*++//////////////////////////////////////////////////////////////////////////// 06787 06788 ClassGetPdoId() 06789 06790 Routine Description: 06791 06792 This routine will call into the driver to retrieve a copy of one of it's 06793 id strings. 06794 06795 Arguments: 06796 06797 Pdo - a pointer to the pdo being queried 06798 06799 IdType - which type of id string is being queried 06800 06801 IdString - an allocated unicode string structure which the driver 06802 can fill in. 06803 06804 Return Value: 06805 06806 status 06807 06808 --*/ 06809 NTSTATUS 06810 ClassGetPdoId( 06811 IN PDEVICE_OBJECT Pdo, 06812 IN BUS_QUERY_ID_TYPE IdType, 06813 IN PUNICODE_STRING IdString 06814 ) 06815 { 06816 PCLASS_DRIVER_EXTENSION 06817 driverExtension = IoGetDriverObjectExtension(Pdo->DriverObject, 06818 CLASS_DRIVER_EXTENSION_KEY); 06819 06820 ASSERT_PDO(Pdo); 06821 ASSERT(driverExtension->InitData.ClassQueryId); 06822 06823 PAGED_CODE(); 06824 06825 return driverExtension->InitData.ClassQueryId( Pdo, IdType, IdString); 06826 } // end ClassGetPdoId() 06827 06828 /*++//////////////////////////////////////////////////////////////////////////// 06829 06830 ClassQueryPnpCapabilities() 06831 06832 Routine Description: 06833 06834 This routine will call into the class driver to retrieve it's pnp 06835 capabilities. 06836 06837 Arguments: 06838 06839 PhysicalDeviceObject - The physical device object to retrieve properties 06840 for. 06841 06842 Return Value: 06843 06844 status 06845 06846 --*/ 06847 NTSTATUS 06848 ClassQueryPnpCapabilities( 06849 IN PDEVICE_OBJECT DeviceObject, 06850 IN PDEVICE_CAPABILITIES Capabilities 06851 ) 06852 { 06853 PCLASS_DRIVER_EXTENSION driverExtension = 06854 ClassGetDriverExtension(DeviceObject->DriverObject); 06855 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 06856 06857 PCLASS_QUERY_PNP_CAPABILITIES queryRoutine = NULL; 06858 06859 PAGED_CODE(); 06860 06861 ASSERT(DeviceObject); 06862 ASSERT(Capabilities); 06863 06864 if(commonExtension->IsFdo) { 06865 queryRoutine = driverExtension->InitData.FdoData.ClassQueryPnpCapabilities; 06866 } else { 06867 queryRoutine = driverExtension->InitData.PdoData.ClassQueryPnpCapabilities; 06868 } 06869 06870 if(queryRoutine) { 06871 return queryRoutine(DeviceObject, 06872 Capabilities); 06873 } else { 06874 return STATUS_NOT_IMPLEMENTED; 06875 } 06876 } // end ClassQueryPnpCapabilities() 06877 06878 /*++//////////////////////////////////////////////////////////////////////////// 06879 06880 ClassInvalidateBusRelations() 06881 06882 Routine Description: 06883 06884 This routine re-enumerates the devices on the "bus". It will call into 06885 the driver's ClassEnumerate routine to update the device objects 06886 immediately. It will then schedule a bus re-enumeration for pnp by calling 06887 IoInvalidateDeviceRelations. 06888 06889 Arguments: 06890 06891 Fdo - a pointer to the functional device object for this bus 06892 06893 Return Value: 06894 06895 none 06896 06897 --*/ 06898 VOID 06899 ClassInvalidateBusRelations( 06900 IN PDEVICE_OBJECT Fdo 06901 ) 06902 { 06903 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 06904 PCLASS_DRIVER_EXTENSION 06905 driverExtension = IoGetDriverObjectExtension(Fdo->DriverObject, 06906 CLASS_DRIVER_EXTENSION_KEY); 06907 06908 NTSTATUS status = STATUS_SUCCESS; 06909 06910 PAGED_CODE(); 06911 06912 ASSERT_FDO(Fdo); 06913 ASSERT(driverExtension->InitData.ClassEnumerateDevice != NULL); 06914 06915 if(InterlockedIncrement(&(fdoExtension->EnumerationInterlock)) == 1) { 06916 status = driverExtension->InitData.ClassEnumerateDevice(Fdo); 06917 } 06918 InterlockedDecrement(&(fdoExtension->EnumerationInterlock)); 06919 06920 if(!NT_SUCCESS(status)) { 06921 06922 DebugPrint((1, "ClassInvalidateBusRelations: EnumerateDevice routine " 06923 "returned %lx\n", status)); 06924 } 06925 06926 IoInvalidateDeviceRelations(fdoExtension->LowerPdo, BusRelations); 06927 06928 return; 06929 } // end ClassInvalidateBusRelations() 06930 06931 /*++//////////////////////////////////////////////////////////////////////////// 06932 06933 ClassRemoveDevice() ISSUE-2000/02/18-henrygab - why public?! 06934 06935 Routine Description: 06936 06937 This routine is called to handle the "removal" of a device. It will 06938 forward the request downwards if necesssary, call into the driver 06939 to release any necessary resources (memory, events, etc) and then 06940 will delete the device object. 06941 06942 Arguments: 06943 06944 DeviceObject - a pointer to the device object being removed 06945 06946 RemoveType - indicates what type of remove this is (regular or surprise). 06947 06948 Return Value: 06949 06950 status 06951 06952 --*/ 06953 NTSTATUS 06954 ClassRemoveDevice( 06955 IN PDEVICE_OBJECT DeviceObject, 06956 IN UCHAR RemoveType 06957 ) 06958 { 06959 PCLASS_DRIVER_EXTENSION 06960 driverExtension = IoGetDriverObjectExtension(DeviceObject->DriverObject, 06961 CLASS_DRIVER_EXTENSION_KEY); 06962 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 06963 PDEVICE_OBJECT lowerDeviceObject = commonExtension->LowerDeviceObject; 06964 PCLASS_WMI_INFO classWmiInfo; 06965 BOOLEAN proceedWithRemove = TRUE; 06966 NTSTATUS status; 06967 06968 PAGED_CODE(); 06969 06970 commonExtension->IsRemoved = REMOVE_PENDING; 06971 06972 /* 06973 * Deregister from WMI. 06974 */ 06975 classWmiInfo = commonExtension->IsFdo ? 06976 &driverExtension->InitData.FdoData.ClassWmiInfo : 06977 &driverExtension->InitData.PdoData.ClassWmiInfo; 06978 if (classWmiInfo->GuidRegInfo){ 06979 status = IoWMIRegistrationControl(DeviceObject, WMIREG_ACTION_DEREGISTER); 06980 DBGTRACE(ClassDebugInfo, ("ClassRemoveDevice: IoWMIRegistrationControl(%p, WMI_ACTION_DEREGISTER) --> %lx", DeviceObject, status)); 06981 } 06982 06983 /* 06984 * If we exposed a "shingle" (a named device interface openable by CreateFile) 06985 * then delete it now. 06986 */ 06987 if (commonExtension->MountedDeviceInterfaceName.Buffer){ 06988 IoSetDeviceInterfaceState(&commonExtension->MountedDeviceInterfaceName, FALSE); 06989 RtlFreeUnicodeString(&commonExtension->MountedDeviceInterfaceName); 06990 RtlInitUnicodeString(&commonExtension->MountedDeviceInterfaceName, NULL); 06991 } 06992 06993 // 06994 // If this is a surprise removal we leave the device around - which means 06995 // we don't have to (or want to) drop the remove lock and wait for pending 06996 // requests to complete. 06997 // 06998 06999 if (RemoveType == IRP_MN_REMOVE_DEVICE){ 07000 07001 // 07002 // Release the lock we acquired when the device object was created. 07003 // 07004 07005 ClassReleaseRemoveLock(DeviceObject, (PIRP) DeviceObject); 07006 07007 DebugPrint((1, "ClasspRemoveDevice - Reference count is now %d\n", 07008 commonExtension->RemoveLock)); 07009 07010 KeWaitForSingleObject(&commonExtension->RemoveEvent, 07011 Executive, 07012 KernelMode, 07013 FALSE, 07014 NULL); 07015 07016 DebugPrint((1, "ClasspRemoveDevice - removing device %p\n", DeviceObject)); 07017 07018 if(commonExtension->IsFdo) { 07019 07020 DebugPrint((1, "ClasspRemoveDevice - FDO %p has received a " 07021 "remove request.\n", DeviceObject)); 07022 07023 } 07024 else { 07025 PPHYSICAL_DEVICE_EXTENSION pdoExtension = DeviceObject->DeviceExtension; 07026 07027 if (pdoExtension->IsMissing){ 07028 /* 07029 * The child partition PDO is missing, so we are going to go ahead 07030 * and delete it for the remove. 07031 */ 07032 DBGTRACE(ClassDebugWarning, ("ClasspRemoveDevice - PDO %p is missing and will be removed", DeviceObject)); 07033 } 07034 else { 07035 /* 07036 * We got a remove for a child partition PDO which is not actually missing. 07037 * So we will NOT actually delete it. 07038 */ 07039 DBGTRACE(ClassDebugWarning, ("ClasspRemoveDevice - PDO %p still exists and will be removed when it disappears", DeviceObject)); 07040 07041 // 07042 // Reacquire the remove lock for the next time this comes around. 07043 // 07044 07045 ClassAcquireRemoveLock(DeviceObject, (PIRP) DeviceObject); 07046 07047 // 07048 // the device wasn't missing so it's not really been removed. 07049 // 07050 07051 commonExtension->IsRemoved = NO_REMOVE; 07052 07053 IoInvalidateDeviceRelations( 07054 commonExtension->PartitionZeroExtension->LowerPdo, 07055 BusRelations); 07056 07057 proceedWithRemove = FALSE; 07058 } 07059 } 07060 } 07061 07062 07063 if (proceedWithRemove){ 07064 07065 /* 07066 * Call the class driver's remove handler. 07067 * All this is supposed to do is clean up its data and device interfaces. 07068 */ 07069 ASSERT(commonExtension->DevInfo->ClassRemoveDevice); 07070 status = commonExtension->DevInfo->ClassRemoveDevice(DeviceObject, RemoveType); 07071 ASSERT(NT_SUCCESS(status)); 07072 status = STATUS_SUCCESS; 07073 07074 if (commonExtension->IsFdo){ 07075 PDEVICE_OBJECT pdo; 07076 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension; 07077 07078 ClasspDisableTimer(fdoExtension->DeviceObject); 07079 07080 if (RemoveType == IRP_MN_REMOVE_DEVICE){ 07081 07082 PPHYSICAL_DEVICE_EXTENSION child; 07083 07084 // 07085 // Cleanup the media detection resources now that the class driver 07086 // has stopped it's timer (if any) and we can be sure they won't 07087 // call us to do detection again. 07088 // 07089 07090 ClassCleanupMediaChangeDetection(fdoExtension); 07091 07092 // 07093 // Cleanup any Failure Prediction stuff 07094 // 07095 if (fdoExtension->FailurePredictionInfo) { 07096 ExFreePool(fdoExtension->FailurePredictionInfo); 07097 fdoExtension->FailurePredictionInfo = NULL; 07098 } 07099 07100 /* 07101 * Ordinarily all child PDOs will be removed by the time 07102 * that the parent gets the REMOVE_DEVICE. 07103 * However, if a child PDO has been created but has not 07104 * been announced in a QueryDeviceRelations, then it is 07105 * just a private data structure unknown to pnp, and we have 07106 * to delete it ourselves. 07107 */ 07108 ClassAcquireChildLock(fdoExtension); 07109 while (child = ClassRemoveChild(fdoExtension, NULL, FALSE)){ 07110 07111 // 07112 // Yank the pdo. This routine will unlink the device from the 07113 // pdo list so NextPdo will point to the next one when it's 07114 // complete. 07115 // 07116 child->IsMissing = TRUE; 07117 ClassRemoveDevice(child->DeviceObject, IRP_MN_REMOVE_DEVICE); 07118 } 07119 ClassReleaseChildLock(fdoExtension); 07120 } 07121 else if (RemoveType == IRP_MN_SURPRISE_REMOVAL){ 07122 /* 07123 * This is a surprise-remove on the parent FDO. 07124 * We will mark the child PDOs as missing so that they 07125 * will actually get deleted when they get a REMOVE_DEVICE. 07126 */ 07127 ClassMarkChildrenMissing(fdoExtension); 07128 } 07129 07130 ClasspFreeReleaseRequest(DeviceObject); 07131 07132 if (RemoveType == IRP_MN_REMOVE_DEVICE){ 07133 07134 // 07135 // Free FDO-specific data structs 07136 // 07137 if (fdoExtension->PrivateFdoData){ 07138 07139 DestroyAllTransferPackets(DeviceObject); 07140 07141 ExFreePool(fdoExtension->PrivateFdoData); 07142 fdoExtension->PrivateFdoData = NULL; 07143 } 07144 07145 if (commonExtension->DeviceName.Buffer) { 07146 ExFreePool(commonExtension->DeviceName.Buffer); 07147 RtlInitUnicodeString(&commonExtension->DeviceName, NULL); 07148 } 07149 07150 if (fdoExtension->AdapterDescriptor) { 07151 ExFreePool(fdoExtension->AdapterDescriptor); 07152 fdoExtension->AdapterDescriptor = NULL; 07153 } 07154 07155 if (fdoExtension->DeviceDescriptor) { 07156 ExFreePool(fdoExtension->DeviceDescriptor); 07157 fdoExtension->DeviceDescriptor = NULL; 07158 } 07159 07160 // 07161 // Detach our device object from the stack - there's no reason 07162 // to hold off our cleanup any longer. 07163 // 07164 07165 IoDetachDevice(lowerDeviceObject); 07166 } 07167 } 07168 else { 07169 /* 07170 * This is a child partition PDO. 07171 * We have already determined that it was previously marked 07172 * as missing. So if this is a REMOVE_DEVICE, we will actually 07173 * delete it. 07174 */ 07175 if (RemoveType == IRP_MN_REMOVE_DEVICE){ 07176 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = 07177 commonExtension->PartitionZeroExtension; 07178 PPHYSICAL_DEVICE_EXTENSION pdoExtension = 07179 (PPHYSICAL_DEVICE_EXTENSION) commonExtension; 07180 07181 // 07182 // See if this device is in the child list (if this was a suprise 07183 // removal it might be) and remove it. 07184 // 07185 07186 ClassRemoveChild(fdoExtension, pdoExtension, TRUE); 07187 } 07188 } 07189 07190 commonExtension->PartitionLength.QuadPart = 0; 07191 07192 if (RemoveType == IRP_MN_REMOVE_DEVICE){ 07193 IoDeleteDevice(DeviceObject); 07194 } 07195 } 07196 07197 return STATUS_SUCCESS; 07198 } // end ClassRemoveDevice() 07199 07200 /*++//////////////////////////////////////////////////////////////////////////// 07201 07202 ClassGetDriverExtension() 07203 07204 Routine Description: 07205 07206 This routine will return the classpnp's driver extension. 07207 07208 Arguments: 07209 07210 DriverObject - the driver object for which to get classpnp's extension 07211 07212 Return Value: 07213 07214 Either NULL if none, or a pointer to the driver extension 07215 07216 --*/ 07217 PCLASS_DRIVER_EXTENSION 07218 ClassGetDriverExtension( 07219 IN PDRIVER_OBJECT DriverObject 07220 ) 07221 { 07222 return IoGetDriverObjectExtension(DriverObject, CLASS_DRIVER_EXTENSION_KEY); 07223 } // end ClassGetDriverExtension() 07224 07225 /*++//////////////////////////////////////////////////////////////////////////// 07226 07227 ClasspStartIo() 07228 07229 Routine Description: 07230 07231 This routine wraps the class driver's start io routine. If the device 07232 is being removed it will complete any requests with 07233 STATUS_DEVICE_DOES_NOT_EXIST and fire up the next packet. 07234 07235 Arguments: 07236 07237 Return Value: 07238 07239 none 07240 07241 --*/ 07242 VOID 07243 ClasspStartIo( 07244 IN PDEVICE_OBJECT DeviceObject, 07245 IN PIRP Irp 07246 ) 07247 { 07248 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 07249 07250 // 07251 // We're already holding the remove lock so just check the variable and 07252 // see what's going on. 07253 // 07254 07255 if(commonExtension->IsRemoved) { 07256 07257 Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST; 07258 07259 ClassAcquireRemoveLock(DeviceObject, (PIRP) ClasspStartIo); 07260 ClassReleaseRemoveLock(DeviceObject, Irp); 07261 ClassCompleteRequest(DeviceObject, Irp, IO_DISK_INCREMENT); 07262 IoStartNextPacket(DeviceObject, FALSE); 07263 ClassReleaseRemoveLock(DeviceObject, (PIRP) ClasspStartIo); 07264 return; 07265 } 07266 07267 commonExtension->DriverExtension->InitData.ClassStartIo( 07268 DeviceObject, 07269 Irp); 07270 07271 return; 07272 } // ClasspStartIo() 07273 07274 /*++//////////////////////////////////////////////////////////////////////////// 07275 07276 ClassUpdateInformationInRegistry() 07277 07278 Routine Description: 07279 07280 This routine has knowledge about the layout of the device map information 07281 in the registry. It will update this information to include a value 07282 entry specifying the dos device name that is assumed to get assigned 07283 to this NT device name. For more information on this assigning of the 07284 dos device name look in the drive support routine in the hal that assigns 07285 all dos names. 07286 07287 Since some versions of some device's firmware did not work and some 07288 vendors did not bother to follow the specification, the entire inquiry 07289 information must also be stored in the registry so than someone can 07290 figure out the firmware version. 07291 07292 Arguments: 07293 07294 DeviceObject - A pointer to the device object for the tape device. 07295 07296 Return Value: 07297 07298 None 07299 07300 --*/ 07301 VOID 07302 ClassUpdateInformationInRegistry( 07303 IN PDEVICE_OBJECT Fdo, 07304 IN PCHAR DeviceName, 07305 IN ULONG DeviceNumber, 07306 IN PINQUIRYDATA InquiryData, 07307 IN ULONG InquiryDataLength 07308 ) 07309 { 07310 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 07311 NTSTATUS status; 07312 SCSI_ADDRESS scsiAddress; 07313 OBJECT_ATTRIBUTES objectAttributes; 07314 PUCHAR buffer; 07315 STRING string; 07316 UNICODE_STRING unicodeName; 07317 UNICODE_STRING unicodeRegistryPath; 07318 UNICODE_STRING unicodeData; 07319 HANDLE targetKey; 07320 IO_STATUS_BLOCK ioStatus; 07321 07322 07323 PAGED_CODE(); 07324 07325 ASSERT(DeviceName); 07326 fdoExtension = Fdo->DeviceExtension; 07327 buffer = NULL; 07328 targetKey = NULL; 07329 RtlZeroMemory(&unicodeName, sizeof(UNICODE_STRING)); 07330 RtlZeroMemory(&unicodeData, sizeof(UNICODE_STRING)); 07331 RtlZeroMemory(&unicodeRegistryPath, sizeof(UNICODE_STRING)); 07332 07333 TRY { 07334 07335 // 07336 // Issue GET_ADDRESS Ioctl to determine path, target, and lun information. 07337 // 07338 07339 ClassSendDeviceIoControlSynchronous( 07340 IOCTL_SCSI_GET_ADDRESS, 07341 Fdo, 07342 &scsiAddress, 07343 0, 07344 sizeof(SCSI_ADDRESS), 07345 FALSE, 07346 &ioStatus 07347 ); 07348 07349 if (!NT_SUCCESS(ioStatus.Status)) { 07350 07351 status = ioStatus.Status; 07352 DebugPrint((1, 07353 "UpdateInformationInRegistry: Get Address failed %lx\n", 07354 status)); 07355 LEAVE; 07356 07357 } else { 07358 07359 DebugPrint((1, 07360 "GetAddress: Port %x, Path %x, Target %x, Lun %x\n", 07361 scsiAddress.PortNumber, 07362 scsiAddress.PathId, 07363 scsiAddress.TargetId, 07364 scsiAddress.Lun)); 07365 07366 } 07367 07368 // 07369 // Allocate a buffer for the reg. spooge. 07370 // 07371 07372 buffer = ExAllocatePoolWithTag(PagedPool, 1024, '6BcS'); 07373 07374 if (buffer == NULL) { 07375 07376 // 07377 // There is not return value for this. Since this is done at 07378 // claim device time (currently only system initialization) getting 07379 // the registry information correct will be the least of the worries. 07380 // 07381 07382 LEAVE; 07383 } 07384 07385 sprintf(buffer, 07386 "\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi\\Scsi Port %d\\Scsi Bus %d\\Target Id %d\\Logical Unit Id %d", 07387 scsiAddress.PortNumber, 07388 scsiAddress.PathId, 07389 scsiAddress.TargetId, 07390 scsiAddress.Lun); 07391 07392 RtlInitString(&string, buffer); 07393 07394 status = RtlAnsiStringToUnicodeString(&unicodeRegistryPath, 07395 &string, 07396 TRUE); 07397 07398 if (!NT_SUCCESS(status)) { 07399 LEAVE; 07400 } 07401 07402 // 07403 // Open the registry key for the scsi information for this 07404 // scsibus, target, lun. 07405 // 07406 07407 InitializeObjectAttributes(&objectAttributes, 07408 &unicodeRegistryPath, 07409 OBJ_CASE_INSENSITIVE, 07410 NULL, 07411 NULL); 07412 07413 status = ZwOpenKey(&targetKey, 07414 KEY_READ | KEY_WRITE, 07415 &objectAttributes); 07416 07417 if (!NT_SUCCESS(status)) { 07418 LEAVE; 07419 } 07420 07421 // 07422 // Now construct and attempt to create the registry value 07423 // specifying the device name in the appropriate place in the 07424 // device map. 07425 // 07426 07427 RtlInitUnicodeString(&unicodeName, L"DeviceName"); 07428 07429 sprintf(buffer, "%s%d", DeviceName, DeviceNumber); 07430 RtlInitString(&string, buffer); 07431 status = RtlAnsiStringToUnicodeString(&unicodeData, 07432 &string, 07433 TRUE); 07434 if (NT_SUCCESS(status)) { 07435 status = ZwSetValueKey(targetKey, 07436 &unicodeName, 07437 0, 07438 REG_SZ, 07439 unicodeData.Buffer, 07440 unicodeData.Length); 07441 } 07442 07443 // 07444 // if they sent in data, update the registry 07445 // 07446 07447 if (InquiryDataLength) { 07448 07449 ASSERT(InquiryData); 07450 07451 RtlInitUnicodeString(&unicodeName, L"InquiryData"); 07452 status = ZwSetValueKey(targetKey, 07453 &unicodeName, 07454 0, 07455 REG_BINARY, 07456 InquiryData, 07457 InquiryDataLength); 07458 } 07459 07460 // that's all, except to clean up. 07461 07462 } FINALLY { 07463 07464 if (unicodeData.Buffer) { 07465 RtlFreeUnicodeString(&unicodeData); 07466 } 07467 if (unicodeRegistryPath.Buffer) { 07468 RtlFreeUnicodeString(&unicodeRegistryPath); 07469 } 07470 if (targetKey) { 07471 ZwClose(targetKey); 07472 } 07473 if (buffer) { 07474 ExFreePool(buffer); 07475 } 07476 07477 } 07478 07479 } // end ClassUpdateInformationInRegistry() 07480 07481 /*++//////////////////////////////////////////////////////////////////////////// 07482 07483 ClasspSendSynchronousCompletion() 07484 07485 Routine Description: 07486 07487 This completion routine will set the user event in the irp after 07488 freeing the irp and the associated MDL (if any). 07489 07490 Arguments: 07491 07492 DeviceObject - the device object which requested the completion routine 07493 07494 Irp - the irp being completed 07495 07496 Context - unused 07497 07498 Return Value: 07499 07500 STATUS_MORE_PROCESSING_REQUIRED 07501 07502 --*/ 07503 NTSTATUS 07504 ClasspSendSynchronousCompletion( 07505 IN PDEVICE_OBJECT DeviceObject, 07506 IN PIRP Irp, 07507 IN PVOID Context 07508 ) 07509 { 07510 DebugPrint((3, "ClasspSendSynchronousCompletion: %p %p %p\n", 07511 DeviceObject, Irp, Context)); 07512 // 07513 // First set the status and information fields in the io status block 07514 // provided by the caller. 07515 // 07516 07517 *(Irp->UserIosb) = Irp->IoStatus; 07518 07519 // 07520 // Unlock the pages for the data buffer. 07521 // 07522 07523 if(Irp->MdlAddress) { 07524 MmUnlockPages(Irp->MdlAddress); 07525 IoFreeMdl(Irp->MdlAddress); 07526 } 07527 07528 // 07529 // Signal the caller's event. 07530 // 07531 07532 KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE); 07533 07534 // 07535 // Free the MDL and the IRP. 07536 // 07537 07538 IoFreeIrp(Irp); 07539 07540 return STATUS_MORE_PROCESSING_REQUIRED; 07541 } // end ClasspSendSynchronousCompletion() 07542 07543 /*++ 07544 07545 ISSUE-2000/02/20-henrygab Not documented ClasspRegisterMountedDeviceInterface 07546 07547 --*/ 07548 VOID 07549 ClasspRegisterMountedDeviceInterface( 07550 IN PDEVICE_OBJECT DeviceObject 07551 ) 07552 { 07553 07554 PCOMMON_DEVICE_EXTENSION commonExtension = DeviceObject->DeviceExtension; 07555 BOOLEAN isFdo = commonExtension->IsFdo; 07556 07557 PDEVICE_OBJECT pdo; 07558 UNICODE_STRING interfaceName; 07559 07560 NTSTATUS status; 07561 07562 if(isFdo) { 07563 07564 PFUNCTIONAL_DEVICE_EXTENSION functionalExtension; 07565 07566 functionalExtension = 07567 (PFUNCTIONAL_DEVICE_EXTENSION) commonExtension; 07568 pdo = functionalExtension->LowerPdo; 07569 } else { 07570 pdo = DeviceObject; 07571 } 07572 07573 status = IoRegisterDeviceInterface( 07574 pdo, 07575 &MOUNTDEV_MOUNTED_DEVICE_GUID, 07576 NULL, 07577 &interfaceName 07578 ); 07579 07580 if(NT_SUCCESS(status)) { 07581 07582 // 07583 // Copy the interface name before setting the interface state - the 07584 // name is needed by the components we notify. 07585 // 07586 07587 commonExtension->MountedDeviceInterfaceName = interfaceName; 07588 status = IoSetDeviceInterfaceState(&interfaceName, TRUE); 07589 07590 if(!NT_SUCCESS(status)) { 07591 RtlFreeUnicodeString(&interfaceName); 07592 } 07593 } 07594 07595 if(!NT_SUCCESS(status)) { 07596 RtlInitUnicodeString(&(commonExtension->MountedDeviceInterfaceName), 07597 NULL); 07598 } 07599 return; 07600 } // end ClasspRegisterMountedDeviceInterface() 07601 07602 /*++//////////////////////////////////////////////////////////////////////////// 07603 07604 ClassSendDeviceIoControlSynchronous() 07605 07606 Routine Description: 07607 07608 This routine is based upon IoBuildDeviceIoControlRequest(). It has been 07609 modified to reduce code and memory by not double-buffering the io, using 07610 the same buffer for both input and output, allocating and deallocating 07611 the mdl on behalf of the caller, and waiting for the io to complete. 07612 07613 This routine also works around the rare cases in which APC's are disabled. 07614 Since IoBuildDeviceIoControl() used APC's to signal completion, this had 07615 led to a number of difficult-to-detect hangs, where the irp was completed, 07616 but the event passed to IoBuild..() was still being waited upon by the 07617 caller. 07618 07619 Arguments: 07620 07621 IoControlCode - the IOCTL to send 07622 07623 TargetDeviceObject - the device object that should handle the ioctl 07624 07625 Buffer - the input and output buffer, or NULL if no input/output 07626 07627 InputBufferLength - the number of bytes prepared for the IOCTL in Buffer 07628 07629 OutputBufferLength - the number of bytes to be filled in upon success 07630 07631 InternalDeviceIoControl - if TRUE, uses IRP_MJ_INTERNAL_DEVICE_CONTROL 07632 07633 IoStatus - the status block that contains the results of the operation 07634 07635 Return Value: 07636 07637 --*/ 07638 VOID 07639 ClassSendDeviceIoControlSynchronous( 07640 IN ULONG IoControlCode, 07641 IN PDEVICE_OBJECT TargetDeviceObject, 07642 IN OUT PVOID Buffer OPTIONAL, 07643 IN ULONG InputBufferLength, 07644 IN ULONG OutputBufferLength, 07645 IN BOOLEAN InternalDeviceIoControl, 07646 OUT PIO_STATUS_BLOCK IoStatus 07647 ) 07648 { 07649 PIRP irp; 07650 PIO_STACK_LOCATION irpSp; 07651 ULONG method; 07652 07653 PAGED_CODE(); 07654 07655 irp = NULL; 07656 method = IoControlCode & 3; 07657 07658 07659 #if DBG // Begin Argument Checking (nop in fre version) 07660 07661 ASSERT(ARGUMENT_PRESENT(IoStatus)); 07662 07663 if ((InputBufferLength != 0) || (OutputBufferLength != 0)) { 07664 ASSERT(ARGUMENT_PRESENT(Buffer)); 07665 } 07666 else { 07667 ASSERT(!ARGUMENT_PRESENT(Buffer)); 07668 } 07669 #endif 07670 07671 // 07672 // Begin by allocating the IRP for this request. Do not charge quota to 07673 // the current process for this IRP. 07674 // 07675 07676 irp = IoAllocateIrp(TargetDeviceObject->StackSize, FALSE); 07677 if (!irp) { 07678 (*IoStatus).Information = 0; 07679 (*IoStatus).Status = STATUS_INSUFFICIENT_RESOURCES; 07680 return; 07681 } 07682 07683 // 07684 // Get a pointer to the stack location of the first driver which will be 07685 // invoked. This is where the function codes and the parameters are set. 07686 // 07687 07688 irpSp = IoGetNextIrpStackLocation(irp); 07689 07690 // 07691 // Set the major function code based on the type of device I/O control 07692 // function the caller has specified. 07693 // 07694 07695 if (InternalDeviceIoControl) { 07696 irpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL; 07697 } else { 07698 irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL; 07699 } 07700 07701 // 07702 // Copy the caller's parameters to the service-specific portion of the 07703 // IRP for those parameters that are the same for all four methods. 07704 // 07705 07706 irpSp->Parameters.DeviceIoControl.OutputBufferLength = OutputBufferLength; 07707 irpSp->Parameters.DeviceIoControl.InputBufferLength = InputBufferLength; 07708 irpSp->Parameters.DeviceIoControl.IoControlCode = IoControlCode; 07709 07710 // 07711 // Get the method bits from the I/O control code to determine how the 07712 // buffers are to be passed to the driver. 07713 // 07714 07715 switch (method) { 07716 // case 0 07717 case METHOD_BUFFERED: { 07718 if ((InputBufferLength != 0) || (OutputBufferLength != 0)) { 07719 07720 irp->AssociatedIrp.SystemBuffer = 07721 ExAllocatePoolWithTag(NonPagedPoolCacheAligned, 07722 max(InputBufferLength, OutputBufferLength), 07723 CLASS_TAG_DEVICE_CONTROL 07724 ); 07725 07726 if (irp->AssociatedIrp.SystemBuffer == NULL) { 07727 IoFreeIrp(irp); 07728 (*IoStatus).Information = 0; 07729 (*IoStatus).Status = STATUS_INSUFFICIENT_RESOURCES; 07730 return; 07731 } 07732 07733 if (InputBufferLength != 0) { 07734 RtlCopyMemory(irp->AssociatedIrp.SystemBuffer, 07735 Buffer, 07736 InputBufferLength); 07737 } 07738 } // end of buffering 07739 07740 irp->UserBuffer = Buffer; 07741 break; 07742 } 07743 07744 // case 1, case 2 07745 case METHOD_IN_DIRECT: 07746 case METHOD_OUT_DIRECT: { 07747 07748 07749 if (InputBufferLength != 0) { 07750 irp->AssociatedIrp.SystemBuffer = Buffer; 07751 } 07752 07753 if (OutputBufferLength != 0) { 07754 07755 irp->MdlAddress = IoAllocateMdl(Buffer, 07756 OutputBufferLength, 07757 FALSE, FALSE, 07758 (PIRP) NULL); 07759 07760 if (irp->MdlAddress == NULL) { 07761 IoFreeIrp(irp); 07762 (*IoStatus).Information = 0; 07763 (*IoStatus).Status = STATUS_INSUFFICIENT_RESOURCES; 07764 return; 07765 } 07766 07767 if (method == METHOD_IN_DIRECT) { 07768 MmProbeAndLockPages(irp->MdlAddress, 07769 KernelMode, 07770 IoReadAccess); 07771 } else if (method == METHOD_OUT_DIRECT) { 07772 MmProbeAndLockPages(irp->MdlAddress, 07773 KernelMode, 07774 IoWriteAccess); 07775 } else { 07776 ASSERT(!"If other methods reach here, code is out of date"); 07777 } 07778 } 07779 break; 07780 } 07781 07782 // case 3 07783 case METHOD_NEITHER: { 07784 07785 ASSERT(!"This routine does not support METHOD_NEITHER ioctls"); 07786 IoStatus->Information = 0; 07787 IoStatus->Status = STATUS_NOT_SUPPORTED; 07788 return; 07789 break; 07790 } 07791 } // end of switch(method) 07792 07793 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 07794 07795 // 07796 // send the irp synchronously 07797 // 07798 07799 ClassSendIrpSynchronous(TargetDeviceObject, irp); 07800 07801 // 07802 // copy the iostatus block for the caller 07803 // 07804 07805 *IoStatus = irp->IoStatus; 07806 07807 // 07808 // free any allocated resources 07809 // 07810 07811 switch (method) { 07812 case METHOD_BUFFERED: { 07813 07814 ASSERT(irp->UserBuffer == Buffer); 07815 07816 // 07817 // first copy the buffered result, if any 07818 // Note that there are no security implications in 07819 // not checking for success since only drivers can 07820 // call into this routine anyways... 07821 // 07822 07823 if (OutputBufferLength != 0) { 07824 RtlCopyMemory(Buffer, // irp->UserBuffer 07825 irp->AssociatedIrp.SystemBuffer, 07826 OutputBufferLength 07827 ); 07828 } 07829 07830 // 07831 // then free the memory allocated to buffer the io 07832 // 07833 07834 if ((InputBufferLength !=0) || (OutputBufferLength != 0)) { 07835 ExFreePool(irp->AssociatedIrp.SystemBuffer); 07836 irp->AssociatedIrp.SystemBuffer = NULL; 07837 } 07838 break; 07839 } 07840 07841 case METHOD_IN_DIRECT: 07842 case METHOD_OUT_DIRECT: { 07843 07844 // 07845 // we alloc a mdl if there is an output buffer specified 07846 // free it here after unlocking the pages 07847 // 07848 07849 if (OutputBufferLength != 0) { 07850 ASSERT(irp->MdlAddress != NULL); 07851 MmUnlockPages(irp->MdlAddress); 07852 IoFreeMdl(irp->MdlAddress); 07853 irp->MdlAddress = (PMDL) NULL; 07854 } 07855 break; 07856 } 07857 07858 case METHOD_NEITHER: { 07859 ASSERT(!"Code is out of date"); 07860 break; 07861 } 07862 } 07863 07864 // 07865 // we always have allocated an irp. free it here. 07866 // 07867 07868 IoFreeIrp(irp); 07869 irp = (PIRP) NULL; 07870 07871 // 07872 // return the io status block's status to the caller 07873 // 07874 07875 return; 07876 } // end ClassSendDeviceIoControlSynchronous() 07877 07878 /*++//////////////////////////////////////////////////////////////////////////// 07879 07880 ClassForwardIrpSynchronous() 07881 07882 Routine Description: 07883 07884 Forwards a given irp to the next lower device object. 07885 07886 Arguments: 07887 07888 CommonExtension - the common class extension 07889 07890 Irp - the request to forward down the stack 07891 07892 Return Value: 07893 07894 --*/ 07895 NTSTATUS 07896 ClassForwardIrpSynchronous( 07897 IN PCOMMON_DEVICE_EXTENSION CommonExtension, 07898 IN PIRP Irp 07899 ) 07900 { 07901 IoCopyCurrentIrpStackLocationToNext(Irp); 07902 return ClassSendIrpSynchronous(CommonExtension->LowerDeviceObject, Irp); 07903 } // end ClassForwardIrpSynchronous() 07904 07905 /*++//////////////////////////////////////////////////////////////////////////// 07906 07907 ClassSendIrpSynchronous() 07908 07909 Routine Description: 07910 07911 This routine sends the given irp to the given device object, and waits for 07912 it to complete. On debug versions, will print out a debug message and 07913 optionally assert for "lost" irps based upon classpnp's globals 07914 07915 Arguments: 07916 07917 TargetDeviceObject - the device object to handle this irp 07918 07919 Irp - the request to be sent 07920 07921 Return Value: 07922 07923 --*/ 07924 NTSTATUS 07925 ClassSendIrpSynchronous( 07926 IN PDEVICE_OBJECT TargetDeviceObject, 07927 IN PIRP Irp 07928 ) 07929 { 07930 KEVENT event; 07931 NTSTATUS status; 07932 07933 ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); 07934 ASSERT(TargetDeviceObject != NULL); 07935 ASSERT(Irp != NULL); 07936 ASSERT(Irp->StackCount >= TargetDeviceObject->StackSize); 07937 07938 // 07939 // ISSUE-2000/02/20-henrygab What if APCs are disabled? 07940 // May need to enter critical section before IoCallDriver() 07941 // until the event is hit? 07942 // 07943 07944 KeInitializeEvent(&event, SynchronizationEvent, FALSE); 07945 IoSetCompletionRoutine(Irp, ClassSignalCompletion, &event, 07946 TRUE, TRUE, TRUE); 07947 07948 status = IoCallDriver(TargetDeviceObject, Irp); 07949 07950 if (status == STATUS_PENDING) { 07951 07952 #if DBG 07953 LARGE_INTEGER timeout; 07954 07955 timeout.QuadPart = (LONGLONG)(-1 * 10 * 1000 * (LONGLONG)1000 * 07956 ClasspnpGlobals.SecondsToWaitForIrps); 07957 07958 do { 07959 status = KeWaitForSingleObject(&event, 07960 Executive, 07961 KernelMode, 07962 FALSE, 07963 &timeout); 07964 07965 07966 if (status == STATUS_TIMEOUT) { 07967 07968 // 07969 // This DebugPrint should almost always be investigated by the 07970 // party who sent the irp and/or the current owner of the irp. 07971 // Synchronous Irps should not take this long (currently 30 07972 // seconds) without good reason. This points to a potentially 07973 // serious problem in the underlying device stack. 07974 // 07975 07976 DebugPrint((0, "ClassSendIrpSynchronous: (%p) irp %p did not " 07977 "complete within %x seconds\n", 07978 TargetDeviceObject, Irp, 07979 ClasspnpGlobals.SecondsToWaitForIrps 07980 )); 07981 07982 if (ClasspnpGlobals.BreakOnLostIrps != 0) { 07983 ASSERT(!" - Irp failed to complete within 30 seconds - "); 07984 } 07985 } 07986 07987 07988 } while (status==STATUS_TIMEOUT); 07989 #else 07990 KeWaitForSingleObject(&event, 07991 Executive, 07992 KernelMode, 07993 FALSE, 07994 NULL); 07995 #endif 07996 07997 status = Irp->IoStatus.Status; 07998 } 07999 08000 return status; 08001 } // end ClassSendIrpSynchronous() 08002 08003 /*++//////////////////////////////////////////////////////////////////////////// 08004 08005 ClassGetVpb() 08006 08007 Routine Description: 08008 08009 This routine returns the current VPB (Volume Parameter Block) for the 08010 given device object. 08011 The Vpb field is only visible in the ntddk.h (not the wdm.h) definition 08012 of DEVICE_OBJECT; hence this exported function. 08013 08014 Arguments: 08015 08016 DeviceObject - the device to get the VPB for 08017 08018 Return Value: 08019 08020 the VPB, or NULL if none. 08021 08022 --*/ 08023 PVPB 08024 ClassGetVpb( 08025 IN PDEVICE_OBJECT DeviceObject 08026 ) 08027 { 08028 return DeviceObject->Vpb; 08029 } // end ClassGetVpb() 08030 08031 /*++ 08032 08033 ISSUE-2000/02/20-henrygab Not documented ClasspAllocateReleaseRequest 08034 08035 --*/ 08036 NTSTATUS 08037 ClasspAllocateReleaseRequest( 08038 IN PDEVICE_OBJECT Fdo 08039 ) 08040 { 08041 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 08042 PIO_STACK_LOCATION irpStack; 08043 08044 KeInitializeSpinLock(&(fdoExtension->ReleaseQueueSpinLock)); 08045 08046 fdoExtension->ReleaseQueueNeeded = FALSE; 08047 fdoExtension->ReleaseQueueInProgress = FALSE; 08048 fdoExtension->ReleaseQueueIrpFromPool = FALSE; 08049 08050 // 08051 // The class driver is responsible for allocating a properly sized irp, 08052 // or ClassReleaseQueue will attempt to do it on the first error. 08053 // 08054 08055 fdoExtension->ReleaseQueueIrp = NULL; 08056 08057 // 08058 // Write length to SRB. 08059 // 08060 08061 fdoExtension->ReleaseQueueSrb.Length = sizeof(SCSI_REQUEST_BLOCK); 08062 08063 return STATUS_SUCCESS; 08064 } // end ClasspAllocateReleaseRequest() 08065 08066 /*++ 08067 08068 ISSUE-2000/02/20-henrygab Not documented ClasspFreeReleaseRequest 08069 08070 --*/ 08071 VOID 08072 ClasspFreeReleaseRequest( 08073 IN PDEVICE_OBJECT Fdo 08074 ) 08075 { 08076 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 08077 //KIRQL oldIrql; 08078 08079 ASSERT(fdoExtension->CommonExtension.IsRemoved != NO_REMOVE); 08080 08081 // 08082 // free anything the driver allocated 08083 // 08084 08085 if (fdoExtension->ReleaseQueueIrp) { 08086 if (fdoExtension->ReleaseQueueIrpFromPool) { 08087 ExFreePool(fdoExtension->ReleaseQueueIrp); 08088 } else { 08089 IoFreeIrp(fdoExtension->ReleaseQueueIrp); 08090 } 08091 fdoExtension->ReleaseQueueIrp = NULL; 08092 } 08093 08094 // 08095 // free anything that we allocated 08096 // 08097 08098 if ((fdoExtension->PrivateFdoData) && 08099 (fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated)) { 08100 08101 ExFreePool(fdoExtension->PrivateFdoData->ReleaseQueueIrp); 08102 fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated = FALSE; 08103 fdoExtension->PrivateFdoData->ReleaseQueueIrp = NULL; 08104 } 08105 08106 return; 08107 } // end ClasspFreeReleaseRequest() 08108 08109 /*++//////////////////////////////////////////////////////////////////////////// 08110 08111 ClassReleaseQueue() 08112 08113 Routine Description: 08114 08115 This routine issues an internal device control command 08116 to the port driver to release a frozen queue. The call 08117 is issued asynchronously as ClassReleaseQueue will be invoked 08118 from the IO completion DPC (and will have no context to 08119 wait for a synchronous call to complete). 08120 08121 This routine must be called with the remove lock held. 08122 08123 Arguments: 08124 08125 Fdo - The functional device object for the device with the frozen queue. 08126 08127 Return Value: 08128 08129 None. 08130 08131 --*/ 08132 VOID 08133 ClassReleaseQueue( 08134 IN PDEVICE_OBJECT Fdo 08135 ) 08136 { 08137 ClasspReleaseQueue(Fdo, NULL); 08138 return; 08139 } // end ClassReleaseQueue() 08140 08141 /*++//////////////////////////////////////////////////////////////////////////// 08142 08143 ClasspAllocateReleaseQueueIrp() 08144 08145 Routine Description: 08146 08147 This routine allocates the release queue irp held in classpnp's private 08148 extension. This was added to allow no-memory conditions to be more 08149 survivable. 08150 08151 Return Value: 08152 08153 NT_SUCCESS value. 08154 08155 Notes: 08156 08157 Does not grab the spinlock. Should only be called from StartDevice() 08158 routine. May be called elsewhere for poorly-behaved drivers that cause 08159 the queue to lockup before the device is started. This should *never* 08160 occur, since it's illegal to send a request to a non-started PDO. This 08161 condition is checked for in ClasspReleaseQueue(). 08162 08163 --*/ 08164 NTSTATUS 08165 ClasspAllocateReleaseQueueIrp( 08166 PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 08167 ) 08168 { 08169 KIRQL oldIrql; 08170 UCHAR lowerStackSize; 08171 08172 // 08173 // do an initial check w/o the spinlock 08174 // 08175 08176 if (FdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) { 08177 return STATUS_SUCCESS; 08178 } 08179 08180 08181 lowerStackSize = FdoExtension->CommonExtension.LowerDeviceObject->StackSize; 08182 08183 // 08184 // don't allocate one if one is in progress! this means whoever called 08185 // this routine didn't check if one was in progress. 08186 // 08187 08188 ASSERT(!(FdoExtension->ReleaseQueueInProgress)); 08189 08190 FdoExtension->PrivateFdoData->ReleaseQueueIrp = 08191 ExAllocatePoolWithTag(NonPagedPool, 08192 IoSizeOfIrp(lowerStackSize), 08193 CLASS_TAG_RELEASE_QUEUE 08194 ); 08195 08196 if (FdoExtension->PrivateFdoData->ReleaseQueueIrp == NULL) { 08197 DebugPrint((0, "ClassPnpStartDevice: Cannot allocate for " 08198 "release queue irp\n")); 08199 return STATUS_INSUFFICIENT_RESOURCES; 08200 } 08201 IoInitializeIrp(FdoExtension->PrivateFdoData->ReleaseQueueIrp, 08202 IoSizeOfIrp(lowerStackSize), 08203 lowerStackSize); 08204 FdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated = TRUE; 08205 08206 return STATUS_SUCCESS; 08207 } 08208 08209 08210 /*++//////////////////////////////////////////////////////////////////////////// 08211 08212 ClasspReleaseQueue() 08213 08214 Routine Description: 08215 08216 This routine issues an internal device control command 08217 to the port driver to release a frozen queue. The call 08218 is issued asynchronously as ClassReleaseQueue will be invoked 08219 from the IO completion DPC (and will have no context to 08220 wait for a synchronous call to complete). 08221 08222 This routine must be called with the remove lock held. 08223 08224 Arguments: 08225 08226 Fdo - The functional device object for the device with the frozen queue. 08227 08228 ReleaseQueueIrp - If this irp is supplied then the test to determine whether 08229 a release queue request is in progress will be ignored. 08230 The irp provided must be the IRP originally allocated 08231 for release queue requests (so this parameter can only 08232 really be provided by the release queue completion 08233 routine.) 08234 08235 Return Value: 08236 08237 None. 08238 08239 --*/ 08240 VOID 08241 ClasspReleaseQueue( 08242 IN PDEVICE_OBJECT Fdo, 08243 IN PIRP ReleaseQueueIrp OPTIONAL 08244 ) 08245 { 08246 PIO_STACK_LOCATION irpStack; 08247 PIRP irp; 08248 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension; 08249 PDEVICE_OBJECT lowerDevice; 08250 PSCSI_REQUEST_BLOCK srb; 08251 KIRQL currentIrql; 08252 08253 lowerDevice = fdoExtension->CommonExtension.LowerDeviceObject; 08254 08255 // 08256 // we raise irql seperately so we're not swapped out or suspended 08257 // while holding the release queue irp in this routine. this lets 08258 // us release the spin lock before lowering irql. 08259 // 08260 08261 KeRaiseIrql(DISPATCH_LEVEL, ¤tIrql); 08262 08263 KeAcquireSpinLockAtDpcLevel(&(fdoExtension->ReleaseQueueSpinLock)); 08264 08265 // 08266 // make sure that if they passed us an irp, it matches our allocated irp. 08267 // 08268 08269 ASSERT((ReleaseQueueIrp == NULL) || 08270 (ReleaseQueueIrp == fdoExtension->PrivateFdoData->ReleaseQueueIrp)); 08271 08272 // 08273 // ASSERT that we've already allocated this. (should not occur) 08274 // try to allocate it anyways, then finally bugcheck if 08275 // there's still no memory... 08276 // 08277 08278 ASSERT(fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated); 08279 if (!fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) { 08280 ClasspAllocateReleaseQueueIrp(fdoExtension); 08281 } 08282 if (!fdoExtension->PrivateFdoData->ReleaseQueueIrpAllocated) { 08283 KeBugCheckEx(SCSI_DISK_DRIVER_INTERNAL, 0x12, (ULONG_PTR)Fdo, 0x0, 0x0); 08284 } 08285 08286 if ((fdoExtension->ReleaseQueueInProgress) && (ReleaseQueueIrp == NULL)) { 08287 08288 // 08289 // Someone is already using the irp - just set the flag to indicate that 08290 // we need to release the queue again. 08291 // 08292 08293 fdoExtension->ReleaseQueueNeeded = TRUE; 08294 KeReleaseSpinLockFromDpcLevel(&(fdoExtension->ReleaseQueueSpinLock)); 08295 KeLowerIrql(currentIrql); 08296 return; 08297 08298 } 08299 08300 // 08301 // Mark that there is a release queue in progress and drop the spinlock. 08302 // 08303 08304 fdoExtension->ReleaseQueueInProgress = TRUE; 08305 if (ReleaseQueueIrp) { 08306 irp = ReleaseQueueIrp; 08307 } else { 08308 irp = fdoExtension->PrivateFdoData->ReleaseQueueIrp; 08309 } 08310 srb = &(fdoExtension->ReleaseQueueSrb); 08311 08312 KeReleaseSpinLockFromDpcLevel(&(fdoExtension->ReleaseQueueSpinLock)); 08313 08314 ASSERT(irp != NULL); 08315 08316 irpStack = IoGetNextIrpStackLocation(irp); 08317 08318 irpStack->MajorFunction = IRP_MJ_SCSI; 08319 08320 srb->OriginalRequest = irp; 08321 08322 // 08323 // Store the SRB address in next stack for port driver. 08324 // 08325 08326 irpStack->Parameters.Scsi.Srb = srb; 08327 08328 // 08329 // If this device is removable then flush the queue. This will also 08330 // release it. 08331 // 08332 08333 if (TEST_FLAG(Fdo->Characteristics, FILE_REMOVABLE_MEDIA)){ 08334 srb->Function = SRB_FUNCTION_FLUSH_QUEUE; 08335 } 08336 else { 08337 srb->Function = SRB_FUNCTION_RELEASE_QUEUE; 08338 } 08339 08340 ClassAcquireRemoveLock(Fdo, irp); 08341 08342 IoSetCompletionRoutine(irp, 08343 ClassReleaseQueueCompletion, 08344 Fdo, 08345 TRUE, 08346 TRUE, 08347 TRUE); 08348 08349 IoCallDriver(lowerDevice, irp); 08350 08351 KeLowerIrql(currentIrql); 08352 08353 return; 08354 08355 } // end ClassReleaseQueue() 08356 08357 /*++//////////////////////////////////////////////////////////////////////////// 08358 08359 ClassReleaseQueueCompletion() 08360 08361 Routine Description: 08362 08363 This routine is called when an asynchronous I/O request 08364 which was issused by the class driver completes. Examples of such requests 08365 are release queue or START UNIT. This routine releases the queue if 08366 necessary. It then frees the context and the IRP. 08367 08368 Arguments: 08369 08370 DeviceObject - The device object for the logical unit; however since this 08371 is the top stack location the value is NULL. 08372 08373 Irp - Supplies a pointer to the Irp to be processed. 08374 08375 Context - Supplies the context to be used to process this request. 08376 08377 Return Value: 08378 08379 None. 08380 08381 --*/ 08382 NTSTATUS 08383 ClassReleaseQueueCompletion( 08384 PDEVICE_OBJECT DeviceObject, 08385 PIRP Irp, 08386 PVOID Context 08387 ) 08388 { 08389 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 08390 KIRQL oldIrql; 08391 08392 BOOLEAN releaseQueueNeeded; 08393 08394 DeviceObject = Context; 08395 08396 fdoExtension = DeviceObject->DeviceExtension; 08397 08398 ClassReleaseRemoveLock(DeviceObject, Irp); 08399 08400 // 08401 // Grab the spinlock and clear the release queue in progress flag so others 08402 // can run. Save (and clear) the state of the release queue needed flag 08403 // so that we can issue a new release queue outside the spinlock. 08404 // 08405 08406 KeAcquireSpinLock(&(fdoExtension->ReleaseQueueSpinLock), &oldIrql); 08407 08408 releaseQueueNeeded = fdoExtension->ReleaseQueueNeeded; 08409 08410 fdoExtension->ReleaseQueueNeeded = FALSE; 08411 fdoExtension->ReleaseQueueInProgress = FALSE; 08412 08413 KeReleaseSpinLock(&(fdoExtension->ReleaseQueueSpinLock), oldIrql); 08414 08415 // 08416 // If we need a release queue then issue one now. Another processor may 08417 // have already started one in which case we'll try to issue this one after 08418 // it is done - but we should never recurse more than one deep. 08419 // 08420 08421 if(releaseQueueNeeded) { 08422 ClasspReleaseQueue(DeviceObject, Irp); 08423 } 08424 08425 // 08426 // Indicate the I/O system should stop processing the Irp completion. 08427 // 08428 08429 return STATUS_MORE_PROCESSING_REQUIRED; 08430 08431 } // ClassAsynchronousCompletion() 08432 08433 /*++//////////////////////////////////////////////////////////////////////////// 08434 08435 ClassAcquireChildLock() 08436 08437 Routine Description: 08438 08439 This routine acquires the lock protecting children PDOs. It may be 08440 acquired recursively by the same thread, but must be release by the 08441 thread once for each acquisition. 08442 08443 Arguments: 08444 08445 FdoExtension - the device whose child list is protected. 08446 08447 Return Value: 08448 08449 None 08450 08451 --*/ 08452 VOID 08453 ClassAcquireChildLock( 08454 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 08455 ) 08456 { 08457 PAGED_CODE(); 08458 08459 if(FdoExtension->ChildLockOwner != KeGetCurrentThread()) { 08460 KeWaitForSingleObject(&FdoExtension->ChildLock, 08461 Executive, KernelMode, 08462 FALSE, NULL); 08463 08464 ASSERT(FdoExtension->ChildLockOwner == NULL); 08465 ASSERT(FdoExtension->ChildLockAcquisitionCount == 0); 08466 08467 FdoExtension->ChildLockOwner = KeGetCurrentThread(); 08468 } else { 08469 ASSERT(FdoExtension->ChildLockAcquisitionCount != 0); 08470 } 08471 08472 FdoExtension->ChildLockAcquisitionCount++; 08473 return; 08474 } 08475 08476 /*++//////////////////////////////////////////////////////////////////////////// 08477 08478 ClassReleaseChildLock() ISSUE-2000/02/18-henrygab - not documented 08479 08480 Routine Description: 08481 08482 This routine releases the lock protecting children PDOs. It must be 08483 called once for each time ClassAcquireChildLock was called. 08484 08485 Arguments: 08486 08487 FdoExtension - the device whose child list is protected 08488 08489 Return Value: 08490 08491 None. 08492 08493 --*/ 08494 VOID 08495 ClassReleaseChildLock( 08496 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 08497 ) 08498 { 08499 ASSERT(FdoExtension->ChildLockOwner == KeGetCurrentThread()); 08500 ASSERT(FdoExtension->ChildLockAcquisitionCount != 0); 08501 08502 FdoExtension->ChildLockAcquisitionCount -= 1; 08503 08504 if(FdoExtension->ChildLockAcquisitionCount == 0) { 08505 FdoExtension->ChildLockOwner = NULL; 08506 KeSetEvent(&FdoExtension->ChildLock, IO_NO_INCREMENT, FALSE); 08507 } 08508 08509 return; 08510 } // end ClassReleaseChildLock( 08511 08512 /*++//////////////////////////////////////////////////////////////////////////// 08513 08514 ClassAddChild() 08515 08516 Routine Description: 08517 08518 This routine will insert a new child into the head of the child list. 08519 08520 Arguments: 08521 08522 Parent - the child's parent (contains the head of the list) 08523 Child - the child to be inserted. 08524 AcquireLock - whether the child lock should be acquired (TRUE) or whether 08525 it's already been acquired by or on behalf of the caller 08526 (FALSE). 08527 08528 Return Value: 08529 08530 None. 08531 08532 --*/ 08533 VOID 08534 ClassAddChild( 08535 IN PFUNCTIONAL_DEVICE_EXTENSION Parent, 08536 IN PPHYSICAL_DEVICE_EXTENSION Child, 08537 IN BOOLEAN AcquireLock 08538 ) 08539 { 08540 if(AcquireLock) { 08541 ClassAcquireChildLock(Parent); 08542 } 08543 08544 #if DBG 08545 // 08546 // Make sure this child's not already in the list. 08547 // 08548 { 08549 PPHYSICAL_DEVICE_EXTENSION testChild; 08550 08551 for (testChild = Parent->CommonExtension.ChildList; 08552 testChild != NULL; 08553 testChild = testChild->CommonExtension.ChildList) { 08554 08555 ASSERT(testChild != Child); 08556 } 08557 } 08558 #endif 08559 08560 Child->CommonExtension.ChildList = Parent->CommonExtension.ChildList; 08561 Parent->CommonExtension.ChildList = Child; 08562 08563 if(AcquireLock) { 08564 ClassReleaseChildLock(Parent); 08565 } 08566 return; 08567 } // end ClassAddChild() 08568 08569 /*++//////////////////////////////////////////////////////////////////////////// 08570 08571 ClassRemoveChild() 08572 08573 Routine Description: 08574 08575 This routine will remove a child from the child list. 08576 08577 Arguments: 08578 08579 Parent - the parent to be removed from. 08580 08581 Child - the child to be removed or NULL if the first child should be 08582 removed. 08583 08584 AcquireLock - whether the child lock should be acquired (TRUE) or whether 08585 it's already been acquired by or on behalf of the caller 08586 (FALSE). 08587 08588 Return Value: 08589 08590 A pointer to the child which was removed or NULL if no such child could 08591 be found in the list (or if Child was NULL but the list is empty). 08592 08593 --*/ 08594 PPHYSICAL_DEVICE_EXTENSION 08595 ClassRemoveChild( 08596 IN PFUNCTIONAL_DEVICE_EXTENSION Parent, 08597 IN PPHYSICAL_DEVICE_EXTENSION Child, 08598 IN BOOLEAN AcquireLock 08599 ) 08600 { 08601 if(AcquireLock) { 08602 ClassAcquireChildLock(Parent); 08603 } 08604 08605 TRY { 08606 PCOMMON_DEVICE_EXTENSION previousChild = &Parent->CommonExtension; 08607 08608 // 08609 // If the list is empty then bail out now. 08610 // 08611 08612 if(Parent->CommonExtension.ChildList == NULL) { 08613 Child = NULL; 08614 LEAVE; 08615 } 08616 08617 // 08618 // If the caller specified a child then find the child object before 08619 // it. If none was specified then the FDO is the child object before 08620 // the one we want to remove. 08621 // 08622 08623 if(Child != NULL) { 08624 08625 // 08626 // Scan through the child list to find the entry which points to 08627 // this one. 08628 // 08629 08630 do { 08631 ASSERT(previousChild != &Child->CommonExtension); 08632 08633 if(previousChild->ChildList == Child) { 08634 break; 08635 } 08636 08637 previousChild = &previousChild->ChildList->CommonExtension; 08638 } while(previousChild != NULL); 08639 08640 if(previousChild == NULL) { 08641 Child = NULL; 08642 LEAVE; 08643 } 08644 } 08645 08646 // 08647 // Save the next child away then unlink it from the list. 08648 // 08649 08650 Child = previousChild->ChildList; 08651 previousChild->ChildList = Child->CommonExtension.ChildList; 08652 Child->CommonExtension.ChildList = NULL; 08653 08654 } FINALLY { 08655 if(AcquireLock) { 08656 ClassReleaseChildLock(Parent); 08657 } 08658 } 08659 return Child; 08660 } // end ClassRemoveChild() 08661 08662 08663 /*++ 08664 08665 ISSUE-2000/02/20-henrygab Not documented ClasspRetryRequestDpc 08666 08667 --*/ 08668 VOID 08669 ClasspRetryRequestDpc( 08670 IN PKDPC Dpc, 08671 IN PDEVICE_OBJECT DeviceObject, 08672 IN PVOID Arg1, 08673 IN PVOID Arg2 08674 ) 08675 { 08676 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 08677 PCOMMON_DEVICE_EXTENSION commonExtension; 08678 PCLASS_PRIVATE_FDO_DATA fdoData; 08679 PCLASS_RETRY_INFO retryList; 08680 KIRQL irql; 08681 08682 08683 commonExtension = DeviceObject->DeviceExtension; 08684 ASSERT(commonExtension->IsFdo); 08685 fdoExtension = DeviceObject->DeviceExtension; 08686 fdoData = fdoExtension->PrivateFdoData; 08687 08688 08689 KeAcquireSpinLock(&fdoData->Retry.Lock, &irql); 08690 { 08691 LARGE_INTEGER now; 08692 KeQueryTickCount(&now); 08693 08694 // 08695 // if CurrentTick is less than now 08696 // fire another DPC 08697 // else 08698 // retry entire list 08699 // endif 08700 // 08701 08702 if (now.QuadPart < fdoData->Retry.Tick.QuadPart) { 08703 08704 ClasspRetryDpcTimer(fdoData); 08705 retryList = NULL; 08706 08707 } else { 08708 08709 retryList = fdoData->Retry.ListHead; 08710 fdoData->Retry.ListHead = NULL; 08711 fdoData->Retry.Delta.QuadPart = (LONGLONG)0; 08712 fdoData->Retry.Tick.QuadPart = (LONGLONG)0; 08713 08714 } 08715 } 08716 KeReleaseSpinLock(&fdoData->Retry.Lock, irql); 08717 08718 while (retryList != NULL) { 08719 08720 PIRP irp; 08721 08722 irp = CONTAINING_RECORD(retryList, IRP, Tail.Overlay.DriverContext[0]); 08723 DebugPrint((ClassDebugDelayedRetry, "ClassRetry: -- %p\n", irp)); 08724 retryList = retryList->Next; 08725 #if DBG 08726 irp->Tail.Overlay.DriverContext[0] = ULongToPtr(0xdddddddd); // invalidate data 08727 irp->Tail.Overlay.DriverContext[1] = ULongToPtr(0xdddddddd); // invalidate data 08728 irp->Tail.Overlay.DriverContext[2] = ULongToPtr(0xdddddddd); // invalidate data 08729 irp->Tail.Overlay.DriverContext[3] = ULongToPtr(0xdddddddd); // invalidate data 08730 #endif 08731 08732 IoCallDriver(commonExtension->LowerDeviceObject, irp); 08733 08734 } 08735 return; 08736 08737 } // end ClasspRetryRequestDpc() 08738 08739 /*++ 08740 08741 ISSUE-2000/02/20-henrygab Not documented ClassRetryRequest 08742 08743 --*/ 08744 VOID 08745 ClassRetryRequest( 08746 IN PDEVICE_OBJECT SelfDeviceObject, 08747 IN PIRP Irp, 08748 IN LARGE_INTEGER TimeDelta100ns // in 100ns units 08749 ) 08750 { 08751 PFUNCTIONAL_DEVICE_EXTENSION fdoExtension; 08752 PCLASS_PRIVATE_FDO_DATA fdoData; 08753 PCLASS_RETRY_INFO retryInfo; 08754 PCLASS_RETRY_INFO *previousNext; 08755 LARGE_INTEGER delta; 08756 KIRQL irql; 08757 08758 // 08759 // this checks we aren't destroying irps 08760 // 08761 ASSERT(sizeof(CLASS_RETRY_INFO) <= (4*sizeof(PVOID))); 08762 08763 fdoExtension = SelfDeviceObject->DeviceExtension; 08764 fdoData = fdoExtension->PrivateFdoData; 08765 08766 if (!fdoExtension->CommonExtension.IsFdo) { 08767 08768 // 08769 // this debug print/assertion should ALWAYS be investigated. 08770 // ClassRetryRequest can currently only be used by FDO's 08771 // 08772 08773 DebugPrint((ClassDebugError, "ClassRetryRequestEx: LOST IRP %p\n", Irp)); 08774 ASSERT(!"ClassRetryRequestEx Called From PDO? LOST IRP"); 08775 return; 08776 08777 } 08778 08779 if (TimeDelta100ns.QuadPart < 0) { 08780 ASSERT(!"ClassRetryRequest - must use positive delay"); 08781 TimeDelta100ns.QuadPart *= -1; 08782 } 08783 08784 // 08785 // prepare what we can out of the loop 08786 // 08787 08788 retryInfo = (PCLASS_RETRY_INFO)(&Irp->Tail.Overlay.DriverContext[0]); 08789 RtlZeroMemory(retryInfo, sizeof(CLASS_RETRY_INFO)); 08790 08791 delta.QuadPart = (TimeDelta100ns.QuadPart / fdoData->Retry.Granularity); 08792 if (TimeDelta100ns.QuadPart % fdoData->Retry.Granularity) { 08793 delta.QuadPart ++; // round up to next tick 08794 } 08795 if (delta.QuadPart == (LONGLONG)0) { 08796 delta.QuadPart = MINIMUM_RETRY_UNITS; 08797 } 08798 08799 // 08800 // now determine if we should fire another DPC or not 08801 // 08802 08803 KeAcquireSpinLock(&fdoData->Retry.Lock, &irql); 08804 08805 // 08806 // always add request to the list 08807 // 08808 08809 retryInfo->Next = fdoData->Retry.ListHead; 08810 fdoData->Retry.ListHead = retryInfo; 08811 08812 if (fdoData->Retry.Delta.QuadPart == (LONGLONG)0) { 08813 08814 DebugPrint((ClassDebugDelayedRetry, "ClassRetry: +++ %p\n", Irp)); 08815 08816 // 08817 // must be exactly one item on list 08818 // 08819 08820 ASSERT(fdoData->Retry.ListHead != NULL); 08821 ASSERT(fdoData->Retry.ListHead->Next == NULL); 08822 08823 // 08824 // if currentDelta is zero, always fire a DPC 08825 // 08826 08827 KeQueryTickCount(&fdoData->Retry.Tick); 08828 fdoData->Retry.Tick.QuadPart += delta.QuadPart; 08829 fdoData->Retry.Delta.QuadPart = delta.QuadPart; 08830 ClasspRetryDpcTimer(fdoData); 08831 08832 } else if (delta.QuadPart > fdoData->Retry.Delta.QuadPart) { 08833 08834 // 08835 // if delta is greater than the list's current delta, 08836 // increase the DPC handling time by difference 08837 // and update the delta to new larger value 08838 // allow the DPC to re-fire itself if needed 08839 // 08840 08841 DebugPrint((ClassDebugDelayedRetry, "ClassRetry: ++ %p\n", Irp)); 08842 08843 // 08844 // must be at least two items on list 08845 // 08846 08847 ASSERT(fdoData->Retry.ListHead != NULL); 08848 ASSERT(fdoData->Retry.ListHead->Next != NULL); 08849 08850 fdoData->Retry.Tick.QuadPart -= fdoData->Retry.Delta.QuadPart; 08851 fdoData->Retry.Tick.QuadPart += delta.QuadPart; 08852 08853 fdoData->Retry.Delta.QuadPart = delta.QuadPart; 08854 08855 } else { 08856 08857 // 08858 // just inserting it on the list was enough 08859 // 08860 08861 DebugPrint((ClassDebugDelayedRetry, "ClassRetry: ++ %p\n", Irp)); 08862 08863 } 08864 08865 08866 KeReleaseSpinLock(&fdoData->Retry.Lock, irql); 08867 08868 08869 } // end ClassRetryRequest() 08870 08871 /*++ 08872 08873 ISSUE-2000/02/20-henrygab Not documented ClasspRetryDpcTimer 08874 08875 --*/ 08876 VOID 08877 ClasspRetryDpcTimer( 08878 IN PCLASS_PRIVATE_FDO_DATA FdoData 08879 ) 08880 { 08881 LARGE_INTEGER fire; 08882 08883 ASSERT(FdoData->Retry.Tick.QuadPart != (LONGLONG)0); 08884 ASSERT(FdoData->Retry.ListHead != NULL); // never fire an empty list 08885 08886 // 08887 // fire == (CurrentTick - now) * (100ns per tick) 08888 // 08889 // NOTE: Overflow is nearly impossible and is ignored here 08890 // 08891 08892 KeQueryTickCount(&fire); 08893 fire.QuadPart = FdoData->Retry.Tick.QuadPart - fire.QuadPart; 08894 fire.QuadPart *= FdoData->Retry.Granularity; 08895 08896 // 08897 // fire is now multiples of 100ns until should fire the timer. 08898 // if timer should already have expired, or would fire too quickly, 08899 // fire it in some arbitrary number of ticks to prevent infinitely 08900 // recursing. 08901 // 08902 08903 if (fire.QuadPart < MINIMUM_RETRY_UNITS) { 08904 fire.QuadPart = MINIMUM_RETRY_UNITS; 08905 } 08906 08907 DebugPrint((ClassDebugDelayedRetry, 08908 "ClassRetry: ======= %I64x ticks\n", 08909 fire.QuadPart)); 08910 08911 // 08912 // must use negative to specify relative time to fire 08913 // 08914 08915 fire.QuadPart = fire.QuadPart * ((LONGLONG)-1); 08916 08917 // 08918 // set the timer, since this is the first addition 08919 // 08920 08921 KeSetTimerEx(&FdoData->Retry.Timer, fire, 0, &FdoData->Retry.Dpc); 08922 08923 return; 08924 } // end ClasspRetryDpcTimer() 08925 08926 NTSTATUS 08927 ClasspInitializeHotplugInfo( 08928 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 08929 ) 08930 { 08931 PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData; 08932 DEVICE_REMOVAL_POLICY deviceRemovalPolicy; 08933 NTSTATUS status; 08934 ULONG resultLength = 0; 08935 ULONG writeCacheOverride; 08936 08937 PAGED_CODE(); 08938 08939 // 08940 // start with some default settings 08941 // 08942 RtlZeroMemory(&(fdoData->HotplugInfo), sizeof(STORAGE_HOTPLUG_INFO)); 08943 08944 // 08945 // set the size (aka version) 08946 // 08947 08948 fdoData->HotplugInfo.Size = sizeof(STORAGE_HOTPLUG_INFO); 08949 08950 // 08951 // set if the device has removable media 08952 // 08953 08954 if (FdoExtension->DeviceDescriptor->RemovableMedia) { 08955 fdoData->HotplugInfo.MediaRemovable = TRUE; 08956 } else { 08957 fdoData->HotplugInfo.MediaRemovable = FALSE; 08958 } 08959 08960 // 08961 // this refers to devices which, for reasons not yet understood, 08962 // do not fail PREVENT_MEDIA_REMOVAL requests even though they 08963 // have no way to lock the media into the drive. this allows 08964 // the filesystems to turn off delayed-write caching for these 08965 // devices as well. 08966 // 08967 08968 if (TEST_FLAG(FdoExtension->PrivateFdoData->HackFlags, 08969 FDO_HACK_CANNOT_LOCK_MEDIA)) { 08970 fdoData->HotplugInfo.MediaHotplug = TRUE; 08971 } else { 08972 fdoData->HotplugInfo.MediaHotplug = FALSE; 08973 } 08974 08975 08976 // 08977 // Look into the registry to see if the user has chosen 08978 // to override the default setting for the removal policy 08979 // 08980 08981 RtlZeroMemory(&deviceRemovalPolicy, sizeof(DEVICE_REMOVAL_POLICY)); 08982 08983 ClassGetDeviceParameter(FdoExtension, 08984 CLASSP_REG_SUBKEY_NAME, 08985 CLASSP_REG_REMOVAL_POLICY_VALUE_NAME, 08986 (PULONG)&deviceRemovalPolicy); 08987 08988 if (deviceRemovalPolicy == 0) 08989 { 08990 // 08991 // Query the default removal policy from the kernel 08992 // 08993 08994 status = IoGetDeviceProperty(FdoExtension->LowerPdo, 08995 DevicePropertyRemovalPolicy, 08996 sizeof(DEVICE_REMOVAL_POLICY), 08997 (PVOID)&deviceRemovalPolicy, 08998 &resultLength); 08999 if (!NT_SUCCESS(status)) 09000 { 09001 return status; 09002 } 09003 09004 if (resultLength != sizeof(DEVICE_REMOVAL_POLICY)) 09005 { 09006 return STATUS_UNSUCCESSFUL; 09007 } 09008 } 09009 09010 // 09011 // use this info to set the DeviceHotplug setting 09012 // don't rely on DeviceCapabilities, since it can't properly 09013 // determine device relations, etc. let the kernel figure this 09014 // stuff out instead. 09015 // 09016 09017 if (deviceRemovalPolicy == RemovalPolicyExpectSurpriseRemoval) { 09018 fdoData->HotplugInfo.DeviceHotplug = TRUE; 09019 } else { 09020 fdoData->HotplugInfo.DeviceHotplug = FALSE; 09021 } 09022 09023 // 09024 // this refers to the *filesystem* caching, but has to be included 09025 // here since it's a per-device setting. this may change to be 09026 // stored by the system in the future. 09027 // 09028 09029 writeCacheOverride = FALSE; 09030 ClassGetDeviceParameter(FdoExtension, 09031 CLASSP_REG_SUBKEY_NAME, 09032 CLASSP_REG_WRITE_CACHE_VALUE_NAME, 09033 &writeCacheOverride); 09034 09035 if (writeCacheOverride) { 09036 fdoData->HotplugInfo.WriteCacheEnableOverride = TRUE; 09037 } else { 09038 fdoData->HotplugInfo.WriteCacheEnableOverride = FALSE; 09039 } 09040 09041 return STATUS_SUCCESS; 09042 } 09043 09044 VOID 09045 ClasspScanForClassHacks( 09046 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 09047 IN ULONG_PTR Data 09048 ) 09049 { 09050 PAGED_CODE(); 09051 09052 // 09053 // remove invalid flags and save 09054 // 09055 09056 CLEAR_FLAG(Data, FDO_HACK_INVALID_FLAGS); 09057 SET_FLAG(FdoExtension->PrivateFdoData->HackFlags, Data); 09058 return; 09059 } 09060 09061 VOID 09062 ClasspScanForSpecialInRegistry( 09063 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 09064 ) 09065 { 09066 HANDLE deviceParameterHandle; // device instance key 09067 HANDLE classParameterHandle; // classpnp subkey 09068 OBJECT_ATTRIBUTES objectAttributes; 09069 UNICODE_STRING subkeyName; 09070 NTSTATUS status; 09071 09072 // 09073 // seeded in the ENUM tree by ClassInstaller 09074 // 09075 ULONG deviceHacks; 09076 RTL_QUERY_REGISTRY_TABLE queryTable[2]; // null terminated array 09077 09078 PAGED_CODE(); 09079 09080 deviceParameterHandle = NULL; 09081 classParameterHandle = NULL; 09082 deviceHacks = 0; 09083 09084 status = IoOpenDeviceRegistryKey(FdoExtension->LowerPdo, 09085 PLUGPLAY_REGKEY_DEVICE, 09086 KEY_WRITE, 09087 &deviceParameterHandle 09088 ); 09089 09090 if (!NT_SUCCESS(status)) { 09091 goto cleanupScanForSpecial; 09092 } 09093 09094 RtlInitUnicodeString(&subkeyName, CLASSP_REG_SUBKEY_NAME); 09095 InitializeObjectAttributes(&objectAttributes, 09096 &subkeyName, 09097 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 09098 deviceParameterHandle, 09099 NULL 09100 ); 09101 09102 status = ZwOpenKey( &classParameterHandle, 09103 KEY_READ, 09104 &objectAttributes 09105 ); 09106 09107 if (!NT_SUCCESS(status)) { 09108 goto cleanupScanForSpecial; 09109 } 09110 09111 // 09112 // Zero out the memory 09113 // 09114 09115 RtlZeroMemory(&queryTable[0], 2*sizeof(RTL_QUERY_REGISTRY_TABLE)); 09116 09117 // 09118 // Setup the structure to read 09119 // 09120 09121 queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; 09122 queryTable[0].Name = CLASSP_REG_HACK_VALUE_NAME; 09123 queryTable[0].EntryContext = &deviceHacks; 09124 queryTable[0].DefaultType = REG_DWORD; 09125 queryTable[0].DefaultData = &deviceHacks; 09126 queryTable[0].DefaultLength = 0; 09127 09128 // 09129 // read values 09130 // 09131 09132 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 09133 (PWSTR)classParameterHandle, 09134 &queryTable[0], 09135 NULL, 09136 NULL 09137 ); 09138 if (!NT_SUCCESS(status)) { 09139 goto cleanupScanForSpecial; 09140 } 09141 09142 // 09143 // remove unknown values and save... 09144 // 09145 09146 KdPrintEx((DPFLTR_CLASSPNP_ID, DPFLTR_ERROR_LEVEL, 09147 "Classpnp => ScanForSpecial: HackFlags %#08x\n", 09148 deviceHacks)); 09149 09150 CLEAR_FLAG(deviceHacks, FDO_HACK_INVALID_FLAGS); 09151 SET_FLAG(FdoExtension->PrivateFdoData->HackFlags, deviceHacks); 09152 09153 09154 cleanupScanForSpecial: 09155 09156 if (deviceParameterHandle) { 09157 ZwClose(deviceParameterHandle); 09158 } 09159 09160 if (classParameterHandle) { 09161 ZwClose(classParameterHandle); 09162 } 09163 09164 // 09165 // we should modify the system hive to include another key for us to grab 09166 // settings from. in this case: Classpnp\HackFlags 09167 // 09168 // the use of a DWORD value for the HackFlags allows 32 hacks w/o 09169 // significant use of the registry, and also reduces OEM exposure. 09170 // 09171 // definition of bit flags: 09172 // 0x00000001 -- Device succeeds PREVENT_MEDIUM_REMOVAL, but 09173 // cannot actually prevent removal. 09174 // 0x00000002 -- Device hard-hangs or times out for GESN requests. 09175 // 0xfffffffc -- Currently reserved, may be used later. 09176 // 09177 09178 return; 09179 } 09180 09181 09182 09183 Generated on Fri May 25 2012 04:26:36 for ReactOS by
1.7.6.1
|