Leaked source code of windows server 2003
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.

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