ReactOS  0.4.14-dev-98-gb0d4763
utils.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (C) Microsoft Corporation, 1991 - 1999
4 
5 Module Name:
6 
7  utils.c
8 
9 Abstract:
10 
11  SCSI class driver routines
12 
13 Environment:
14 
15  kernel mode only
16 
17 Notes:
18 
19 
20 Revision History:
21 
22 --*/
23 
24 #include "classp.h"
25 
26 #ifdef ALLOC_PRAGMA
27  #pragma alloc_text(PAGE, ClassGetDeviceParameter)
28  #pragma alloc_text(PAGE, ClassScanForSpecial)
29  #pragma alloc_text(PAGE, ClassSetDeviceParameter)
30 #endif
31 
32 // custom string match -- careful!
34 {
35  ULONG length; // strlen returns an int, not size_t (!)
36  PAGED_CODE();
37  ASSERT(TargetString);
38  // if no match requested, return TRUE
39  if (StringToMatch == NULL) {
40  return TRUE;
41  }
42  // cache the string length for efficiency
43  length = strlen(StringToMatch);
44  // ZERO-length strings may only match zero-length strings
45  if (length == 0) {
46  return (strlen(TargetString) == 0);
47  }
48  // strncmp returns zero if the strings match
49  return (strncmp(StringToMatch, TargetString, length) == 0);
50 }
51 
56  IN OUT PULONG ParameterValue // also default value
57  )
58 {
60  RTL_QUERY_REGISTRY_TABLE queryTable[2];
61  HANDLE deviceParameterHandle;
62  HANDLE deviceSubkeyHandle;
63  ULONG defaultParameterValue;
64 
65  PAGED_CODE();
66 
67  //
68  // open the given parameter
69  //
70 
73  KEY_READ,
74  &deviceParameterHandle);
75 
76  if (NT_SUCCESS(status) && (SubkeyName != NULL)) {
77 
78  UNICODE_STRING subkeyName;
79  OBJECT_ATTRIBUTES objectAttributes;
80 
81  RtlInitUnicodeString(&subkeyName, SubkeyName);
82  InitializeObjectAttributes(&objectAttributes,
83  &subkeyName,
85  deviceParameterHandle,
86  NULL);
87 
88  status = ZwOpenKey(&deviceSubkeyHandle,
89  KEY_READ,
90  &objectAttributes);
91  if (!NT_SUCCESS(status)) {
92  ZwClose(deviceParameterHandle);
93  }
94 
95  }
96 
97  if (NT_SUCCESS(status)) {
98 
99  RtlZeroMemory(queryTable, sizeof(queryTable));
100 
101  defaultParameterValue = *ParameterValue;
102 
104  queryTable->Name = ParameterName;
105  queryTable->EntryContext = ParameterValue;
106  queryTable->DefaultType = REG_DWORD;
107  queryTable->DefaultData = NULL;
108  queryTable->DefaultLength = 0;
109 
111  (PWSTR)(SubkeyName ?
112  deviceSubkeyHandle :
113  deviceParameterHandle),
114  queryTable,
115  NULL,
116  NULL);
117  if (!NT_SUCCESS(status)) {
118  *ParameterValue = defaultParameterValue; // use default value
119  }
120 
121  //
122  // close what we open
123  //
124 
125  if (SubkeyName) {
126  ZwClose(deviceSubkeyHandle);
127  }
128 
129  ZwClose(deviceParameterHandle);
130  }
131 
132  return;
133 
134 } // end ClassGetDeviceParameter()
135 
141 {
143  HANDLE deviceParameterHandle;
144  HANDLE deviceSubkeyHandle;
145 
146  PAGED_CODE();
147 
148  //
149  // open the given parameter
150  //
151 
155  &deviceParameterHandle);
156 
157  if (NT_SUCCESS(status) && (SubkeyName != NULL)) {
158 
159  UNICODE_STRING subkeyName;
160  OBJECT_ATTRIBUTES objectAttributes;
161 
162  RtlInitUnicodeString(&subkeyName, SubkeyName);
163  InitializeObjectAttributes(&objectAttributes,
164  &subkeyName,
166  deviceParameterHandle,
167  NULL);
168 
169  status = ZwCreateKey(&deviceSubkeyHandle,
171  &objectAttributes,
172  0, NULL, 0, NULL);
173  if (!NT_SUCCESS(status)) {
174  ZwClose(deviceParameterHandle);
175  }
176 
177  }
178 
179  if (NT_SUCCESS(status)) {
180 
183  (PWSTR) (SubkeyName ?
184  deviceSubkeyHandle :
185  deviceParameterHandle),
187  REG_DWORD,
189  sizeof(ULONG));
190 
191  //
192  // close what we open
193  //
194 
195  if (SubkeyName) {
196  ZwClose(deviceSubkeyHandle);
197  }
198 
199  ZwClose(deviceParameterHandle);
200  }
201 
202  return status;
203 
204 } // end ClassSetDeviceParameter()
205 
206 /*
207  * ClassScanForSpecial
208  *
209  * This routine was written to simplify scanning for special
210  * hardware based upon id strings. it does not check the registry.
211  */
212 
216  IN PCLASS_SCAN_FOR_SPECIAL_HANDLER Function)
217 {
218  PSTORAGE_DEVICE_DESCRIPTOR deviceDescriptor;
219  PCSTR vendorId;
220  PCSTR productId;
221  PCSTR productRevision;
222  CHAR nullString[] = "";
223  //ULONG j;
224 
225  PAGED_CODE();
227  ASSERT(Function);
228 
229  deviceDescriptor = FdoExtension->DeviceDescriptor;
230 
231  if (DeviceList == NULL) {
232  return;
233  }
234  if (Function == NULL) {
235  return;
236  }
237 
238  //
239  // SCSI sets offsets to -1, ATAPI sets to 0. check for both.
240  //
241 
242  if (deviceDescriptor->VendorIdOffset != 0 &&
243  deviceDescriptor->VendorIdOffset != -1) {
244  vendorId = ((PCSTR)deviceDescriptor);
245  vendorId += deviceDescriptor->VendorIdOffset;
246  } else {
247  vendorId = nullString;
248  }
249  if (deviceDescriptor->ProductIdOffset != 0 &&
250  deviceDescriptor->ProductIdOffset != -1) {
251  productId = ((PCSTR)deviceDescriptor);
252  productId += deviceDescriptor->ProductIdOffset;
253  } else {
254  productId = nullString;
255  }
256  if (deviceDescriptor->VendorIdOffset != 0 &&
257  deviceDescriptor->VendorIdOffset != -1) {
258  productRevision = ((PCSTR)deviceDescriptor);
259  productRevision += deviceDescriptor->ProductRevisionOffset;
260  } else {
261  productRevision = nullString;
262  }
263 
264  //
265  // loop while the device list is valid (not null-filled)
266  //
267 
268  for (;(DeviceList->VendorId != NULL ||
269  DeviceList->ProductId != NULL ||
270  DeviceList->ProductRevision != NULL);DeviceList++) {
271 
272  if (ClasspMyStringMatches(DeviceList->VendorId, vendorId) &&
273  ClasspMyStringMatches(DeviceList->ProductId, productId) &&
274  ClasspMyStringMatches(DeviceList->ProductRevision, productRevision)
275  ) {
276 
277  DebugPrint((1, "ClasspScanForSpecialByInquiry: Found matching "
278  "controller Ven: %s Prod: %s Rev: %s\n",
279  vendorId, productId, productRevision));
280 
281  //
282  // pass the context to the call back routine and exit
283  //
284 
285  (Function)(FdoExtension, DeviceList->Data);
286 
287  //
288  // for CHK builds, try to prevent wierd stacks by having a debug
289  // print here. it's a hack, but i know of no other way to prevent
290  // the stack from being wrong.
291  //
292 
293  DebugPrint((16, "ClasspScanForSpecialByInquiry: "
294  "completed callback\n"));
295  return;
296 
297  } // else the strings did not match
298 
299  } // none of the devices matched.
300 
301  DebugPrint((1, "ClasspScanForSpecialByInquiry: no match found for %p\n",
302  FdoExtension->DeviceObject));
303  return;
304 
305 } // end ClasspScanForSpecialByInquiry()
306 
307 //
308 // In order to provide better performance without the need to reboot,
309 // we need to implement a self-adjusting method to set and clear the
310 // srb flags based upon current performance.
311 //
312 // whenever there is an error, immediately grab the spin lock. the
313 // MP perf hit here is acceptable, since we're in an error path. this
314 // is also necessary because we are guaranteed to be modifying the
315 // SRB flags here, setting SuccessfulIO to zero, and incrementing the
316 // actual error count (which is always done within this spinlock).
317 //
318 // whenever there is no error, increment a counter. if there have been
319 // errors on the device, and we've enabled dynamic perf, *and* we've
320 // just crossed the perf threshold, then grab the spin lock and
321 // double check that the threshold has, indeed been hit(*). then
322 // decrement the error count, and if it's dropped sufficiently, undo
323 // some of the safety changes made in the SRB flags due to the errors.
324 //
325 // * this works in all cases. even if lots of ios occur after the
326 // previous guy went in and cleared the successfulio counter, that
327 // just means that we've hit the threshold again, and so it's proper
328 // to run the inner loop again.
329 //
330 
331 VOID
332 NTAPI
335  )
336 {
337  PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
338  KIRQL oldIrql;
339  ULONG errors;
340 
341  KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
342 
343  fdoData->Perf.SuccessfulIO = 0; // implicit interlock
344  errors = InterlockedIncrement((PLONG)&FdoExtension->ErrorCount);
345 
346  if (errors >= CLASS_ERROR_LEVEL_1) {
347 
348  //
349  // If the error count has exceeded the error limit, then disable
350  // any tagged queuing, multiple requests per lu queueing
351  // and synchronous data transfers.
352  //
353  // Clearing the no queue freeze flag prevents the port driver
354  // from sending multiple requests per logical unit.
355  //
356 
359 
361 
362  DebugPrint((ClassDebugError, "ClasspPerfIncrementErrorCount: "
363  "Too many errors; disabling tagged queuing and "
364  "synchronous data tranfers.\n"));
365 
366  }
367 
368  if (errors >= CLASS_ERROR_LEVEL_2) {
369 
370  //
371  // If a second threshold is reached, disable disconnects.
372  //
373 
375  DebugPrint((ClassDebugError, "ClasspPerfIncrementErrorCount: "
376  "Too many errors; disabling disconnects.\n"));
377  }
378 
379  KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
380  return;
381 }
382 
383 VOID
384 NTAPI
387  )
388 {
389  PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
390  KIRQL oldIrql;
391  ULONG errors;
392  ULONG succeeded = 0;
393 
394  //
395  // don't take a hit from the interlocked op unless we're in
396  // a degraded state and we've got a threshold to hit.
397  //
398 
399  if (FdoExtension->ErrorCount == 0) {
400  return;
401  }
402 
403  if (fdoData->Perf.ReEnableThreshold == 0) {
404  return;
405  }
406 
407  succeeded = InterlockedIncrement((PLONG)&fdoData->Perf.SuccessfulIO);
408  if (succeeded < fdoData->Perf.ReEnableThreshold) {
409  return;
410  }
411 
412  //
413  // if we hit the threshold, grab the spinlock and verify we've
414  // actually done so. this allows us to ignore the spinlock 99%
415  // of the time.
416  //
417 
418  KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
419 
420  //
421  // re-read the value, so we don't run this multiple times
422  // for a single threshold being hit. this keeps errorcount
423  // somewhat useful.
424  //
425 
426  succeeded = fdoData->Perf.SuccessfulIO;
427 
428  if ((FdoExtension->ErrorCount != 0) &&
429  (fdoData->Perf.ReEnableThreshold <= succeeded)
430  ) {
431 
432  fdoData->Perf.SuccessfulIO = 0; // implicit interlock
433 
434  ASSERT(FdoExtension->ErrorCount > 0);
435  errors = InterlockedDecrement((PLONG)&FdoExtension->ErrorCount);
436 
437  //
438  // note: do in reverse order of the sets "just in case"
439  //
440 
441  if (errors < CLASS_ERROR_LEVEL_2) {
442  if (errors == CLASS_ERROR_LEVEL_2 - 1) {
443  DebugPrint((ClassDebugError, "ClasspPerfIncrementSuccessfulIo: "
444  "Error level 2 no longer required.\n"));
445  }
446  if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
448  CLEAR_FLAG(FdoExtension->SrbFlags,
450  }
451  }
452 
453  if (errors < CLASS_ERROR_LEVEL_1) {
454  if (errors == CLASS_ERROR_LEVEL_1 - 1) {
455  DebugPrint((ClassDebugError, "ClasspPerfIncrementSuccessfulIo: "
456  "Error level 1 no longer required.\n"));
457  }
458  if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
460  CLEAR_FLAG(FdoExtension->SrbFlags,
462  }
463  if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
465  SET_FLAG(FdoExtension->SrbFlags,
467  }
468  if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
470  SET_FLAG(FdoExtension->SrbFlags,
472  }
473  }
474  } // end of threshold definitely being hit for first time
475 
476  KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
477  return;
478 }
479 
481 {
482  PMDL mdl;
483 
484  mdl = IoAllocateMdl(Buffer, BufferLen, FALSE, FALSE, NULL);
485  if (mdl){
486  _SEH2_TRY {
487  /*
488  * We are reading from the device.
489  * Therefore, the device is WRITING to the locked memory.
490  * So we request IoWriteAccess.
491  */
493 
496 
497  DBGWARN(("BuildReadMdl: MmProbeAndLockPages failed with %xh.", status));
498  IoFreeMdl(mdl);
499  mdl = NULL;
500  } _SEH2_END;
501  }
502  else {
503  DBGWARN(("BuildReadMdl: IoAllocateMdl failed"));
504  }
505 
506  return mdl;
507 }
508 
510 {
511  MmUnlockPages(Mdl);
512  IoFreeMdl(Mdl);
513 }
514 
515 #if 0
516  VOID
517  ClasspPerfResetCounters(
519  )
520  {
521  PCLASS_PRIVATE_FDO_DATA fdoData = FdoExtension->PrivateFdoData;
522  KIRQL oldIrql;
523 
524  KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
525  DebugPrint((ClassDebugError, "ClasspPerfResetCounters: "
526  "Resetting all perf counters.\n"));
527  fdoData->Perf.SuccessfulIO = 0;
528  FdoExtension->ErrorCount = 0;
529 
530  if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
532  CLEAR_FLAG(FdoExtension->SrbFlags,
534  }
535  if (!TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
537  CLEAR_FLAG(FdoExtension->SrbFlags,
539  }
540  if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
542  SET_FLAG(FdoExtension->SrbFlags,
544  }
545  if (TEST_FLAG(fdoData->Perf.OriginalSrbFlags,
547  SET_FLAG(FdoExtension->SrbFlags,
549  }
550  KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
551  return;
552  }
553 #endif
VOID NTAPI ClasspPerfIncrementErrorCount(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: utils.c:333
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
VOID NTAPI FreeDeviceInputMdl(PMDL Mdl)
Definition: utils.c:509
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define TEST_FLAG(Flags, Bit)
Definition: classpnp.h:156
#define PLUGPLAY_REGKEY_DEVICE
Definition: iofuncs.h:2738
#define SRB_FLAGS_NO_QUEUE_FREEZE
Definition: srb.h:396
#define KEY_READ
Definition: nt_native.h:1023
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
uint16_t * PWSTR
Definition: typedefs.h:54
char CHAR
Definition: xmlstorage.h:175
LONG NTSTATUS
Definition: precomp.h:26
KSPIN_LOCK SpinLock
Definition: classp.h:456
VOID NTAPI MmUnlockPages(IN PMDL Mdl)
Definition: mdlsup.c:1439
PMDL NTAPI BuildDeviceInputMdl(PVOID Buffer, ULONG BufferLen)
Definition: utils.c:480
#define PAGED_CODE()
Definition: video.h:57
_SEH2_TRY
Definition: create.c:4250
UCHAR KIRQL
Definition: env_spec_w32.h:591
VOID NTAPI ClassGetDeviceParameter(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PWSTR SubkeyName OPTIONAL, IN PWSTR ParameterName, IN OUT PULONG ParameterValue)
Definition: utils.c:52
* PSTORAGE_DEVICE_DESCRIPTOR
Definition: ntddstor.h:457
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
static LPOVERLAPPED_COMPLETION_ROUTINE Function
Definition: sync.c:684
#define CLEAR_FLAG(Flags, Bit)
Definition: classpnp.h:155
VOID NTAPI ClasspPerfIncrementSuccessfulIo(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension)
Definition: utils.c:385
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
Definition: bufpool.h:45
#define CLASS_ERROR_LEVEL_2
Definition: classp.h:51
#define KEY_WRITE
Definition: nt_native.h:1031
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
GLenum GLuint GLenum GLsizei length
Definition: glext.h:5579
NTSTATUS NTAPI ClassSetDeviceParameter(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN PWSTR SubkeyName OPTIONAL, IN PWSTR ParameterName, IN ULONG ParameterValue)
Definition: utils.c:136
#define KeAcquireSpinLock(sl, irql)
Definition: env_spec_w32.h:609
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
#define SRB_FLAGS_DISABLE_SYNCH_TRANSFER
Definition: srb.h:389
NTSYSAPI NTSTATUS WINAPI RtlQueryRegistryValues(ULONG, PCWSTR, PRTL_QUERY_REGISTRY_TABLE, PVOID, PVOID)
VOID NTAPI IoFreeMdl(PMDL Mdl)
Definition: iomdl.c:146
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define CLASS_ERROR_LEVEL_1
Definition: classp.h:50
_In_opt_ PWSTR _In_ PWSTR _Inout_ PULONG ParameterValue
Definition: classpnp.h:1209
#define SRB_FLAGS_DISABLE_DISCONNECT
Definition: srb.h:388
NTSYSAPI NTSTATUS WINAPI RtlWriteRegistryValue(ULONG, PCWSTR, PCWSTR, ULONG, PVOID, ULONG)
#define InterlockedDecrement
Definition: armddk.h:52
BOOLEAN NTAPI ClasspMyStringMatches(IN PCSTR StringToMatch OPTIONAL, IN PCSTR TargetString)
Definition: utils.c:33
#define RTL_REGISTRY_HANDLE
Definition: nt_native.h:168
_In_opt_ PWSTR SubkeyName
Definition: classpnp.h:1209
#define SET_FLAG(Flags, Bit)
Definition: classpnp.h:154
ULONG NTAPI DebugPrint(IN PSTRING DebugString, IN ULONG ComponentId, IN ULONG Level)
Definition: debug.c:23
PMDL NTAPI IoAllocateMdl(IN PVOID VirtualAddress, IN ULONG Length, IN BOOLEAN SecondaryBuffer, IN BOOLEAN ChargeQuota, IN PIRP Irp)
Definition: iomdl.c:22
_SEH2_END
Definition: create.c:4424
#define InterlockedIncrement
Definition: armddk.h:53
VOID NTAPI MmProbeAndLockPages(IN PMDL Mdl, IN KPROCESSOR_MODE AccessMode, IN LOCK_OPERATION Operation)
Definition: mdlsup.c:935
PDEVICE_LIST DeviceList
Definition: utils.c:27
VOID NTAPI ClassScanForSpecial(IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension, IN CLASSPNP_SCAN_FOR_SPECIAL_INFO DeviceList[], IN PCLASS_SCAN_FOR_SPECIAL_HANDLER Function)
Definition: utils.c:213
_In_opt_ PWSTR _In_ PWSTR ParameterName
Definition: classpnp.h:1209
unsigned int * PULONG
Definition: retypes.h:1
#define KeReleaseSpinLock(sl, irql)
Definition: env_spec_w32.h:627
NTSTATUS NTAPI IoOpenDeviceRegistryKey(IN PDEVICE_OBJECT DeviceObject, IN ULONG DevInstKeyType, IN ACCESS_MASK DesiredAccess, OUT PHANDLE DevInstRegKey)
Definition: pnpmgr.c:4583
#define OUT
Definition: typedefs.h:39
unsigned int ULONG
Definition: retypes.h:1
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
struct _CLASS_PRIVATE_FDO_DATA::@1008 Perf
#define DBGWARN(args_in_parens)
Definition: debug.h:134
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:6
const char * PCSTR
Definition: typedefs.h:51
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:12
#define RTL_QUERY_REGISTRY_REQUIRED
Definition: nt_native.h:132
#define REG_DWORD
Definition: sdbapi.c:596
signed int * PLONG
Definition: retypes.h:5
static SERVICE_STATUS status
Definition: service.c:31
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define RTL_QUERY_REGISTRY_DIRECT
Definition: nt_native.h:144
#define SRB_FLAGS_QUEUE_ACTION_ENABLE
Definition: srb.h:387
Definition: ps.c:97
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68