Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3136 lines
78 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1990 - 1999
  3. Module Name:
  4. port.c
  5. Abstract:
  6. This is the NT SCSI port driver.
  7. Authors:
  8. Mike Glass
  9. Jeff Havens
  10. Environment:
  11. kernel mode only
  12. Notes:
  13. This module is a dll for the kernel.
  14. Revision History:
  15. --*/
  16. #include "port.h"
  17. #if DBG
  18. static const char *__file__ = __FILE__;
  19. #endif
  20. #define __FILE_ID__ 'util'
  21. typedef struct SP_GUID_INTERFACE_MAPPING {
  22. GUID Guid;
  23. INTERFACE_TYPE InterfaceType;
  24. } SP_GUID_INTERFACE_MAPPING, *PSP_GUID_INTERFACE_MAPPING;
  25. PSP_GUID_INTERFACE_MAPPING SpGuidInterfaceMappingList = NULL;
  26. VOID
  27. SpProcessSpecialControllerList(
  28. IN PDRIVER_OBJECT DriverObject,
  29. IN PINQUIRYDATA InquiryData,
  30. IN HANDLE ListKey,
  31. OUT PSP_SPECIAL_CONTROLLER_FLAGS Flags
  32. );
  33. VOID
  34. SpProcessSpecialControllerFlags(
  35. IN HANDLE FlagsKey,
  36. OUT PSP_SPECIAL_CONTROLLER_FLAGS Flags
  37. );
  38. NTSTATUS
  39. ScsiPortBuildMultiString(
  40. IN PDRIVER_OBJECT DriverObject,
  41. PUNICODE_STRING MultiString,
  42. ...
  43. );
  44. NTSTATUS
  45. SpMultiStringToStringArray(
  46. IN PDRIVER_OBJECT DriverObject,
  47. IN PUNICODE_STRING MultiString,
  48. OUT PWSTR *StringArray[],
  49. BOOLEAN Forward
  50. );
  51. VOID
  52. FASTCALL
  53. SpFreeSrbData(
  54. IN PADAPTER_EXTENSION Adapter,
  55. IN PSRB_DATA SrbData
  56. );
  57. VOID
  58. FASTCALL
  59. SpFreeBypassSrbData(
  60. IN PADAPTER_EXTENSION Adapter,
  61. IN PSRB_DATA SrbData
  62. );
  63. #ifdef ALLOC_PRAGMA
  64. #pragma alloc_text(PAGE, ScsiPortBuildMultiString)
  65. #pragma alloc_text(PAGE, ScsiPortStringArrayToMultiString)
  66. #pragma alloc_text(PAGE, SpMultiStringToStringArray)
  67. #pragma alloc_text(PAGE, RtlDuplicateCmResourceList)
  68. #pragma alloc_text(PAGE, RtlSizeOfCmResourceList)
  69. #pragma alloc_text(PAGE, SpTranslateResources)
  70. #pragma alloc_text(PAGE, SpCheckSpecialDeviceFlags)
  71. #pragma alloc_text(PAGE, SpProcessSpecialControllerList)
  72. #pragma alloc_text(PAGE, SpProcessSpecialControllerFlags)
  73. #pragma alloc_text(PAGE, SpAllocateTagBitMap)
  74. #pragma alloc_text(PAGE, SpGetPdoInterfaceType)
  75. #pragma alloc_text(PAGE, SpReadNumericInstanceValue)
  76. #pragma alloc_text(PAGE, SpWriteNumericInstanceValue)
  77. #pragma alloc_text(PAGE, SpReleaseMappedAddresses)
  78. #pragma alloc_text(PAGE, SpInitializeGuidInterfaceMapping)
  79. #pragma alloc_text(PAGE, SpSendIrpSynchronous)
  80. #pragma alloc_text(PAGE, SpGetBusTypeGuid)
  81. #pragma alloc_text(PAGE, SpDetermine64BitSupport)
  82. #pragma alloc_text(PAGE, SpReadNumericValue)
  83. #pragma alloc_text(PAGE, SpAllocateAddressMapping)
  84. #pragma alloc_text(PAGE, SpPreallocateAddressMapping)
  85. #pragma alloc_text(PAGE, SpPurgeFreeMappedAddressList)
  86. #pragma alloc_text(PAGE, SpFreeMappedAddress)
  87. #endif
  88. NTSTATUS
  89. SpInitializeGuidInterfaceMapping(
  90. IN PDRIVER_OBJECT DriverObject
  91. )
  92. {
  93. ULONG size;
  94. PAGED_CODE();
  95. ASSERT(SpGuidInterfaceMappingList == NULL);
  96. size = sizeof(SP_GUID_INTERFACE_MAPPING) * 5;
  97. SpGuidInterfaceMappingList = SpAllocatePool(PagedPool,
  98. size,
  99. SCSIPORT_TAG_INTERFACE_MAPPING,
  100. DriverObject);
  101. if(SpGuidInterfaceMappingList == NULL) {
  102. return STATUS_INSUFFICIENT_RESOURCES;
  103. }
  104. RtlZeroMemory(SpGuidInterfaceMappingList, size);
  105. SpGuidInterfaceMappingList[0].Guid = GUID_BUS_TYPE_PCMCIA;
  106. SpGuidInterfaceMappingList[0].InterfaceType = Isa;
  107. SpGuidInterfaceMappingList[1].Guid = GUID_BUS_TYPE_PCI;
  108. SpGuidInterfaceMappingList[1].InterfaceType = PCIBus;
  109. SpGuidInterfaceMappingList[2].Guid = GUID_BUS_TYPE_ISAPNP;
  110. SpGuidInterfaceMappingList[2].InterfaceType = Isa;
  111. SpGuidInterfaceMappingList[3].Guid = GUID_BUS_TYPE_EISA;
  112. SpGuidInterfaceMappingList[3].InterfaceType = Eisa;
  113. SpGuidInterfaceMappingList[4].InterfaceType = InterfaceTypeUndefined;
  114. return STATUS_SUCCESS;
  115. }
  116. NTSTATUS
  117. ScsiPortBuildMultiString(
  118. IN PDRIVER_OBJECT DriverObject,
  119. IN PUNICODE_STRING MultiString,
  120. ...
  121. )
  122. /*++
  123. Routine Description:
  124. This routine will take a null terminated list of ascii strings and combine
  125. them together into a unicode multi-string block.
  126. This routine allocates memory for the string buffer - is the caller's
  127. responsibility to free it.
  128. Arguments:
  129. MultiString - a UNICODE_STRING structure into which the multi string will
  130. be built.
  131. ... - a NULL terminated list of narrow strings which will be combined
  132. together. This list may not be empty.
  133. Return Value:
  134. status
  135. --*/
  136. {
  137. PCSTR rawEntry;
  138. ANSI_STRING ansiEntry;
  139. UNICODE_STRING unicodeEntry;
  140. PWSTR unicodeLocation;
  141. ULONG multiLength = 0;
  142. NTSTATUS status;
  143. va_list ap;
  144. va_start(ap, MultiString);
  145. PAGED_CODE();
  146. //
  147. // Make sure we aren't going to leak any memory
  148. //
  149. ASSERT(MultiString->Buffer == NULL);
  150. rawEntry = va_arg(ap, PCSTR);
  151. while(rawEntry != NULL) {
  152. RtlInitAnsiString(&ansiEntry, rawEntry);
  153. multiLength += RtlAnsiStringToUnicodeSize(&ansiEntry);
  154. rawEntry = va_arg(ap, PCSTR);
  155. }
  156. ASSERT(multiLength != 0);
  157. multiLength += sizeof(WCHAR);
  158. MultiString->Buffer = SpAllocatePool(PagedPool,
  159. multiLength,
  160. SCSIPORT_TAG_PNP_ID,
  161. DriverObject);
  162. if(MultiString->Buffer == NULL) {
  163. return STATUS_INSUFFICIENT_RESOURCES;
  164. }
  165. unicodeEntry.Buffer = MultiString->Buffer;
  166. unicodeEntry.MaximumLength = (USHORT) multiLength;
  167. va_start(ap, MultiString);
  168. rawEntry = va_arg(ap, PCSTR);
  169. while(rawEntry != NULL) {
  170. RtlInitAnsiString(&ansiEntry, rawEntry);
  171. status = RtlAnsiStringToUnicodeString(
  172. &unicodeEntry,
  173. &ansiEntry,
  174. FALSE);
  175. //
  176. // Since we're not allocating any memory the only failure possible
  177. // is if this function is bad
  178. //
  179. ASSERT(NT_SUCCESS(status));
  180. //
  181. // Push the buffer location up and reduce the maximum count
  182. //
  183. unicodeEntry.Buffer += unicodeEntry.Length + sizeof(WCHAR);
  184. unicodeEntry.MaximumLength -= unicodeEntry.Length + sizeof(WCHAR);
  185. rawEntry = va_arg(ap, PCSTR);
  186. };
  187. ASSERT(unicodeEntry.MaximumLength == sizeof(WCHAR));
  188. //
  189. // Stick the final NUL on the end of the multisz
  190. //
  191. RtlZeroMemory(unicodeEntry.Buffer, unicodeEntry.MaximumLength);
  192. return STATUS_SUCCESS;
  193. }
  194. NTSTATUS
  195. ScsiPortStringArrayToMultiString(
  196. IN PDRIVER_OBJECT DriverObject,
  197. PUNICODE_STRING MultiString,
  198. PCSTR StringArray[]
  199. )
  200. /*++
  201. Routine Description:
  202. This routine will take a null terminated array of ascii strings and merge
  203. them together into a unicode multi-string block.
  204. This routine allocates memory for the string buffer - is the caller's
  205. responsibility to free it.
  206. Arguments:
  207. MultiString - a UNICODE_STRING structure into which the multi string will
  208. be built.
  209. StringArray - a NULL terminated list of narrow strings which will be combined
  210. together. This list may not be empty.
  211. Return Value:
  212. status
  213. --*/
  214. {
  215. ANSI_STRING ansiEntry;
  216. UNICODE_STRING unicodeEntry;
  217. PWSTR unicodeLocation;
  218. UCHAR i;
  219. NTSTATUS status;
  220. PAGED_CODE();
  221. //
  222. // Make sure we aren't going to leak any memory
  223. //
  224. ASSERT(MultiString->Buffer == NULL);
  225. RtlInitUnicodeString(MultiString, NULL);
  226. for(i = 0; StringArray[i] != NULL; i++) {
  227. RtlInitAnsiString(&ansiEntry, StringArray[i]);
  228. MultiString->Length += (USHORT) RtlAnsiStringToUnicodeSize(&ansiEntry);
  229. }
  230. ASSERT(MultiString->Length != 0);
  231. MultiString->MaximumLength = MultiString->Length + sizeof(UNICODE_NULL);
  232. MultiString->Buffer = SpAllocatePool(PagedPool,
  233. MultiString->MaximumLength,
  234. SCSIPORT_TAG_PNP_ID,
  235. DriverObject);
  236. if(MultiString->Buffer == NULL) {
  237. return STATUS_INSUFFICIENT_RESOURCES;
  238. }
  239. RtlZeroMemory(MultiString->Buffer, MultiString->MaximumLength);
  240. unicodeEntry = *MultiString;
  241. for(i = 0; StringArray[i] != NULL; i++) {
  242. RtlInitAnsiString(&ansiEntry, StringArray[i]);
  243. status = RtlAnsiStringToUnicodeString(
  244. &unicodeEntry,
  245. &ansiEntry,
  246. FALSE);
  247. //
  248. // Since we're not allocating any memory the only failure possible
  249. // is if this function is bad
  250. //
  251. ASSERT(NT_SUCCESS(status));
  252. //
  253. // Push the buffer location up and reduce the maximum count
  254. //
  255. ((PSTR) unicodeEntry.Buffer) += unicodeEntry.Length + sizeof(WCHAR);
  256. unicodeEntry.MaximumLength -= unicodeEntry.Length + sizeof(WCHAR);
  257. };
  258. //
  259. // Stick the final NUL on the end of the multisz
  260. //
  261. // RtlZeroMemory(unicodeEntry.Buffer, unicodeEntry.MaximumLength);
  262. return STATUS_SUCCESS;
  263. }
  264. NTSTATUS
  265. SpMultiStringToStringArray(
  266. IN PDRIVER_OBJECT DriverObject,
  267. IN PUNICODE_STRING MultiString,
  268. OUT PWSTR *StringArray[],
  269. BOOLEAN Forward
  270. )
  271. {
  272. ULONG stringCount = 0;
  273. ULONG stringNumber;
  274. ULONG i;
  275. PWSTR *stringArray;
  276. PAGED_CODE();
  277. //
  278. // Pass one: count the number of string elements.
  279. //
  280. for(i = 0; i < (MultiString->MaximumLength / sizeof(WCHAR)); i++) {
  281. if(MultiString->Buffer[i] == UNICODE_NULL) {
  282. stringCount++;
  283. }
  284. }
  285. //
  286. // Allocate the memory for a NULL-terminated string array.
  287. //
  288. stringArray = SpAllocatePool(PagedPool,
  289. (stringCount + 1) * sizeof(PWSTR),
  290. SCSIPORT_TAG_PNP_ID,
  291. DriverObject);
  292. if(stringArray == NULL) {
  293. return STATUS_INSUFFICIENT_RESOURCES;
  294. }
  295. RtlZeroMemory(stringArray, (stringCount + 1) * sizeof(PWSTR));
  296. //
  297. // Pass two : Put the string pointers in place.
  298. //
  299. i = 0;
  300. for(stringNumber = 0; stringNumber < stringCount; stringNumber++) {
  301. ULONG arrayNumber;
  302. if(Forward) {
  303. arrayNumber = stringNumber;
  304. } else {
  305. arrayNumber = stringCount - stringNumber - 1;
  306. }
  307. //
  308. // Put a pointer to the head of the string into the array.
  309. //
  310. stringArray[arrayNumber] = &MultiString->Buffer[i];
  311. //
  312. // Scan for the end of the string.
  313. //
  314. while((i < (MultiString->MaximumLength / sizeof(WCHAR))) &&
  315. (MultiString->Buffer[i] != UNICODE_NULL)) {
  316. i++;
  317. }
  318. //
  319. // Jump past the NULL.
  320. //
  321. i++;
  322. }
  323. *StringArray = stringArray;
  324. return STATUS_SUCCESS;
  325. }
  326. PCM_RESOURCE_LIST
  327. RtlDuplicateCmResourceList(
  328. IN PDRIVER_OBJECT DriverObject,
  329. POOL_TYPE PoolType,
  330. PCM_RESOURCE_LIST ResourceList,
  331. ULONG Tag
  332. )
  333. /*++
  334. Routine Description:
  335. This routine will attempt to allocate memory to copy the supplied
  336. resource list. If sufficient memory cannot be allocated then the routine
  337. will return NULL.
  338. Arguments:
  339. PoolType - the type of pool to allocate the duplicate from
  340. ResourceList - the resource list to be copied
  341. Tag - a value to tag the memory allocation with. If 0 then untagged
  342. memory will be allocated.
  343. Return Value:
  344. an allocated copy of the resource list (caller must free) or
  345. NULL if memory could not be allocated.
  346. --*/
  347. {
  348. ULONG size = sizeof(CM_RESOURCE_LIST);
  349. PVOID buffer;
  350. PAGED_CODE();
  351. size = RtlSizeOfCmResourceList(ResourceList);
  352. buffer = SpAllocatePool(PoolType,
  353. size,
  354. Tag,
  355. DriverObject);
  356. if (buffer != NULL) {
  357. RtlCopyMemory(buffer,
  358. ResourceList,
  359. size);
  360. }
  361. return buffer;
  362. }
  363. ULONG
  364. RtlSizeOfCmResourceList(
  365. IN PCM_RESOURCE_LIST ResourceList
  366. )
  367. /*++
  368. Routine Description:
  369. This routine returns the size of a CM_RESOURCE_LIST.
  370. Arguments:
  371. ResourceList - the resource list to be copied
  372. Return Value:
  373. an allocated copy of the resource list (caller must free) or
  374. NULL if memory could not be allocated.
  375. --*/
  376. {
  377. ULONG size = sizeof(CM_RESOURCE_LIST);
  378. ULONG i;
  379. PAGED_CODE();
  380. for(i = 0; i < ResourceList->Count; i++) {
  381. PCM_FULL_RESOURCE_DESCRIPTOR fullDescriptor = &(ResourceList->List[i]);
  382. ULONG j;
  383. //
  384. // First descriptor is included in the size of the resource list.
  385. //
  386. if(i != 0) {
  387. size += sizeof(CM_FULL_RESOURCE_DESCRIPTOR);
  388. }
  389. for(j = 0; j < fullDescriptor->PartialResourceList.Count; j++) {
  390. //
  391. // First descriptor is included in the size of the partial list.
  392. //
  393. if(j != 0) {
  394. size += sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR);
  395. }
  396. }
  397. }
  398. return size;
  399. }
  400. #if !defined(NO_LEGACY_DRIVERS)
  401. BOOLEAN
  402. SpTranslateResources(
  403. IN PDRIVER_OBJECT DriverObject,
  404. IN PCM_RESOURCE_LIST AllocatedResources,
  405. OUT PCM_RESOURCE_LIST *TranslatedResources
  406. )
  407. /*++
  408. Routine Description:
  409. This routine will call into the Hal to translate any recognizable resources
  410. in the AllocatedResources list. This routine allocates the space for the
  411. translated list - the caller is responsible for freeing this buffer.
  412. If any errors occur the TranslatedResources will be NULL and the routine
  413. will return FALSE.
  414. Arguments:
  415. AllocatedResources - The list of resources to be translated.
  416. TranslatedResources - A location to store the translated resources. There
  417. will be a one to one mapping between translated and
  418. untranslated. Any non-standard resource types will
  419. be blindly copied.
  420. Return Value:
  421. TRUE if all resources were translated properly.
  422. FALSE otherwise.
  423. --*/
  424. {
  425. PCM_RESOURCE_LIST list;
  426. ULONG listNumber;
  427. PAGED_CODE();
  428. (*TranslatedResources) = NULL;
  429. list = RtlDuplicateCmResourceList(DriverObject,
  430. NonPagedPool,
  431. AllocatedResources,
  432. SCSIPORT_TAG_RESOURCE_LIST);
  433. if(list == NULL) {
  434. return FALSE;
  435. }
  436. for(listNumber = 0; listNumber < list->Count; listNumber++) {
  437. PCM_FULL_RESOURCE_DESCRIPTOR fullDescriptor;
  438. ULONG resourceNumber;
  439. fullDescriptor = &(list->List[listNumber]);
  440. for(resourceNumber = 0;
  441. resourceNumber < fullDescriptor->PartialResourceList.Count;
  442. resourceNumber++) {
  443. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
  444. CM_PARTIAL_RESOURCE_DESCRIPTOR tmp;
  445. partialDescriptor =
  446. &(fullDescriptor->PartialResourceList.PartialDescriptors[resourceNumber]);
  447. switch(partialDescriptor->Type) {
  448. case CmResourceTypePort:
  449. case CmResourceTypeMemory: {
  450. ULONG addressSpace;
  451. if(partialDescriptor->Type == CmResourceTypePort) {
  452. addressSpace = 1;
  453. } else {
  454. addressSpace = 0;
  455. }
  456. tmp = *partialDescriptor;
  457. if(HalTranslateBusAddress(
  458. fullDescriptor->InterfaceType,
  459. fullDescriptor->BusNumber,
  460. partialDescriptor->u.Generic.Start,
  461. &addressSpace,
  462. &(tmp.u.Generic.Start))) {
  463. tmp.Type = (addressSpace == 0) ? CmResourceTypeMemory :
  464. CmResourceTypePort;
  465. } else {
  466. ExFreePool(list);
  467. return FALSE;
  468. }
  469. break;
  470. }
  471. case CmResourceTypeInterrupt: {
  472. tmp = *partialDescriptor;
  473. tmp.u.Interrupt.Vector =
  474. HalGetInterruptVector(
  475. fullDescriptor->InterfaceType,
  476. fullDescriptor->BusNumber,
  477. partialDescriptor->u.Interrupt.Level,
  478. partialDescriptor->u.Interrupt.Vector,
  479. &((UCHAR) tmp.u.Interrupt.Level),
  480. &(tmp.u.Interrupt.Affinity));
  481. if(tmp.u.Interrupt.Affinity == 0) {
  482. //
  483. // Translation failed.
  484. //
  485. ExFreePool(list);
  486. return FALSE;
  487. }
  488. break;
  489. }
  490. };
  491. *partialDescriptor = tmp;
  492. }
  493. }
  494. *TranslatedResources = list;
  495. return TRUE;
  496. }
  497. #endif // NO_LEGACY_DRIVERS
  498. BOOLEAN
  499. SpFindAddressTranslation(
  500. IN PADAPTER_EXTENSION AdapterExtension,
  501. IN INTERFACE_TYPE BusType,
  502. IN ULONG BusNumber,
  503. IN PHYSICAL_ADDRESS RangeStart,
  504. IN ULONG RangeLength,
  505. IN BOOLEAN InIoSpace,
  506. IN OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Translation
  507. )
  508. /*++
  509. Routine Description:
  510. This routine will search the resource lists in the AdapterExtension to
  511. translate the given memory or i/o range using the resources provided by
  512. pnp or the Hal.
  513. Arguments:
  514. AdapterExtesnion - the device extension for the adapter making the request
  515. RangeStart - the starting address of the memory range
  516. RangeLength - the number of bytes in the memory range
  517. InIoSpace - whether the untranslated range is in io or memory space.
  518. Return Value:
  519. a pointer to a partial resource descriptor describing the proper range to
  520. be used or NULL if no matching range of sufficient length can be found.
  521. --*/
  522. {
  523. PCM_RESOURCE_LIST list;
  524. ULONG listNumber;
  525. list = AdapterExtension->AllocatedResources;
  526. ASSERT(!AdapterExtension->IsMiniportDetected);
  527. ASSERT(AdapterExtension->AllocatedResources);
  528. ASSERT(AdapterExtension->TranslatedResources);
  529. for(listNumber = 0; listNumber < list->Count; listNumber++) {
  530. PCM_FULL_RESOURCE_DESCRIPTOR fullDescriptor;
  531. ULONG resourceNumber;
  532. fullDescriptor = &(list->List[listNumber]);
  533. if((fullDescriptor->InterfaceType != BusType) ||
  534. (fullDescriptor->BusNumber != BusNumber)) {
  535. continue;
  536. }
  537. for(resourceNumber = 0;
  538. resourceNumber < fullDescriptor->PartialResourceList.Count;
  539. resourceNumber++) {
  540. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptor;
  541. UCHAR desiredType =
  542. InIoSpace ? CmResourceTypePort : CmResourceTypeMemory;
  543. partialDescriptor =
  544. &(fullDescriptor->PartialResourceList.PartialDescriptors[resourceNumber]);
  545. if(partialDescriptor->Type == desiredType) {
  546. ULONGLONG requestedStart = (ULONGLONG) RangeStart.QuadPart;
  547. ULONGLONG requestedEnd =
  548. ((ULONGLONG) RangeStart.QuadPart) + RangeLength;
  549. ULONGLONG testStart =
  550. (ULONGLONG) partialDescriptor->u.Generic.Start.QuadPart;
  551. ULONGLONG testEnd =
  552. testStart + partialDescriptor->u.Generic.Length;
  553. ULONGLONG requestedOffset = requestedStart - testStart;
  554. ULONG rangeOffset;
  555. //
  556. // Make sure the base address is within the current range.
  557. //
  558. if((requestedStart < testStart) ||
  559. (requestedStart >= testEnd)) {
  560. continue;
  561. }
  562. //
  563. // Make sure the end of the requested range is within this
  564. // descriptor.
  565. //
  566. if(requestedEnd > testEnd) {
  567. continue;
  568. }
  569. //
  570. // We seem to have found a match. Copy the equivalent resource
  571. // in the translated resource list.
  572. //
  573. *Translation =
  574. AdapterExtension->TranslatedResources->List[listNumber].
  575. PartialResourceList.PartialDescriptors[resourceNumber];
  576. //
  577. // Return an offset into the translated range equivalent to the
  578. // offset in the untranslated range.
  579. //
  580. requestedStart = Translation->u.Generic.Start.QuadPart;
  581. requestedStart += requestedOffset;
  582. Translation->u.Generic.Start.QuadPart = requestedStart;
  583. return TRUE;
  584. };
  585. }
  586. }
  587. return FALSE;
  588. }
  589. NTSTATUS
  590. SpLockUnlockQueue(
  591. IN PDEVICE_OBJECT LogicalUnit,
  592. IN BOOLEAN LockQueue,
  593. IN BOOLEAN BypassLockedQueue
  594. )
  595. /*++
  596. Routine Description:
  597. This routine will lock or unlock the logical unit queue.
  598. This routine is synchronous.
  599. Arguments:
  600. LogicalUnit - the logical unit to be locked or unlocked
  601. LockQueue - whether the queue should be locked or unlocked
  602. BypassLockedQueue - whether the operation should bypass other locks or
  603. whether it should sit in the queue. Must be true for
  604. unlock requests.
  605. Return Value:
  606. STATUS_SUCCESS if the operation was successful
  607. error status otherwise.
  608. --*/
  609. {
  610. PLOGICAL_UNIT_EXTENSION luExtension = LogicalUnit->DeviceExtension;
  611. PIRP irp;
  612. PIO_STACK_LOCATION irpStack;
  613. PSCSI_REQUEST_BLOCK srb;
  614. PKEVENT event = NULL;
  615. NTSTATUS status;
  616. ASSERTMSG("Must bypass locked queue when unlocking: ",
  617. (LockQueue || BypassLockedQueue));
  618. DebugPrint((1, "SpLockUnlockQueue: %sing queue for logical unit extension "
  619. "%#p\n",
  620. LockQueue ? "Lock" : "Unlock",
  621. luExtension));
  622. //
  623. // Build an IRP to send to the logical unit. We need one stack
  624. // location for our completion routine and one for the irp to be
  625. // processed with. This irp should never be dispatched to the
  626. //
  627. irp = SpAllocateIrp((CCHAR) (LogicalUnit->StackSize + 1),
  628. FALSE,
  629. LogicalUnit->DriverObject);
  630. if(irp == NULL) {
  631. DebugPrint((1, "SpLockUnlockQueue: Couldn't allocate IRP\n"));
  632. return STATUS_INSUFFICIENT_RESOURCES;
  633. }
  634. try {
  635. srb = SpAllocatePool(NonPagedPool,
  636. sizeof(SCSI_REQUEST_BLOCK),
  637. SCSIPORT_TAG_ENABLE,
  638. LogicalUnit->DriverObject);
  639. if(srb == NULL) {
  640. DebugPrint((1, "SpLockUnlockQueue: Couldn't allocate SRB\n"));
  641. status = STATUS_INSUFFICIENT_RESOURCES;
  642. leave;
  643. }
  644. event = SpAllocatePool(NonPagedPool,
  645. sizeof(KEVENT),
  646. SCSIPORT_TAG_EVENT,
  647. LogicalUnit->DriverObject);
  648. if(event == NULL) {
  649. DebugPrint((1, "SpLockUnlockQueue: Couldn't allocate Context\n"));
  650. status = STATUS_INSUFFICIENT_RESOURCES;
  651. leave;
  652. }
  653. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  654. KeInitializeEvent(event, NotificationEvent, FALSE);
  655. srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  656. srb->Function = LockQueue ? SRB_FUNCTION_LOCK_QUEUE :
  657. SRB_FUNCTION_UNLOCK_QUEUE;
  658. srb->OriginalRequest = irp;
  659. srb->DataBuffer = NULL;
  660. srb->QueueTag = SP_UNTAGGED;
  661. if(BypassLockedQueue) {
  662. srb->SrbFlags |= SRB_FLAGS_BYPASS_LOCKED_QUEUE;
  663. }
  664. IoSetCompletionRoutine(irp,
  665. SpSignalCompletion,
  666. event,
  667. TRUE,
  668. TRUE,
  669. TRUE);
  670. irpStack = IoGetNextIrpStackLocation(irp);
  671. irpStack->Parameters.Scsi.Srb = srb;
  672. irpStack->MajorFunction = IRP_MJ_SCSI;
  673. status = IoCallDriver(LogicalUnit, irp);
  674. if(status == STATUS_PENDING) {
  675. KeWaitForSingleObject(event,
  676. Executive,
  677. KernelMode,
  678. FALSE,
  679. NULL);
  680. status = irp->IoStatus.Status;
  681. }
  682. } finally {
  683. if(irp != NULL) {
  684. IoFreeIrp(irp);
  685. }
  686. if(srb != NULL) {
  687. ExFreePool(srb);
  688. }
  689. if(event != NULL) {
  690. ExFreePool(event);
  691. }
  692. }
  693. return status;
  694. }
  695. NTSTATUS
  696. SpCheckSpecialDeviceFlags(
  697. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  698. IN PINQUIRYDATA InquiryData
  699. )
  700. /*++
  701. Routine Description:
  702. This routine will check the registry to determine what sort of special
  703. handling a target device requires. If there is a device-node then the
  704. routine will check under the device parameters for this particular logical
  705. unit.
  706. If there is no device node for the logical unit the hardware id will be
  707. looked up (first) under the devnode for the adapter or (if not found) the
  708. bad controller list stored under the scsiport Control key.
  709. The flags tested for include (this list should be updated as more are
  710. added):
  711. * OneLun - used to keep from enumerating past LUN 0 on a particular
  712. device.
  713. * SparseLun - used to indicate the device may have holes in the LUN
  714. numbers.
  715. * NonStandardVPD - used to indicate that a target does not support VPD 0x00
  716. but does support VPD 0x80 and 0x83.
  717. * BinarySN - used to indicate that the target supplied a binary
  718. serial number and that we need to convert it to ascii.
  719. These values are REG_DWORD's. REG_NULL can be used to return a value
  720. to it's default.
  721. Arguments:
  722. LogicalUnit - the logical unit
  723. InquiryData - the inquiry data retreived for the lun
  724. Return Value:
  725. status
  726. --*/
  727. {
  728. HANDLE baseKey = NULL;
  729. HANDLE listKey = NULL;
  730. HANDLE entryKey = NULL;
  731. UNICODE_STRING keyName;
  732. OBJECT_ATTRIBUTES objectAttributes;
  733. SP_SPECIAL_CONTROLLER_FLAGS flags = {
  734. 0, // SparseLun
  735. 0, // OneLun
  736. 0, // LargeLuns
  737. 0, // SetLunInCdb
  738. 0, // NonStandardVPD
  739. 0 // BinarySN
  740. };
  741. NTSTATUS status;
  742. PAGED_CODE();
  743. DebugPrint((1, "SpCheckSpecialDeviceFlags - checking flags for %#p\n",
  744. LogicalUnit));
  745. //
  746. // Check the bad controller list in the scsiport control key
  747. //
  748. try {
  749. DebugPrint((2, "SpCheckSpecialDeviceFlags - trying control list\n"));
  750. RtlInitUnicodeString(&keyName,
  751. SCSIPORT_CONTROL_KEY SCSIPORT_SPECIAL_TARGET_KEY);
  752. InitializeObjectAttributes(&objectAttributes,
  753. &keyName,
  754. OBJ_CASE_INSENSITIVE,
  755. NULL,
  756. NULL);
  757. status = ZwOpenKey(&listKey,
  758. KEY_READ,
  759. &objectAttributes);
  760. if(!NT_SUCCESS(status)) {
  761. DebugPrint((2, "SpCheckSpecialDeviceFlags - error %#08lx opening "
  762. "key %wZ\n",
  763. status,
  764. &keyName));
  765. leave;
  766. }
  767. SpProcessSpecialControllerList(
  768. LogicalUnit->DeviceObject->DriverObject,
  769. InquiryData,
  770. listKey,
  771. &flags);
  772. } finally {
  773. if(listKey != NULL) {
  774. ZwClose(listKey);
  775. listKey = NULL;
  776. }
  777. }
  778. //
  779. // Next check the special list in the adapter's devnode.
  780. //
  781. try {
  782. PDEVICE_OBJECT adapterPdo = LogicalUnit->AdapterExtension->LowerPdo;
  783. DebugPrint((2, "SpCheckSpecialDeviceFlags - trying adapter list\n"));
  784. status = IoOpenDeviceRegistryKey(adapterPdo,
  785. PLUGPLAY_REGKEY_DEVICE,
  786. KEY_READ,
  787. &baseKey);
  788. if(!NT_SUCCESS(status)) {
  789. DebugPrint((2, "SpCheckSpecialDeviceFlags - error %#08lx opening "
  790. "adapter devnode key\n", status));
  791. leave;
  792. }
  793. RtlInitUnicodeString(&keyName,
  794. L"ScsiPort\\" SCSIPORT_SPECIAL_TARGET_KEY);
  795. InitializeObjectAttributes(&objectAttributes,
  796. &keyName,
  797. OBJ_CASE_INSENSITIVE,
  798. baseKey,
  799. NULL);
  800. status = ZwOpenKey(&listKey,
  801. KEY_READ,
  802. &objectAttributes);
  803. if(!NT_SUCCESS(status)) {
  804. DebugPrint((2, "SpCheckSpecialDeviceFlags - error %#08lx opening "
  805. "adapter devnode key %wZ\n", status, &keyName));
  806. leave;
  807. }
  808. SpProcessSpecialControllerList(
  809. LogicalUnit->DeviceObject->DriverObject,
  810. InquiryData,
  811. listKey,
  812. &flags);
  813. } finally {
  814. if(baseKey != NULL) {
  815. ZwClose(baseKey);
  816. baseKey = NULL;
  817. if(listKey != NULL) {
  818. ZwClose(listKey);
  819. listKey = NULL;
  820. }
  821. }
  822. }
  823. //
  824. // Finally check the devnode (if any) for the logical unit. This one is
  825. // special - the hardware id already matchs so the key just contains the
  826. // values to be used, not a database of values.
  827. //
  828. try {
  829. status = IoOpenDeviceRegistryKey(LogicalUnit->CommonExtension.DeviceObject,
  830. PLUGPLAY_REGKEY_DEVICE,
  831. KEY_READ,
  832. &baseKey);
  833. if(!NT_SUCCESS(status)) {
  834. DebugPrint((2, "SpCheckSpecialDeviceFlags - error %#08lx opening "
  835. "device devnode key\n", status));
  836. leave;
  837. }
  838. RtlInitUnicodeString(&keyName,
  839. L"ScsiPort\\" SCSIPORT_SPECIAL_TARGET_KEY);
  840. InitializeObjectAttributes(&objectAttributes,
  841. &keyName,
  842. OBJ_CASE_INSENSITIVE,
  843. baseKey,
  844. NULL);
  845. status = ZwOpenKey(&listKey,
  846. KEY_READ,
  847. &objectAttributes);
  848. if(!NT_SUCCESS(status)) {
  849. DebugPrint((2, "SpCheckSpecialDeviceFlags - error %#08lx opening "
  850. "device devnode key %wZ\n", status, &keyName));
  851. leave;
  852. }
  853. SpProcessSpecialControllerFlags(listKey, &flags);
  854. } finally {
  855. if(baseKey != NULL) {
  856. ZwClose(baseKey);
  857. baseKey = NULL;
  858. if(listKey != NULL) {
  859. ZwClose(listKey);
  860. listKey = NULL;
  861. }
  862. }
  863. }
  864. LogicalUnit->SpecialFlags = flags;
  865. return STATUS_SUCCESS;
  866. }
  867. VOID
  868. SpProcessSpecialControllerList(
  869. IN PDRIVER_OBJECT DriverObject,
  870. IN PINQUIRYDATA InquiryData,
  871. IN HANDLE ListKey,
  872. OUT PSP_SPECIAL_CONTROLLER_FLAGS Flags
  873. )
  874. /*++
  875. Routine Description:
  876. This routine will match the specified logical unit to a set of special
  877. controller flags stored in the registry key ListKey. These flags will
  878. be written into the Flags structure, overwriting any flags which already
  879. exist.
  880. If no logical unit is provided then the ListKey handle is assumed to point
  881. at the appropriate list entry and the values stored there will be copied
  882. into the Flags structure.
  883. Arguments:
  884. InquiryData - The inquiry data for the logical unit. This is used to
  885. match strings in the special target list.
  886. ListKey - a handle to the special controller list to locate the logical
  887. unit in, or a handle to a list of flags if the LogicalUnit value
  888. is not present.
  889. Flags - a location to store the flags.
  890. Return Value:
  891. None
  892. --*/
  893. {
  894. UNICODE_STRING hardwareIds;
  895. PWSTR *hardwareIdList;
  896. ULONG idNumber;
  897. NTSTATUS status;
  898. PAGED_CODE();
  899. RtlInitUnicodeString(&hardwareIds, NULL);
  900. status = ScsiPortGetHardwareIds(DriverObject, InquiryData, &hardwareIds);
  901. if(!NT_SUCCESS(status)) {
  902. DebugPrint((2, "SpProcessSpecialControllerList: Error %#08lx getting "
  903. "hardware id's\n", status));
  904. return;
  905. }
  906. status = SpMultiStringToStringArray(DriverObject,
  907. &hardwareIds,
  908. &hardwareIdList,
  909. FALSE);
  910. if(!NT_SUCCESS(status)) {
  911. RtlFreeUnicodeString(&hardwareIds);
  912. return;
  913. }
  914. for(idNumber = 0; hardwareIdList[idNumber] != NULL; idNumber++) {
  915. PWSTR hardwareId = hardwareIdList[idNumber];
  916. ULONG j;
  917. UNICODE_STRING keyName;
  918. OBJECT_ATTRIBUTES objectAttributes;
  919. HANDLE flagsKey;
  920. DebugPrint((2, "SpProcessSpecialControllerList: processing id %ws\n",
  921. hardwareId));
  922. //
  923. // Remove the leading slash from the name.
  924. //
  925. for(j = 0; hardwareId[j] != UNICODE_NULL; j++) {
  926. if(hardwareId[j] == L'\\') {
  927. hardwareId = &(hardwareId[j+1]);
  928. break;
  929. }
  930. }
  931. //
  932. // Process the hardware id that we just found the end of.
  933. //
  934. RtlInitUnicodeString(&keyName, hardwareId);
  935. DebugPrint((2, "SpProcessSpecialControllerList: Finding match for "
  936. "%wZ - id %d\n", &keyName, idNumber));
  937. InitializeObjectAttributes(&objectAttributes,
  938. &keyName,
  939. OBJ_CASE_INSENSITIVE,
  940. ListKey,
  941. NULL);
  942. status = ZwOpenKey(&flagsKey,
  943. KEY_READ,
  944. &objectAttributes);
  945. if(NT_SUCCESS(status)) {
  946. SpProcessSpecialControllerFlags(flagsKey, Flags);
  947. ZwClose(flagsKey);
  948. } else {
  949. DebugPrint((2, "SpProcessSpecialControllerList: Error %#08lx "
  950. "opening key\n", status));
  951. }
  952. }
  953. ExFreePool(hardwareIdList);
  954. RtlFreeUnicodeString(&hardwareIds);
  955. return;
  956. }
  957. VOID
  958. SpProcessSpecialControllerFlags(
  959. IN HANDLE FlagsKey,
  960. OUT PSP_SPECIAL_CONTROLLER_FLAGS Flags
  961. )
  962. {
  963. RTL_QUERY_REGISTRY_TABLE queryTable[7];
  964. NTSTATUS status;
  965. PAGED_CODE();
  966. RtlZeroMemory(queryTable, sizeof(queryTable));
  967. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  968. queryTable[0].Name = L"SparseLUN";
  969. queryTable[0].EntryContext = &(Flags->SparseLun);
  970. queryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  971. queryTable[1].Name = L"OneLUN";
  972. queryTable[1].EntryContext = &(Flags->OneLun);
  973. queryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT;
  974. queryTable[2].Name = L"LargeLuns";
  975. queryTable[2].EntryContext = &(Flags->LargeLuns);
  976. queryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
  977. queryTable[3].Name = L"SetLunInCdb";
  978. queryTable[3].EntryContext = &(Flags->SetLunInCdb);
  979. queryTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
  980. queryTable[4].Name = L"NonStandardVPD";
  981. queryTable[4].EntryContext = &(Flags->NonStandardVPD);
  982. queryTable[5].Flags = RTL_QUERY_REGISTRY_DIRECT;
  983. queryTable[5].Name = L"BinarySN";
  984. queryTable[5].EntryContext = &(Flags->BinarySN);
  985. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  986. FlagsKey,
  987. queryTable,
  988. NULL,
  989. NULL);
  990. if(!NT_SUCCESS(status)) {
  991. DebugPrint((2, "SpProcssSpecialControllerFlags: Error %#08lx reading "
  992. "values\n", status));
  993. } else {
  994. DebugPrint((2, "SpProcessSpecialControllerFlags: %s%s%s%s%s\n",
  995. ((Flags->SparseLun ||
  996. Flags->OneLun ||
  997. Flags->LargeLuns ||
  998. Flags->SetLunInCdb ||
  999. Flags->NonStandardVPD ||
  1000. Flags->BinarySN) ? "" : "none"),
  1001. (Flags->SparseLun ? "SparseLun " : ""),
  1002. (Flags->OneLun ? "OneLun " : ""),
  1003. (Flags->LargeLuns ? "LargeLuns " : ""),
  1004. (Flags->SetLunInCdb ? "SetLunInCdb" : ""),
  1005. (Flags->NonStandardVPD ? "NonStandardVPD" : ""),
  1006. (Flags->BinarySN ? "BinarySN" : "")));
  1007. }
  1008. return;
  1009. }
  1010. PSRB_DATA
  1011. FASTCALL
  1012. SpAllocateSrbData(
  1013. IN PADAPTER_EXTENSION Adapter,
  1014. IN OPTIONAL PIRP Request
  1015. )
  1016. {
  1017. PSRB_DATA srbData;
  1018. srbData = ExAllocateFromNPagedLookasideList(
  1019. &Adapter->SrbDataLookasideList);
  1020. #if TEST_LISTS
  1021. if(srbData != NULL) {
  1022. InterlockedIncrement64(&Adapter->SrbDataAllocationCount);
  1023. }
  1024. #endif
  1025. if((srbData == NULL) && (Request != NULL)) {
  1026. KIRQL oldIrql;
  1027. PSRB_DATA emergencySrbData;
  1028. //
  1029. // Use the emergency srb data if it's not already in use.
  1030. //
  1031. KeAcquireSpinLock(&Adapter->EmergencySrbDataSpinLock,
  1032. &oldIrql);
  1033. emergencySrbData =
  1034. (PSRB_DATA) InterlockedExchangePointer(
  1035. (PVOID) &(Adapter->EmergencySrbData),
  1036. NULL);
  1037. if(emergencySrbData == NULL) {
  1038. //
  1039. // It's in use - queue the request until an srb data block
  1040. // goes free.
  1041. //
  1042. InsertTailList(
  1043. &Adapter->SrbDataBlockedRequests,
  1044. &Request->Tail.Overlay.DeviceQueueEntry.DeviceListEntry);
  1045. } else {
  1046. //
  1047. // There is an SRB_DATA block available after all.
  1048. //
  1049. srbData = emergencySrbData;
  1050. #if TEST_LISTS
  1051. InterlockedIncrement64(&Adapter->SrbDataEmergencyFreeCount);
  1052. #endif
  1053. }
  1054. KeReleaseSpinLock(&Adapter->EmergencySrbDataSpinLock,
  1055. oldIrql);
  1056. }
  1057. return srbData;
  1058. }
  1059. VOID
  1060. FASTCALL
  1061. SpFreeSrbData(
  1062. IN PADAPTER_EXTENSION Adapter,
  1063. IN PSRB_DATA SrbData
  1064. )
  1065. {
  1066. PSRB_DATA emergencySrbData = NULL;
  1067. BOOLEAN startedRequest = FALSE;
  1068. LONG depth;
  1069. ASSERT_SRB_DATA(SrbData);
  1070. ASSERT(SrbData->CurrentIrp == NULL);
  1071. ASSERT(SrbData->CurrentSrb == NULL);
  1072. ASSERT(SrbData->CompletedRequests == NULL);
  1073. //
  1074. // Determine if there are any other instances of this routine running. If
  1075. // there are, don't start a blocked request.
  1076. //
  1077. depth = InterlockedIncrement(&Adapter->SrbDataFreeRunning);
  1078. //
  1079. // Clear out some of the flags so we don't get confused when we reuse this
  1080. // request.
  1081. //
  1082. SrbData->Flags = 0;
  1083. //
  1084. // See if we need to store away a new emergency SRB_DATA block
  1085. //
  1086. emergencySrbData = InterlockedCompareExchangePointer(
  1087. &(Adapter->EmergencySrbData),
  1088. SrbData,
  1089. NULL);
  1090. //
  1091. // If we stored this SRB_DATA block as the new emergency block AND if this
  1092. // routine is not recursively nested, check if there are any blocked
  1093. // requests waiting to be started.
  1094. //
  1095. if(emergencySrbData == NULL && depth == 1) {
  1096. KIRQL oldIrql;
  1097. CheckForBlockedRequest:
  1098. //
  1099. // We did - now grab the spinlock and see if we can use it to issue
  1100. // a new request.
  1101. //
  1102. KeAcquireSpinLock(&(Adapter->EmergencySrbDataSpinLock), &oldIrql);
  1103. //
  1104. // First check to see if we have a request to process.
  1105. //
  1106. if(IsListEmpty(&(Adapter->SrbDataBlockedRequests)) == TRUE) {
  1107. KeReleaseSpinLock(&(Adapter->EmergencySrbDataSpinLock), oldIrql);
  1108. InterlockedDecrement(&Adapter->SrbDataFreeRunning);
  1109. return;
  1110. }
  1111. //
  1112. // make sure the emergency request is still there (doesn't really
  1113. // matter if it's the one we were called with or another one - just
  1114. // make sure one is available).
  1115. //
  1116. emergencySrbData = (PSRB_DATA)
  1117. InterlockedExchangePointer(
  1118. (PVOID) &(Adapter->EmergencySrbData),
  1119. NULL);
  1120. if(emergencySrbData == NULL) {
  1121. //
  1122. // Our work here is done.
  1123. //
  1124. KeReleaseSpinLock(&(Adapter->EmergencySrbDataSpinLock), oldIrql);
  1125. InterlockedDecrement(&Adapter->SrbDataFreeRunning);
  1126. return;
  1127. } else {
  1128. PLIST_ENTRY entry;
  1129. PIRP request;
  1130. PIO_STACK_LOCATION currentIrpStack;
  1131. PSCSI_REQUEST_BLOCK srb;
  1132. entry = RemoveHeadList(&(Adapter->SrbDataBlockedRequests));
  1133. ASSERT(entry != NULL);
  1134. request =
  1135. CONTAINING_RECORD(
  1136. entry,
  1137. IRP,
  1138. Tail.Overlay.DeviceQueueEntry);
  1139. KeReleaseSpinLock(&(Adapter->EmergencySrbDataSpinLock), oldIrql);
  1140. currentIrpStack = IoGetCurrentIrpStackLocation(request);
  1141. srb = currentIrpStack->Parameters.Scsi.Srb;
  1142. ASSERT_PDO(currentIrpStack->DeviceObject);
  1143. emergencySrbData->CurrentIrp = request;
  1144. emergencySrbData->CurrentSrb = srb;
  1145. emergencySrbData->LogicalUnit =
  1146. currentIrpStack->DeviceObject->DeviceExtension;
  1147. srb->OriginalRequest = emergencySrbData;
  1148. startedRequest = TRUE;
  1149. SpDispatchRequest(emergencySrbData->LogicalUnit,
  1150. request);
  1151. #if TEST_LISTS
  1152. InterlockedIncrement64(&Adapter->SrbDataResurrectionCount);
  1153. #endif
  1154. }
  1155. //
  1156. // If we started a blocked request, go back and see if another one
  1157. // needs to be started.
  1158. //
  1159. if (startedRequest == TRUE) {
  1160. startedRequest = FALSE;
  1161. goto CheckForBlockedRequest;
  1162. }
  1163. } else if (emergencySrbData != NULL) {
  1164. //
  1165. // We did not store this SRB_DATA block as the emergency block, so
  1166. // we need to free it back to the lookaside list.
  1167. //
  1168. ExFreeToNPagedLookasideList(
  1169. &Adapter->SrbDataLookasideList,
  1170. SrbData);
  1171. }
  1172. InterlockedDecrement(&Adapter->SrbDataFreeRunning);
  1173. return;
  1174. }
  1175. PVOID
  1176. SpAllocateSrbDataBackend(
  1177. IN POOL_TYPE PoolType,
  1178. IN ULONG NumberOfBytes,
  1179. IN ULONG AdapterIndex
  1180. )
  1181. {
  1182. KIRQL oldIrql;
  1183. PADAPTER_EXTENSION Adapter;
  1184. PSRB_DATA srbData;
  1185. ULONG tag;
  1186. KeAcquireSpinLock(&ScsiGlobalAdapterListSpinLock, &oldIrql);
  1187. Adapter = ScsiGlobalAdapterList[AdapterIndex]->DeviceExtension;
  1188. KeReleaseSpinLock(&ScsiGlobalAdapterListSpinLock, oldIrql);
  1189. ASSERT_FDO(Adapter->DeviceObject);
  1190. tag = SpAllocateQueueTag(Adapter);
  1191. if(tag == -1) {
  1192. return NULL;
  1193. }
  1194. srbData = SpAllocatePool(PoolType,
  1195. NumberOfBytes,
  1196. SCSIPORT_TAG_SRB_DATA,
  1197. Adapter->DeviceObject->DriverObject);
  1198. if(srbData == NULL) {
  1199. SpReleaseQueueTag(Adapter, tag);
  1200. return NULL;
  1201. }
  1202. RtlZeroMemory(srbData, sizeof(SRB_DATA));
  1203. srbData->Adapter = Adapter;
  1204. srbData->QueueTag = tag;
  1205. srbData->Type = SRB_DATA_TYPE;
  1206. srbData->Size = sizeof(SRB_DATA);
  1207. srbData->Flags = 0;
  1208. srbData->FreeRoutine = SpFreeSrbData;
  1209. return srbData;
  1210. }
  1211. VOID
  1212. SpFreeSrbDataBackend(
  1213. IN PSRB_DATA SrbData
  1214. )
  1215. {
  1216. ASSERT_SRB_DATA(SrbData);
  1217. ASSERT_FDO(SrbData->Adapter->DeviceObject);
  1218. ASSERT(SrbData->QueueTag != 0);
  1219. SpReleaseQueueTag(SrbData->Adapter, SrbData->QueueTag);
  1220. SrbData->Type = 0;
  1221. ExFreePool(SrbData);
  1222. return;
  1223. }
  1224. NTSTATUS
  1225. SpAllocateTagBitMap(
  1226. IN PADAPTER_EXTENSION Adapter
  1227. )
  1228. {
  1229. ULONG size; // number of bits
  1230. PRTL_BITMAP bitMap;
  1231. PAGED_CODE();
  1232. //
  1233. // Initialize the queue tag bitMap.
  1234. //
  1235. if(Adapter->MaxQueueTag == 0) {
  1236. #if SMALL_QUEUE_TAG_BITMAP
  1237. if(Adapter->NumberOfRequests <= 240) {
  1238. Adapter->MaxQueueTag = (UCHAR) (Adapter->NumberOfRequests) + 10;
  1239. } else {
  1240. Adapter->MaxQueueTag = 254;
  1241. }
  1242. #else
  1243. Adapter->MaxQueueTag = 254;
  1244. #endif
  1245. } else if (Adapter->MaxQueueTag < Adapter->NumberOfRequests) {
  1246. DbgPrint("SpAllocateTagBitmap: MaxQueueTag %d < NumberOfRequests %d\n"
  1247. "This will negate the advantage of having increased the "
  1248. "number of requests.\n",
  1249. Adapter->MaxQueueTag,
  1250. Adapter->NumberOfRequests);
  1251. }
  1252. DebugPrint((1, "SpAllocateAdapterResources: %d bits in queue tag "
  1253. "bitMap\n",
  1254. Adapter->MaxQueueTag));
  1255. size = (Adapter->MaxQueueTag + 1);
  1256. size /= 8;
  1257. size += 1;
  1258. size *= sizeof(UCHAR);
  1259. size += sizeof(RTL_BITMAP);
  1260. bitMap = SpAllocatePool(NonPagedPool,
  1261. size,
  1262. SCSIPORT_TAG_QUEUE_BITMAP,
  1263. Adapter->DeviceObject->DriverObject);
  1264. if(bitMap == NULL) {
  1265. return STATUS_INSUFFICIENT_RESOURCES;
  1266. }
  1267. RtlInitializeBitMap(bitMap,
  1268. (PULONG) (bitMap + 1),
  1269. Adapter->MaxQueueTag);
  1270. RtlClearAllBits(bitMap);
  1271. //
  1272. // Queue tag 0 is invalid and should never be returned by the allocator.
  1273. //
  1274. RtlSetBits(bitMap, 0, 1);
  1275. Adapter->QueueTagBitMap = bitMap;
  1276. Adapter->QueueTagHint = 1;
  1277. //
  1278. // Create a spinlock to protect our queue tag bitmap. There's no reason
  1279. // for this to contend with the regular port spinlock.
  1280. //
  1281. KeInitializeSpinLock(&(Adapter->QueueTagSpinLock));
  1282. return STATUS_SUCCESS;
  1283. }
  1284. ULONG
  1285. SpAllocateQueueTag(
  1286. IN PADAPTER_EXTENSION Adapter
  1287. )
  1288. {
  1289. KIRQL oldIrql;
  1290. ULONG tagValue;
  1291. ASSERT_FDO(Adapter->DeviceObject);
  1292. KeAcquireSpinLock(&(Adapter->QueueTagSpinLock), &oldIrql);
  1293. //
  1294. // Find an available queue tag.
  1295. //
  1296. tagValue = RtlFindClearBitsAndSet(Adapter->QueueTagBitMap,
  1297. 1,
  1298. Adapter->QueueTagHint);
  1299. KeReleaseSpinLock(&(Adapter->QueueTagSpinLock), oldIrql);
  1300. ASSERT(Adapter->QueueTagHint < Adapter->MaxQueueTag);
  1301. ASSERT(tagValue != 0);
  1302. if(tagValue != -1) {
  1303. ASSERT(tagValue <= Adapter->MaxQueueTag);
  1304. //
  1305. // This we can do unsynchronized. if we nuke the hint accidentally it
  1306. // will just increase the cost of the next lookup which should
  1307. // hopefully occur rarely.
  1308. //
  1309. Adapter->QueueTagHint = (tagValue + 1) % Adapter->MaxQueueTag;
  1310. }
  1311. return tagValue;
  1312. }
  1313. VOID
  1314. SpReleaseQueueTag(
  1315. IN PADAPTER_EXTENSION Adapter,
  1316. IN ULONG QueueTag
  1317. )
  1318. {
  1319. KIRQL oldIrql;
  1320. KeAcquireSpinLock(&(Adapter->QueueTagSpinLock), &oldIrql);
  1321. RtlClearBits(Adapter->QueueTagBitMap,
  1322. QueueTag,
  1323. 1);
  1324. KeReleaseSpinLock(&(Adapter->QueueTagSpinLock), oldIrql);
  1325. return;
  1326. }
  1327. INTERFACE_TYPE
  1328. SpGetPdoInterfaceType(
  1329. IN PDEVICE_OBJECT Pdo
  1330. )
  1331. {
  1332. ULONG value;
  1333. GUID busTypeGuid;
  1334. INTERFACE_TYPE interfaceType = InterfaceTypeUndefined;
  1335. ULONG result;
  1336. NTSTATUS status;
  1337. PAGED_CODE();
  1338. status = SpReadNumericInstanceValue(Pdo,
  1339. L"LegacyInterfaceType",
  1340. &value);
  1341. if(NT_SUCCESS(status)) {
  1342. interfaceType = value;
  1343. return interfaceType;
  1344. }
  1345. //
  1346. // Attempt to get and interpret the bus type GUID.
  1347. //
  1348. status = IoGetDeviceProperty(Pdo,
  1349. DevicePropertyBusTypeGuid,
  1350. sizeof(GUID),
  1351. &busTypeGuid,
  1352. &result);
  1353. if(NT_SUCCESS(status)) {
  1354. ULONG i;
  1355. for(i = 0;
  1356. (SpGuidInterfaceMappingList[i].InterfaceType !=
  1357. InterfaceTypeUndefined);
  1358. i++) {
  1359. if(RtlEqualMemory(&(SpGuidInterfaceMappingList[i].Guid),
  1360. &busTypeGuid,
  1361. sizeof(GUID))) {
  1362. //
  1363. // We have a legacy interface type for this guid already.
  1364. //
  1365. interfaceType = SpGuidInterfaceMappingList[i].InterfaceType;
  1366. break;
  1367. }
  1368. }
  1369. }
  1370. if(interfaceType != InterfaceTypeUndefined) {
  1371. return interfaceType;
  1372. }
  1373. status = IoGetDeviceProperty(Pdo,
  1374. DevicePropertyLegacyBusType,
  1375. sizeof(INTERFACE_TYPE),
  1376. &interfaceType,
  1377. &result);
  1378. if(NT_SUCCESS(status)) {
  1379. ASSERT(result == sizeof(INTERFACE_TYPE));
  1380. //
  1381. // Munge the interface type for the case of PCMCIA cards to allow SCSI
  1382. // pccards (i.e. sparrow) to be recognized. Much better would be a way
  1383. // to get the interface type correct before we enter this routine.
  1384. //
  1385. if (interfaceType == PCMCIABus) {
  1386. interfaceType = Isa;
  1387. }
  1388. }
  1389. if(interfaceType != InterfaceTypeUndefined) {
  1390. return interfaceType;
  1391. } else {
  1392. //
  1393. // No idea what the interface type is - guess isa.
  1394. //
  1395. DebugPrint((1, "SpGetPdoInterfaceType: Status %#08lx getting legacy "
  1396. "bus type - assuming device is ISA\n", status));
  1397. return Isa;
  1398. }
  1399. }
  1400. NTSTATUS
  1401. SpReadNumericInstanceValue(
  1402. IN PDEVICE_OBJECT Pdo,
  1403. IN PWSTR ValueName,
  1404. OUT PULONG Value
  1405. )
  1406. {
  1407. ULONG value;
  1408. HANDLE baseKey = NULL;
  1409. HANDLE scsiportKey = NULL;
  1410. NTSTATUS status;
  1411. PAGED_CODE();
  1412. ASSERT(Value != NULL);
  1413. ASSERT(ValueName != NULL);
  1414. ASSERT(Pdo != NULL);
  1415. status = IoOpenDeviceRegistryKey(Pdo,
  1416. PLUGPLAY_REGKEY_DEVICE,
  1417. KEY_READ,
  1418. &baseKey);
  1419. if(!NT_SUCCESS(status)) {
  1420. return status;
  1421. }
  1422. try {
  1423. UNICODE_STRING unicodeKeyName;
  1424. OBJECT_ATTRIBUTES objectAttributes;
  1425. RtlInitUnicodeString(&unicodeKeyName, L"Scsiport");
  1426. InitializeObjectAttributes(&objectAttributes,
  1427. &unicodeKeyName,
  1428. OBJ_CASE_INSENSITIVE,
  1429. baseKey,
  1430. NULL);
  1431. status = ZwOpenKey(&scsiportKey,
  1432. KEY_READ,
  1433. &objectAttributes);
  1434. if(!NT_SUCCESS(status)) {
  1435. leave;
  1436. } else {
  1437. UNICODE_STRING unicodeValueName;
  1438. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  1439. PKEY_VALUE_PARTIAL_INFORMATION keyValue =
  1440. (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  1441. ULONG result;
  1442. RtlInitUnicodeString(&unicodeValueName, ValueName);
  1443. status = ZwQueryValueKey(scsiportKey,
  1444. &unicodeValueName,
  1445. KeyValuePartialInformation,
  1446. keyValue,
  1447. sizeof(buffer),
  1448. &result);
  1449. if(!NT_SUCCESS(status)) {
  1450. leave;
  1451. }
  1452. if(keyValue->Type != REG_DWORD) {
  1453. status = STATUS_OBJECT_TYPE_MISMATCH;
  1454. leave;
  1455. }
  1456. if(result < sizeof(ULONG)) {
  1457. status = STATUS_OBJECT_TYPE_MISMATCH;
  1458. leave;
  1459. }
  1460. value = ((PULONG) (keyValue->Data))[0];
  1461. }
  1462. } finally {
  1463. if(baseKey != NULL) {ZwClose(baseKey);}
  1464. if(scsiportKey != NULL) {ZwClose(scsiportKey);}
  1465. }
  1466. *Value = value;
  1467. return status;
  1468. }
  1469. NTSTATUS
  1470. SpWriteNumericInstanceValue(
  1471. IN PDEVICE_OBJECT Pdo,
  1472. IN PWSTR ValueName,
  1473. IN ULONG Value
  1474. )
  1475. {
  1476. ULONG value;
  1477. HANDLE baseKey = NULL;
  1478. HANDLE scsiportKey = NULL;
  1479. NTSTATUS status;
  1480. PAGED_CODE();
  1481. ASSERT(ValueName != NULL);
  1482. ASSERT(Pdo != NULL);
  1483. status = IoOpenDeviceRegistryKey(Pdo,
  1484. PLUGPLAY_REGKEY_DEVICE,
  1485. KEY_READ | KEY_WRITE,
  1486. &baseKey);
  1487. if(!NT_SUCCESS(status)) {
  1488. return status;
  1489. }
  1490. try {
  1491. UNICODE_STRING unicodeKeyName;
  1492. OBJECT_ATTRIBUTES objectAttributes;
  1493. RtlInitUnicodeString(&unicodeKeyName, L"Scsiport");
  1494. InitializeObjectAttributes(&objectAttributes,
  1495. &unicodeKeyName,
  1496. OBJ_CASE_INSENSITIVE,
  1497. baseKey,
  1498. NULL);
  1499. status = ZwCreateKey(&scsiportKey,
  1500. KEY_READ | KEY_WRITE,
  1501. &objectAttributes,
  1502. 0,
  1503. NULL,
  1504. REG_OPTION_NON_VOLATILE,
  1505. NULL
  1506. );
  1507. if(!NT_SUCCESS(status)) {
  1508. leave;
  1509. } else {
  1510. UNICODE_STRING unicodeValueName;
  1511. ULONG result;
  1512. RtlInitUnicodeString(&unicodeValueName, ValueName);
  1513. status = ZwSetValueKey(scsiportKey,
  1514. &unicodeValueName,
  1515. 0,
  1516. REG_DWORD,
  1517. &Value,
  1518. sizeof(ULONG));
  1519. }
  1520. } finally {
  1521. if(baseKey != NULL) {ZwClose(baseKey);}
  1522. if(scsiportKey != NULL) {ZwClose(scsiportKey);}
  1523. }
  1524. return status;
  1525. }
  1526. PMAPPED_ADDRESS
  1527. SpAllocateAddressMapping(
  1528. PADAPTER_EXTENSION Adapter
  1529. )
  1530. /*++
  1531. Routine Description:
  1532. This routine will attempt to allocate a free address mapping block and
  1533. place it on the adapter's MappedAddressList. If there is an available
  1534. block in the free list then it will be used. Otherwise it will attempt
  1535. to allocate a block from non-paged pool.
  1536. Arguments:
  1537. Adapter - the adapter we are allocating the mapping for.
  1538. Preallocate - indicates that the caller is trying to preallocate buffers.
  1539. Return Value:
  1540. a pointer to the new mapping (which has been inserted into the address
  1541. mapping list) or NULL if none could be allocated.
  1542. --*/
  1543. {
  1544. PMAPPED_ADDRESS mapping;
  1545. PAGED_CODE();
  1546. //
  1547. // First check the free address mapping list. If there's one there
  1548. // unlink it and return.
  1549. //
  1550. if(Adapter->FreeMappedAddressList != NULL) {
  1551. mapping = Adapter->FreeMappedAddressList;
  1552. Adapter->FreeMappedAddressList = mapping->NextMappedAddress;
  1553. } else {
  1554. mapping = SpAllocatePool(NonPagedPool,
  1555. sizeof(MAPPED_ADDRESS),
  1556. SCSIPORT_TAG_MAPPING_LIST,
  1557. Adapter->DeviceObject->DriverObject);
  1558. }
  1559. if(mapping == NULL) {
  1560. DebugPrint((0, "SpAllocateAddressMapping: Unable to allocate "
  1561. "mapping\n"));
  1562. return NULL;
  1563. }
  1564. RtlZeroMemory(mapping, sizeof(MAPPED_ADDRESS));
  1565. mapping->NextMappedAddress = Adapter->MappedAddressList;
  1566. Adapter->MappedAddressList = mapping;
  1567. return mapping;
  1568. }
  1569. BOOLEAN
  1570. SpPreallocateAddressMapping(
  1571. PADAPTER_EXTENSION Adapter,
  1572. IN UCHAR NumberOfBlocks
  1573. )
  1574. /*++
  1575. Routine Description:
  1576. This routine will allocate a number of address mapping structures and
  1577. place them on the free mapped address list.
  1578. Arguments:
  1579. Adapter - the adapter we are allocating the mapping for.
  1580. NumberOfBlocks - the number of blocks to allocate
  1581. Return Value:
  1582. TRUE if the requested number of blocks was successfully allocated,
  1583. FALSE if there was not sufficient memory to allocate them all. The caller
  1584. is still responsible for freeing them in this case.
  1585. --*/
  1586. {
  1587. PMAPPED_ADDRESS mapping;
  1588. ULONG i;
  1589. PAGED_CODE();
  1590. for(i = 0; i < NumberOfBlocks; i++) {
  1591. mapping = SpAllocatePool(NonPagedPool,
  1592. sizeof(MAPPED_ADDRESS),
  1593. SCSIPORT_TAG_MAPPING_LIST,
  1594. Adapter->DeviceObject->DriverObject);
  1595. if(mapping == NULL) {
  1596. return FALSE;
  1597. }
  1598. RtlZeroMemory(mapping, sizeof(MAPPED_ADDRESS));
  1599. mapping->NextMappedAddress = Adapter->FreeMappedAddressList;
  1600. Adapter->FreeMappedAddressList = mapping;
  1601. }
  1602. return TRUE;
  1603. }
  1604. VOID
  1605. SpPurgeFreeMappedAddressList(
  1606. IN PADAPTER_EXTENSION Adapter
  1607. )
  1608. /*++
  1609. Routine Description:
  1610. This routine frees all of the mapped address blocks on the
  1611. FreeMappedAddressList.
  1612. Arguments:
  1613. Adapter - the adapter who's FreeMappedAddressList is to be dumped.
  1614. Return Value:
  1615. none
  1616. --*/
  1617. {
  1618. PMAPPED_ADDRESS mapping;
  1619. PAGED_CODE();
  1620. while(Adapter->FreeMappedAddressList != NULL) {
  1621. mapping = Adapter->FreeMappedAddressList;
  1622. Adapter->FreeMappedAddressList = mapping->NextMappedAddress;
  1623. ExFreePool(mapping);
  1624. }
  1625. return;
  1626. }
  1627. BOOLEAN
  1628. SpFreeMappedAddress(
  1629. IN PADAPTER_EXTENSION Adapter,
  1630. IN PVOID MappedAddress
  1631. )
  1632. /*++
  1633. Routine Description:
  1634. This routine will unmap the specified mapping and then return the mapping
  1635. block to the free list. If no mapped address was specified then this
  1636. will simply free the first mapping on the MappedAddressList.
  1637. Arguments:
  1638. Adapter - the adapter which has the mapping
  1639. MappedAddress - the base address of the mapping we're attempting to free.
  1640. ignored if FreeSpecificBlock is false.
  1641. Return Value:
  1642. TRUE if a matching list element was found.
  1643. FALSE otherwise.
  1644. --*/
  1645. {
  1646. PMAPPED_ADDRESS *mapping;
  1647. PAGED_CODE();
  1648. for(mapping = &(Adapter->MappedAddressList);
  1649. *mapping != NULL;
  1650. mapping = &((*mapping)->NextMappedAddress)) {
  1651. if((*mapping)->MappedAddress == MappedAddress) {
  1652. PMAPPED_ADDRESS tmp = *mapping;
  1653. //
  1654. // Unmap address.
  1655. //
  1656. MmUnmapIoSpace(tmp->MappedAddress, tmp->NumberOfBytes);
  1657. //
  1658. // Unlink this entry from the mapped address list. Stick it on
  1659. // the free mapped address list. Then return.
  1660. //
  1661. *mapping = tmp->NextMappedAddress;
  1662. tmp->NextMappedAddress = Adapter->FreeMappedAddressList;
  1663. Adapter->FreeMappedAddressList = tmp;
  1664. return TRUE;
  1665. }
  1666. }
  1667. return FALSE;
  1668. }
  1669. PMAPPED_ADDRESS
  1670. SpFindMappedAddress(
  1671. IN PADAPTER_EXTENSION Adapter,
  1672. IN LARGE_INTEGER IoAddress,
  1673. IN ULONG NumberOfBytes,
  1674. IN ULONG SystemIoBusNumber
  1675. )
  1676. {
  1677. PMAPPED_ADDRESS mapping;
  1678. for(mapping = Adapter->MappedAddressList;
  1679. mapping != NULL;
  1680. mapping = mapping->NextMappedAddress) {
  1681. if((mapping->IoAddress.QuadPart == IoAddress.QuadPart) &&
  1682. (mapping->NumberOfBytes == NumberOfBytes) &&
  1683. (mapping->BusNumber == SystemIoBusNumber)) {
  1684. return mapping;
  1685. }
  1686. }
  1687. return NULL;
  1688. }
  1689. VOID
  1690. SpReleaseMappedAddresses(
  1691. IN PADAPTER_EXTENSION Adapter
  1692. )
  1693. {
  1694. ULONG i;
  1695. PAGED_CODE();
  1696. //
  1697. // Iterate through the mapped address list and punt every entry onto the
  1698. // free list.
  1699. //
  1700. while(Adapter->MappedAddressList != NULL) {
  1701. SpFreeMappedAddress(Adapter, Adapter->MappedAddressList->MappedAddress);
  1702. }
  1703. //
  1704. // Now dump the free list.
  1705. //
  1706. SpPurgeFreeMappedAddressList(Adapter);
  1707. return;
  1708. }
  1709. NTSTATUS
  1710. SpSignalCompletion(
  1711. IN PDEVICE_OBJECT DeviceObject,
  1712. IN PIRP Irp,
  1713. IN PKEVENT Event
  1714. )
  1715. {
  1716. KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
  1717. return STATUS_MORE_PROCESSING_REQUIRED;
  1718. }
  1719. NTSTATUS
  1720. SpSendIrpSynchronous(
  1721. IN PDEVICE_OBJECT DeviceObject,
  1722. IN PIRP Irp
  1723. )
  1724. {
  1725. KEVENT event;
  1726. PAGED_CODE();
  1727. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1728. IoCopyCurrentIrpStackLocationToNext(Irp);
  1729. IoSetCompletionRoutine(Irp,
  1730. SpSignalCompletion,
  1731. &event,
  1732. TRUE,
  1733. TRUE,
  1734. TRUE);
  1735. IoCallDriver(DeviceObject, Irp);
  1736. KeWaitForSingleObject(&event,
  1737. Executive,
  1738. KernelMode,
  1739. FALSE,
  1740. NULL);
  1741. return Irp->IoStatus.Status;
  1742. }
  1743. NTSTATUS
  1744. SpGetBusTypeGuid(
  1745. IN PADAPTER_EXTENSION Adapter
  1746. )
  1747. {
  1748. ULONG result;
  1749. NTSTATUS status;
  1750. PAGED_CODE();
  1751. //
  1752. // Grab the bus interface GUID and save it away in the adapter extension.
  1753. //
  1754. status = IoGetDeviceProperty(Adapter->LowerPdo,
  1755. DevicePropertyBusTypeGuid,
  1756. sizeof(GUID),
  1757. &(Adapter->BusTypeGuid),
  1758. &result);
  1759. if(!NT_SUCCESS(status)) {
  1760. RtlZeroMemory(&(Adapter->BusTypeGuid), sizeof(GUID));
  1761. }
  1762. return status;
  1763. }
  1764. BOOLEAN
  1765. SpDetermine64BitSupport(
  1766. VOID
  1767. )
  1768. /*++
  1769. Routine Description:
  1770. This routine determines if 64-bit physical addressing is supported by
  1771. the system to be saved in the global Sp64BitPhysicalAddressing. Eventually
  1772. this routine can be removed and the scsiport global will just point to the
  1773. one exported by MM. However the global isn't hooked up for PAE36 at the
  1774. moment so we need to do some x86 specific tricks.
  1775. Arguments:
  1776. none
  1777. Return Value:
  1778. Does the system support 64-bit (or something over 32-bit) addresses?
  1779. --*/
  1780. {
  1781. PAGED_CODE();
  1782. if((*Mm64BitPhysicalAddress) == TRUE) {
  1783. DbgPrintEx(DPFLTR_SCSIPORT_ID,
  1784. DPFLTR_INFO_LEVEL,
  1785. "SpDetermine64BitSupport: Mm64BitPhysicalAddress is TRUE\n");
  1786. return TRUE;
  1787. }
  1788. return FALSE;
  1789. }
  1790. VOID
  1791. SpAdjustDisabledBit(
  1792. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  1793. IN BOOLEAN Enable
  1794. )
  1795. {
  1796. ULONG newCount;
  1797. KIRQL oldIrql;
  1798. KeAcquireSpinLock(&(LogicalUnit->AdapterExtension->SpinLock), &oldIrql);
  1799. if(Enable) {
  1800. if(LogicalUnit->QueuePauseCount != 0) {
  1801. LogicalUnit->QueuePauseCount -= 1;
  1802. }
  1803. if(LogicalUnit->QueuePauseCount == 0) {
  1804. CLEAR_FLAG(LogicalUnit->LuFlags, LU_QUEUE_PAUSED);
  1805. }
  1806. } else {
  1807. LogicalUnit->QueuePauseCount += 1;
  1808. SET_FLAG(LogicalUnit->LuFlags, LU_QUEUE_PAUSED);
  1809. }
  1810. KeReleaseSpinLock(&(LogicalUnit->AdapterExtension->SpinLock), oldIrql);
  1811. return;
  1812. }
  1813. NTSTATUS
  1814. SpReadNumericValue(
  1815. IN OPTIONAL HANDLE Root,
  1816. IN OPTIONAL PUNICODE_STRING KeyName,
  1817. IN PUNICODE_STRING ValueName,
  1818. OUT PULONG Value
  1819. )
  1820. /*++
  1821. Routine Description:
  1822. This routine will read a REG_DWORD value from the specified registry
  1823. location. The caller can specify the key by providing a handle to a root
  1824. registry key and the name of a subkey.
  1825. The caller must supply either Root or KeyName. Both may be supplied.
  1826. Arguments:
  1827. Root - the key the value resides in (if KeyName is NULL), a parent
  1828. key of the one the value resides in, or NULL if KeyName specifies
  1829. the entire registry path.
  1830. KeyName - the name of the subkey (either from the root of the registry or
  1831. from the key specified in Root.
  1832. ValueName - the name of the value to be read
  1833. Value - returns the value in the key. this will be zero if an error occurs
  1834. Return Value:
  1835. STATUS_SUCCESS if successful.
  1836. STATUS_UNSUCCESSFUL if the specified value is not a REG_DWORD value.
  1837. other status values explaining the cause of the failure.
  1838. --*/
  1839. {
  1840. ULONG value = 0;
  1841. HANDLE key = Root;
  1842. NTSTATUS status = STATUS_SUCCESS;
  1843. PAGED_CODE();
  1844. ASSERT(Value != NULL);
  1845. ASSERT(ValueName != NULL);
  1846. ASSERT((KeyName != NULL) || (Root != NULL));
  1847. if(ARGUMENT_PRESENT(KeyName)) {
  1848. OBJECT_ATTRIBUTES objectAttributes;
  1849. InitializeObjectAttributes(&(objectAttributes),
  1850. KeyName,
  1851. OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
  1852. Root,
  1853. NULL);
  1854. status = ZwOpenKey(&(key), KEY_QUERY_VALUE, &objectAttributes);
  1855. }
  1856. if(NT_SUCCESS(status)) {
  1857. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  1858. PKEY_VALUE_PARTIAL_INFORMATION data;
  1859. ULONG result;
  1860. RtlZeroMemory(buffer, sizeof(buffer));
  1861. data = (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  1862. status = ZwQueryValueKey(key,
  1863. ValueName,
  1864. KeyValuePartialInformation,
  1865. data,
  1866. sizeof(buffer),
  1867. &result);
  1868. if(NT_SUCCESS(status)) {
  1869. if (data->Type != REG_DWORD) {
  1870. status = STATUS_UNSUCCESSFUL;
  1871. } else {
  1872. value = ((PULONG) data->Data)[0];
  1873. }
  1874. }
  1875. }
  1876. *Value = value;
  1877. if(key != Root) {
  1878. ZwClose(key);
  1879. }
  1880. return status;
  1881. }
  1882. PMDL
  1883. SpBuildMdlForMappedTransfer(
  1884. IN PDEVICE_OBJECT DeviceObject,
  1885. IN PDMA_ADAPTER AdapterObject,
  1886. IN PMDL OriginalMdl,
  1887. IN PVOID StartVa,
  1888. IN ULONG ByteCount,
  1889. IN PSRB_SCATTER_GATHER ScatterGatherList,
  1890. IN ULONG ScatterGatherEntries
  1891. )
  1892. {
  1893. ULONG size;
  1894. PMDL mdl;
  1895. ULONG pageCount;
  1896. PPFN_NUMBER pages;
  1897. ULONG sgPage;
  1898. ULONG mdlPage;
  1899. ULONG sgSpan;
  1900. mdl = SpAllocateMdl(StartVa,
  1901. ByteCount,
  1902. FALSE,
  1903. FALSE,
  1904. NULL,
  1905. DeviceObject->DriverObject);
  1906. if (mdl == NULL) {
  1907. return NULL;
  1908. }
  1909. pageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(StartVa, ByteCount);
  1910. //
  1911. // Indicate that the memory has already been locked down.
  1912. //
  1913. //
  1914. // Indicate that the memory is "I/O space" so that MM doesn't won't
  1915. // reference the (nonexistent) PFNs for this buffer. We have to do this
  1916. // for the time being because MM isn't aware of the pages the HAL is using
  1917. // for bounce buffers.
  1918. //
  1919. SET_FLAG(mdl->MdlFlags, MDL_PAGES_LOCKED | MDL_IO_SPACE);
  1920. //
  1921. // Run through our scatter gather list and build the page list based
  1922. // on that.
  1923. //
  1924. pages = (PPFN_NUMBER) (mdl + 1);
  1925. for(sgPage = 0, mdlPage = 0; sgPage < ScatterGatherEntries; sgPage++) {
  1926. PVOID pa;
  1927. ULONG sgLength;
  1928. ASSERT(ScatterGatherList[sgPage].Length != 0);
  1929. pa = (PVOID) ScatterGatherList[sgPage].Address.QuadPart;
  1930. sgLength =
  1931. ADDRESS_AND_SIZE_TO_SPAN_PAGES(pa,
  1932. ScatterGatherList[sgPage].Length);
  1933. for(sgSpan = 0; sgSpan < sgLength; sgSpan++, mdlPage++) {
  1934. ULONGLONG pa;
  1935. pa = ScatterGatherList[sgPage].Address.QuadPart;
  1936. pa += sgSpan * PAGE_SIZE;
  1937. pa >>= PAGE_SHIFT;
  1938. pages[mdlPage] = (PFN_NUMBER) (pa);
  1939. }
  1940. }
  1941. pages = (PPFN_NUMBER) (mdl + 1);
  1942. pages = (PPFN_NUMBER) (OriginalMdl + 1);
  1943. ASSERT(mdlPage == pageCount);
  1944. return mdl;
  1945. }
  1946. #if defined(FORWARD_PROGRESS)
  1947. VOID
  1948. SpPrepareMdlForMappedTransfer(
  1949. IN PMDL mdl,
  1950. IN PDEVICE_OBJECT DeviceObject,
  1951. IN PDMA_ADAPTER AdapterObject,
  1952. IN PMDL OriginalMdl,
  1953. IN PVOID StartVa,
  1954. IN ULONG ByteCount,
  1955. IN PSRB_SCATTER_GATHER ScatterGatherList,
  1956. IN ULONG ScatterGatherEntries
  1957. )
  1958. {
  1959. ULONG size;
  1960. ULONG pageCount;
  1961. PPFN_NUMBER pages;
  1962. ULONG sgPage;
  1963. ULONG mdlPage;
  1964. ULONG sgSpan;
  1965. pageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(StartVa, ByteCount);
  1966. //
  1967. // Indicate that the memory has already been locked down.
  1968. //
  1969. //
  1970. // Indicate that the memory is "I/O space" so that MM doesn't won't
  1971. // reference the (nonexistent) PFNs for this buffer. We have to do this
  1972. // for the time being because MM isn't aware of the pages the HAL is using
  1973. // for bounce buffers.
  1974. //
  1975. SET_FLAG(mdl->MdlFlags, MDL_PAGES_LOCKED | MDL_IO_SPACE);
  1976. //
  1977. // Run through our scatter gather list and build the page list based
  1978. // on that.
  1979. //
  1980. pages = (PPFN_NUMBER) (mdl + 1);
  1981. for(sgPage = 0, mdlPage = 0; sgPage < ScatterGatherEntries; sgPage++) {
  1982. PVOID pa;
  1983. ULONG sgLength;
  1984. ASSERT(ScatterGatherList[sgPage].Length != 0);
  1985. pa = (PVOID) ScatterGatherList[sgPage].Address.QuadPart;
  1986. sgLength =
  1987. ADDRESS_AND_SIZE_TO_SPAN_PAGES(pa,
  1988. ScatterGatherList[sgPage].Length);
  1989. for(sgSpan = 0; sgSpan < sgLength; sgSpan++, mdlPage++) {
  1990. ULONGLONG pa;
  1991. pa = ScatterGatherList[sgPage].Address.QuadPart;
  1992. pa += sgSpan * PAGE_SIZE;
  1993. pa >>= PAGE_SHIFT;
  1994. pages[mdlPage] = (PFN_NUMBER) (pa);
  1995. }
  1996. }
  1997. pages = (PPFN_NUMBER) (mdl + 1);
  1998. pages = (PPFN_NUMBER) (OriginalMdl + 1);
  1999. ASSERT(mdlPage == pageCount);
  2000. }
  2001. #endif
  2002. PSRB_DATA
  2003. FASTCALL
  2004. SpAllocateBypassSrbData(
  2005. IN PLOGICAL_UNIT_EXTENSION LogicalUnit
  2006. )
  2007. {
  2008. PSINGLE_LIST_ENTRY entry;
  2009. PSRB_DATA srbData;
  2010. entry = ExInterlockedPopEntrySList(&(LogicalUnit->BypassSrbDataList),
  2011. &(LogicalUnit->BypassSrbDataSpinLock));
  2012. if(entry == NULL) {
  2013. KeBugCheckEx(PORT_DRIVER_INTERNAL,
  2014. 5,
  2015. NUMBER_BYPASS_SRB_DATA_BLOCKS,
  2016. (ULONG_PTR) LogicalUnit->BypassSrbDataBlocks,
  2017. 0);
  2018. }
  2019. srbData = CONTAINING_RECORD(entry, SRB_DATA, Reserved);
  2020. srbData->Adapter = LogicalUnit->AdapterExtension;
  2021. srbData->QueueTag = SP_UNTAGGED;
  2022. srbData->Type = SRB_DATA_TYPE;
  2023. srbData->Size = sizeof(SRB_DATA);
  2024. srbData->Flags = SRB_DATA_BYPASS_REQUEST;
  2025. srbData->FreeRoutine = SpFreeBypassSrbData;
  2026. return srbData;
  2027. }
  2028. VOID
  2029. FASTCALL
  2030. SpFreeBypassSrbData(
  2031. IN PADAPTER_EXTENSION Adapter,
  2032. IN PSRB_DATA SrbData
  2033. )
  2034. {
  2035. PLOGICAL_UNIT_EXTENSION lu = SrbData->LogicalUnit;
  2036. ASSERT_SRB_DATA(SrbData);
  2037. ASSERT(SrbData->CurrentIrp == NULL);
  2038. ASSERT(SrbData->CurrentSrb == NULL);
  2039. ASSERT(SrbData->CompletedRequests == NULL);
  2040. ASSERT(TEST_FLAG(SrbData->Flags, SRB_DATA_BYPASS_REQUEST));
  2041. RtlZeroMemory(SrbData, sizeof(SRB_DATA));
  2042. ExInterlockedPushEntrySList(&(lu->BypassSrbDataList),
  2043. &(SrbData->Reserved),
  2044. &(lu->BypassSrbDataSpinLock));
  2045. return;
  2046. }
  2047. PVOID
  2048. SpAllocateErrorLogEntry(
  2049. IN PDRIVER_OBJECT DriverObject
  2050. )
  2051. {
  2052. PVOID Packet;
  2053. ASSERT(DriverObject);
  2054. Packet = IoAllocateErrorLogEntry(
  2055. DriverObject,
  2056. sizeof(IO_ERROR_LOG_PACKET) + sizeof(SCSIPORT_ALLOCFAILURE_DATA));
  2057. return Packet;
  2058. }
  2059. VOID
  2060. FASTCALL
  2061. SpLogAllocationFailureFn(
  2062. IN PDRIVER_OBJECT DriverObject,
  2063. IN POOL_TYPE PoolType,
  2064. IN SIZE_T Size,
  2065. IN ULONG Tag,
  2066. IN ULONG FileId,
  2067. IN ULONG LineNumber
  2068. )
  2069. /*++
  2070. Routine Description:
  2071. This routine writes a message to the event log indicating that an
  2072. allocation failure has occurred.
  2073. Arguments:
  2074. DriverObject - pointer to the driver object for which the allocation
  2075. failure event is being logged.
  2076. PoolType - identifies the pool the failed allocation attempt was from.
  2077. Size - indicates the number of bytes that the failed allocation
  2078. attempt tried to obtain.
  2079. Tag - identifies the pool tag associated with the failed
  2080. allocation.
  2081. AllocId - uniquely identifies this allocation w/in scsiport.
  2082. Return Value:
  2083. VOID
  2084. --*/
  2085. {
  2086. NTSTATUS status;
  2087. PIO_ERROR_LOG_PACKET Packet;
  2088. PIO_ERROR_LOG_PACKET CurrentValue;
  2089. SCSIPORT_ALLOCFAILURE_DATA *Data;
  2090. // PSCSIPORT_ALLOCFAILURE_ENTRY Entry;
  2091. // PSCSIPORT_ALLOCFAILURE_ENTRY CurrentValue;
  2092. PSCSIPORT_DRIVER_EXTENSION DriverExtension;
  2093. DebugPrint((2, "SpLogAllocationFailureFn: DriverObject:%p\nId:%08X|%08X\n",
  2094. DriverObject,
  2095. FileId, LineNumber));
  2096. //
  2097. // Try to allocate a new error log event.
  2098. //
  2099. Packet = (PIO_ERROR_LOG_PACKET)
  2100. SpAllocateErrorLogEntry(DriverObject);
  2101. //
  2102. // If we could not allocate a log event, we check the driver extension to
  2103. // see if it has a reserve event we can use. If we cannot get the driver
  2104. // extension or if it does not contain a reserve event, we return
  2105. // without logging the allocation failure.
  2106. //
  2107. if (Packet == NULL) {
  2108. //
  2109. // See if there is a driver extension for this driver. It is possible
  2110. // that one has not been created yet, so this may fail, in which case
  2111. // we give up and return.
  2112. //
  2113. DriverExtension = IoGetDriverObjectExtension(
  2114. DriverObject,
  2115. ScsiPortInitialize
  2116. );
  2117. if (DriverExtension == NULL) {
  2118. DebugPrint((1, "SpLogAllocationFailureFn: no driver extension\n"));
  2119. return;
  2120. }
  2121. //
  2122. // Get the reserve event in the driver extension. The reserve event
  2123. // may have already been used, so it's possible that it is NULL. If
  2124. // this is the case, we give up and return.
  2125. //
  2126. Packet = (PIO_ERROR_LOG_PACKET)
  2127. DriverExtension->ReserveAllocFailureLogEntry;
  2128. if (Packet == NULL) {
  2129. DebugPrint((1, "SpLogAllocationFailureFn: no reserve packet\n"));
  2130. return;
  2131. }
  2132. //
  2133. // We have to ensure that we are the only instance to use this
  2134. // event. To do so, we attempt to NULL the event in the driver
  2135. // extension. If somebody else beats us to it, they own the
  2136. // event and we have to give up.
  2137. //
  2138. CurrentValue = InterlockedCompareExchangePointer(
  2139. DriverExtension->ReserveAllocFailureLogEntry,
  2140. NULL,
  2141. Packet
  2142. );
  2143. if (Packet != CurrentValue) {
  2144. DebugPrint((1, "SpLogAllocationFailureFn: someone already owns packet\n"));
  2145. return;
  2146. }
  2147. }
  2148. //
  2149. // Initialize the error log packet.
  2150. //
  2151. Packet->ErrorCode = IO_WARNING_ALLOCATION_FAILED;
  2152. Packet->SequenceNumber = 0;
  2153. Packet->MajorFunctionCode = 0;
  2154. Packet->RetryCount = 0;
  2155. Packet->UniqueErrorValue = 0x10;
  2156. Packet->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
  2157. Packet->DumpDataSize = sizeof(ULONG) * 4;
  2158. Packet->NumberOfStrings = 0;
  2159. Packet->DumpData[0] = Tag;
  2160. Data = (SCSIPORT_ALLOCFAILURE_DATA*) &Packet->DumpData[1];
  2161. Data->Size = (ULONG) Size;
  2162. Data->FileId = FileId;
  2163. Data->LineNumber = LineNumber;
  2164. //
  2165. // Queue the error log entry.
  2166. //
  2167. IoWriteErrorLogEntry(Packet);
  2168. }
  2169. PVOID
  2170. SpAllocatePoolEx(
  2171. IN POOL_TYPE PoolType,
  2172. IN SIZE_T NumberOfBytes,
  2173. IN ULONG Tag,
  2174. IN PDRIVER_OBJECT DriverObject,
  2175. IN ULONG FileId,
  2176. IN ULONG LineNumber
  2177. )
  2178. {
  2179. PVOID Block;
  2180. Block = ExAllocatePoolWithTag(PoolType,
  2181. NumberOfBytes,
  2182. Tag);
  2183. if (Block == NULL) {
  2184. SpLogAllocationFailureFn(DriverObject,
  2185. PoolType,
  2186. NumberOfBytes,
  2187. Tag,
  2188. FileId,
  2189. LineNumber);
  2190. }
  2191. return Block;
  2192. }
  2193. PMDL
  2194. SpAllocateMdlEx(
  2195. IN PVOID VirtualAddress,
  2196. IN ULONG Length,
  2197. IN BOOLEAN SecondaryBuffer,
  2198. IN BOOLEAN ChargeQuota,
  2199. IN OUT PIRP Irp,
  2200. IN PDRIVER_OBJECT DriverObject,
  2201. IN ULONG FileId,
  2202. IN ULONG LineNumber
  2203. )
  2204. {
  2205. PMDL mdl = IoAllocateMdl(VirtualAddress,
  2206. Length,
  2207. SecondaryBuffer,
  2208. ChargeQuota,
  2209. Irp);
  2210. if (mdl == NULL) {
  2211. SpLogAllocationFailureFn(DriverObject,
  2212. NonPagedPool,
  2213. 0,
  2214. SCSIPORT_TAG_ALLOCMDL,
  2215. FileId,
  2216. LineNumber);
  2217. }
  2218. return mdl;
  2219. }
  2220. PIRP
  2221. SpAllocateIrpEx(
  2222. IN CCHAR StackSize,
  2223. IN BOOLEAN ChargeQuota,
  2224. IN PDRIVER_OBJECT DriverObject,
  2225. IN ULONG FileId,
  2226. IN ULONG LineNumber
  2227. )
  2228. {
  2229. PIRP irp = IoAllocateIrp(StackSize, ChargeQuota);
  2230. if (irp == NULL) {
  2231. SpLogAllocationFailureFn(DriverObject,
  2232. NonPagedPool,
  2233. 0,
  2234. SCSIPORT_TAG_ALLOCIRP,
  2235. FileId,
  2236. LineNumber);
  2237. }
  2238. return irp;
  2239. }
  2240. #ifndef USE_DMA_MACROS
  2241. VOID
  2242. SpFreeSGList(
  2243. IN PADAPTER_EXTENSION Adapter,
  2244. IN PSRB_DATA SrbData
  2245. )
  2246. {
  2247. ASSERT(TEST_FLAG(SrbData->Flags,
  2248. (SRB_DATA_MEDIUM_SG_LIST |
  2249. SRB_DATA_SMALL_SG_LIST |
  2250. SRB_DATA_LARGE_SG_LIST)));
  2251. if (TEST_FLAG(SrbData->Flags, SRB_DATA_MEDIUM_SG_LIST)) {
  2252. //
  2253. // Release the scatter gather list back to the lookaside list.
  2254. //
  2255. ExFreeToNPagedLookasideList(
  2256. &(Adapter->MediumScatterGatherLookasideList),
  2257. (PVOID) SrbData->ScatterGatherList);
  2258. } else if(TEST_FLAG(SrbData->Flags, SRB_DATA_LARGE_SG_LIST)) {
  2259. //
  2260. // We allocated the SG list from pool, so free it.
  2261. //
  2262. ExFreePool(SrbData->ScatterGatherList);
  2263. } else {
  2264. //
  2265. // We used the preallocated SG list embedded in the SRB_DATA object,
  2266. // so we don't have to free anything.
  2267. //
  2268. NOTHING
  2269. }
  2270. //
  2271. // Clear the SG-related flags on the SRB_DATA object.
  2272. //
  2273. CLEAR_FLAG(SrbData->Flags, (SRB_DATA_LARGE_SG_LIST |
  2274. SRB_DATA_MEDIUM_SG_LIST |
  2275. SRB_DATA_SMALL_SG_LIST));
  2276. //
  2277. // NULL the SRB_DATA's SG list pointer.
  2278. //
  2279. SrbData->ScatterGatherList = NULL;
  2280. }
  2281. #endif