Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenutils.c
Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (C) Microsoft Corporation, 1991 - 1999 00004 00005 Module Name: 00006 00007 utils.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 #include "classp.h" 00025 #include "debug.h" 00026 00027 00028 00029 #ifdef ALLOC_PRAGMA 00030 #pragma alloc_text(PAGE, ClassGetDeviceParameter) 00031 #pragma alloc_text(PAGE, ClassScanForSpecial) 00032 #pragma alloc_text(PAGE, ClassSetDeviceParameter) 00033 #endif 00034 00035 00036 00037 // custom string match -- careful! 00038 BOOLEAN ClasspMyStringMatches(IN PCHAR StringToMatch OPTIONAL, IN PCHAR TargetString) 00039 { 00040 ULONG length; // strlen returns an int, not size_t (!) 00041 PAGED_CODE(); 00042 ASSERT(TargetString); 00043 // if no match requested, return TRUE 00044 if (StringToMatch == NULL) { 00045 return TRUE; 00046 } 00047 // cache the string length for efficiency 00048 length = strlen(StringToMatch); 00049 // ZERO-length strings may only match zero-length strings 00050 if (length == 0) { 00051 return (strlen(TargetString) == 0); 00052 } 00053 // strncmp returns zero if the strings match 00054 return (strncmp(StringToMatch, TargetString, length) == 0); 00055 } 00056 00057 00058 VOID ClassGetDeviceParameter( 00059 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00060 IN PWSTR SubkeyName OPTIONAL, 00061 IN PWSTR ParameterName, 00062 IN OUT PULONG ParameterValue // also default value 00063 ) 00064 { 00065 NTSTATUS status; 00066 RTL_QUERY_REGISTRY_TABLE queryTable[2]; 00067 HANDLE deviceParameterHandle; 00068 HANDLE deviceSubkeyHandle; 00069 ULONG defaultParameterValue; 00070 00071 PAGED_CODE(); 00072 00073 // 00074 // open the given parameter 00075 // 00076 00077 status = IoOpenDeviceRegistryKey(FdoExtension->LowerPdo, 00078 PLUGPLAY_REGKEY_DEVICE, 00079 KEY_READ, 00080 &deviceParameterHandle); 00081 00082 if (NT_SUCCESS(status) && (SubkeyName != NULL)) { 00083 00084 UNICODE_STRING subkeyName; 00085 OBJECT_ATTRIBUTES objectAttributes; 00086 00087 RtlInitUnicodeString(&subkeyName, SubkeyName); 00088 InitializeObjectAttributes(&objectAttributes, 00089 &subkeyName, 00090 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 00091 deviceParameterHandle, 00092 NULL); 00093 00094 status = ZwOpenKey(&deviceSubkeyHandle, 00095 KEY_READ, 00096 &objectAttributes); 00097 if (!NT_SUCCESS(status)) { 00098 ZwClose(deviceParameterHandle); 00099 } 00100 00101 } 00102 00103 if (NT_SUCCESS(status)) { 00104 00105 RtlZeroMemory(queryTable, sizeof(queryTable)); 00106 00107 defaultParameterValue = *ParameterValue; 00108 00109 queryTable->Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; 00110 queryTable->Name = ParameterName; 00111 queryTable->EntryContext = ParameterValue; 00112 queryTable->DefaultType = REG_DWORD; 00113 queryTable->DefaultData = NULL; 00114 queryTable->DefaultLength = 0; 00115 00116 status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, 00117 (PWSTR)(SubkeyName ? 00118 deviceSubkeyHandle : 00119 deviceParameterHandle), 00120 queryTable, 00121 NULL, 00122 NULL); 00123 if (!NT_SUCCESS(status)) { 00124 *ParameterValue = defaultParameterValue; // use default value 00125 } 00126 00127 // 00128 // close what we open 00129 // 00130 00131 if (SubkeyName) { 00132 ZwClose(deviceSubkeyHandle); 00133 } 00134 00135 ZwClose(deviceParameterHandle); 00136 } 00137 00138 return; 00139 00140 } // end ClassGetDeviceParameter() 00141 00142 00143 NTSTATUS ClassSetDeviceParameter( 00144 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00145 IN PWSTR SubkeyName OPTIONAL, 00146 IN PWSTR ParameterName, 00147 IN ULONG ParameterValue) 00148 { 00149 NTSTATUS status; 00150 HANDLE deviceParameterHandle; 00151 HANDLE deviceSubkeyHandle; 00152 00153 PAGED_CODE(); 00154 00155 // 00156 // open the given parameter 00157 // 00158 00159 status = IoOpenDeviceRegistryKey(FdoExtension->LowerPdo, 00160 PLUGPLAY_REGKEY_DEVICE, 00161 KEY_READ | KEY_WRITE, 00162 &deviceParameterHandle); 00163 00164 if (NT_SUCCESS(status) && (SubkeyName != NULL)) { 00165 00166 UNICODE_STRING subkeyName; 00167 OBJECT_ATTRIBUTES objectAttributes; 00168 00169 RtlInitUnicodeString(&subkeyName, SubkeyName); 00170 InitializeObjectAttributes(&objectAttributes, 00171 &subkeyName, 00172 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 00173 deviceParameterHandle, 00174 NULL); 00175 00176 status = ZwCreateKey(&deviceSubkeyHandle, 00177 KEY_READ | KEY_WRITE, 00178 &objectAttributes, 00179 0, NULL, 0, NULL); 00180 if (!NT_SUCCESS(status)) { 00181 ZwClose(deviceParameterHandle); 00182 } 00183 00184 } 00185 00186 if (NT_SUCCESS(status)) { 00187 00188 status = RtlWriteRegistryValue( 00189 RTL_REGISTRY_HANDLE, 00190 (PWSTR) (SubkeyName ? 00191 deviceSubkeyHandle : 00192 deviceParameterHandle), 00193 ParameterName, 00194 REG_DWORD, 00195 &ParameterValue, 00196 sizeof(ULONG)); 00197 00198 // 00199 // close what we open 00200 // 00201 00202 if (SubkeyName) { 00203 ZwClose(deviceSubkeyHandle); 00204 } 00205 00206 ZwClose(deviceParameterHandle); 00207 } 00208 00209 return status; 00210 00211 } // end ClassSetDeviceParameter() 00212 00213 00214 /* 00215 * ClassScanForSpecial 00216 * 00217 * This routine was written to simplify scanning for special 00218 * hardware based upon id strings. it does not check the registry. 00219 */ 00220 00221 VOID ClassScanForSpecial( 00222 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, 00223 IN CLASSPNP_SCAN_FOR_SPECIAL_INFO DeviceList[], 00224 IN PCLASS_SCAN_FOR_SPECIAL_HANDLER Function) 00225 { 00226 PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor; 00227 PUCHAR vendorId; 00228 PUCHAR productId; 00229 PUCHAR productRevision; 00230 UCHAR nullString[] = ""; 00231 ULONG j; 00232 00233 PAGED_CODE(); 00234 ASSERT(DeviceList); 00235 ASSERT(Function); 00236 00237 deviceDescriptor = FdoExtension->DeviceDescriptor; 00238 00239 if (DeviceList == NULL) { 00240 return; 00241 } 00242 if (Function == NULL) { 00243 return; 00244 } 00245 00246 // 00247 // SCSI sets offsets to -1, ATAPI sets to 0. check for both. 00248 // 00249 00250 if (deviceDescriptor->VendorIdOffset != 0 && 00251 deviceDescriptor->VendorIdOffset != -1) { 00252 vendorId = ((PUCHAR)deviceDescriptor); 00253 vendorId += deviceDescriptor->VendorIdOffset; 00254 } else { 00255 vendorId = nullString; 00256 } 00257 if (deviceDescriptor->ProductIdOffset != 0 && 00258 deviceDescriptor->ProductIdOffset != -1) { 00259 productId = ((PUCHAR)deviceDescriptor); 00260 productId += deviceDescriptor->ProductIdOffset; 00261 } else { 00262 productId = nullString; 00263 } 00264 if (deviceDescriptor->VendorIdOffset != 0 && 00265 deviceDescriptor->VendorIdOffset != -1) { 00266 productRevision = ((PUCHAR)deviceDescriptor); 00267 productRevision += deviceDescriptor->ProductRevisionOffset; 00268 } else { 00269 productRevision = nullString; 00270 } 00271 00272 // 00273 // loop while the device list is valid (not null-filled) 00274 // 00275 00276 for (;(DeviceList->VendorId != NULL || 00277 DeviceList->ProductId != NULL || 00278 DeviceList->ProductRevision != NULL);DeviceList++) { 00279 00280 if (ClasspMyStringMatches(DeviceList->VendorId, vendorId) && 00281 ClasspMyStringMatches(DeviceList->ProductId, productId) && 00282 ClasspMyStringMatches(DeviceList->ProductRevision, productRevision) 00283 ) { 00284 00285 DebugPrint((1, "ClasspScanForSpecialByInquiry: Found matching " 00286 "controller Ven: %s Prod: %s Rev: %s\n", 00287 vendorId, productId, productRevision)); 00288 00289 // 00290 // pass the context to the call back routine and exit 00291 // 00292 00293 (Function)(FdoExtension, DeviceList->Data); 00294 00295 // 00296 // for CHK builds, try to prevent wierd stacks by having a debug 00297 // print here. it's a hack, but i know of no other way to prevent 00298 // the stack from being wrong. 00299 // 00300 00301 DebugPrint((16, "ClasspScanForSpecialByInquiry: " 00302 "completed callback\n")); 00303 return; 00304 00305 } // else the strings did not match 00306 00307 } // none of the devices matched. 00308 00309 DebugPrint((1, "ClasspScanForSpecialByInquiry: no match found for %p\n", 00310 FdoExtension->DeviceObject)); 00311 return; 00312 00313 } // end ClasspScanForSpecialByInquiry() 00314 00315 00316 // 00317 // In order to provide better performance without the need to reboot, 00318 // we need to implement a self-adjusting method to set and clear the 00319 // srb flags based upon current performance. 00320 // 00321 // whenever there is an error, immediately grab the spin lock. the 00322 // MP perf hit here is acceptable, since we're in an error path. this 00323 // is also neccessary because we are guaranteed to be modifying the 00324 // SRB flags here, setting SuccessfulIO to zero, and incrementing the 00325 // actual error count (which is always done within this spinlock). 00326 // 00327 // whenever there is no error, increment a counter. if there have been 00328 // errors on the device, and we've enabled dynamic perf, *and* we've 00329 // just crossed the perf threshhold, then grab the spin lock and 00330 // double check that the threshhold has, indeed been hit(*). then 00331 // decrement the error count, and if it's dropped sufficiently, undo 00332 // some of the safety changes made in the SRB flags due to the errors. 00333 // 00334 // * this works in all cases. even if lots of ios occur after the 00335 // previous guy went in and cleared the successfulio counter, that 00336 // just means that we've hit the threshhold again, and so it's proper 00337 // to run the inner loop again. 00338 // 00339 00340 VOID 00341 ClasspPerfIncrementErrorCount( 00342 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 00343 ) 00344 { 00345 PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData; 00346 KIRQL oldIrql; 00347 ULONG errors; 00348 00349 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 00350 00351 fdoData->Perf.SuccessfulIO = 0; // implicit interlock 00352 errors = InterlockedIncrement(&FdoExtension->ErrorCount); 00353 00354 if (errors >= CLASS_ERROR_LEVEL_1) { 00355 00356 // 00357 // If the error count has exceeded the error limit, then disable 00358 // any tagged queuing, multiple requests per lu queueing 00359 // and sychronous data transfers. 00360 // 00361 // Clearing the no queue freeze flag prevents the port driver 00362 // from sending multiple requests per logical unit. 00363 // 00364 00365 CLEAR_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE); 00366 CLEAR_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE); 00367 00368 SET_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER); 00369 00370 DebugPrint((ClassDebugError, "ClasspPerfIncrementErrorCount: " 00371 "Too many errors; disabling tagged queuing and " 00372 "synchronous data tranfers.\n")); 00373 00374 } 00375 00376 if (errors >= CLASS_ERROR_LEVEL_2) { 00377 00378 // 00379 // If a second threshold is reached, disable disconnects. 00380 // 00381 00382 SET_FLAG(FdoExtension->SrbFlags, SRB_FLAGS_DISABLE_DISCONNECT); 00383 DebugPrint((ClassDebugError, "ClasspPerfIncrementErrorCount: " 00384 "Too many errors; disabling disconnects.\n")); 00385 } 00386 00387 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 00388 return; 00389 } 00390 00391 VOID 00392 ClasspPerfIncrementSuccessfulIo( 00393 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 00394 ) 00395 { 00396 PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData; 00397 KIRQL oldIrql; 00398 ULONG errors; 00399 ULONG succeeded = 0; 00400 00401 // 00402 // don't take a hit from the interlocked op unless we're in 00403 // a degraded state and we've got a threshold to hit. 00404 // 00405 00406 if (FdoExtension->ErrorCount == 0) { 00407 return; 00408 } 00409 00410 if (fdoData->Perf.ReEnableThreshhold == 0) { 00411 return; 00412 } 00413 00414 succeeded = InterlockedIncrement(&fdoData->Perf.SuccessfulIO); 00415 if (succeeded < fdoData->Perf.ReEnableThreshhold) { 00416 return; 00417 } 00418 00419 // 00420 // if we hit the threshold, grab the spinlock and verify we've 00421 // actually done so. this allows us to ignore the spinlock 99% 00422 // of the time. 00423 // 00424 00425 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 00426 00427 // 00428 // re-read the value, so we don't run this multiple times 00429 // for a single threshhold being hit. this keeps errorcount 00430 // somewhat useful. 00431 // 00432 00433 succeeded = fdoData->Perf.SuccessfulIO; 00434 00435 if ((FdoExtension->ErrorCount != 0) && 00436 (fdoData->Perf.ReEnableThreshhold <= succeeded) 00437 ) { 00438 00439 fdoData->Perf.SuccessfulIO = 0; // implicit interlock 00440 00441 ASSERT(FdoExtension->ErrorCount > 0); 00442 errors = InterlockedDecrement(&FdoExtension->ErrorCount); 00443 00444 // 00445 // note: do in reverse order of the sets "just in case" 00446 // 00447 00448 if (errors < CLASS_ERROR_LEVEL_2) { 00449 if (errors == CLASS_ERROR_LEVEL_2 - 1) { 00450 DebugPrint((ClassDebugError, "ClasspPerfIncrementSuccessfulIo: " 00451 "Error level 2 no longer required.\n")); 00452 } 00453 if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags, 00454 SRB_FLAGS_DISABLE_DISCONNECT)) { 00455 CLEAR_FLAG(FdoExtension->SrbFlags, 00456 SRB_FLAGS_DISABLE_DISCONNECT); 00457 } 00458 } 00459 00460 if (errors < CLASS_ERROR_LEVEL_1) { 00461 if (errors == CLASS_ERROR_LEVEL_1 - 1) { 00462 DebugPrint((ClassDebugError, "ClasspPerfIncrementSuccessfulIo: " 00463 "Error level 1 no longer required.\n")); 00464 } 00465 if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags, 00466 SRB_FLAGS_DISABLE_SYNCH_TRANSFER)) { 00467 CLEAR_FLAG(FdoExtension->SrbFlags, 00468 SRB_FLAGS_DISABLE_SYNCH_TRANSFER); 00469 } 00470 if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags, 00471 SRB_FLAGS_QUEUE_ACTION_ENABLE)) { 00472 SET_FLAG(FdoExtension->SrbFlags, 00473 SRB_FLAGS_QUEUE_ACTION_ENABLE); 00474 } 00475 if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags, 00476 SRB_FLAGS_NO_QUEUE_FREEZE)) { 00477 SET_FLAG(FdoExtension->SrbFlags, 00478 SRB_FLAGS_NO_QUEUE_FREEZE); 00479 } 00480 } 00481 } // end of threshhold definitely being hit for first time 00482 00483 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 00484 return; 00485 } 00486 00487 00488 PMDL BuildDeviceInputMdl(PVOID Buffer, ULONG BufferLen) 00489 { 00490 PMDL mdl; 00491 00492 mdl = IoAllocateMdl(Buffer, BufferLen, FALSE, FALSE, NULL); 00493 if (mdl){ 00494 _SEH2_TRY { 00495 /* 00496 * We are reading from the device. 00497 * Therefore, the device is WRITING to the locked memory. 00498 * So we request IoWriteAccess. 00499 */ 00500 MmProbeAndLockPages(mdl, KernelMode, IoWriteAccess); 00501 00502 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 00503 NTSTATUS status = _SEH2_GetExceptionCode(); 00504 00505 DBGWARN(("BuildReadMdl: MmProbeAndLockPages failed with %xh.", status)); 00506 IoFreeMdl(mdl); 00507 mdl = NULL; 00508 } _SEH2_END; 00509 } 00510 else { 00511 DBGWARN(("BuildReadMdl: IoAllocateMdl failed")); 00512 } 00513 00514 return mdl; 00515 } 00516 00517 00518 VOID FreeDeviceInputMdl(PMDL Mdl) 00519 { 00520 MmUnlockPages(Mdl); 00521 IoFreeMdl(Mdl); 00522 } 00523 00524 00525 #if 0 00526 VOID 00527 ClasspPerfResetCounters( 00528 IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension 00529 ) 00530 { 00531 PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData; 00532 KIRQL oldIrql; 00533 00534 KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql); 00535 DebugPrint((ClassDebugError, "ClasspPerfResetCounters: " 00536 "Resetting all perf counters.\n")); 00537 fdoData->Perf.SuccessfulIO = 0; 00538 FdoExtension->ErrorCount = 0; 00539 00540 if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags, 00541 SRB_FLAGS_DISABLE_DISCONNECT)) { 00542 CLEAR_FLAG(FdoExtension->SrbFlags, 00543 SRB_FLAGS_DISABLE_DISCONNECT); 00544 } 00545 if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags, 00546 SRB_FLAGS_DISABLE_SYNCH_TRANSFER)) { 00547 CLEAR_FLAG(FdoExtension->SrbFlags, 00548 SRB_FLAGS_DISABLE_SYNCH_TRANSFER); 00549 } 00550 if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags, 00551 SRB_FLAGS_QUEUE_ACTION_ENABLE)) { 00552 SET_FLAG(FdoExtension->SrbFlags, 00553 SRB_FLAGS_QUEUE_ACTION_ENABLE); 00554 } 00555 if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags, 00556 SRB_FLAGS_NO_QUEUE_FREEZE)) { 00557 SET_FLAG(FdoExtension->SrbFlags, 00558 SRB_FLAGS_NO_QUEUE_FREEZE); 00559 } 00560 KeReleaseSpinLock(&fdoData->SpinLock, oldIrql); 00561 return; 00562 } 00563 #endif 00564 00565 Generated on Sun May 27 2012 04:22:17 for ReactOS by
1.7.6.1
|