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.

6191 lines
173 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. This file contains the initialization
  7. code.
  8. Authors:
  9. Mike Glass
  10. Jeff Havens
  11. Environment:
  12. kernel mode only
  13. Notes:
  14. This module is a driver dll for scsi miniports.
  15. Revision History:
  16. --*/
  17. #include "port.h"
  18. #define __FILE_ID__ 'init'
  19. #if DBG
  20. static const char *__file__ = __FILE__;
  21. #endif
  22. //
  23. // Instantiate GUIDs for this module
  24. //
  25. #include <initguid.h>
  26. #include <devguid.h>
  27. #include <ntddstor.h>
  28. #include <wdmguid.h>
  29. ULONG ScsiPortLegacyAdapterDetection = FALSE;
  30. PVOID ScsiDirectory = NULL;
  31. //
  32. // Global list of adapter device objects. This is used to maintain a tag
  33. // value for all the adapters. This tag is used as a lookup key by the
  34. // lookaside list allocators in order to find the device object.
  35. //
  36. KSPIN_LOCK ScsiGlobalAdapterListSpinLock;
  37. PDEVICE_OBJECT *ScsiGlobalAdapterList = (PVOID) -1;
  38. ULONG ScsiGlobalAdapterListElements = 0;
  39. //
  40. // Indicates that the system can handle 64 bit physical addresses.
  41. //
  42. ULONG Sp64BitPhysicalAddresses = FALSE;
  43. //
  44. // Debugging switches.
  45. //
  46. ULONG SpRemapBuffersByDefault = FALSE;
  47. VOID
  48. SpCreateScsiDirectory(
  49. VOID
  50. );
  51. NTSTATUS
  52. DriverEntry(
  53. IN PDRIVER_OBJECT DriverObject,
  54. IN PUNICODE_STRING RegistryPath
  55. );
  56. ULONG
  57. SpGetBusData(
  58. IN PADAPTER_EXTENSION Adapter,
  59. IN PDEVICE_OBJECT Pdo OPTIONAL,
  60. IN BUS_DATA_TYPE BusDataType,
  61. IN ULONG BusNumber,
  62. IN ULONG SlotNumber,
  63. IN PVOID Buffer,
  64. IN ULONG Length
  65. );
  66. NTSTATUS
  67. SpAllocateDriverExtension(
  68. IN PDRIVER_OBJECT DriverObject,
  69. IN PUNICODE_STRING RegistryPath,
  70. OUT PSCSIPORT_DRIVER_EXTENSION *DriverExtension
  71. );
  72. ULONG
  73. SpQueryPnpInterfaceFlags(
  74. IN PSCSIPORT_DRIVER_EXTENSION DriverExtension,
  75. IN INTERFACE_TYPE InterfaceType
  76. );
  77. NTSTATUS
  78. SpInitializeSrbDataLookasideList(
  79. IN PDEVICE_OBJECT AdapterObject
  80. );
  81. VOID
  82. SpInitializeRequestSenseParams(
  83. IN PADAPTER_EXTENSION AdapterExtension
  84. );
  85. VOID
  86. SpInitializePerformanceParams(
  87. IN PADAPTER_EXTENSION AdapterExtension
  88. );
  89. VOID
  90. SpInitializePowerParams(
  91. IN PADAPTER_EXTENSION AdapterExtension
  92. );
  93. #ifdef ALLOC_PRAGMA
  94. #pragma alloc_text(PAGE, ScsiPortInitialize)
  95. #pragma alloc_text(PAGE, SpAllocateDriverExtension)
  96. #pragma alloc_text(PAGE, SpGetCommonBuffer)
  97. #pragma alloc_text(PAGE, SpInitializeConfiguration)
  98. #pragma alloc_text(PAGE, SpBuildResourceList)
  99. #pragma alloc_text(PAGE, SpParseDevice)
  100. #pragma alloc_text(PAGE, GetPciConfiguration)
  101. #pragma alloc_text(PAGE, SpBuildConfiguration)
  102. #pragma alloc_text(PAGE, SpQueryPnpInterfaceFlags)
  103. #pragma alloc_text(PAGE, SpConfigurationCallout)
  104. #pragma alloc_text(PAGE, SpReportNewAdapter)
  105. #pragma alloc_text(PAGE, SpCreateAdapter)
  106. #pragma alloc_text(PAGE, SpInitializeAdapterExtension)
  107. #pragma alloc_text(PAGE, ScsiPortInitLegacyAdapter)
  108. #pragma alloc_text(PAGE, SpAllocateAdapterResources)
  109. #pragma alloc_text(PAGE, SpOpenDeviceKey)
  110. #pragma alloc_text(PAGE, SpOpenParametersKey)
  111. #pragma alloc_text(PAGE, SpInitializeRequestSenseParams)
  112. #pragma alloc_text(PAGE, SpInitializePerformanceParams)
  113. #pragma alloc_text(PAGE, SpInitializePowerParams)
  114. #pragma alloc_text(PAGE, SpGetRegistryValue)
  115. #pragma alloc_text(PAGELOCK, SpInitializeSrbDataLookasideList)
  116. #pragma alloc_text(INIT, DriverEntry)
  117. #pragma alloc_text(INIT, SpCreateScsiDirectory)
  118. #endif
  119. ULONG
  120. ScsiPortInitialize(
  121. IN PVOID Argument1,
  122. IN PVOID Argument2,
  123. IN PHW_INITIALIZATION_DATA HwInitializationData,
  124. IN PVOID HwContext OPTIONAL
  125. )
  126. /*++
  127. Routine Description:
  128. This routine initializes the port driver.
  129. Arguments:
  130. Argument1 - Pointer to driver object created by system
  131. HwInitializationData - Miniport initialization structure
  132. HwContext - Value passed to miniport driver's config routine
  133. Return Value:
  134. The function value is the final status from the initialization operation.
  135. --*/
  136. {
  137. PDRIVER_OBJECT driverObject = Argument1;
  138. PSCSIPORT_DRIVER_EXTENSION driverExtension;
  139. PUNICODE_STRING registryPath = (PUNICODE_STRING) Argument2;
  140. ULONG pnpInterfaceFlags;
  141. NTSTATUS status;
  142. PAGED_CODE();
  143. //
  144. // If the global adapter list pointer is negative one then we need to do
  145. // our global initialization. This includes creating the scsi directory
  146. // and initializing the spinlock for protecting the global adapter list.
  147. //
  148. if(((LONG_PTR)ScsiGlobalAdapterList) == -1) {
  149. ScsiGlobalAdapterList = NULL;
  150. ScsiGlobalAdapterListElements = 0;
  151. KeInitializeSpinLock(&ScsiGlobalAdapterListSpinLock);
  152. ScsiPortInitializeDispatchTables();
  153. SpCreateScsiDirectory();
  154. status = SpInitializeGuidInterfaceMapping(driverObject);
  155. if(!NT_SUCCESS(status)) {
  156. return status;
  157. }
  158. //
  159. // Create the SCSI device map in the registry.
  160. //
  161. SpInitDeviceMap();
  162. //
  163. // Determine if the system can do 64-bit physical addresses.
  164. //
  165. Sp64BitPhysicalAddresses = SpDetermine64BitSupport();
  166. }
  167. //
  168. // Check that the length of this structure is equal to or less than
  169. // what the port driver expects it to be. This is effectively a
  170. // version check.
  171. //
  172. if (HwInitializationData->HwInitializationDataSize > sizeof(HW_INITIALIZATION_DATA)) {
  173. DebugPrint((0,"ScsiPortInitialize: Miniport driver wrong version\n"));
  174. return (ULONG) STATUS_REVISION_MISMATCH;
  175. }
  176. //
  177. // Check that each required entry is not NULL.
  178. //
  179. if ((!HwInitializationData->HwInitialize) ||
  180. (!HwInitializationData->HwFindAdapter) ||
  181. (!HwInitializationData->HwStartIo) ||
  182. (!HwInitializationData->HwResetBus)) {
  183. DebugPrint((0,
  184. "ScsiPortInitialize: Miniport driver missing required entry\n"));
  185. return (ULONG) STATUS_REVISION_MISMATCH;
  186. }
  187. //
  188. // Try to allocate a driver extension
  189. //
  190. driverExtension = IoGetDriverObjectExtension(driverObject,
  191. ScsiPortInitialize);
  192. if (driverExtension == NULL) {
  193. //
  194. // None exists for this key so we need to initialize the new one
  195. //
  196. status = SpAllocateDriverExtension(driverObject,
  197. registryPath,
  198. &driverExtension);
  199. if(!NT_SUCCESS(status)) {
  200. //
  201. // Something else went wrong - we cannot continue.
  202. //
  203. DebugPrint((0, "ScsiPortInitialize: Error %#08lx allocating driver "
  204. "extension - cannot continue\n", status));
  205. return status;
  206. }
  207. }
  208. //
  209. // Set up the device driver entry points.
  210. //
  211. driverObject->DriverStartIo = ScsiPortStartIo;
  212. driverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortGlobalDispatch;
  213. driverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortGlobalDispatch;
  214. driverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortGlobalDispatch;
  215. driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortGlobalDispatch;
  216. driverObject->MajorFunction[IRP_MJ_PNP] = ScsiPortGlobalDispatch;
  217. driverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = ScsiPortGlobalDispatch;
  218. driverObject->MajorFunction[IRP_MJ_POWER] = ScsiPortGlobalDispatch;
  219. //
  220. // Set up the device driver's pnp-power routine, add routine and unload
  221. // routine
  222. //
  223. driverObject->DriverExtension->AddDevice = ScsiPortAddDevice;
  224. driverObject->DriverUnload = ScsiPortUnload;
  225. //
  226. // Find out if this interface type is safe for this adapter
  227. //
  228. pnpInterfaceFlags = SpQueryPnpInterfaceFlags(
  229. driverExtension,
  230. HwInitializationData->AdapterInterfaceType);
  231. //
  232. // Special handling for the "Internal" interface type
  233. //
  234. if(HwInitializationData->AdapterInterfaceType == Internal) {
  235. if (TEST_FLAG(pnpInterfaceFlags, SP_PNP_IS_SAFE) == SP_PNP_NOT_SAFE) {
  236. return STATUS_NO_SUCH_DEVICE;
  237. }
  238. }
  239. //
  240. // If there's a chance this interface can handle pnp then store away
  241. // the interface information.
  242. //
  243. if(TEST_FLAG(pnpInterfaceFlags, SP_PNP_IS_SAFE)) {
  244. PSP_INIT_CHAIN_ENTRY entry = NULL;
  245. PSP_INIT_CHAIN_ENTRY *nextEntry = &(driverExtension->InitChain);
  246. //
  247. // Run to the end of the chain and make sure we don't have any information
  248. // about this interface type already
  249. //
  250. while(*nextEntry != NULL) {
  251. if((*nextEntry)->InitData.AdapterInterfaceType ==
  252. HwInitializationData->AdapterInterfaceType) {
  253. //
  254. // We already have enough information about this interface type
  255. //
  256. return STATUS_SUCCESS;
  257. }
  258. nextEntry = &((*nextEntry)->NextEntry);
  259. }
  260. //
  261. // Allocate an init chain entry to store the config information away in
  262. //
  263. entry = SpAllocatePool(NonPagedPool,
  264. sizeof(SP_INIT_CHAIN_ENTRY),
  265. SCSIPORT_TAG_INIT_CHAIN,
  266. driverObject);
  267. if(entry == NULL) {
  268. DebugPrint((1, "ScsiPortInitialize: couldn't allocate chain entry\n"));
  269. return (ULONG) STATUS_INSUFFICIENT_RESOURCES;
  270. }
  271. RtlCopyMemory(&(entry->InitData),
  272. HwInitializationData,
  273. sizeof(HW_INITIALIZATION_DATA));
  274. //
  275. // Stick this entry onto the end of the chain
  276. //
  277. entry->NextEntry = NULL;
  278. *nextEntry = entry;
  279. }
  280. //
  281. // There are two possible reasons we might be doing this in legacy
  282. // mode. If it's an internal bus type we always detect. Otherwise, if
  283. // the interface isn't safe for pnp we'll use the legacy path. Or if
  284. // the registry indicates we should do detection for this miniport AND
  285. // the pnp interface flags indicate that this bus may not be enumerable
  286. // we'll hit the legacy path.
  287. //
  288. #if !defined(NO_LEGACY_DRIVERS)
  289. if((TEST_FLAG(pnpInterfaceFlags, SP_PNP_IS_SAFE) == FALSE) ||
  290. (driverExtension->LegacyAdapterDetection &&
  291. TEST_FLAG(pnpInterfaceFlags, SP_PNP_NON_ENUMERABLE))) {
  292. //
  293. // If we're supposed to detect this device then just call directly into
  294. // SpInitLegacyAdapter to find what we can find
  295. //
  296. DebugPrint((1, "ScsiPortInitialize: flags = %#08lx & LegacyAdapterDetection = %d\n",
  297. pnpInterfaceFlags, driverExtension->LegacyAdapterDetection));
  298. DebugPrint((1, "ScsiPortInitialize: Doing Legacy Adapter detection\n"));
  299. status = ScsiPortInitLegacyAdapter(driverExtension,
  300. HwInitializationData,
  301. HwContext);
  302. }
  303. #endif // NO_LEGACY_DRIVERS
  304. //
  305. // Always return success if there's an interface which can handle pnp,
  306. // even if the detection fails.
  307. //
  308. if(driverExtension->SafeInterfaceCount != 0) {
  309. status = STATUS_SUCCESS;
  310. }
  311. return status;
  312. }
  313. PVOID
  314. ScsiPortGetDeviceBase(
  315. IN PVOID HwDeviceExtension,
  316. IN INTERFACE_TYPE BusType,
  317. IN ULONG SystemIoBusNumber,
  318. SCSI_PHYSICAL_ADDRESS IoAddress,
  319. ULONG NumberOfBytes,
  320. BOOLEAN InIoSpace
  321. )
  322. /*++
  323. Routine Description:
  324. This routine maps an IO address to system address space.
  325. Use ScsiPortFreeDeviceBase to unmap address.
  326. Arguments:
  327. HwDeviceExtension - used to find port device extension.
  328. BusType - what type of bus - eisa, mca, isa
  329. SystemIoBusNumber - which IO bus (for machines with multiple buses).
  330. IoAddress - base device address to be mapped.
  331. NumberOfBytes - number of bytes for which address is valid.
  332. InIoSpace - indicates an IO address.
  333. Return Value:
  334. Mapped address.
  335. --*/
  336. {
  337. PADAPTER_EXTENSION adapter = GET_FDO_EXTENSION(HwDeviceExtension);
  338. BOOLEAN isReinit;
  339. PHYSICAL_ADDRESS cardAddress;
  340. ULONG addressSpace = InIoSpace;
  341. PVOID mappedAddress = NULL;
  342. PMAPPED_ADDRESS newMappedAddress;
  343. BOOLEAN b = FALSE;
  344. isReinit = (TEST_FLAG(adapter->Flags, PD_MINIPORT_REINITIALIZING) ==
  345. PD_MINIPORT_REINITIALIZING);
  346. //
  347. // If a set of resources was provided to the miniport for this adapter then
  348. // get the translation out of the resource lists provided.
  349. //
  350. if(!adapter->IsMiniportDetected) {
  351. CM_PARTIAL_RESOURCE_DESCRIPTOR translation;
  352. b = SpFindAddressTranslation(adapter,
  353. BusType,
  354. SystemIoBusNumber,
  355. IoAddress,
  356. NumberOfBytes,
  357. InIoSpace,
  358. &translation);
  359. if(b) {
  360. cardAddress = translation.u.Generic.Start;
  361. addressSpace = (translation.Type == CmResourceTypePort) ? 1 : 0;
  362. } else {
  363. DebugPrint((1, "ScsiPortGetDeviceBase: SpFindAddressTranslation failed. %s Address = %lx\n",
  364. InIoSpace ? "I/O" : "Memory", IoAddress.LowPart));
  365. }
  366. }
  367. if((isReinit == FALSE) && (b == FALSE)) {
  368. //
  369. // This isn't a reinitialization. Either the miniport is not pnp
  370. // or it asked for something that it wasn't assigned. Unfortunately
  371. // we need to deal with both cases for the time being.
  372. //
  373. b = HalTranslateBusAddress(
  374. BusType,
  375. SystemIoBusNumber,
  376. IoAddress,
  377. &addressSpace,
  378. &cardAddress
  379. );
  380. }
  381. if (b == FALSE) {
  382. //
  383. // Still no translated address. Error
  384. //
  385. DebugPrint((1, "ScsiPortGetDeviceBase: Translate bus address "
  386. "failed. %s Address = %lx\n",
  387. InIoSpace ? "I/O" : "Memory", IoAddress.LowPart));
  388. return NULL;
  389. }
  390. //
  391. // Map the device base address into the virtual address space
  392. // if the address is in memory space.
  393. //
  394. if ((isReinit == FALSE) && (addressSpace == FALSE)) {
  395. //
  396. // We're not reinitializing and we need to map the address space.
  397. // Use MM to do the mapping.
  398. //
  399. newMappedAddress = SpAllocateAddressMapping(adapter);
  400. if(newMappedAddress == NULL) {
  401. DebugPrint((0, "ScsiPortGetDeviceBase: could not find free block "
  402. "to track address mapping - returning NULL\n"));
  403. return NULL;
  404. }
  405. mappedAddress = MmMapIoSpace(cardAddress,
  406. NumberOfBytes,
  407. FALSE);
  408. //
  409. // Store mapped address, bytes count, etc.
  410. //
  411. newMappedAddress->MappedAddress = mappedAddress;
  412. newMappedAddress->NumberOfBytes = NumberOfBytes;
  413. newMappedAddress->IoAddress = IoAddress;
  414. newMappedAddress->BusNumber = SystemIoBusNumber;
  415. } else if ((isReinit == TRUE) && (addressSpace == FALSE)) {
  416. ULONG i;
  417. //
  418. // This is a reinitialization - we should already have the mapping
  419. // for the address saved away in our list.
  420. //
  421. newMappedAddress = SpFindMappedAddress(adapter,
  422. IoAddress,
  423. NumberOfBytes,
  424. SystemIoBusNumber);
  425. if(newMappedAddress != NULL) {
  426. mappedAddress = newMappedAddress->MappedAddress;
  427. return mappedAddress;
  428. }
  429. //
  430. // We should always find the mapped address here if the miniport
  431. // is behaving itself.
  432. //
  433. KeBugCheckEx(PORT_DRIVER_INTERNAL,
  434. 0,
  435. 0,
  436. 0,
  437. 0);
  438. } else {
  439. mappedAddress = (PVOID)(ULONG_PTR)cardAddress.QuadPart;
  440. }
  441. return mappedAddress;
  442. } // end ScsiPortGetDeviceBase()
  443. VOID
  444. ScsiPortFreeDeviceBase(
  445. IN PVOID HwDeviceExtension,
  446. IN PVOID MappedAddress
  447. )
  448. /*++
  449. Routine Description:
  450. This routine unmaps an IO address that has been previously mapped
  451. to system address space using ScsiPortGetDeviceBase().
  452. Arguments:
  453. HwDeviceExtension - used to find port device extension.
  454. MappedAddress - address to unmap.
  455. NumberOfBytes - number of bytes mapped.
  456. InIoSpace - address is in IO space.
  457. Return Value:
  458. None
  459. --*/
  460. {
  461. PADAPTER_EXTENSION adapter;
  462. ULONG i;
  463. PMAPPED_ADDRESS nextMappedAddress;
  464. PMAPPED_ADDRESS lastMappedAddress;
  465. adapter = GET_FDO_EXTENSION(HwDeviceExtension);
  466. SpFreeMappedAddress(adapter, MappedAddress);
  467. return;
  468. } // end ScsiPortFreeDeviceBase()
  469. PVOID
  470. ScsiPortGetUncachedExtension(
  471. IN PVOID HwDeviceExtension,
  472. IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  473. IN ULONG NumberOfBytes
  474. )
  475. /*++
  476. Routine Description:
  477. This function allocates a common buffer to be used as the uncached device
  478. extension for the miniport driver. This function will also allocate any
  479. required SRB extensions. The DmaAdapter is allocated if it has not been
  480. allocated previously.
  481. Arguments:
  482. DeviceExtension - Supplies a pointer to the miniports device extension.
  483. ConfigInfo - Supplies a pointer to the partially initialized configuraiton
  484. information. This is used to get an DMA adapter object.
  485. NumberOfBytes - Supplies the size of the extension which needs to be
  486. allocated
  487. Return Value:
  488. A pointer to the uncached device extension or NULL if the extension could
  489. not be allocated or was previously allocated.
  490. --*/
  491. {
  492. PADAPTER_EXTENSION adapter = GET_FDO_EXTENSION(HwDeviceExtension);
  493. DEVICE_DESCRIPTION deviceDescription;
  494. ULONG numberOfMapRegisters;
  495. NTSTATUS status;
  496. PVOID SrbExtensionBuffer;
  497. //
  498. // If the miniport is being reinitialized then just return the current
  499. // uncached extension (if any).
  500. //
  501. if (TEST_FLAG(adapter->Flags, PD_MINIPORT_REINITIALIZING)) {
  502. DebugPrint((1, "ScsiPortGetUncachedExtension - miniport is "
  503. "reinitializing returning %#p\n",
  504. adapter->NonCachedExtension));
  505. if(TEST_FLAG(adapter->Flags, PD_UNCACHED_EXTENSION_RETURNED)) {
  506. //
  507. // The miniport asked for it's uncached extension once during
  508. // reinitialization - simulate the behavior on the original second
  509. // call and return NULL.
  510. //
  511. return NULL;
  512. } else {
  513. //
  514. // The miniport only gets one non-cached extension - keep track
  515. // of the fact that we returned it and don't give them a pointer
  516. // to it again. This flag is cleared once the initialization
  517. // is complete.
  518. //
  519. SET_FLAG(adapter->Flags, PD_UNCACHED_EXTENSION_RETURNED);
  520. return(adapter->NonCachedExtension);
  521. }
  522. }
  523. //
  524. // Make sure that a common buffer has not already been allocated.
  525. //
  526. SrbExtensionBuffer = SpGetSrbExtensionBuffer(adapter);
  527. if (SrbExtensionBuffer != NULL) {
  528. return(NULL);
  529. }
  530. //
  531. // If there no adapter object then try and get one.
  532. //
  533. if (adapter->DmaAdapterObject == NULL) {
  534. RtlZeroMemory(&deviceDescription, sizeof(DEVICE_DESCRIPTION));
  535. deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
  536. deviceDescription.DmaChannel = ConfigInfo->DmaChannel;
  537. deviceDescription.InterfaceType = ConfigInfo->AdapterInterfaceType;
  538. deviceDescription.DmaWidth = ConfigInfo->DmaWidth;
  539. deviceDescription.DmaSpeed = ConfigInfo->DmaSpeed;
  540. deviceDescription.ScatterGather = ConfigInfo->ScatterGather;
  541. deviceDescription.Master = ConfigInfo->Master;
  542. deviceDescription.DmaPort = ConfigInfo->DmaPort;
  543. deviceDescription.Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
  544. adapter->Dma32BitAddresses = ConfigInfo->Dma32BitAddresses;
  545. //
  546. // If the miniport puts anything in here other than 0x80 then we
  547. // assume it wants to support 64-bit addresses.
  548. //
  549. DebugPrint((1, "ScsiPortGetUncachedExtension: Dma64BitAddresses = "
  550. "%#0x\n",
  551. ConfigInfo->Dma64BitAddresses));
  552. adapter->RemapBuffers = (BOOLEAN) (SpRemapBuffersByDefault != 0);
  553. if((ConfigInfo->Dma64BitAddresses & ~SCSI_DMA64_SYSTEM_SUPPORTED) != 0){
  554. DebugPrint((1, "ScsiPortGetUncachedExtension: will request "
  555. "64-bit PA's\n"));
  556. deviceDescription.Dma64BitAddresses = TRUE;
  557. adapter->Dma64BitAddresses = TRUE;
  558. } else if(Sp64BitPhysicalAddresses == TRUE) {
  559. DebugPrint((1, "ScsiPortGetUncachedExtension: Will remap buffers for adapter %#p\n", adapter));
  560. adapter->RemapBuffers = TRUE;
  561. }
  562. deviceDescription.BusNumber = ConfigInfo->SystemIoBusNumber;
  563. deviceDescription.AutoInitialize = FALSE;
  564. //
  565. // If we get here then it's unlikely that the adapter is doing
  566. // slave mode DMA - if it were it wouldn't need a shared memory segment
  567. // to share with it's controller (because it's unlikely it could use it)
  568. //
  569. deviceDescription.DemandMode = FALSE;
  570. deviceDescription.MaximumLength = ConfigInfo->MaximumTransferLength;
  571. adapter->DmaAdapterObject = IoGetDmaAdapter(adapter->LowerPdo,
  572. &deviceDescription,
  573. &numberOfMapRegisters
  574. );
  575. //
  576. // If an adapter could not be allocated then return NULL.
  577. //
  578. if (adapter->DmaAdapterObject == NULL) {
  579. return(NULL);
  580. }
  581. //
  582. // Determine the number of page breaks allowed.
  583. //
  584. if (numberOfMapRegisters > ConfigInfo->NumberOfPhysicalBreaks &&
  585. ConfigInfo->NumberOfPhysicalBreaks != 0) {
  586. adapter->Capabilities.MaximumPhysicalPages =
  587. ConfigInfo->NumberOfPhysicalBreaks;
  588. } else {
  589. adapter->Capabilities.MaximumPhysicalPages =
  590. numberOfMapRegisters;
  591. }
  592. }
  593. //
  594. // Set auto request sense in device extension.
  595. //
  596. adapter->AutoRequestSense = ConfigInfo->AutoRequestSense;
  597. //
  598. // Initialize power parameters.
  599. //
  600. SpInitializePowerParams(adapter);
  601. //
  602. // Initialize configurable performance parameters.
  603. //
  604. SpInitializePerformanceParams(adapter);
  605. //
  606. // Initialize configurable request sense parameters.
  607. //
  608. SpInitializeRequestSenseParams(adapter);
  609. //
  610. // Update SrbExtensionSize, if necessary. The miniport's FindAdapter routine
  611. // has the opportunity to adjust it after being called, depending upon
  612. // it's Scatter/Gather List requirements.
  613. //
  614. if (adapter->SrbExtensionSize != ConfigInfo->SrbExtensionSize) {
  615. adapter->SrbExtensionSize = ConfigInfo->SrbExtensionSize;
  616. }
  617. //
  618. // If the adapter supports AutoRequestSense or needs SRB extensions
  619. // then an SRB list needs to be allocated.
  620. //
  621. if (adapter->SrbExtensionSize != 0 ||
  622. ConfigInfo->AutoRequestSense) {
  623. adapter->AllocateSrbExtension = TRUE;
  624. }
  625. //
  626. // Allocate the common buffer.
  627. //
  628. status = SpGetCommonBuffer( adapter, NumberOfBytes);
  629. if (!NT_SUCCESS(status)) {
  630. return(NULL);
  631. }
  632. return(adapter->NonCachedExtension);
  633. }
  634. NTSTATUS
  635. SpGetCommonBuffer(
  636. PADAPTER_EXTENSION DeviceExtension,
  637. ULONG NonCachedExtensionSize
  638. )
  639. /*++
  640. Routine Description:
  641. This routine determines the required size of the common buffer. Allocates
  642. the common buffer and finally sets up the srb extension list. This routine
  643. expects that the adapter object has already been allocated.
  644. Arguments:
  645. DeviceExtension - Supplies a pointer to the device extension.
  646. NonCachedExtensionSize - Supplies the size of the noncached device
  647. extension for the miniport driver.
  648. Return Value:
  649. Returns the status of the allocate operation.
  650. --*/
  651. {
  652. PVOID buffer;
  653. ULONG length;
  654. ULONG blockSize;
  655. PVOID *srbExtension;
  656. ULONG uncachedExtAlignment = 0;
  657. PAGED_CODE();
  658. //
  659. // Round the uncached extension up to a page boundary so the srb
  660. // extensions following it begin page aligned.
  661. //
  662. if (NonCachedExtensionSize != 0) {
  663. uncachedExtAlignment = DeviceExtension->UncachedExtAlignment;
  664. NonCachedExtensionSize = ROUND_UP_COUNT(NonCachedExtensionSize,
  665. PAGE_SIZE);
  666. DeviceExtension->NonCachedExtensionSize = NonCachedExtensionSize;
  667. }
  668. //
  669. // If verifier is enabled and configured to allocate common buffer space in
  670. // separate blocks, call out to the verifier routine to do the allocation.
  671. //
  672. if (SpVerifyingCommonBuffer(DeviceExtension)) {
  673. return SpGetCommonBufferVrfy(DeviceExtension,NonCachedExtensionSize);
  674. }
  675. //
  676. // Calculate the size of the entire common buffer block.
  677. //
  678. length = SpGetCommonBufferSize(DeviceExtension,
  679. NonCachedExtensionSize,
  680. &blockSize);
  681. //
  682. // If the adapter has an alignment requirement for its uncached extension,
  683. // round the size of the entire common buffer up to the required boundary.
  684. //
  685. if (uncachedExtAlignment != 0 && NonCachedExtensionSize != 0) {
  686. length = ROUND_UP_COUNT(length, uncachedExtAlignment);
  687. }
  688. //
  689. // Allocate the common buffer.
  690. //
  691. if (DeviceExtension->DmaAdapterObject == NULL) {
  692. //
  693. // Since there is no adapter just allocate from non-paged pool.
  694. //
  695. buffer = SpAllocatePool(NonPagedPool,
  696. length,
  697. SCSIPORT_TAG_COMMON_BUFFER,
  698. DeviceExtension->DeviceObject->DriverObject);
  699. } else {
  700. //
  701. // If the controller can do 64-bit addresses or if the adapter has
  702. // alignment requirements for its uncached extension, then we need to
  703. // specifically force the uncached extension area below the 4GB mark
  704. // and force it to be aligned on the appropriate boundary.
  705. //
  706. if( ((Sp64BitPhysicalAddresses) &&
  707. (DeviceExtension->Dma64BitAddresses == TRUE)) ||
  708. (uncachedExtAlignment != 0)) {
  709. PHYSICAL_ADDRESS boundary;
  710. if (uncachedExtAlignment != 0) {
  711. boundary.QuadPart = length;
  712. } else {
  713. boundary.HighPart = 1;
  714. boundary.LowPart = 0;
  715. }
  716. //
  717. // We'll get page aligned memory out of this which is probably
  718. // better than the requirements of the adapter.
  719. //
  720. buffer = MmAllocateContiguousMemorySpecifyCache(
  721. length,
  722. (DeviceExtension->MinimumCommonBufferBase),
  723. (DeviceExtension->MaximumCommonBufferBase),
  724. boundary,
  725. MmCached);
  726. if(buffer != NULL) {
  727. DeviceExtension->PhysicalCommonBuffer =
  728. MmGetPhysicalAddress(buffer);
  729. }
  730. DeviceExtension->UncachedExtensionIsCommonBuffer = FALSE;
  731. } else {
  732. buffer = AllocateCommonBuffer(
  733. DeviceExtension->DmaAdapterObject,
  734. length,
  735. &DeviceExtension->PhysicalCommonBuffer,
  736. FALSE );
  737. DeviceExtension->UncachedExtensionIsCommonBuffer = TRUE;
  738. }
  739. }
  740. DebugPrint((1, "SpGetCommonBuffer: buffer:%p PhysicalCommonBuffer:%p\n",
  741. buffer, DeviceExtension->PhysicalCommonBuffer));
  742. if (buffer == NULL) {
  743. return STATUS_INSUFFICIENT_RESOURCES;
  744. }
  745. //
  746. // Clear the common buffer.
  747. //
  748. RtlZeroMemory(buffer, length);
  749. //
  750. // Save the size of the common buffer.
  751. //
  752. DeviceExtension->CommonBufferSize = length;
  753. //
  754. // Set the Srb Extension to the start of the buffer. This address
  755. // is used to deallocate the common buffer, so it must be
  756. // set whether the device is using an Srb Extension or not.
  757. //
  758. DeviceExtension->SrbExtensionBuffer = buffer;
  759. //
  760. // Initialize the noncached extension.
  761. //
  762. if (NonCachedExtensionSize != 0) {
  763. DeviceExtension->NonCachedExtension = buffer;
  764. } else {
  765. DeviceExtension->NonCachedExtension = NULL;
  766. }
  767. //
  768. // Initialize the SRB extension list.
  769. //
  770. if (DeviceExtension->AllocateSrbExtension) {
  771. ULONG i = 0;
  772. //
  773. // Subtract the length of the non-cached extension from the common
  774. // buffer block.
  775. //
  776. length -= DeviceExtension->NonCachedExtensionSize;
  777. //
  778. // Initialize the SRB extension list.
  779. //
  780. srbExtension =
  781. (PVOID*)((PUCHAR)buffer + DeviceExtension->NonCachedExtensionSize);
  782. DeviceExtension->SrbExtensionListHeader = srbExtension;
  783. while (length >= blockSize * 2) {
  784. *srbExtension = (PVOID *)((PCHAR) srbExtension + blockSize);
  785. srbExtension = *srbExtension;
  786. length -= blockSize;
  787. i++;
  788. }
  789. DebugPrint((1, "SpGetCommonBuffer: %d entries put onto "
  790. "SrbExtension list\n", i));
  791. DeviceExtension->NumberOfRequests = i;
  792. }
  793. return(STATUS_SUCCESS);
  794. }
  795. NTSTATUS
  796. DriverEntry(
  797. IN PDRIVER_OBJECT DriverObject,
  798. IN PUNICODE_STRING RegistryPath
  799. )
  800. /*++
  801. Routine Description:
  802. Temporary entry point needed to initialize the scsi port driver.
  803. Arguments:
  804. DriverObject - Pointer to the driver object created by the system.
  805. Return Value:
  806. STATUS_SUCCESS
  807. --*/
  808. {
  809. //
  810. // NOTE: This routine should not be needed ! DriverEntry is defined
  811. // in the miniport driver.
  812. //
  813. UNREFERENCED_PARAMETER(DriverObject);
  814. return STATUS_SUCCESS;
  815. } // end DriverEntry()
  816. NTSTATUS
  817. SpInitializeConfiguration(
  818. IN PADAPTER_EXTENSION DeviceExtension,
  819. IN PUNICODE_STRING RegistryPath,
  820. IN PHW_INITIALIZATION_DATA HwInitData,
  821. IN PCONFIGURATION_CONTEXT Context
  822. )
  823. /*++
  824. Routine Description:
  825. This routine initializes the port configuration information structure.
  826. Any necessary information is extracted from the registery.
  827. Arguments:
  828. DeviceExtension - Supplies the device extension.
  829. HwInitData - Supplies the initial miniport data.
  830. Context - Supplies the context data used access calls.
  831. Return Value:
  832. NTSTATUS - Success if requested bus type exists and additional
  833. configuration information is available.
  834. --*/
  835. {
  836. ULONG j;
  837. NTSTATUS status;
  838. UNICODE_STRING unicodeString;
  839. OBJECT_ATTRIBUTES objectAttributes;
  840. PCONFIGURATION_INFORMATION configurationInformation;
  841. HANDLE deviceKey;
  842. HANDLE generalKey;
  843. BOOLEAN found;
  844. ANSI_STRING ansiString;
  845. CCHAR deviceBuffer[16];
  846. CCHAR nodeBuffer[SP_REG_BUFFER_SIZE];
  847. //
  848. // If this is the initial call then zero the information and set
  849. // the structure to the uninitialized values.
  850. //
  851. RtlZeroMemory(&Context->PortConfig, sizeof(PORT_CONFIGURATION_INFORMATION));
  852. ASSERT(Context->AccessRanges != NULL);
  853. RtlZeroMemory(
  854. Context->AccessRanges,
  855. HwInitData->NumberOfAccessRanges * sizeof(ACCESS_RANGE)
  856. );
  857. Context->PortConfig.Length = sizeof(PORT_CONFIGURATION_INFORMATION);
  858. Context->PortConfig.AdapterInterfaceType = HwInitData->AdapterInterfaceType;
  859. Context->PortConfig.InterruptMode = Latched;
  860. Context->PortConfig.MaximumTransferLength = SP_UNINITIALIZED_VALUE;
  861. Context->PortConfig.DmaChannel = SP_UNINITIALIZED_VALUE;
  862. Context->PortConfig.DmaPort = SP_UNINITIALIZED_VALUE;
  863. Context->PortConfig.NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
  864. Context->PortConfig.MaximumNumberOfTargets = 8;
  865. Context->PortConfig.MaximumNumberOfLogicalUnits = SCSI_MAXIMUM_LOGICAL_UNITS;
  866. Context->PortConfig.WmiDataProvider = FALSE;
  867. //
  868. // If the system indicates it can do 64-bit physical addressing then tell
  869. // the miniport it's an option.
  870. //
  871. if(Sp64BitPhysicalAddresses == TRUE) {
  872. Context->PortConfig.Dma64BitAddresses = SCSI_DMA64_SYSTEM_SUPPORTED;
  873. } else {
  874. Context->PortConfig.Dma64BitAddresses = 0;
  875. }
  876. //
  877. // Save away the some of the attributes.
  878. //
  879. Context->PortConfig.NeedPhysicalAddresses = HwInitData->NeedPhysicalAddresses;
  880. Context->PortConfig.MapBuffers = HwInitData->MapBuffers;
  881. Context->PortConfig.AutoRequestSense = HwInitData->AutoRequestSense;
  882. Context->PortConfig.ReceiveEvent = HwInitData->ReceiveEvent;
  883. Context->PortConfig.TaggedQueuing = HwInitData->TaggedQueuing;
  884. Context->PortConfig.MultipleRequestPerLu = HwInitData->MultipleRequestPerLu;
  885. //
  886. // Indicate the current AT disk usage.
  887. //
  888. configurationInformation = IoGetConfigurationInformation();
  889. Context->PortConfig.AtdiskPrimaryClaimed = configurationInformation->AtDiskPrimaryAddressClaimed;
  890. Context->PortConfig.AtdiskSecondaryClaimed = configurationInformation->AtDiskSecondaryAddressClaimed;
  891. for (j = 0; j < 8; j++) {
  892. Context->PortConfig.InitiatorBusId[j] = (UCHAR)SP_UNINITIALIZED_VALUE;
  893. }
  894. Context->PortConfig.NumberOfPhysicalBreaks = SP_DEFAULT_PHYSICAL_BREAK_VALUE;
  895. //
  896. // Clear some of the context information.
  897. //
  898. Context->DisableTaggedQueueing = FALSE;
  899. Context->DisableMultipleLu = FALSE;
  900. //
  901. // Record the system bus number.
  902. //
  903. Context->PortConfig.SystemIoBusNumber = Context->BusNumber;
  904. //
  905. // Initialize the adapter number on the context.
  906. //
  907. Context->AdapterNumber = DeviceExtension->AdapterNumber - 1;
  908. ASSERT((LONG)Context->AdapterNumber > -1);
  909. //
  910. // Check for device parameters.
  911. //
  912. if (Context->Parameter) {
  913. ExFreePool(Context->Parameter);
  914. Context->Parameter = NULL;
  915. }
  916. generalKey = SpOpenDeviceKey(RegistryPath, -1);
  917. //
  918. // First parse the device information.
  919. //
  920. if (generalKey != NULL) {
  921. SpParseDevice(DeviceExtension, generalKey, Context, nodeBuffer);
  922. ZwClose(generalKey);
  923. }
  924. //
  925. // Next parse the specific device information so that it can override the
  926. // general device information. This node is not used if the last adapter
  927. // was not found.
  928. //
  929. deviceKey = SpOpenDeviceKey(RegistryPath, Context->AdapterNumber);
  930. if (deviceKey != NULL) {
  931. SpParseDevice(DeviceExtension, deviceKey, Context, nodeBuffer);
  932. ZwClose(deviceKey);
  933. }
  934. //
  935. // Determine if the requested bus type is on this system.
  936. //
  937. if(HwInitData->AdapterInterfaceType != PNPBus) {
  938. found = FALSE;
  939. if(HwInitData->AdapterInterfaceType != MicroChannel) {
  940. status = IoQueryDeviceDescription(&HwInitData->AdapterInterfaceType,
  941. &Context->BusNumber,
  942. NULL,
  943. NULL,
  944. NULL,
  945. NULL,
  946. SpConfigurationCallout,
  947. &found);
  948. }
  949. //
  950. // If the request failed, then assume this type of bus is not here.
  951. //
  952. if (!found) {
  953. INTERFACE_TYPE interfaceType = Eisa;
  954. if (HwInitData->AdapterInterfaceType == Isa) {
  955. //
  956. // Check for an Eisa bus.
  957. //
  958. status = IoQueryDeviceDescription(&interfaceType,
  959. &Context->BusNumber,
  960. NULL,
  961. NULL,
  962. NULL,
  963. NULL,
  964. SpConfigurationCallout,
  965. &found);
  966. //
  967. // If the request failed, then assume this type of bus is not here.
  968. //
  969. if (found) {
  970. return(STATUS_SUCCESS);
  971. } else {
  972. return(STATUS_DEVICE_DOES_NOT_EXIST);
  973. }
  974. } else {
  975. return(STATUS_DEVICE_DOES_NOT_EXIST);
  976. }
  977. } else {
  978. return(STATUS_SUCCESS);
  979. }
  980. } else {
  981. return STATUS_SUCCESS;
  982. }
  983. }
  984. PCM_RESOURCE_LIST
  985. SpBuildResourceList(
  986. PADAPTER_EXTENSION DeviceExtension,
  987. PPORT_CONFIGURATION_INFORMATION ConfigInfo
  988. )
  989. /*++
  990. Routine Description:
  991. Creates a resource list which is used to query or report resource usage
  992. in the system
  993. Arguments:
  994. DeviceExtension - Pointer to the port's deviceExtension.
  995. ConfigInfo - Pointer to the information structure filled out by the
  996. miniport findAdapter routine.
  997. Return Value:
  998. Returns a pointer to a filled up resource list, or 0 if the call failed.
  999. Note:
  1000. Memory is allocated by the routine for the resourcelist. It must be
  1001. freed up by the caller by calling ExFreePool();
  1002. --*/
  1003. {
  1004. PCM_RESOURCE_LIST resourceList;
  1005. PCM_PARTIAL_RESOURCE_DESCRIPTOR resourceDescriptor;
  1006. PCONFIGURATION_INFORMATION configurationInformation;
  1007. PACCESS_RANGE accessRange;
  1008. ULONG listLength = 0;
  1009. ULONG hasInterrupt;
  1010. ULONG i;
  1011. BOOLEAN hasDma;
  1012. PAGED_CODE();
  1013. //
  1014. // Indicate the current AT disk usage.
  1015. //
  1016. configurationInformation = IoGetConfigurationInformation();
  1017. if (ConfigInfo->AtdiskPrimaryClaimed) {
  1018. configurationInformation->AtDiskPrimaryAddressClaimed = TRUE;
  1019. }
  1020. if (ConfigInfo->AtdiskSecondaryClaimed) {
  1021. configurationInformation->AtDiskSecondaryAddressClaimed = TRUE;
  1022. }
  1023. //
  1024. // Determine if adapter uses DMA. Only report the DMA channel if a
  1025. // channel number is used.
  1026. //
  1027. if (ConfigInfo->DmaChannel != SP_UNINITIALIZED_VALUE ||
  1028. ConfigInfo->DmaPort != SP_UNINITIALIZED_VALUE) {
  1029. hasDma = TRUE;
  1030. listLength++;
  1031. } else {
  1032. hasDma = FALSE;
  1033. }
  1034. DeviceExtension->HasInterrupt = FALSE;
  1035. if (DeviceExtension->HwInterrupt == NULL ||
  1036. (ConfigInfo->BusInterruptLevel == 0 &&
  1037. ConfigInfo->BusInterruptVector == 0)) {
  1038. hasInterrupt = 0;
  1039. } else {
  1040. hasInterrupt = 1;
  1041. listLength++;
  1042. }
  1043. //
  1044. // Detemine whether the second interrupt is used.
  1045. //
  1046. if (DeviceExtension->HwInterrupt != NULL &&
  1047. (ConfigInfo->BusInterruptLevel2 != 0 ||
  1048. ConfigInfo->BusInterruptVector2 != 0)) {
  1049. hasInterrupt++;
  1050. listLength++;
  1051. }
  1052. if(hasInterrupt) {
  1053. DeviceExtension->HasInterrupt = TRUE;
  1054. }
  1055. //
  1056. // Determine the number of access ranges used.
  1057. //
  1058. accessRange = &((*(ConfigInfo->AccessRanges))[0]);
  1059. for (i = 0; i < ConfigInfo->NumberOfAccessRanges; i++) {
  1060. if (accessRange->RangeLength != 0) {
  1061. listLength++;
  1062. }
  1063. accessRange++;
  1064. }
  1065. resourceList = (PCM_RESOURCE_LIST)
  1066. SpAllocatePool(PagedPool,
  1067. (sizeof(CM_RESOURCE_LIST) +
  1068. ((listLength - 1) *
  1069. sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR))),
  1070. SCSIPORT_TAG_RESOURCE_LIST,
  1071. DeviceExtension->DeviceObject->DriverObject);
  1072. //
  1073. // Return NULL if the structure could not be allocated.
  1074. // Otherwise, fill it out.
  1075. //
  1076. if (!resourceList) {
  1077. return NULL;
  1078. } else {
  1079. //
  1080. // Clear the resource list.
  1081. //
  1082. RtlZeroMemory(
  1083. resourceList,
  1084. sizeof(CM_RESOURCE_LIST) + (listLength - 1)
  1085. * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)
  1086. );
  1087. //
  1088. // Initialize the various fields.
  1089. //
  1090. resourceList->Count = 1;
  1091. resourceList->List[0].InterfaceType = ConfigInfo->AdapterInterfaceType;
  1092. resourceList->List[0].BusNumber = ConfigInfo->SystemIoBusNumber;
  1093. resourceList->List[0].PartialResourceList.Count = listLength;
  1094. resourceDescriptor =
  1095. resourceList->List[0].PartialResourceList.PartialDescriptors;
  1096. //
  1097. // For each entry in the access range, fill in an entry in the
  1098. // resource list
  1099. //
  1100. for (i = 0; i < ConfigInfo->NumberOfAccessRanges; i++) {
  1101. accessRange = &((*(ConfigInfo->AccessRanges))[i]);
  1102. if (accessRange->RangeLength == 0) {
  1103. //
  1104. // Skip the empty ranges.
  1105. //
  1106. continue;
  1107. }
  1108. if (accessRange->RangeInMemory) {
  1109. resourceDescriptor->Type = CmResourceTypeMemory;
  1110. resourceDescriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
  1111. } else {
  1112. resourceDescriptor->Type = CmResourceTypePort;
  1113. resourceDescriptor->Flags = CM_RESOURCE_PORT_IO;
  1114. if(ConfigInfo->AdapterInterfaceType == Eisa) {
  1115. resourceDescriptor->Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
  1116. }
  1117. }
  1118. resourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1119. resourceDescriptor->u.Memory.Start = accessRange->RangeStart;
  1120. resourceDescriptor->u.Memory.Length = accessRange->RangeLength;
  1121. resourceDescriptor++;
  1122. }
  1123. //
  1124. // Fill in the entry for the interrupt if it was present.
  1125. //
  1126. if (hasInterrupt) {
  1127. resourceDescriptor->Type = CmResourceTypeInterrupt;
  1128. if (ConfigInfo->AdapterInterfaceType == MicroChannel ||
  1129. ConfigInfo->InterruptMode == LevelSensitive) {
  1130. resourceDescriptor->ShareDisposition = CmResourceShareShared;
  1131. resourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  1132. } else {
  1133. resourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1134. resourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
  1135. }
  1136. resourceDescriptor->u.Interrupt.Level =
  1137. ConfigInfo->BusInterruptLevel;
  1138. resourceDescriptor->u.Interrupt.Vector =
  1139. ConfigInfo->BusInterruptVector;
  1140. resourceDescriptor->u.Interrupt.Affinity = 0;
  1141. resourceDescriptor++;
  1142. --hasInterrupt;
  1143. }
  1144. if (hasInterrupt) {
  1145. resourceDescriptor->Type = CmResourceTypeInterrupt;
  1146. if (ConfigInfo->AdapterInterfaceType == MicroChannel ||
  1147. ConfigInfo->InterruptMode2 == LevelSensitive) {
  1148. resourceDescriptor->ShareDisposition = CmResourceShareShared;
  1149. resourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  1150. } else {
  1151. resourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1152. resourceDescriptor->Flags = CM_RESOURCE_INTERRUPT_LATCHED;
  1153. }
  1154. resourceDescriptor->u.Interrupt.Level =
  1155. ConfigInfo->BusInterruptLevel2;
  1156. resourceDescriptor->u.Interrupt.Vector =
  1157. ConfigInfo->BusInterruptVector2;
  1158. resourceDescriptor->u.Interrupt.Affinity = 0;
  1159. resourceDescriptor++;
  1160. }
  1161. if (hasDma) {
  1162. //
  1163. // Fill out DMA information;
  1164. //
  1165. resourceDescriptor->Type = CmResourceTypeDma;
  1166. resourceDescriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  1167. resourceDescriptor->u.Dma.Channel = ConfigInfo->DmaChannel;
  1168. resourceDescriptor->u.Dma.Port = ConfigInfo->DmaPort;
  1169. resourceDescriptor->Flags = 0;
  1170. //
  1171. // Set the initialized values to zero.
  1172. //
  1173. if (ConfigInfo->DmaChannel == SP_UNINITIALIZED_VALUE) {
  1174. resourceDescriptor->u.Dma.Channel = 0;
  1175. }
  1176. if (ConfigInfo->DmaPort == SP_UNINITIALIZED_VALUE) {
  1177. resourceDescriptor->u.Dma.Port = 0;
  1178. }
  1179. }
  1180. return resourceList;
  1181. }
  1182. } // end SpBuildResourceList()
  1183. VOID
  1184. SpParseDevice(
  1185. IN PADAPTER_EXTENSION DeviceExtension,
  1186. IN HANDLE Key,
  1187. IN PCONFIGURATION_CONTEXT Context,
  1188. IN PUCHAR Buffer
  1189. )
  1190. /*++
  1191. Routine Description:
  1192. This routine parses a device key node and updates the configuration
  1193. information.
  1194. Arguments:
  1195. DeviceExtension - Supplies the device extension.
  1196. Key - Supplies an open key to the device node.
  1197. ConfigInfo - Supplies the configuration information to be
  1198. initialized.
  1199. Context - Supplies the configuration context.
  1200. Buffer - Supplies a scratch buffer for temporary data storage.
  1201. Return Value:
  1202. None
  1203. --*/
  1204. {
  1205. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  1206. NTSTATUS status = STATUS_SUCCESS;
  1207. PCM_FULL_RESOURCE_DESCRIPTOR resource;
  1208. PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor;
  1209. PCM_SCSI_DEVICE_DATA scsiData;
  1210. UNICODE_STRING unicodeString;
  1211. ANSI_STRING ansiString;
  1212. ULONG length;
  1213. ULONG index = 0;
  1214. ULONG rangeCount = 0;
  1215. ULONG count;
  1216. PAGED_CODE();
  1217. keyValueInformation = (PKEY_VALUE_FULL_INFORMATION) Buffer;
  1218. //
  1219. // Look at each of the values in the device node.
  1220. //
  1221. while(TRUE){
  1222. status = ZwEnumerateValueKey(
  1223. Key,
  1224. index,
  1225. KeyValueFullInformation,
  1226. Buffer,
  1227. SP_REG_BUFFER_SIZE,
  1228. &length
  1229. );
  1230. if (!NT_SUCCESS(status)) {
  1231. #if DBG
  1232. if (status != STATUS_NO_MORE_ENTRIES) {
  1233. DebugPrint((1, "SpParseDevice: ZwEnumerateValueKey failed. Status: %lx", status));
  1234. }
  1235. #endif
  1236. return;
  1237. }
  1238. //
  1239. // Update the index for the next time around the loop.
  1240. //
  1241. index++;
  1242. //
  1243. // Check that the length is reasonable.
  1244. //
  1245. if (keyValueInformation->Type == REG_DWORD &&
  1246. keyValueInformation->DataLength != sizeof(ULONG)) {
  1247. continue;
  1248. }
  1249. //
  1250. // Check for a maximum lu number.
  1251. //
  1252. if (_wcsnicmp(keyValueInformation->Name, L"MaximumLogicalUnit",
  1253. keyValueInformation->NameLength/2) == 0) {
  1254. if (keyValueInformation->Type != REG_DWORD) {
  1255. DebugPrint((1, "SpParseDevice: Bad data type for MaximumLogicalUnit.\n"));
  1256. continue;
  1257. }
  1258. DeviceExtension->MaxLuCount = *((PUCHAR)
  1259. (Buffer + keyValueInformation->DataOffset));
  1260. DebugPrint((1, "SpParseDevice: MaximumLogicalUnit = %d found.\n",
  1261. DeviceExtension->MaxLuCount));
  1262. //
  1263. // If the value is out of bounds, then reset it.
  1264. //
  1265. if (DeviceExtension->MaxLuCount > SCSI_MAXIMUM_LOGICAL_UNITS) {
  1266. DeviceExtension->MaxLuCount = SCSI_MAXIMUM_LOGICAL_UNITS;
  1267. }
  1268. }
  1269. if (_wcsnicmp(keyValueInformation->Name, L"InitiatorTargetId",
  1270. keyValueInformation->NameLength/2) == 0) {
  1271. if (keyValueInformation->Type != REG_DWORD) {
  1272. DebugPrint((1, "SpParseDevice: Bad data type for InitiatorTargetId.\n"));
  1273. continue;
  1274. }
  1275. Context->PortConfig.InitiatorBusId[0] = *((PUCHAR)
  1276. (Buffer + keyValueInformation->DataOffset));
  1277. DebugPrint((1, "SpParseDevice: InitiatorTargetId = %d found.\n",
  1278. Context->PortConfig.InitiatorBusId[0]));
  1279. //
  1280. // If the value is out of bounds, then reset it.
  1281. //
  1282. if (Context->PortConfig.InitiatorBusId[0] > Context->PortConfig.MaximumNumberOfTargets - 1) {
  1283. Context->PortConfig.InitiatorBusId[0] = (UCHAR)SP_UNINITIALIZED_VALUE;
  1284. }
  1285. }
  1286. if (_wcsnicmp(keyValueInformation->Name, L"ScsiDebug",
  1287. keyValueInformation->NameLength/2) == 0) {
  1288. if (keyValueInformation->Type != REG_DWORD) {
  1289. DebugPrint((1, "SpParseDevice: Bad data type for ScsiDebug.\n"));
  1290. continue;
  1291. }
  1292. #if DBG
  1293. ScsiDebug = *((PULONG) (Buffer + keyValueInformation->DataOffset));
  1294. #endif
  1295. }
  1296. if (_wcsnicmp(keyValueInformation->Name, L"BreakPointOnEntry",
  1297. keyValueInformation->NameLength/2) == 0) {
  1298. DebugPrint((0, "SpParseDevice: Break point requested on entry.\n"));
  1299. DbgBreakPoint();
  1300. }
  1301. //
  1302. // Check for disabled synchonous tranfers.
  1303. //
  1304. if (_wcsnicmp(keyValueInformation->Name, L"DisableSynchronousTransfers",
  1305. keyValueInformation->NameLength/2) == 0) {
  1306. DeviceExtension->CommonExtension.SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  1307. DebugPrint((1, "SpParseDevice: Disabling synchonous transfers\n"));
  1308. }
  1309. //
  1310. // Check for disabled disconnects.
  1311. //
  1312. if (_wcsnicmp(keyValueInformation->Name, L"DisableDisconnects",
  1313. keyValueInformation->NameLength/2) == 0) {
  1314. DeviceExtension->CommonExtension.SrbFlags |= SRB_FLAGS_DISABLE_DISCONNECT;
  1315. DebugPrint((1, "SpParseDevice: Disabling disconnects\n"));
  1316. }
  1317. //
  1318. // Check for disabled tagged queuing.
  1319. //
  1320. if (_wcsnicmp(keyValueInformation->Name, L"DisableTaggedQueuing",
  1321. keyValueInformation->NameLength/2) == 0) {
  1322. Context->DisableTaggedQueueing = TRUE;
  1323. DebugPrint((1, "SpParseDevice: Disabling tagged queueing\n"));
  1324. }
  1325. //
  1326. // Check for disabled multiple requests per logical unit.
  1327. //
  1328. if (_wcsnicmp(keyValueInformation->Name, L"DisableMultipleRequests",
  1329. keyValueInformation->NameLength/2) == 0) {
  1330. Context->DisableMultipleLu = TRUE;
  1331. DebugPrint((1, "SpParseDevice: Disabling multiple requests\n"));
  1332. }
  1333. //
  1334. // Check for the minimum & maximum physical addresses that this
  1335. // controller can use for it's uncached extension. If none is provided
  1336. // assume it must be in the first 4GB of memory.
  1337. //
  1338. if(_wcsnicmp(keyValueInformation->Name, L"MinimumUCXAddress",
  1339. keyValueInformation->NameLength/2) == 0) {
  1340. if (keyValueInformation->Type == REG_BINARY) {
  1341. DeviceExtension->MinimumCommonBufferBase.QuadPart =
  1342. *((PULONGLONG) (Buffer + keyValueInformation->DataOffset));
  1343. }
  1344. }
  1345. if(_wcsnicmp(keyValueInformation->Name, L"MaximumUCXAddress",
  1346. keyValueInformation->NameLength/2) == 0) {
  1347. if (keyValueInformation->Type == REG_BINARY) {
  1348. DeviceExtension->MaximumCommonBufferBase.QuadPart =
  1349. *((PULONGLONG) (Buffer + keyValueInformation->DataOffset));
  1350. }
  1351. }
  1352. if(DeviceExtension->MaximumCommonBufferBase.QuadPart == 0) {
  1353. DeviceExtension->MaximumCommonBufferBase.LowPart = 0xffffffff;
  1354. DeviceExtension->MaximumCommonBufferBase.HighPart = 0x0;
  1355. }
  1356. //
  1357. // Make sure that the minimum and maximum parameters are valid.
  1358. // If there's not at least one valid page between them then reset
  1359. // the minimum to zero.
  1360. //
  1361. if(DeviceExtension->MinimumCommonBufferBase.QuadPart >=
  1362. (DeviceExtension->MaximumCommonBufferBase.QuadPart - PAGE_SIZE)) {
  1363. DebugPrint((0, "SpParseDevice: MinimumUCXAddress %I64x is invalid\n",
  1364. DeviceExtension->MinimumCommonBufferBase.QuadPart));
  1365. DeviceExtension->MinimumCommonBufferBase.QuadPart = 0;
  1366. }
  1367. //
  1368. // Check for driver parameters tranfers.
  1369. //
  1370. if (_wcsnicmp(keyValueInformation->Name, L"DriverParameters",
  1371. keyValueInformation->NameLength/2) == 0) {
  1372. if (keyValueInformation->DataLength == 0) {
  1373. continue;
  1374. }
  1375. //
  1376. // Free any previous driver parameters.
  1377. //
  1378. if (Context->Parameter != NULL) {
  1379. ExFreePool(Context->Parameter);
  1380. }
  1381. Context->Parameter =
  1382. SpAllocatePool(NonPagedPool,
  1383. keyValueInformation->DataLength,
  1384. SCSIPORT_TAG_MINIPORT_PARAM,
  1385. DeviceExtension->DeviceObject->DriverObject);
  1386. if (Context->Parameter != NULL) {
  1387. if (keyValueInformation->Type != REG_SZ) {
  1388. //
  1389. // This is some random information just copy it.
  1390. //
  1391. RtlCopyMemory(
  1392. Context->Parameter,
  1393. (PCCHAR) keyValueInformation + keyValueInformation->DataOffset,
  1394. keyValueInformation->DataLength
  1395. );
  1396. } else {
  1397. //
  1398. // This is a unicode string. Convert it to a ANSI string.
  1399. // Initialize the strings.
  1400. //
  1401. unicodeString.Buffer = (PWSTR) ((PCCHAR) keyValueInformation +
  1402. keyValueInformation->DataOffset);
  1403. unicodeString.Length = (USHORT) keyValueInformation->DataLength;
  1404. unicodeString.MaximumLength = (USHORT) keyValueInformation->DataLength;
  1405. ansiString.Buffer = (PCHAR) Context->Parameter;
  1406. ansiString.Length = 0;
  1407. ansiString.MaximumLength = (USHORT) keyValueInformation->DataLength;
  1408. status = RtlUnicodeStringToAnsiString(
  1409. &ansiString,
  1410. &unicodeString,
  1411. FALSE
  1412. );
  1413. if (!NT_SUCCESS(status)) {
  1414. //
  1415. // Free the context.
  1416. //
  1417. ExFreePool(Context->Parameter);
  1418. Context->Parameter = NULL;
  1419. }
  1420. }
  1421. }
  1422. DebugPrint((1, "SpParseDevice: Found driver parameter.\n"));
  1423. }
  1424. //
  1425. // See if an entry for Maximum Scatter-Gather List has been
  1426. // set.
  1427. //
  1428. if (_wcsnicmp(keyValueInformation->Name, L"MaximumSGList",
  1429. keyValueInformation->NameLength/2) == 0) {
  1430. ULONG maxBreaks, minBreaks;
  1431. if (keyValueInformation->Type != REG_DWORD) {
  1432. DebugPrint((1, "SpParseDevice: Bad data type for MaximumSGList.\n"));
  1433. continue;
  1434. }
  1435. Context->PortConfig.NumberOfPhysicalBreaks = *((PUCHAR)(Buffer + keyValueInformation->DataOffset));
  1436. DebugPrint((1, "SpParseDevice: MaximumSGList = %d found.\n",
  1437. Context->PortConfig.NumberOfPhysicalBreaks));
  1438. //
  1439. // If the value is out of bounds, then reset it.
  1440. //
  1441. if ((Context->PortConfig.MapBuffers) && (!Context->PortConfig.Master)) {
  1442. maxBreaks = SP_UNINITIALIZED_VALUE;
  1443. minBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS;
  1444. } else {
  1445. maxBreaks = SCSI_MAXIMUM_PHYSICAL_BREAKS;
  1446. minBreaks = SCSI_MINIMUM_PHYSICAL_BREAKS;
  1447. }
  1448. if (Context->PortConfig.NumberOfPhysicalBreaks > maxBreaks) {
  1449. Context->PortConfig.NumberOfPhysicalBreaks = maxBreaks;
  1450. } else if (Context->PortConfig.NumberOfPhysicalBreaks < minBreaks) {
  1451. Context->PortConfig.NumberOfPhysicalBreaks = minBreaks;
  1452. }
  1453. }
  1454. //
  1455. // See if an entry for Number of request has been set.
  1456. //
  1457. if (_wcsnicmp(keyValueInformation->Name, L"NumberOfRequests",
  1458. keyValueInformation->NameLength/2) == 0) {
  1459. ULONG value;
  1460. if (keyValueInformation->Type != REG_DWORD) {
  1461. DebugPrint((1, "SpParseDevice: Bad data type for NumberOfRequests.\n"));
  1462. continue;
  1463. }
  1464. value = *((PULONG)(Buffer + keyValueInformation->DataOffset));
  1465. //
  1466. // If the value is out of bounds, then reset it.
  1467. //
  1468. if (value < MINIMUM_SRB_EXTENSIONS) {
  1469. DeviceExtension->NumberOfRequests = MINIMUM_SRB_EXTENSIONS;
  1470. } else if (value > MAXIMUM_SRB_EXTENSIONS) {
  1471. DeviceExtension->NumberOfRequests = MAXIMUM_SRB_EXTENSIONS;
  1472. } else {
  1473. DeviceExtension->NumberOfRequests = value;
  1474. }
  1475. DebugPrint((1, "SpParseDevice: Number Of Requests = %d found.\n",
  1476. DeviceExtension->NumberOfRequests));
  1477. }
  1478. //
  1479. // Check for resource list.
  1480. //
  1481. if (_wcsnicmp(keyValueInformation->Name, L"ResourceList",
  1482. keyValueInformation->NameLength/2) == 0 ||
  1483. _wcsnicmp(keyValueInformation->Name, L"Configuration Data",
  1484. keyValueInformation->NameLength/2) == 0 ) {
  1485. if (keyValueInformation->Type != REG_FULL_RESOURCE_DESCRIPTOR ||
  1486. keyValueInformation->DataLength < sizeof(REG_FULL_RESOURCE_DESCRIPTOR)) {
  1487. DebugPrint((1, "SpParseDevice: Bad data type for ResourceList.\n"));
  1488. continue;
  1489. } else {
  1490. DebugPrint((1, "SpParseDevice: ResourceList found!\n"));
  1491. }
  1492. resource = (PCM_FULL_RESOURCE_DESCRIPTOR)
  1493. (Buffer + keyValueInformation->DataOffset);
  1494. //
  1495. // Set the bus number equal to the bus number for the
  1496. // resouce. Note the context value is also set to the
  1497. // new bus number.
  1498. //
  1499. Context->BusNumber = resource->BusNumber;
  1500. Context->PortConfig.SystemIoBusNumber = resource->BusNumber;
  1501. //
  1502. // Walk the resource list and update the configuration.
  1503. //
  1504. for (count = 0; count < resource->PartialResourceList.Count; count++) {
  1505. descriptor = &resource->PartialResourceList.PartialDescriptors[count];
  1506. //
  1507. // Verify size is ok.
  1508. //
  1509. if ((ULONG)((PCHAR) (descriptor + 1) - (PCHAR) resource) >
  1510. keyValueInformation->DataLength) {
  1511. DebugPrint((1, "SpParseDevice: Resource data too small.\n"));
  1512. break;
  1513. }
  1514. //
  1515. // Switch on descriptor type;
  1516. //
  1517. switch (descriptor->Type) {
  1518. case CmResourceTypePort:
  1519. if (rangeCount >= Context->PortConfig.NumberOfAccessRanges) {
  1520. DebugPrint((1, "SpParseDevice: Too many access ranges.\n"));
  1521. continue;
  1522. }
  1523. Context->AccessRanges[rangeCount].RangeStart =
  1524. descriptor->u.Port.Start;
  1525. Context->AccessRanges[rangeCount].RangeLength =
  1526. descriptor->u.Port.Length;
  1527. Context->AccessRanges[rangeCount].RangeInMemory = FALSE;
  1528. rangeCount++;
  1529. break;
  1530. case CmResourceTypeMemory:
  1531. if (rangeCount >= Context->PortConfig.NumberOfAccessRanges) {
  1532. DebugPrint((1, "SpParseDevice: Too many access ranges.\n"));
  1533. continue;
  1534. }
  1535. Context->AccessRanges[rangeCount].RangeStart =
  1536. descriptor->u.Memory.Start;
  1537. Context->AccessRanges[rangeCount].RangeLength =
  1538. descriptor->u.Memory.Length;
  1539. Context->AccessRanges[rangeCount].RangeInMemory = TRUE;
  1540. rangeCount++;
  1541. break;
  1542. case CmResourceTypeInterrupt:
  1543. Context->PortConfig.BusInterruptVector =
  1544. descriptor->u.Interrupt.Vector;
  1545. Context->PortConfig.BusInterruptLevel =
  1546. descriptor->u.Interrupt.Level;
  1547. break;
  1548. case CmResourceTypeDma:
  1549. Context->PortConfig.DmaChannel = descriptor->u.Dma.Channel;
  1550. Context->PortConfig.DmaPort = descriptor->u.Dma.Port;
  1551. break;
  1552. case CmResourceTypeDeviceSpecific:
  1553. if (descriptor->u.DeviceSpecificData.DataSize <
  1554. sizeof(CM_SCSI_DEVICE_DATA) ||
  1555. (PCHAR) (descriptor + 1) - (PCHAR) resource +
  1556. descriptor->u.DeviceSpecificData.DataSize >
  1557. keyValueInformation->DataLength) {
  1558. DebugPrint((1, "SpParseDevice: Device specific resource data too small.\n"));
  1559. break;
  1560. }
  1561. //
  1562. // The actual data follows the descriptor.
  1563. //
  1564. scsiData = (PCM_SCSI_DEVICE_DATA) (descriptor+1);
  1565. Context->PortConfig.InitiatorBusId[0] = scsiData->HostIdentifier;
  1566. break;
  1567. }
  1568. }
  1569. }
  1570. //
  1571. // See if an entry for uncached extension alignment has been set.
  1572. //
  1573. if (_wcsnicmp(keyValueInformation->Name, L"UncachedExtAlignment",
  1574. keyValueInformation->NameLength/2) == 0) {
  1575. ULONG value;
  1576. if (keyValueInformation->Type != REG_DWORD) {
  1577. DebugPrint((1, "SpParseDevice: Bad data type for "
  1578. "UncachedExtAlignment.\n"));
  1579. continue;
  1580. }
  1581. value = *((PULONG)(Buffer + keyValueInformation->DataOffset));
  1582. //
  1583. // Specified alignment must be 3 to 16, which equates to 8-byte and
  1584. // 64k-byte alignment, respectively.
  1585. //
  1586. if (value > 16) {
  1587. value = 16;
  1588. } else if (value < 3) {
  1589. value = 3;
  1590. }
  1591. DeviceExtension->UncachedExtAlignment = 1 << value;
  1592. DebugPrint((1, "SpParseDevice: Uncached ext alignment = %d.\n",
  1593. DeviceExtension->UncachedExtAlignment));
  1594. } // UncachedExtAlignment
  1595. }
  1596. }
  1597. NTSTATUS
  1598. SpConfigurationCallout(
  1599. IN PVOID Context,
  1600. IN PUNICODE_STRING PathName,
  1601. IN INTERFACE_TYPE BusType,
  1602. IN ULONG BusNumber,
  1603. IN PKEY_VALUE_FULL_INFORMATION *BusInformation,
  1604. IN CONFIGURATION_TYPE ControllerType,
  1605. IN ULONG ControllerNumber,
  1606. IN PKEY_VALUE_FULL_INFORMATION *ControllerInformation,
  1607. IN CONFIGURATION_TYPE PeripheralType,
  1608. IN ULONG PeripheralNumber,
  1609. IN PKEY_VALUE_FULL_INFORMATION *PeripheralInformation
  1610. )
  1611. /*++
  1612. Routine Description:
  1613. This routine indicate that the requested perpherial data was found.
  1614. Arguments:
  1615. Context - Supplies a pointer to boolean which is set to TURE when this
  1616. routine is call.
  1617. The remaining arguments are unsed.
  1618. Return Value:
  1619. Returns success.
  1620. --*/
  1621. {
  1622. PAGED_CODE();
  1623. *(PBOOLEAN) Context = TRUE;
  1624. return(STATUS_SUCCESS);
  1625. }
  1626. NTSTATUS
  1627. SpGetRegistryValue(
  1628. IN PDRIVER_OBJECT DriverObject,
  1629. IN HANDLE Handle,
  1630. IN PWSTR KeyString,
  1631. OUT PKEY_VALUE_FULL_INFORMATION *KeyInformation
  1632. )
  1633. /*++
  1634. Routine Description:
  1635. This routine retrieve's any data associated with a registry key.
  1636. The key is queried with a zero-length buffer to get it's actual size
  1637. then a buffer is allocated and the actual query takes place.
  1638. It is the responsibility of the caller to free the buffer.
  1639. Arguments:
  1640. Handle - Supplies the key handle whose value is to be queried
  1641. KeyString - Supplies the null-terminated Unicode name of the value.
  1642. KeyInformation - Returns a pointer to the allocated data buffer.
  1643. Return Value:
  1644. The function value is the final status of the query operation.
  1645. --*/
  1646. {
  1647. UNICODE_STRING unicodeString;
  1648. NTSTATUS status;
  1649. PKEY_VALUE_FULL_INFORMATION infoBuffer;
  1650. ULONG keyValueLength;
  1651. PAGED_CODE();
  1652. RtlInitUnicodeString(&unicodeString, KeyString);
  1653. //
  1654. // Query with a zero-length buffer, to get the size needed.
  1655. //
  1656. status = ZwQueryValueKey( Handle,
  1657. &unicodeString,
  1658. KeyValueFullInformation,
  1659. (PVOID) NULL,
  1660. 0,
  1661. &keyValueLength);
  1662. if (status != STATUS_BUFFER_OVERFLOW &&
  1663. status != STATUS_BUFFER_TOO_SMALL) {
  1664. *KeyInformation = NULL;
  1665. return status;
  1666. }
  1667. //
  1668. // Allocate a buffer large enough to contain the entire key data value.
  1669. //
  1670. infoBuffer = SpAllocatePool(NonPagedPool,
  1671. keyValueLength,
  1672. SCSIPORT_TAG_REGISTRY,
  1673. DriverObject);
  1674. if(!infoBuffer) {
  1675. *KeyInformation = NULL;
  1676. return STATUS_INSUFFICIENT_RESOURCES;
  1677. }
  1678. //
  1679. // Query the data for the key value.
  1680. //
  1681. status = ZwQueryValueKey( Handle,
  1682. &unicodeString,
  1683. KeyValueFullInformation,
  1684. infoBuffer,
  1685. keyValueLength,
  1686. &keyValueLength);
  1687. if(!NT_SUCCESS(status)) {
  1688. ExFreePool(infoBuffer);
  1689. *KeyInformation = NULL;
  1690. return status;
  1691. }
  1692. *KeyInformation = infoBuffer;
  1693. return STATUS_SUCCESS;
  1694. }
  1695. VOID
  1696. SpBuildConfiguration(
  1697. IN PADAPTER_EXTENSION AdapterExtension,
  1698. IN PHW_INITIALIZATION_DATA HwInitializationData,
  1699. IN PPORT_CONFIGURATION_INFORMATION ConfigInformation
  1700. )
  1701. /*++
  1702. Routine Description:
  1703. Given a full resource description, fill in the port configuration
  1704. information.
  1705. Arguments:
  1706. HwInitializationData - to know maximum resources for device.
  1707. ControllerData - the CM_FULL_RESOURCE list for this configuration
  1708. ConfigInformation - the config info structure to be filled in
  1709. Return Value:
  1710. None
  1711. --*/
  1712. {
  1713. ULONG rangeNumber;
  1714. ULONG index;
  1715. PACCESS_RANGE accessRange;
  1716. PCM_FULL_RESOURCE_DESCRIPTOR resourceList;
  1717. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialData;
  1718. PAGED_CODE();
  1719. rangeNumber = 0;
  1720. ASSERT(!AdapterExtension->IsMiniportDetected);
  1721. ASSERT(AdapterExtension->AllocatedResources);
  1722. resourceList = AdapterExtension->AllocatedResources->List;
  1723. for (index = 0; index < resourceList->PartialResourceList.Count; index++) {
  1724. partialData = &resourceList->PartialResourceList.PartialDescriptors[index];
  1725. switch (partialData->Type) {
  1726. case CmResourceTypePort:
  1727. //
  1728. // Verify range count does not exceed what the
  1729. // miniport indicated.
  1730. //
  1731. if (HwInitializationData->NumberOfAccessRanges > rangeNumber) {
  1732. //
  1733. // Get next access range.
  1734. //
  1735. accessRange =
  1736. &((*(ConfigInformation->AccessRanges))[rangeNumber]);
  1737. accessRange->RangeStart = partialData->u.Port.Start;
  1738. accessRange->RangeLength = partialData->u.Port.Length;
  1739. accessRange->RangeInMemory = FALSE;
  1740. rangeNumber++;
  1741. }
  1742. break;
  1743. case CmResourceTypeInterrupt:
  1744. ConfigInformation->BusInterruptLevel = partialData->u.Interrupt.Level;
  1745. ConfigInformation->BusInterruptVector = partialData->u.Interrupt.Vector;
  1746. //
  1747. // Check interrupt mode.
  1748. //
  1749. if (partialData->Flags == CM_RESOURCE_INTERRUPT_LATCHED) {
  1750. ConfigInformation->InterruptMode = Latched;
  1751. } else if (partialData->Flags == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) {
  1752. ConfigInformation->InterruptMode = LevelSensitive;
  1753. }
  1754. AdapterExtension->HasInterrupt = TRUE;
  1755. break;
  1756. case CmResourceTypeMemory:
  1757. //
  1758. // Verify range count does not exceed what the
  1759. // miniport indicated.
  1760. //
  1761. if (HwInitializationData->NumberOfAccessRanges > rangeNumber) {
  1762. //
  1763. // Get next access range.
  1764. //
  1765. accessRange =
  1766. &((*(ConfigInformation->AccessRanges))[rangeNumber]);
  1767. accessRange->RangeStart = partialData->u.Memory.Start;
  1768. accessRange->RangeLength = partialData->u.Memory.Length;
  1769. accessRange->RangeInMemory = TRUE;
  1770. rangeNumber++;
  1771. }
  1772. break;
  1773. case CmResourceTypeDma:
  1774. ConfigInformation->DmaChannel = partialData->u.Dma.Channel;
  1775. ConfigInformation->DmaPort = partialData->u.Dma.Port;
  1776. break;
  1777. }
  1778. }
  1779. }
  1780. #if !defined(NO_LEGACY_DRIVERS)
  1781. BOOLEAN
  1782. GetPciConfiguration(
  1783. IN PDRIVER_OBJECT DriverObject,
  1784. IN OUT PDEVICE_OBJECT DeviceObject,
  1785. IN PHW_INITIALIZATION_DATA HwInitializationData,
  1786. IN PVOID RegistryPath,
  1787. IN ULONG BusNumber,
  1788. IN OUT PPCI_SLOT_NUMBER SlotNumber
  1789. )
  1790. /*++
  1791. Routine Description:
  1792. Walk PCI slot information looking for Vendor and Product ID matches.
  1793. Get slot information for matches and register with hal for the resources.
  1794. Arguments:
  1795. DriverObject - Miniport driver object.
  1796. DeviceObject - Represents this adapter.
  1797. HwInitializationData - Miniport description.
  1798. RegistryPath - Service key path.
  1799. BusNumber - PCI bus number for this search.
  1800. SlotNumber - Starting slot number for this search.
  1801. Return Value:
  1802. TRUE if card found. Slot and function numbers will return values that
  1803. should be used to continue the search for additional cards, when a card
  1804. is found.
  1805. --*/
  1806. {
  1807. PADAPTER_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  1808. ULONG rangeNumber = 0;
  1809. ULONG pciBuffer;
  1810. ULONG slotNumber;
  1811. ULONG functionNumber;
  1812. ULONG status;
  1813. PCI_SLOT_NUMBER slotData;
  1814. PPCI_COMMON_CONFIG pciData;
  1815. UNICODE_STRING unicodeString;
  1816. UCHAR vendorString[5];
  1817. UCHAR deviceString[5];
  1818. PAGED_CODE();
  1819. pciData = (PPCI_COMMON_CONFIG)&pciBuffer;
  1820. //
  1821. //
  1822. // typedef struct _PCI_SLOT_NUMBER {
  1823. // union {
  1824. // struct {
  1825. // ULONG DeviceNumber:5;
  1826. // ULONG FunctionNumber:3;
  1827. // ULONG Reserved:24;
  1828. // } bits;
  1829. // ULONG AsULONG;
  1830. // } u;
  1831. // } PCI_SLOT_NUMBER, *PPCI_SLOT_NUMBER;
  1832. //
  1833. slotData.u.AsULONG = 0;
  1834. //
  1835. // Look at each device.
  1836. //
  1837. for (slotNumber = (*SlotNumber).u.bits.DeviceNumber;
  1838. slotNumber < 32;
  1839. slotNumber++) {
  1840. slotData.u.bits.DeviceNumber = slotNumber;
  1841. //
  1842. // Look at each function.
  1843. //
  1844. for (functionNumber= (*SlotNumber).u.bits.FunctionNumber;
  1845. functionNumber < 8;
  1846. functionNumber++) {
  1847. slotData.u.bits.FunctionNumber = functionNumber;
  1848. //
  1849. // Make sure that the function number loop restarts at function
  1850. // zero, not what was passed in. If we find an adapter we'll
  1851. // reset this value to contain the next function number to
  1852. // be tested.
  1853. //
  1854. (*SlotNumber).u.bits.FunctionNumber = 0;
  1855. if (!HalGetBusData(PCIConfiguration,
  1856. BusNumber,
  1857. slotData.u.AsULONG,
  1858. pciData,
  1859. sizeof(ULONG))) {
  1860. //
  1861. // Out of PCI data.
  1862. //
  1863. return FALSE;
  1864. }
  1865. if (pciData->VendorID == PCI_INVALID_VENDORID) {
  1866. //
  1867. // No PCI device, or no more functions on device
  1868. // move to next PCI device.
  1869. //
  1870. break;
  1871. }
  1872. //
  1873. // Translate hex ids to strings.
  1874. //
  1875. sprintf(vendorString, "%04x", pciData->VendorID);
  1876. sprintf(deviceString, "%04x", pciData->DeviceID);
  1877. DebugPrint((1,
  1878. "GetPciConfiguration: Bus %x Slot %x Function %x Vendor %s Product %s\n",
  1879. BusNumber,
  1880. slotNumber,
  1881. functionNumber,
  1882. vendorString,
  1883. deviceString));
  1884. //
  1885. // Compare strings.
  1886. //
  1887. if (_strnicmp(vendorString,
  1888. HwInitializationData->VendorId,
  1889. HwInitializationData->VendorIdLength) ||
  1890. _strnicmp(deviceString,
  1891. HwInitializationData->DeviceId,
  1892. HwInitializationData->DeviceIdLength)) {
  1893. //
  1894. // Not our PCI device. Try next device/function
  1895. //
  1896. continue;
  1897. }
  1898. //
  1899. // This is the miniport drivers slot. Allocate the
  1900. // resources.
  1901. //
  1902. RtlInitUnicodeString(&unicodeString, L"ScsiAdapter");
  1903. status = HalAssignSlotResources(
  1904. RegistryPath,
  1905. &unicodeString,
  1906. DriverObject,
  1907. DeviceObject,
  1908. PCIBus,
  1909. BusNumber,
  1910. slotData.u.AsULONG,
  1911. &(fdoExtension->AllocatedResources));
  1912. if (!NT_SUCCESS(status)) {
  1913. //
  1914. // ToDo: Log this error.
  1915. //
  1916. DebugPrint((0, "SCSIPORT - GetPciConfiguration: Resources for "
  1917. "bus %d slot %d could not be retrieved [%#08lx]\n",
  1918. BusNumber,
  1919. slotData.u.AsULONG,
  1920. status));
  1921. break;
  1922. }
  1923. //
  1924. // Record PCI slot number for miniport.
  1925. //
  1926. slotData.u.bits.FunctionNumber++;
  1927. *SlotNumber = slotData;
  1928. //
  1929. // Translate the resources
  1930. //
  1931. status = SpTranslateResources(DriverObject,
  1932. fdoExtension->AllocatedResources,
  1933. &(fdoExtension->TranslatedResources));
  1934. return TRUE;
  1935. } // next PCI function
  1936. } // next PCI slot
  1937. return FALSE;
  1938. } // GetPciConfiguration()
  1939. #endif // NO_LEGACY_DRIVERS
  1940. ULONG
  1941. ScsiPortSetBusDataByOffset(
  1942. IN PVOID DeviceExtension,
  1943. IN ULONG BusDataType,
  1944. IN ULONG SystemIoBusNumber,
  1945. IN ULONG SlotNumber,
  1946. IN PVOID Buffer,
  1947. IN ULONG Offset,
  1948. IN ULONG Length
  1949. )
  1950. /*++
  1951. Routine Description:
  1952. The function returns writes bus data to a specific offset within a slot.
  1953. Arguments:
  1954. DeviceExtension - State information for a particular adapter.
  1955. BusDataType - Supplies the type of bus.
  1956. SystemIoBusNumber - Indicates which system IO bus.
  1957. SlotNumber - Indicates which slot.
  1958. Buffer - Supplies the data to write.
  1959. Offset - Byte offset to begin the write.
  1960. Length - Supplies a count in bytes of the maximum amount to return.
  1961. Return Value:
  1962. Number of bytes written.
  1963. --*/
  1964. {
  1965. PADAPTER_EXTENSION fdoExtension =
  1966. GET_FDO_EXTENSION(DeviceExtension);
  1967. if(!fdoExtension->IsInVirtualSlot) {
  1968. #if defined(NO_LEGACY_DRIVERS)
  1969. DebugPrint((1,"ScsiPortSetBusDataByOffset: !fdoExtension->"
  1970. "IsInVirtualSlot, not supported for 64-bits.\n"));
  1971. return STATUS_INVALID_PARAMETER;
  1972. #else
  1973. return(HalSetBusDataByOffset(BusDataType,
  1974. SystemIoBusNumber,
  1975. SlotNumber,
  1976. Buffer,
  1977. Offset,
  1978. Length));
  1979. #endif // NO_LEGACY_DRIVERS
  1980. } else {
  1981. ASSERT(fdoExtension->LowerBusInterfaceStandardRetrieved == TRUE);
  1982. return fdoExtension->LowerBusInterfaceStandard.SetBusData(
  1983. fdoExtension->LowerBusInterfaceStandard.Context,
  1984. BusDataType,
  1985. Buffer,
  1986. Offset,
  1987. Length);
  1988. }
  1989. } // end ScsiPortSetBusDataByOffset()
  1990. VOID
  1991. SpCreateScsiDirectory(
  1992. VOID
  1993. )
  1994. {
  1995. UNICODE_STRING unicodeDirectoryName;
  1996. OBJECT_ATTRIBUTES objectAttributes;
  1997. HANDLE directory;
  1998. NTSTATUS status;
  1999. PAGED_CODE();
  2000. RtlInitUnicodeString(
  2001. &unicodeDirectoryName,
  2002. L"\\Device\\Scsi");
  2003. InitializeObjectAttributes(
  2004. &objectAttributes,
  2005. &unicodeDirectoryName,
  2006. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  2007. NULL,
  2008. NULL);
  2009. status = ZwCreateDirectoryObject(&directory,
  2010. DIRECTORY_ALL_ACCESS,
  2011. &objectAttributes);
  2012. if(NT_SUCCESS(status)) {
  2013. ObReferenceObjectByHandle(directory,
  2014. FILE_READ_ATTRIBUTES,
  2015. NULL,
  2016. KernelMode,
  2017. &ScsiDirectory,
  2018. NULL);
  2019. ZwClose(directory);
  2020. }
  2021. return;
  2022. }
  2023. NTSTATUS
  2024. SpReportNewAdapter(
  2025. IN PDEVICE_OBJECT DeviceObject
  2026. )
  2027. /*++
  2028. Routine Description:
  2029. This routine will report an adapter discovered while sniffing through the
  2030. system to plug and play in order to get an add device call for it
  2031. This is done by:
  2032. * calling IoReportDetectedDevice to inform PnP about the new device
  2033. * storing the returned PDO pointer into the device extension as the
  2034. lower device object so we can match PDO to FDO when the add device
  2035. rolls around
  2036. Arguments:
  2037. DeviceObject - a pointer to the device object that was "found"
  2038. Return Value:
  2039. status
  2040. --*/
  2041. {
  2042. PDRIVER_OBJECT driverObject = DeviceObject->DriverObject;
  2043. PADAPTER_EXTENSION functionalExtension = DeviceObject->DeviceExtension;
  2044. PPORT_CONFIGURATION_INFORMATION configInfo =
  2045. functionalExtension->PortConfig;
  2046. PDEVICE_OBJECT pdo = NULL;
  2047. BOOLEAN resourceAssigned;
  2048. NTSTATUS status;
  2049. PAGED_CODE();
  2050. ASSERT(functionalExtension->AllocatedResources != NULL);
  2051. ASSERT(functionalExtension->IsPnp == FALSE);
  2052. if(functionalExtension->IsMiniportDetected) {
  2053. //
  2054. // We haven't claimed the resources yet and we need pnp to give them
  2055. // to us the next time around.
  2056. //
  2057. resourceAssigned = FALSE;
  2058. } else {
  2059. //
  2060. // The port driver located this device using the HAL to scan all
  2061. // appropriate bus slots. It's already claimed those resources and
  2062. // on the next boot we'll hopefully have a duplicate PDO to use
  2063. // for the device. Don't let pnp grab the resources on our behalf.
  2064. //
  2065. resourceAssigned = TRUE;
  2066. }
  2067. status = IoReportDetectedDevice(driverObject,
  2068. configInfo->AdapterInterfaceType,
  2069. configInfo->SystemIoBusNumber,
  2070. configInfo->SlotNumber,
  2071. functionalExtension->AllocatedResources,
  2072. NULL,
  2073. resourceAssigned,
  2074. &pdo);
  2075. //
  2076. // If we got a PDO then setup information about slot and bus numbers in
  2077. // the devnode in the registry. These may not be valid but we assume that
  2078. // if the miniport asks for slot info then it's on a bus that supports it.
  2079. //
  2080. if(NT_SUCCESS(status)) {
  2081. HANDLE instanceHandle;
  2082. NTSTATUS writeStatus;
  2083. writeStatus = SpWriteNumericInstanceValue(
  2084. pdo,
  2085. L"BusNumber",
  2086. configInfo->SystemIoBusNumber);
  2087. status = min(writeStatus, status);
  2088. writeStatus = SpWriteNumericInstanceValue(
  2089. pdo,
  2090. L"SlotNumber",
  2091. configInfo->SlotNumber);
  2092. status = min(writeStatus, status);
  2093. writeStatus = SpWriteNumericInstanceValue(
  2094. pdo,
  2095. L"LegacyInterfaceType",
  2096. configInfo->AdapterInterfaceType);
  2097. status = min(writeStatus, status);
  2098. }
  2099. if(NT_SUCCESS(status)) {
  2100. PDEVICE_OBJECT newStack;
  2101. newStack = IoAttachDeviceToDeviceStack( DeviceObject, pdo);
  2102. functionalExtension->CommonExtension.LowerDeviceObject = newStack;
  2103. functionalExtension->LowerPdo = pdo;
  2104. if(newStack == NULL) {
  2105. status = STATUS_UNSUCCESSFUL;
  2106. } else {
  2107. status = STATUS_SUCCESS;
  2108. }
  2109. }
  2110. return status;
  2111. }
  2112. NTSTATUS
  2113. SpCreateAdapter(
  2114. IN PDRIVER_OBJECT DriverObject,
  2115. OUT PDEVICE_OBJECT *Fdo
  2116. )
  2117. /*++
  2118. Routine Description:
  2119. This routine will allocate a new functional device object for an adapter.
  2120. It will allocate the device and fill in the common and functional device
  2121. extension fields which can be setup without any information about the
  2122. adapter this device object is for.
  2123. This routine will increment the global ScsiPortCount
  2124. Arguments:
  2125. DriverObject - a pointer to the driver object for this device
  2126. Fdo - a location to store the FDO pointer if the routine is successful
  2127. Return Value:
  2128. status
  2129. --*/
  2130. {
  2131. PSCSIPORT_DRIVER_EXTENSION driverExtension;
  2132. LONG adapterNumber;
  2133. ULONG i, j;
  2134. PUNICODE_STRING registryPath;
  2135. WCHAR wideBuffer[128];
  2136. ULONG serviceNameIndex = 0;
  2137. ULONG serviceNameChars;
  2138. WCHAR wideDeviceName[64];
  2139. UNICODE_STRING unicodeDeviceName;
  2140. PWCHAR savedDeviceName = NULL;
  2141. PADAPTER_EXTENSION fdoExtension;
  2142. PCOMMON_EXTENSION commonExtension;
  2143. NTSTATUS status;
  2144. PAGED_CODE();
  2145. driverExtension = IoGetDriverObjectExtension(DriverObject,
  2146. ScsiPortInitialize);
  2147. adapterNumber = InterlockedIncrement(&driverExtension->AdapterCount);
  2148. RtlZeroMemory(wideBuffer, sizeof(wideBuffer));
  2149. registryPath = &(driverExtension->RegistryPath);
  2150. for(i = 0; i < (registryPath->Length / sizeof(WCHAR)); i++) {
  2151. if(registryPath->Buffer[i] == UNICODE_NULL) {
  2152. i--;
  2153. break;
  2154. }
  2155. if((registryPath->Buffer[i] == L'\\') ||
  2156. (registryPath->Buffer[i] == L'/')) {
  2157. serviceNameIndex = i+1;
  2158. }
  2159. }
  2160. serviceNameChars = (i - serviceNameIndex) + 1;
  2161. DebugPrint((2, "SpCreateAdapter: Registry buffer %#p\n", registryPath));
  2162. DebugPrint((2, "SpCreateAdapter: Starting offset %d chars\n",
  2163. serviceNameIndex));
  2164. DebugPrint((2, "SpCreateAdapter: Ending offset %d chars\n", i));
  2165. DebugPrint((2, "SpCreateAdapter: %d chars or %d bytes will be copied\n",
  2166. serviceNameChars, (serviceNameChars * sizeof(WCHAR))));
  2167. DebugPrint((2, "SpCreateAdapter: Name is \""));
  2168. for(j = 0; j < serviceNameChars; j++) {
  2169. DebugPrint((2, "%wc", registryPath->Buffer[serviceNameIndex + j]));
  2170. }
  2171. DebugPrint((2, "\"\n"));
  2172. RtlCopyMemory(wideBuffer,
  2173. &(registryPath->Buffer[serviceNameIndex]),
  2174. serviceNameChars * sizeof(WCHAR));
  2175. swprintf(wideDeviceName,
  2176. L"\\Device\\Scsi\\%ws%d",
  2177. wideBuffer,
  2178. adapterNumber);
  2179. RtlInitUnicodeString(&unicodeDeviceName, wideDeviceName);
  2180. DebugPrint((1, "SpCreateFdo: Device object name is %wZ\n",
  2181. &unicodeDeviceName));
  2182. status = IoCreateDevice(
  2183. DriverObject,
  2184. ADAPTER_EXTENSION_SIZE + unicodeDeviceName.MaximumLength,
  2185. &unicodeDeviceName,
  2186. FILE_DEVICE_CONTROLLER,
  2187. FILE_DEVICE_SECURE_OPEN,
  2188. FALSE,
  2189. Fdo);
  2190. ASSERTMSG("Name isn't unique: ", status != STATUS_OBJECT_NAME_COLLISION);
  2191. if(!NT_SUCCESS(status)) {
  2192. DebugPrint((1, "ScsiPortAddDevice: couldn't allocate new FDO "
  2193. "[%#08lx]\n", status));
  2194. return status;
  2195. }
  2196. fdoExtension = (*Fdo)->DeviceExtension;
  2197. commonExtension = &(fdoExtension->CommonExtension);
  2198. RtlZeroMemory(fdoExtension, ADAPTER_EXTENSION_SIZE);
  2199. commonExtension->DeviceObject = *Fdo;
  2200. commonExtension->IsPdo = FALSE;
  2201. commonExtension->MajorFunction = AdapterMajorFunctionTable;
  2202. commonExtension->WmiInitialized = FALSE;
  2203. commonExtension->WmiMiniPortSupport = FALSE;
  2204. commonExtension->WmiScsiPortRegInfoBuf = NULL;
  2205. commonExtension->WmiScsiPortRegInfoBufSize = 0;
  2206. commonExtension->CurrentPnpState = 0xff;
  2207. commonExtension->PreviousPnpState = 0xff;
  2208. commonExtension->CurrentDeviceState = PowerDeviceD0;
  2209. commonExtension->DesiredDeviceState = PowerDeviceUnspecified;
  2210. commonExtension->CurrentSystemState = PowerSystemWorking;
  2211. KeInitializeEvent(&commonExtension->RemoveEvent,
  2212. SynchronizationEvent,
  2213. FALSE);
  2214. //
  2215. // Initialize remove lock to zero. It will be incremented once pnp is aware
  2216. // of its existance.
  2217. //
  2218. commonExtension->RemoveLock = 0;
  2219. #if DBG
  2220. KeInitializeSpinLock(&commonExtension->RemoveTrackingSpinlock);
  2221. commonExtension->RemoveTrackingList = NULL;
  2222. ExInitializeNPagedLookasideList(
  2223. &(commonExtension->RemoveTrackingLookasideList),
  2224. NULL,
  2225. NULL,
  2226. 0,
  2227. sizeof(REMOVE_TRACKING_BLOCK),
  2228. SCSIPORT_TAG_LOCK_TRACKING,
  2229. 64);
  2230. commonExtension->RemoveTrackingLookasideListInitialized = TRUE;
  2231. #else
  2232. commonExtension->RemoveTrackingSpinlock = (ULONG) -1L;
  2233. commonExtension->RemoveTrackingList = (PVOID) -1L;
  2234. #endif
  2235. SpAcquireRemoveLock(*Fdo, *Fdo);
  2236. //
  2237. // Initialize the logical unit list locks.
  2238. //
  2239. for(i = 0; i < NUMBER_LOGICAL_UNIT_BINS; i++) {
  2240. KeInitializeSpinLock(&fdoExtension->LogicalUnitList[i].Lock);
  2241. }
  2242. //
  2243. // Don't set port number until the device has been started.
  2244. //
  2245. fdoExtension->PortNumber = (ULONG) -1;
  2246. fdoExtension->AdapterNumber = adapterNumber;
  2247. //
  2248. // Copy the device name for later use.
  2249. //
  2250. fdoExtension->DeviceName = (PWSTR) (fdoExtension + 1);
  2251. RtlCopyMemory(fdoExtension->DeviceName,
  2252. unicodeDeviceName.Buffer,
  2253. unicodeDeviceName.MaximumLength);
  2254. //
  2255. // Initialize the enumeration synchronization event.
  2256. //
  2257. KeInitializeMutex(&(fdoExtension->EnumerationDeviceMutex), 0);
  2258. ExInitializeFastMutex(&(fdoExtension->EnumerationWorklistMutex));
  2259. ExInitializeWorkItem(&(fdoExtension->EnumerationWorkItem),
  2260. SpEnumerationWorker,
  2261. fdoExtension);
  2262. //
  2263. // Initialize the power up mutex.
  2264. //
  2265. ExInitializeFastMutex(&(fdoExtension->PowerMutex));
  2266. //
  2267. // Set uncached extension limits to valid values.
  2268. //
  2269. fdoExtension->MaximumCommonBufferBase.HighPart = 0;
  2270. fdoExtension->MaximumCommonBufferBase.LowPart = 0xffffffff;
  2271. (*Fdo)->Flags |= DO_DIRECT_IO;
  2272. (*Fdo)->Flags &= ~DO_DEVICE_INITIALIZING;
  2273. // fdoExtension->CommonExtension.IsInitialized = TRUE;
  2274. return status;
  2275. }
  2276. VOID
  2277. SpInitializeAdapterExtension(
  2278. IN PADAPTER_EXTENSION FdoExtension,
  2279. IN PHW_INITIALIZATION_DATA HwInitializationData,
  2280. IN OUT PHW_DEVICE_EXTENSION HwDeviceExtension OPTIONAL
  2281. )
  2282. /*++
  2283. Routine Description:
  2284. This routine will setup the miniport entry points and initialize values
  2285. in the port driver device extension. It will also setup the pointers
  2286. to the HwDeviceExtension if supplied
  2287. Arguments:
  2288. FdoExtension - the fdo extension being initialized
  2289. HwInitializationData - the init data we are using to initalize the fdo
  2290. extension
  2291. HwDeviceExtension - the miniport's private extension
  2292. Return Value:
  2293. none
  2294. --*/
  2295. {
  2296. PSCSIPORT_DRIVER_EXTENSION DrvExt;
  2297. PAGED_CODE();
  2298. FdoExtension->HwFindAdapter = HwInitializationData->HwFindAdapter;
  2299. FdoExtension->HwInitialize = HwInitializationData->HwInitialize;
  2300. FdoExtension->HwStartIo = HwInitializationData->HwStartIo;
  2301. FdoExtension->HwInterrupt = HwInitializationData->HwInterrupt;
  2302. FdoExtension->HwResetBus = HwInitializationData->HwResetBus;
  2303. FdoExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
  2304. FdoExtension->HwLogicalUnitExtensionSize =
  2305. HwInitializationData->SpecificLuExtensionSize;
  2306. FdoExtension->HwAdapterControl = NULL;
  2307. if(HwInitializationData->HwInitializationDataSize >=
  2308. (FIELD_OFFSET(HW_INITIALIZATION_DATA, HwAdapterControl) +
  2309. sizeof(PHW_ADAPTER_CONTROL))) {
  2310. //
  2311. // This miniport knows about the stop adapter routine. Store the
  2312. // pointer away.
  2313. //
  2314. FdoExtension->HwAdapterControl = HwInitializationData->HwAdapterControl;
  2315. }
  2316. //
  2317. // If scsiport's verifier is configured, initialize the verifier extension.
  2318. //
  2319. DrvExt = IoGetDriverObjectExtension(
  2320. FdoExtension->DeviceObject->DriverObject,
  2321. ScsiPortInitialize);
  2322. if (DrvExt != NULL && DrvExt->Verifying == 1) {
  2323. SpDoVerifierInit(FdoExtension, HwInitializationData);
  2324. }
  2325. //
  2326. // Check if the miniport driver requires any noncached memory.
  2327. // SRB extensions will come from this memory. Round the size
  2328. // a multiple of quadwords
  2329. //
  2330. FdoExtension->SrbExtensionSize =
  2331. (HwInitializationData->SrbExtensionSize + sizeof(LONGLONG) - 1) &
  2332. ~(sizeof(LONGLONG) - 1);
  2333. //
  2334. // Initialize the maximum lu count
  2335. //
  2336. FdoExtension->MaxLuCount = SCSI_MAXIMUM_LOGICAL_UNITS;
  2337. FdoExtension->NumberOfRequests = MINIMUM_SRB_EXTENSIONS;
  2338. if(ARGUMENT_PRESENT(HwDeviceExtension)) {
  2339. HwDeviceExtension->FdoExtension = FdoExtension;
  2340. FdoExtension->HwDeviceExtension = HwDeviceExtension->HwDeviceExtension;
  2341. }
  2342. #if defined(FORWARD_PROGRESS)
  2343. //
  2344. // Initialize the reserved pages which we use to ensure that forward progress
  2345. // can be made in low-memory conditions.
  2346. //
  2347. FdoExtension->ReservedPages = MmAllocateMappingAddress(
  2348. SP_RESERVED_PAGES * PAGE_SIZE,
  2349. SCSIPORT_TAG_MAPPING_LIST);
  2350. //
  2351. // Allocate a spare MDL for use in low memory conditions. Note that we
  2352. // pass NULL as the VirtualAddress. We do this because we're reinitialize
  2353. // the MDL everytime we use it with the appropriate VA and size.
  2354. //
  2355. FdoExtension->ReservedMdl = IoAllocateMdl(NULL,
  2356. SP_RESERVED_PAGES * PAGE_SIZE,
  2357. FALSE,
  2358. FALSE,
  2359. NULL);
  2360. #endif
  2361. return;
  2362. }
  2363. #if !defined(NO_LEGACY_DRIVERS)
  2364. NTSTATUS
  2365. ScsiPortInitLegacyAdapter(
  2366. IN PSCSIPORT_DRIVER_EXTENSION DriverExtension,
  2367. IN PHW_INITIALIZATION_DATA HwInitializationData,
  2368. IN PVOID HwContext
  2369. )
  2370. /*++
  2371. Routine Description:
  2372. This routine will locate the adapters attached to a given bus type and
  2373. then report them (and their necessary resources) to the pnp system to
  2374. be initialized later.
  2375. If adapters are found, this routine will pre-initialize their device
  2376. extensions and place them into one of the init chains for use during
  2377. Add/Start device routines.
  2378. Arguments:
  2379. DriverExtension - a pointer to the driver extension for this miniport
  2380. HwInitializationData - the init data that the miniport handed to
  2381. ScsiPortInitialize
  2382. Return Value:
  2383. status
  2384. --*/
  2385. {
  2386. CONFIGURATION_CONTEXT configurationContext;
  2387. PPORT_CONFIGURATION_INFORMATION configInfo = NULL;
  2388. PUNICODE_STRING registryPath = &(DriverExtension->RegistryPath);
  2389. PHW_DEVICE_EXTENSION hwDeviceExtension = NULL;
  2390. PDEVICE_OBJECT fdo;
  2391. PADAPTER_EXTENSION fdoExtension;
  2392. BOOLEAN callAgain = FALSE;
  2393. BOOLEAN isPci = FALSE;
  2394. PCI_SLOT_NUMBER slotNumber;
  2395. OBJECT_ATTRIBUTES objectAttributes;
  2396. UNICODE_STRING unicodeString;
  2397. PCM_RESOURCE_LIST resourceList;
  2398. ULONG uniqueId;
  2399. BOOLEAN attached = FALSE;
  2400. NTSTATUS returnStatus = STATUS_DEVICE_DOES_NOT_EXIST;
  2401. NTSTATUS status;
  2402. PAGED_CODE();
  2403. slotNumber.u.AsULONG = 0;
  2404. RtlZeroMemory(&configurationContext, sizeof(configurationContext));
  2405. if(HwInitializationData->NumberOfAccessRanges != 0) {
  2406. configurationContext.AccessRanges =
  2407. SpAllocatePool(PagedPool,
  2408. (HwInitializationData->NumberOfAccessRanges *
  2409. sizeof(ACCESS_RANGE)),
  2410. SCSIPORT_TAG_ACCESS_RANGE,
  2411. DriverExtension->DriverObject);
  2412. if(configurationContext.AccessRanges == NULL) {
  2413. return STATUS_INSUFFICIENT_RESOURCES;
  2414. }
  2415. }
  2416. //
  2417. // Keep calling the miniport's find adapter routine until the miniport
  2418. // indicates it is doen and there is no more configuration information.
  2419. // The loop is terminated when the SpInitializeConfiguration routine
  2420. // inidcates ther eis no more configuration information or an error occurs.
  2421. //
  2422. do {
  2423. ULONG hwDeviceExtensionSize = HwInitializationData->DeviceExtensionSize +
  2424. sizeof(HW_DEVICE_EXTENSION);
  2425. attached = FALSE;
  2426. fdo = NULL;
  2427. fdoExtension = NULL;
  2428. //
  2429. // Allocate the HwDeviceExtension first - it's easier to deallocate :)
  2430. //
  2431. hwDeviceExtension = SpAllocatePool(NonPagedPool,
  2432. hwDeviceExtensionSize,
  2433. SCSIPORT_TAG_DEV_EXT,
  2434. DriverExtension->DriverObject);
  2435. if(hwDeviceExtension == NULL) {
  2436. DebugPrint((1, "SpInitLegacyAdapter: Could not allocate "
  2437. "HwDeviceExtension\n"));
  2438. RtlFreeUnicodeString(&unicodeString);
  2439. fdoExtension = NULL;
  2440. uniqueId = __LINE__;
  2441. status = STATUS_INSUFFICIENT_RESOURCES;
  2442. break;
  2443. }
  2444. RtlZeroMemory(hwDeviceExtension, hwDeviceExtensionSize);
  2445. status = SpCreateAdapter(DriverExtension->DriverObject,
  2446. &fdo);
  2447. if(!NT_SUCCESS(status)) {
  2448. DebugPrint((1, "SpInitLegacyAdapter: Could not allocate "
  2449. "fdo [%#08lx]\n", status));
  2450. RtlFreeUnicodeString(&unicodeString);
  2451. ExFreePool(hwDeviceExtension);
  2452. uniqueId = __LINE__;
  2453. break;
  2454. }
  2455. fdoExtension = fdo->DeviceExtension;
  2456. fdoExtension->IsMiniportDetected = TRUE;
  2457. //
  2458. // Setup device extension pointers
  2459. //
  2460. SpInitializeAdapterExtension(fdoExtension,
  2461. HwInitializationData,
  2462. hwDeviceExtension);
  2463. hwDeviceExtension = NULL;
  2464. fdoExtension->CommonExtension.IsInitialized = TRUE;
  2465. NewConfiguration:
  2466. //
  2467. // initialize the miniport config info buffer
  2468. //
  2469. status = SpInitializeConfiguration(
  2470. fdoExtension,
  2471. &DriverExtension->RegistryPath,
  2472. HwInitializationData,
  2473. &configurationContext);
  2474. if(!NT_SUCCESS(status)) {
  2475. uniqueId = __LINE__;
  2476. break;
  2477. }
  2478. //
  2479. // Allocate a config-info structure and access ranges for the
  2480. // miniport drivers to use
  2481. //
  2482. configInfo = SpAllocatePool(
  2483. NonPagedPool,
  2484. ((sizeof(PORT_CONFIGURATION_INFORMATION) +
  2485. (HwInitializationData->NumberOfAccessRanges *
  2486. sizeof(ACCESS_RANGE)) + 7) & ~7),
  2487. SCSIPORT_TAG_ACCESS_RANGE,
  2488. DriverExtension->DriverObject);
  2489. if(configInfo == NULL) {
  2490. status = STATUS_INSUFFICIENT_RESOURCES;
  2491. uniqueId = __LINE__;
  2492. break;
  2493. }
  2494. fdoExtension->PortConfig = configInfo;
  2495. //
  2496. // Copy the current structure to the writable copy
  2497. //
  2498. RtlCopyMemory(configInfo,
  2499. &configurationContext.PortConfig,
  2500. sizeof(PORT_CONFIGURATION_INFORMATION));
  2501. //
  2502. // Copy the SrbExtensionSize from device extension to ConfigInfo.
  2503. // A check will be made later to determine if the miniport updated
  2504. // this value
  2505. //
  2506. configInfo->SrbExtensionSize = fdoExtension->SrbExtensionSize;
  2507. configInfo->SpecificLuExtensionSize = fdoExtension->HwLogicalUnitExtensionSize;
  2508. //
  2509. // initialize the access range array
  2510. //
  2511. if(HwInitializationData->NumberOfAccessRanges != 0) {
  2512. configInfo->AccessRanges = (PVOID) (configInfo + 1);
  2513. //
  2514. // Quadword align this
  2515. //
  2516. (ULONG_PTR) (configInfo->AccessRanges) += 7;
  2517. (ULONG_PTR) (configInfo->AccessRanges) &= ~7;
  2518. RtlCopyMemory(configInfo->AccessRanges,
  2519. configurationContext.AccessRanges,
  2520. (HwInitializationData->NumberOfAccessRanges *
  2521. sizeof(ACCESS_RANGE)));
  2522. }
  2523. ASSERT(HwInitializationData->AdapterInterfaceType != Internal);
  2524. //
  2525. // If PCI bus initialize configuration information with
  2526. // slot information.
  2527. //
  2528. if(HwInitializationData->AdapterInterfaceType == PCIBus &&
  2529. HwInitializationData->VendorIdLength > 0 &&
  2530. HwInitializationData->DeviceIdLength > 0 &&
  2531. HwInitializationData->DeviceId &&
  2532. HwInitializationData->VendorId) {
  2533. PCI_SLOT_NUMBER tmp;
  2534. isPci = TRUE;
  2535. configInfo->BusInterruptLevel = 0;
  2536. if(!GetPciConfiguration(DriverExtension->DriverObject,
  2537. fdo,
  2538. HwInitializationData,
  2539. registryPath,
  2540. configurationContext.BusNumber,
  2541. &slotNumber)) {
  2542. //
  2543. // Adapter not found. Continue search with next bus
  2544. //
  2545. configurationContext.BusNumber++;
  2546. slotNumber.u.AsULONG = 0;
  2547. fdoExtension->PortConfig = NULL;
  2548. ExFreePool(configInfo);
  2549. callAgain = FALSE;
  2550. goto NewConfiguration;
  2551. }
  2552. fdoExtension->IsMiniportDetected = FALSE;
  2553. //
  2554. // GetPciConfiguration increments the function number when it
  2555. // finds something. We need to be looking at the previous
  2556. // function number.
  2557. //
  2558. tmp.u.AsULONG = slotNumber.u.AsULONG;
  2559. tmp.u.bits.FunctionNumber--;
  2560. configInfo->SlotNumber = tmp.u.AsULONG;
  2561. SpBuildConfiguration(fdoExtension,
  2562. HwInitializationData,
  2563. configInfo);
  2564. if(!configInfo->BusInterruptLevel) {
  2565. //
  2566. // No interrupt was assigned - skip this slot and call
  2567. // again
  2568. //
  2569. fdoExtension->PortConfig = NULL;
  2570. ExFreePool(configInfo);
  2571. goto NewConfiguration;
  2572. }
  2573. }
  2574. //
  2575. // Get the miniport configuration inofmraiton
  2576. //
  2577. callAgain = FALSE;
  2578. status = SpCallHwFindAdapter(fdo,
  2579. HwInitializationData,
  2580. HwContext,
  2581. &configurationContext,
  2582. configInfo,
  2583. &callAgain);
  2584. if(NT_SUCCESS(status)) {
  2585. status = SpAllocateAdapterResources(fdo);
  2586. if(NT_SUCCESS(status)) {
  2587. status = SpCallHwInitialize(fdo);
  2588. }
  2589. attached = TRUE;
  2590. } else if (status == STATUS_DEVICE_DOES_NOT_EXIST) {
  2591. PCM_RESOURCE_LIST emptyResources = NULL;
  2592. configurationContext.BusNumber++;
  2593. fdoExtension->PortConfig = NULL;
  2594. ExFreePool(configInfo);
  2595. callAgain = FALSE;
  2596. //
  2597. // Release the resources we've allocated for this device object
  2598. // if it's a PCI system.
  2599. //
  2600. IoAssignResources(registryPath,
  2601. NULL,
  2602. DriverExtension->DriverObject,
  2603. fdo,
  2604. NULL,
  2605. &emptyResources);
  2606. if(emptyResources != NULL) {
  2607. ExFreePool(emptyResources);
  2608. }
  2609. goto NewConfiguration;
  2610. }
  2611. if(NT_SUCCESS(status)) {
  2612. //
  2613. // Try to start the adapter
  2614. //
  2615. status = ScsiPortStartAdapter(fdo);
  2616. if(NT_SUCCESS(status)) {
  2617. fdoExtension->CommonExtension.CurrentPnpState =
  2618. IRP_MN_START_DEVICE;
  2619. }
  2620. }
  2621. if(!NT_SUCCESS(returnStatus)) {
  2622. //
  2623. // if no devices were found then just return the current status
  2624. //
  2625. returnStatus = status;
  2626. }
  2627. if(!NT_SUCCESS(status)) {
  2628. break;
  2629. }
  2630. SpEnumerateAdapterSynchronous(fdoExtension, TRUE);
  2631. //
  2632. // update the local adapter count
  2633. //
  2634. configurationContext.AdapterNumber++;
  2635. //
  2636. // Bump the bus number if miniport inidicated that it should not be
  2637. // called again on this bus.
  2638. //
  2639. if(!callAgain) {
  2640. configurationContext.BusNumber++;
  2641. }
  2642. //
  2643. // Set the return status to STATUS_SUCCESS to indicate that one HBA
  2644. // was found.
  2645. //
  2646. returnStatus = STATUS_SUCCESS;
  2647. } while(TRUE);
  2648. if(!NT_SUCCESS(status)) {
  2649. //
  2650. // If the device existed but some other error occurred then log it.
  2651. //
  2652. if(status != STATUS_DEVICE_DOES_NOT_EXIST) {
  2653. PIO_ERROR_LOG_PACKET errorLogEntry;
  2654. //
  2655. // An error occured - log it.
  2656. //
  2657. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  2658. IoAllocateErrorLogEntry(
  2659. fdo,
  2660. sizeof(IO_ERROR_LOG_PACKET));
  2661. if(errorLogEntry != NULL) {
  2662. errorLogEntry->ErrorCode = IO_ERR_DRIVER_ERROR;
  2663. errorLogEntry->UniqueErrorValue = uniqueId;
  2664. errorLogEntry->FinalStatus = status;
  2665. errorLogEntry->DumpDataSize = 0;
  2666. IoWriteErrorLogEntry(errorLogEntry);
  2667. }
  2668. }
  2669. if(attached) {
  2670. //
  2671. // Tell PNP that this device should be destroyed.
  2672. //
  2673. fdoExtension->DeviceState = PNP_DEVICE_DISABLED | PNP_DEVICE_FAILED;
  2674. fdoExtension->CommonExtension.CurrentPnpState = IRP_MN_REMOVE_DEVICE;
  2675. IoInvalidateDeviceState(fdoExtension->LowerPdo);
  2676. } else {
  2677. //
  2678. // If the HwDeviceExtension hasn't been deleted or assigned to the
  2679. // adapter yet then delete it.
  2680. //
  2681. if(hwDeviceExtension != NULL) {
  2682. ExFreePool(hwDeviceExtension);
  2683. }
  2684. //
  2685. // Clean up the last device object which is not used.
  2686. //
  2687. if (fdoExtension != NULL) {
  2688. fdoExtension->CommonExtension.IsRemoved = REMOVE_PENDING;
  2689. fdoExtension->CommonExtension.CurrentPnpState = IRP_MN_REMOVE_DEVICE;
  2690. SpReleaseRemoveLock(fdoExtension->DeviceObject,
  2691. fdoExtension->DeviceObject);
  2692. SpDestroyAdapter(fdoExtension, FALSE);
  2693. }
  2694. //
  2695. // Delete it.
  2696. //
  2697. IoDeleteDevice(fdo);
  2698. }
  2699. if (configurationContext.AccessRanges != NULL) {
  2700. ExFreePool(configurationContext.AccessRanges);
  2701. }
  2702. if (configurationContext.Parameter != NULL) {
  2703. ExFreePool(configurationContext.Parameter);
  2704. }
  2705. }
  2706. return returnStatus;
  2707. }
  2708. #endif // NO_LEGACY_DRIVERS
  2709. NTSTATUS
  2710. SpCallHwFindAdapter(
  2711. IN PDEVICE_OBJECT Fdo,
  2712. IN PHW_INITIALIZATION_DATA HwInitData,
  2713. IN PVOID HwContext OPTIONAL,
  2714. IN OUT PCONFIGURATION_CONTEXT ConfigurationContext,
  2715. IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  2716. OUT PBOOLEAN CallAgain
  2717. )
  2718. /*++
  2719. Routine Description:
  2720. This routine will issue a call to the miniport's find adapter routine
  2721. Arguments:
  2722. Fdo - the fdo for the adapter being found. This fdo must have already
  2723. had it's device extension initialized and a HwDeviceExtension
  2724. allocated
  2725. HwInitData - a pointer to the HwINitializationData block passed in by the
  2726. miniport
  2727. HwContext - the context information passed into ScsiPortInitialize by
  2728. the miniport if it's still available
  2729. ConfigurationContext - A configuration context structure which contains
  2730. state information during a device detection
  2731. ConfigInfo - the config info structure for the miniport's resources
  2732. CallAgain - a boolean flag indicating whether the miniport said to call it
  2733. again for this interface type
  2734. Return Value:
  2735. status
  2736. --*/
  2737. {
  2738. PADAPTER_EXTENSION adapter = Fdo->DeviceExtension;
  2739. PSCSIPORT_DRIVER_EXTENSION
  2740. driverExtension = IoGetDriverObjectExtension(Fdo->DriverObject,
  2741. ScsiPortInitialize);
  2742. NTSTATUS status;
  2743. PCM_RESOURCE_LIST resourceList;
  2744. *CallAgain = FALSE;
  2745. //
  2746. // Preallocate space for 20 address mappings. This should be enough
  2747. // to handle any miniport. We'll shrink down the allocation and
  2748. // setup the appropriate "next" pointers once the adapter has been
  2749. // initialized.
  2750. //
  2751. SpPreallocateAddressMapping(adapter, 20);
  2752. status = adapter->HwFindAdapter(adapter->HwDeviceExtension,
  2753. HwContext,
  2754. NULL,
  2755. ConfigurationContext->Parameter,
  2756. ConfigInfo,
  2757. CallAgain);
  2758. if(adapter->InterruptData.InterruptFlags & PD_LOG_ERROR) {
  2759. adapter->InterruptData.InterruptFlags &=
  2760. ~(PD_LOG_ERROR | PD_NOTIFICATION_REQUIRED);
  2761. LogErrorEntry(adapter, &(adapter->InterruptData.LogEntry));
  2762. }
  2763. //
  2764. // Free the pointer to the bus data at map register base. This was
  2765. // allocated by ScsiPortGetBusData
  2766. //
  2767. if(adapter->MapRegisterBase) {
  2768. ExFreePool(adapter->MapRegisterBase);
  2769. adapter->MapRegisterBase = NULL;
  2770. }
  2771. //
  2772. // If the device/driver doesn't support bus mastering then it cannot run
  2773. // on a system with 64-bit addresses.
  2774. //
  2775. if((status == SP_RETURN_FOUND) &&
  2776. (ConfigInfo->Master == FALSE) &&
  2777. (Sp64BitPhysicalAddresses == TRUE)) {
  2778. DebugPrint((0, "SpCallHwFindAdapter: Driver does not support bus "
  2779. "mastering for adapter %#08lx - this type of adapter is "
  2780. "not supported on systems with 64-bit physical "
  2781. "addresses\n", adapter));
  2782. return STATUS_NOT_SUPPORTED;
  2783. }
  2784. //
  2785. // If no device was found then return an error
  2786. //
  2787. if(status != SP_RETURN_FOUND) {
  2788. DebugPrint((1, "SpFindAdapter: miniport find adapter routine reported "
  2789. "an error %d\n", status));
  2790. switch(status) {
  2791. case SP_RETURN_NOT_FOUND: {
  2792. //
  2793. // The driver could not find any devices on this bus.
  2794. // Try the next bus.
  2795. //
  2796. *CallAgain = FALSE;
  2797. return STATUS_DEVICE_DOES_NOT_EXIST;
  2798. }
  2799. case SP_RETURN_BAD_CONFIG: {
  2800. return STATUS_INVALID_PARAMETER;
  2801. }
  2802. case SP_RETURN_ERROR: {
  2803. return STATUS_ADAPTER_HARDWARE_ERROR;
  2804. }
  2805. default: {
  2806. return STATUS_INTERNAL_ERROR;
  2807. }
  2808. }
  2809. return status;
  2810. } else {
  2811. status = STATUS_SUCCESS;
  2812. }
  2813. //
  2814. // Cleanup the mapped address list.
  2815. //
  2816. SpPurgeFreeMappedAddressList(adapter);
  2817. DebugPrint((1, "SpFindAdapter: SCSI Adapter ID is %d\n",
  2818. ConfigInfo->InitiatorBusId[0]));
  2819. //
  2820. // Check the resource requirements against the registry. This will
  2821. // check for conflicts and store the information if none were found.
  2822. //
  2823. if(!adapter->IsPnp) {
  2824. UNICODE_STRING unicodeString;
  2825. BOOLEAN conflict;
  2826. PCM_RESOURCE_LIST resourceList;
  2827. RtlInitUnicodeString(&unicodeString, L"ScsiAdapter");
  2828. adapter->AllocatedResources =
  2829. SpBuildResourceList(adapter, ConfigInfo);
  2830. status = SpReportNewAdapter(Fdo);
  2831. if(!NT_SUCCESS(status)) {
  2832. return status;
  2833. }
  2834. }
  2835. //
  2836. // Update SrbExtensionSize and SpecificLuExtensionSize, if necessary.
  2837. // If the common buffer has already been allocated, this has already
  2838. // been done
  2839. //
  2840. if(!adapter->NonCachedExtension &&
  2841. (ConfigInfo->SrbExtensionSize != adapter->SrbExtensionSize)) {
  2842. adapter->SrbExtensionSize =
  2843. (ConfigInfo->SrbExtensionSize + sizeof(LONGLONG)) &
  2844. ~(sizeof(LONGLONG) - 1);
  2845. }
  2846. if(ConfigInfo->SpecificLuExtensionSize !=
  2847. adapter->HwLogicalUnitExtensionSize) {
  2848. adapter->HwLogicalUnitExtensionSize =
  2849. ConfigInfo->SpecificLuExtensionSize;
  2850. }
  2851. //
  2852. // Get maximum target IDs.
  2853. //
  2854. if(ConfigInfo->MaximumNumberOfTargets > SCSI_MAXIMUM_TARGETS_PER_BUS) {
  2855. adapter->MaximumTargetIds = SCSI_MAXIMUM_TARGETS_PER_BUS;
  2856. } else {
  2857. adapter->MaximumTargetIds = ConfigInfo->MaximumNumberOfTargets;
  2858. }
  2859. //
  2860. // Get number of SCSI buses.
  2861. //
  2862. adapter->NumberOfBuses = ConfigInfo->NumberOfBuses;
  2863. //
  2864. // Remember if the adapter caches data.
  2865. //
  2866. adapter->CachesData = ConfigInfo->CachesData;
  2867. //
  2868. // Save away some of the attributes.
  2869. //
  2870. adapter->ReceiveEvent = ConfigInfo->ReceiveEvent;
  2871. adapter->TaggedQueuing = ConfigInfo->TaggedQueuing;
  2872. adapter->MultipleRequestPerLu = ConfigInfo->MultipleRequestPerLu;
  2873. adapter->CommonExtension.WmiMiniPortSupport = ConfigInfo->WmiDataProvider;
  2874. //
  2875. // Clear those options which have been disabled in the registry.
  2876. //
  2877. if(ConfigurationContext->DisableMultipleLu) {
  2878. adapter->MultipleRequestPerLu =
  2879. ConfigInfo->MultipleRequestPerLu = FALSE;
  2880. }
  2881. if(ConfigurationContext->DisableTaggedQueueing) {
  2882. adapter->TaggedQueuing =
  2883. ConfigInfo->TaggedQueuing =
  2884. ConfigInfo->MultipleRequestPerLu = FALSE;
  2885. }
  2886. //
  2887. // If the adapter supports tagged queuing or multiple requests per logical
  2888. // unit, SRB data needs to be allocated.
  2889. //
  2890. if (adapter->TaggedQueuing || adapter->MultipleRequestPerLu) {
  2891. adapter->SupportsMultipleRequests = TRUE;
  2892. } else {
  2893. adapter->SupportsMultipleRequests = FALSE;
  2894. }
  2895. return status;
  2896. }
  2897. NTSTATUS
  2898. SpAllocateAdapterResources(
  2899. IN PDEVICE_OBJECT Fdo
  2900. )
  2901. /*++
  2902. Routine Description:
  2903. This routine will allocate and initialize any necessary resources for the
  2904. adapter. It handles one time initialization of the srb data blocks,
  2905. srb extensions, etc...
  2906. Arguments:
  2907. Fdo - a pointer to the functional device object being initialized
  2908. Return Value:
  2909. status
  2910. --*/
  2911. {
  2912. PADAPTER_EXTENSION fdoExtension = Fdo->DeviceExtension;
  2913. PIO_SCSI_CAPABILITIES capabilities;
  2914. PPORT_CONFIGURATION_INFORMATION configInfo =
  2915. fdoExtension->PortConfig;
  2916. NTSTATUS status = STATUS_SUCCESS;
  2917. PVOID SrbExtensionBuffer;
  2918. PAGED_CODE();
  2919. //
  2920. // Initialize the capabilities pointer
  2921. //
  2922. capabilities = &fdoExtension->Capabilities;
  2923. //
  2924. // Set indicator as to whether adapter needs kernel mapped buffers
  2925. //
  2926. fdoExtension->MapBuffers = configInfo->MapBuffers;
  2927. capabilities->AdapterUsesPio = configInfo->MapBuffers;
  2928. //
  2929. // Determine if a DMA Adapter must be allocated
  2930. //
  2931. if((fdoExtension->DmaAdapterObject == NULL) &&
  2932. (configInfo->Master ||
  2933. configInfo->DmaChannel != SP_UNINITIALIZED_VALUE)) {
  2934. DEVICE_DESCRIPTION deviceDescription;
  2935. ULONG numberOfMapRegisters;
  2936. //
  2937. // Get the adapter object for this card
  2938. //
  2939. RtlZeroMemory(&deviceDescription, sizeof(deviceDescription));
  2940. deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
  2941. deviceDescription.DmaChannel = configInfo->DmaChannel;
  2942. deviceDescription.InterfaceType = configInfo->AdapterInterfaceType;
  2943. deviceDescription.BusNumber = configInfo->SystemIoBusNumber;
  2944. deviceDescription.DmaWidth = configInfo->DmaWidth;
  2945. deviceDescription.DmaSpeed = configInfo->DmaSpeed;
  2946. deviceDescription.ScatterGather = configInfo->ScatterGather;
  2947. deviceDescription.Master = configInfo->Master;
  2948. deviceDescription.DmaPort = configInfo->DmaPort;
  2949. deviceDescription.Dma32BitAddresses = configInfo->Dma32BitAddresses;
  2950. deviceDescription.AutoInitialize = FALSE;
  2951. deviceDescription.DemandMode = configInfo->DemandMode;
  2952. deviceDescription.MaximumLength = configInfo->MaximumTransferLength;
  2953. fdoExtension->Dma32BitAddresses = configInfo->Dma32BitAddresses;
  2954. //
  2955. // If the miniport puts anything in here other than 0x80 then we
  2956. // assume it wants to support 64-bit addresses.
  2957. //
  2958. DebugPrint((1, "SpAllocateAdapterResources: Dma64BitAddresses = "
  2959. "%#0x\n",
  2960. configInfo->Dma64BitAddresses));
  2961. fdoExtension->RemapBuffers = (BOOLEAN) (SpRemapBuffersByDefault != 0);
  2962. if((configInfo->Dma64BitAddresses & ~SCSI_DMA64_SYSTEM_SUPPORTED) != 0){
  2963. DebugPrint((1, "SpAllocateAdapterResources: will request "
  2964. "64-bit PA's\n"));
  2965. deviceDescription.Dma64BitAddresses = TRUE;
  2966. fdoExtension->Dma64BitAddresses = TRUE;
  2967. } else if(Sp64BitPhysicalAddresses == TRUE) {
  2968. DebugPrint((1, "SpAllocateAdapterResources: Will remap buffers for adapter %#p\n", fdoExtension));
  2969. fdoExtension->RemapBuffers = TRUE;
  2970. }
  2971. fdoExtension->DmaAdapterObject = IoGetDmaAdapter(fdoExtension->LowerPdo,
  2972. &deviceDescription,
  2973. &numberOfMapRegisters);
  2974. ASSERT(fdoExtension->DmaAdapterObject);
  2975. //
  2976. // Set maximum number of page breaks
  2977. //
  2978. if(numberOfMapRegisters > configInfo->NumberOfPhysicalBreaks) {
  2979. capabilities->MaximumPhysicalPages =
  2980. configInfo->NumberOfPhysicalBreaks;
  2981. } else {
  2982. capabilities->MaximumPhysicalPages = numberOfMapRegisters;
  2983. }
  2984. }
  2985. status = SpAllocateTagBitMap(fdoExtension);
  2986. if(!NT_SUCCESS(status)) {
  2987. return status;
  2988. }
  2989. //
  2990. // Initialize power parameters.
  2991. //
  2992. SpInitializePowerParams(fdoExtension);
  2993. //
  2994. // Initialize tunable per-adapter performance parameters.
  2995. //
  2996. SpInitializePerformanceParams(fdoExtension);
  2997. //
  2998. // Allocate memory for the noncached extension if it has not already
  2999. // been allocated. If the adapter supports AutoRequestSense or
  3000. // needs SRB extensions then an SRB list needs to be allocated.
  3001. //
  3002. SrbExtensionBuffer = SpGetSrbExtensionBuffer(fdoExtension);
  3003. if(((fdoExtension->SrbExtensionSize != 0) || (configInfo->AutoRequestSense)) &&
  3004. (SrbExtensionBuffer == NULL)) {
  3005. //
  3006. // Initialize configurable request sense parameters.
  3007. //
  3008. SpInitializeRequestSenseParams(fdoExtension);
  3009. //
  3010. // Capture the auto request sense flag when the common buffer is
  3011. // allocated.
  3012. //
  3013. fdoExtension->AutoRequestSense = configInfo->AutoRequestSense;
  3014. fdoExtension->AllocateSrbExtension = TRUE;
  3015. status = SpGetCommonBuffer(fdoExtension, 0);
  3016. if(!NT_SUCCESS(status)) {
  3017. return status;
  3018. }
  3019. }
  3020. status = SpInitializeSrbDataLookasideList(Fdo);
  3021. if(!NT_SUCCESS(status)) {
  3022. return status;
  3023. }
  3024. //
  3025. // Initialize the emergency SRB_DATA structures.
  3026. //
  3027. fdoExtension->EmergencySrbData = SpAllocateSrbData(fdoExtension, NULL);
  3028. if(fdoExtension->EmergencySrbData == NULL) {
  3029. return STATUS_INSUFFICIENT_RESOURCES;
  3030. }
  3031. //
  3032. // If we are re-initializing a stopped adapter, we must not wipe out any
  3033. // existing blocked requests.
  3034. //
  3035. if (fdoExtension->SrbDataBlockedRequests.Flink == NULL &&
  3036. fdoExtension->SrbDataBlockedRequests.Blink == NULL) {
  3037. InitializeListHead(&fdoExtension->SrbDataBlockedRequests);
  3038. }
  3039. KeInitializeSpinLock(&fdoExtension->EmergencySrbDataSpinLock);
  3040. //
  3041. // Initialize the pointer to the enumeration request block.
  3042. //
  3043. fdoExtension->PnpEnumRequestPtr = &(fdoExtension->PnpEnumerationRequest);
  3044. #ifndef USE_DMA_MACROS
  3045. //
  3046. // Create the scatter gather lookaside list. This list contains
  3047. // medium sized SG lists.
  3048. //
  3049. fdoExtension->LargeScatterGatherListSize = SP_LARGE_PHYSICAL_BREAK_VALUE;
  3050. ExInitializeNPagedLookasideList(
  3051. &fdoExtension->MediumScatterGatherLookasideList,
  3052. NULL,
  3053. NULL,
  3054. 0L,
  3055. (sizeof(SRB_SCATTER_GATHER) *
  3056. (fdoExtension->LargeScatterGatherListSize - 1)),
  3057. SCSIPORT_TAG_MEDIUM_SG_ENTRY,
  3058. (USHORT) fdoExtension->NumberOfRequests);
  3059. fdoExtension->MediumScatterGatherListInitialized = TRUE;
  3060. #endif
  3061. //
  3062. // Allocate buffers needed for bus scans.
  3063. //
  3064. fdoExtension->InquiryBuffer = SpAllocatePool(
  3065. NonPagedPoolCacheAligned,
  3066. SP_INQUIRY_BUFFER_SIZE,
  3067. SCSIPORT_TAG_INQUIRY,
  3068. Fdo->DriverObject);
  3069. if(fdoExtension->InquiryBuffer == NULL) {
  3070. return STATUS_INSUFFICIENT_RESOURCES;
  3071. }
  3072. fdoExtension->InquirySenseBuffer =
  3073. SpAllocatePool(
  3074. NonPagedPoolCacheAligned,
  3075. SENSE_BUFFER_SIZE + fdoExtension->AdditionalSenseBytes,
  3076. SCSIPORT_TAG_INQUIRY,
  3077. Fdo->DriverObject);
  3078. if(fdoExtension->InquirySenseBuffer == NULL) {
  3079. return STATUS_INSUFFICIENT_RESOURCES;
  3080. }
  3081. //
  3082. // Preallocate an irp for inquiries. Since this is only used for scsi
  3083. // operations we should only need one stack location.
  3084. //
  3085. fdoExtension->InquiryIrp = SpAllocateIrp(INQUIRY_STACK_LOCATIONS, FALSE, Fdo->DriverObject);
  3086. if(fdoExtension->InquiryIrp == NULL) {
  3087. return STATUS_INSUFFICIENT_RESOURCES;
  3088. }
  3089. //
  3090. // Build an MDL for the inquiry buffer.
  3091. //
  3092. fdoExtension->InquiryMdl = SpAllocateMdl(fdoExtension->InquiryBuffer,
  3093. INQUIRYDATABUFFERSIZE,
  3094. FALSE,
  3095. FALSE,
  3096. NULL,
  3097. Fdo->DriverObject);
  3098. if(fdoExtension->InquiryMdl == NULL) {
  3099. return STATUS_INSUFFICIENT_RESOURCES;
  3100. }
  3101. MmBuildMdlForNonPagedPool(fdoExtension->InquiryMdl);
  3102. //
  3103. // Initialize the capabilities structure.
  3104. //
  3105. capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
  3106. capabilities->MaximumTransferLength = configInfo->MaximumTransferLength;
  3107. if(configInfo->ReceiveEvent) {
  3108. capabilities->SupportedAsynchronousEvents |=
  3109. SRBEV_SCSI_ASYNC_NOTIFICATION;
  3110. }
  3111. capabilities->TaggedQueuing = fdoExtension->TaggedQueuing;
  3112. capabilities->AdapterScansDown = configInfo->AdapterScansDown;
  3113. //
  3114. // Update the device object alignment if necessary.
  3115. //
  3116. if(configInfo->AlignmentMask > Fdo->AlignmentRequirement) {
  3117. Fdo->AlignmentRequirement = configInfo->AlignmentMask;
  3118. }
  3119. capabilities->AlignmentMask = Fdo->AlignmentRequirement;
  3120. //
  3121. // Make sure maximum number of pages is set to a reasonable value.
  3122. // This occurs for miniports with no Dma adapter.
  3123. //
  3124. if(capabilities->MaximumPhysicalPages == 0) {
  3125. capabilities->MaximumPhysicalPages =
  3126. BYTES_TO_PAGES(capabilities->MaximumTransferLength);
  3127. //
  3128. // Honor any limit requested by the miniport
  3129. //
  3130. if(configInfo->NumberOfPhysicalBreaks < capabilities->MaximumPhysicalPages) {
  3131. capabilities->MaximumPhysicalPages =
  3132. configInfo->NumberOfPhysicalBreaks;
  3133. }
  3134. }
  3135. return status;
  3136. }
  3137. NTSTATUS
  3138. SpCallHwInitialize(
  3139. IN PDEVICE_OBJECT Fdo
  3140. )
  3141. /*++
  3142. Routine Description:
  3143. This routine will initialize the specified adapter, connect the interrupts,
  3144. and initialize any necessary resources
  3145. Arguments:
  3146. Fdo - a pointer to the functional device object being initialized
  3147. Return Value:
  3148. status
  3149. --*/
  3150. {
  3151. PADAPTER_EXTENSION fdoExtension = Fdo->DeviceExtension;
  3152. PPORT_CONFIGURATION_INFORMATION configInfo =
  3153. fdoExtension->PortConfig;
  3154. KIRQL irql;
  3155. NTSTATUS status;
  3156. //
  3157. // Allocate spin lock for critical sections.
  3158. //
  3159. KeInitializeSpinLock(&fdoExtension->SpinLock);
  3160. //
  3161. // Initialize DPC routine.
  3162. //
  3163. IoInitializeDpcRequest(fdoExtension->CommonExtension.DeviceObject,
  3164. ScsiPortCompletionDpc);
  3165. //
  3166. // Initialize the port timeout counter.
  3167. //
  3168. fdoExtension->PortTimeoutCounter = PD_TIMER_STOPPED;
  3169. //
  3170. // Initialize the device object timer only if it doesn't already exist
  3171. // (there's no way to delete a timer without deleting the device so if
  3172. // we are stopped and restarted then the timer stays around. Reinitializing
  3173. // it could cause the timer list to go circular)
  3174. //
  3175. if(Fdo->Timer == NULL) {
  3176. IoInitializeTimer(Fdo, ScsiPortTickHandler, NULL);
  3177. }
  3178. //
  3179. // Initialize miniport timer and timer DPC
  3180. //
  3181. KeInitializeTimer(&fdoExtension->MiniPortTimer);
  3182. KeInitializeDpc(&fdoExtension->MiniPortTimerDpc,
  3183. SpMiniPortTimerDpc,
  3184. Fdo);
  3185. KeInitializeSpinLock(&fdoExtension->InterruptSpinLock);
  3186. if((fdoExtension->HwInterrupt == NULL) ||
  3187. (fdoExtension->HasInterrupt == FALSE)) {
  3188. //
  3189. // There is no interrupt so use the dummy routine.
  3190. //
  3191. fdoExtension->SynchronizeExecution = SpSynchronizeExecution;
  3192. fdoExtension->InterruptObject = (PVOID) fdoExtension;
  3193. DebugPrint((1, "ScsiPortInitialize: Adapter has no interrupt.\n"));
  3194. } else {
  3195. KIRQL syncIrql = 0;
  3196. KIRQL irql = 0, irql2 = 0;
  3197. ULONG vector = 0, vector2 = 0;
  3198. KAFFINITY affinity = 0, affinity2 = 0;
  3199. BOOLEAN interruptSharable = FALSE;
  3200. BOOLEAN secondInterrupt = FALSE;
  3201. DebugPrint((1, "ScsiPortInitialize: Interrupt Info for adapter %#p\n", Fdo));
  3202. DebugPrint((1, "ScsiPortInitialize: AdapterInterfaceType = %d\n", configInfo->AdapterInterfaceType));
  3203. DebugPrint((1, "ScsiPortInitialize: BusInterruptLevel = %d\n", configInfo->BusInterruptLevel));
  3204. DebugPrint((1, "ScsiPortInitialize: BusInterruptVector = %d\n", configInfo->BusInterruptVector));
  3205. DebugPrint((1, "ScsiPortInitialize: BusInterruptLevel2 = %d\n", configInfo->BusInterruptLevel2));
  3206. DebugPrint((1, "ScsiPortInitialize: BusInterruptVector2 = %d\n", configInfo->BusInterruptVector2));
  3207. //
  3208. // Determine if 2 interrupt sync. is needed.
  3209. //
  3210. if(fdoExtension->HwInterrupt != NULL &&
  3211. (configInfo->BusInterruptLevel != 0 ||
  3212. configInfo->BusInterruptVector != 0) &&
  3213. (configInfo->BusInterruptLevel2 != 0 ||
  3214. configInfo->BusInterruptVector2 != 0)) {
  3215. secondInterrupt = TRUE;
  3216. }
  3217. //
  3218. // Save the interrupt level.
  3219. //
  3220. fdoExtension->InterruptLevel = configInfo->BusInterruptLevel;
  3221. //
  3222. // Set up for a real interrupt.
  3223. //
  3224. fdoExtension->SynchronizeExecution = KeSynchronizeExecution;
  3225. //
  3226. // Call HAL to get system interrupt parameters for the first
  3227. // interrupt.
  3228. //
  3229. if(fdoExtension->IsMiniportDetected) {
  3230. #if defined(NO_LEGACY_DRIVERS)
  3231. DbgPrint("SpCallHwInitialize: fdoExtension->IsMiniportDetected "
  3232. "not supported for 64 bits!\n");
  3233. #else
  3234. vector = HalGetInterruptVector(
  3235. configInfo->AdapterInterfaceType,
  3236. configInfo->SystemIoBusNumber,
  3237. configInfo->BusInterruptLevel,
  3238. configInfo->BusInterruptVector,
  3239. &irql,
  3240. &affinity);
  3241. if(secondInterrupt) {
  3242. //
  3243. // Spin lock to sync. multiple IRQ's (PCI IDE).
  3244. //
  3245. KeInitializeSpinLock(&fdoExtension->MultipleIrqSpinLock);
  3246. //
  3247. // Call HAL to get system interrupt parameters for the
  3248. // second interrupt.
  3249. //
  3250. vector2 = HalGetInterruptVector(
  3251. configInfo->AdapterInterfaceType,
  3252. configInfo->SystemIoBusNumber,
  3253. configInfo->BusInterruptLevel2,
  3254. configInfo->BusInterruptVector2,
  3255. &irql2,
  3256. &affinity2);
  3257. }
  3258. ASSERT(affinity != 0);
  3259. if(configInfo->AdapterInterfaceType == MicroChannel ||
  3260. configInfo->InterruptMode == LevelSensitive) {
  3261. interruptSharable = TRUE;
  3262. }
  3263. #endif // NO_LEGACY_DRIVERS
  3264. } else {
  3265. ULONG i, j;
  3266. ASSERT(secondInterrupt == FALSE);
  3267. for(i = 0; i < fdoExtension->TranslatedResources->Count; i++) {
  3268. for(j = 0;
  3269. j < fdoExtension->TranslatedResources->List[i].PartialResourceList.Count;
  3270. j++) {
  3271. PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor =
  3272. &fdoExtension->TranslatedResources->List[i].PartialResourceList.PartialDescriptors[j];
  3273. if(descriptor->Type == CmResourceTypeInterrupt) {
  3274. vector = descriptor->u.Interrupt.Vector;
  3275. affinity = descriptor->u.Interrupt.Affinity;
  3276. irql = (KIRQL) descriptor->u.Interrupt.Level;
  3277. if(descriptor->ShareDisposition == CmResourceShareShared) {
  3278. interruptSharable = TRUE;
  3279. }
  3280. break;
  3281. }
  3282. }
  3283. }
  3284. }
  3285. syncIrql = (irql > irql2) ? irql : irql2;
  3286. DebugPrint((1, "SpInitializeAdapter: vector = %d\n", vector));
  3287. DebugPrint((1, "SpInitializeAdapter: irql = %d\n", irql));
  3288. DebugPrint((1, "SpInitializeAdapter: affinity = %#08lx\n", affinity));
  3289. status = IoConnectInterrupt(
  3290. &fdoExtension->InterruptObject,
  3291. (PKSERVICE_ROUTINE) ScsiPortInterrupt,
  3292. Fdo,
  3293. (secondInterrupt ?
  3294. (&fdoExtension->MultipleIrqSpinLock) : NULL),
  3295. vector,
  3296. irql,
  3297. syncIrql,
  3298. configInfo->InterruptMode,
  3299. interruptSharable,
  3300. affinity,
  3301. FALSE);
  3302. if(!NT_SUCCESS(status)) {
  3303. DebugPrint((1, "SpInitializeAdapter: Can't connect "
  3304. "interrupt %d\n", vector));
  3305. fdoExtension->InterruptObject = NULL;
  3306. return status;
  3307. }
  3308. if(secondInterrupt) {
  3309. DebugPrint((1, "SpInitializeAdapter: SCSI adapter second IRQ is %d\n",
  3310. configInfo->BusInterruptLevel2));
  3311. DebugPrint((1, "SpInitializeAdapter: vector = %d\n", vector));
  3312. DebugPrint((1, "SpInitializeAdapter: irql = %d\n", irql));
  3313. DebugPrint((1, "SpInitializeAdapter: affinity = %#08lx\n", affinity));
  3314. status = IoConnectInterrupt(
  3315. &fdoExtension->InterruptObject2,
  3316. (PKSERVICE_ROUTINE) ScsiPortInterrupt,
  3317. Fdo,
  3318. &fdoExtension->MultipleIrqSpinLock,
  3319. vector2,
  3320. irql2,
  3321. syncIrql,
  3322. configInfo->InterruptMode2,
  3323. interruptSharable,
  3324. affinity2,
  3325. FALSE);
  3326. if(!NT_SUCCESS(status)) {
  3327. //
  3328. // If we needed both interrupts, we will continue but not
  3329. // claim any of the resources for the second one
  3330. //
  3331. DebugPrint((1, "SpInitializeAdapter: Can't connect "
  3332. "second interrupt %d\n", vector2));
  3333. fdoExtension->InterruptObject2 = NULL;
  3334. configInfo->BusInterruptVector2 = 0;
  3335. configInfo->BusInterruptLevel2 = 0;
  3336. }
  3337. }
  3338. }
  3339. //
  3340. // Record first access range if it exists.
  3341. //
  3342. if(configInfo->NumberOfAccessRanges != 0) {
  3343. fdoExtension->IoAddress =
  3344. ((*(configInfo->AccessRanges))[0]).RangeStart.LowPart;
  3345. DebugPrint((1, "SpInitializeAdapter: IO Base address %x\n",
  3346. fdoExtension->IoAddress));
  3347. }
  3348. //
  3349. // Indicate that a disconnect allowed command running. This bit is
  3350. // normally on.
  3351. //
  3352. fdoExtension->Flags |= PD_DISCONNECT_RUNNING;
  3353. //
  3354. // Initialize the request count to -1. This count is biased by -1 so
  3355. // that a value of zero indicates the adapter must be allocated
  3356. //
  3357. fdoExtension->ActiveRequestCount = -1;
  3358. //
  3359. // Indiciate if a scatter/gather list needs to be built.
  3360. //
  3361. if(fdoExtension->DmaAdapterObject != NULL &&
  3362. configInfo->Master &&
  3363. configInfo->NeedPhysicalAddresses) {
  3364. fdoExtension->MasterWithAdapter = TRUE;
  3365. } else {
  3366. fdoExtension->MasterWithAdapter = FALSE;
  3367. }
  3368. //
  3369. // Call the hardware dependant driver to do it's initialization.
  3370. // This routine must be called at DISPATCH_LEVEL.
  3371. //
  3372. KeRaiseIrql(DISPATCH_LEVEL, &irql);
  3373. if(!fdoExtension->SynchronizeExecution(fdoExtension->InterruptObject,
  3374. fdoExtension->HwInitialize,
  3375. fdoExtension->HwDeviceExtension)) {
  3376. DebugPrint((1, "SpInitializeAdapter: initialization failed\n"));
  3377. KeLowerIrql(irql);
  3378. return STATUS_ADAPTER_HARDWARE_ERROR;
  3379. }
  3380. //
  3381. // Check for miniport work requests. Note this is an unsynchronized
  3382. // test on the bit that can be set by the interrupt routine; However,
  3383. // the worst that can happen is that the completion DPC checks for work
  3384. // twice.
  3385. //
  3386. if(fdoExtension->InterruptData.InterruptFlags & PD_NOTIFICATION_REQUIRED) {
  3387. //
  3388. // Call the completion DPC directly. It must be called at dispatch
  3389. // level.
  3390. //
  3391. SpRequestCompletionDpc(Fdo);
  3392. }
  3393. KeLowerIrql(irql);
  3394. return STATUS_SUCCESS;
  3395. }
  3396. HANDLE
  3397. SpOpenDeviceKey(
  3398. IN PUNICODE_STRING RegistryPath,
  3399. IN ULONG DeviceNumber
  3400. )
  3401. /*++
  3402. Routine Description:
  3403. This routine will open the services keys for the miniport and put handles
  3404. to them into the configuration context structure.
  3405. Arguments:
  3406. RegistryPath - a pointer to the service key name for this miniport
  3407. DeviceNumber - which device too search for under the service key. -1
  3408. indicates that the default device key should be opened.
  3409. Return Value:
  3410. status
  3411. --*/
  3412. {
  3413. OBJECT_ATTRIBUTES objectAttributes;
  3414. WCHAR buffer[64];
  3415. UNICODE_STRING unicodeString;
  3416. HANDLE serviceKey;
  3417. HANDLE deviceKey = NULL;
  3418. NTSTATUS status;
  3419. PAGED_CODE();
  3420. serviceKey = SpOpenParametersKey(RegistryPath);
  3421. if(serviceKey != NULL) {
  3422. //
  3423. // Check for a Device Node. The device node applies to every device
  3424. //
  3425. if(DeviceNumber == (ULONG) -1) {
  3426. swprintf(buffer, L"Device");
  3427. } else {
  3428. swprintf(buffer, L"Device%d", DeviceNumber);
  3429. }
  3430. RtlInitUnicodeString(&unicodeString, buffer);
  3431. InitializeObjectAttributes(&objectAttributes,
  3432. &unicodeString,
  3433. OBJ_CASE_INSENSITIVE,
  3434. serviceKey,
  3435. (PSECURITY_DESCRIPTOR) NULL);
  3436. //
  3437. // It doesn't matter if this call fails or not. If it fails, then there
  3438. // is no default device node. If it works then the handle will be set.
  3439. //
  3440. ZwOpenKey(&deviceKey,
  3441. KEY_READ,
  3442. &objectAttributes);
  3443. ZwClose(serviceKey);
  3444. }
  3445. return deviceKey;
  3446. }
  3447. HANDLE
  3448. SpOpenParametersKey(
  3449. IN PUNICODE_STRING RegistryPath
  3450. )
  3451. /*++
  3452. Routine Description:
  3453. This routine will open the services keys for the miniport and put handles
  3454. to them into the configuration context structure.
  3455. Arguments:
  3456. RegistryPath - a pointer to the service key name for this miniport
  3457. Return Value:
  3458. status
  3459. --*/
  3460. {
  3461. OBJECT_ATTRIBUTES objectAttributes;
  3462. UNICODE_STRING unicodeString;
  3463. HANDLE serviceKey;
  3464. NTSTATUS status;
  3465. PAGED_CODE();
  3466. //
  3467. // Open the service node
  3468. //
  3469. InitializeObjectAttributes(&objectAttributes,
  3470. RegistryPath,
  3471. OBJ_CASE_INSENSITIVE,
  3472. NULL,
  3473. (PSECURITY_DESCRIPTOR) NULL);
  3474. status = ZwOpenKey(&serviceKey, KEY_READ, &objectAttributes);
  3475. if(!NT_SUCCESS(status)) {
  3476. DebugPrint((1, "SpOpenParameterKey: cannot open service key node for "
  3477. "driver. Name: %wZ Status: %08lx\n",
  3478. RegistryPath, status));
  3479. }
  3480. //
  3481. // Try to open the parameters key. If it exists then replace the service
  3482. // key with the new key. This allows the device nodes to be placed
  3483. // under DriverName\Parameters\Device or DriverName\Device
  3484. //
  3485. if(serviceKey != NULL) {
  3486. HANDLE parametersKey;
  3487. //
  3488. // Check for a device node. The device node applies to every device
  3489. //
  3490. RtlInitUnicodeString(&unicodeString, L"Parameters");
  3491. InitializeObjectAttributes(&objectAttributes,
  3492. &unicodeString,
  3493. OBJ_CASE_INSENSITIVE,
  3494. serviceKey,
  3495. (PSECURITY_DESCRIPTOR) NULL);
  3496. //
  3497. // Attempt to open the parameters key
  3498. //
  3499. status = ZwOpenKey(&parametersKey,
  3500. KEY_READ,
  3501. &objectAttributes);
  3502. if(NT_SUCCESS(status)) {
  3503. //
  3504. // There is a Parameters key. Use that instead of the service
  3505. // node key. Close the service node and set the new value
  3506. //
  3507. ZwClose(serviceKey);
  3508. serviceKey = parametersKey;
  3509. }
  3510. }
  3511. return serviceKey;
  3512. }
  3513. ULONG
  3514. SpQueryPnpInterfaceFlags(
  3515. IN PSCSIPORT_DRIVER_EXTENSION DriverExtension,
  3516. IN INTERFACE_TYPE InterfaceType
  3517. )
  3518. /*++
  3519. Routine Description:
  3520. This routine will look up the interface type in the PnpInterface value
  3521. in the service's parameters key. If the interface is found in this binary
  3522. value the routine will return TRUE. If the interface type is not there or
  3523. if any errors occur reading the data, this routine will return FALSE.
  3524. Arguments:
  3525. ConfigurationContext - a pointer to the configuration context for this
  3526. miniport
  3527. InterfaceType - the interface type we are searching for
  3528. Return Value:
  3529. TRUE if the interface type is in the safe list
  3530. FALSE if the interface type is not in the safe list or if the value cannot
  3531. be found
  3532. --*/
  3533. {
  3534. ULONG i;
  3535. PAGED_CODE();
  3536. for(i = 0; i < DriverExtension->PnpInterfaceCount; i++) {
  3537. if(DriverExtension->PnpInterface[i].InterfaceType == InterfaceType) {
  3538. DebugPrint((2, "SpQueryPnpInterfaceFlags: interface %d has flags "
  3539. "%#08lx\n",
  3540. InterfaceType,
  3541. DriverExtension->PnpInterface[i].Flags));
  3542. return DriverExtension->PnpInterface[i].Flags;
  3543. }
  3544. }
  3545. DebugPrint((2, "SpQueryPnpInterfaceFlags: No interface flags for %d\n",
  3546. InterfaceType));
  3547. return SP_PNP_NOT_SAFE;
  3548. }
  3549. ULONG
  3550. ScsiPortGetBusData(
  3551. IN PVOID DeviceExtension,
  3552. IN ULONG BusDataType,
  3553. IN ULONG SystemIoBusNumber,
  3554. IN ULONG SlotNumber,
  3555. IN PVOID Buffer,
  3556. IN ULONG Length
  3557. )
  3558. /*++
  3559. Routine Description:
  3560. The function returns the bus data for an adapter slot or CMOS address.
  3561. Arguments:
  3562. BusDataType - Supplies the type of bus.
  3563. BusNumber - Indicates which bus.
  3564. Buffer - Supplies the space to store the data.
  3565. Length - Supplies a count in bytes of the maximum amount to return.
  3566. Return Value:
  3567. Returns the amount of data stored into the buffer.
  3568. --*/
  3569. {
  3570. PADAPTER_EXTENSION fdoExtension = GET_FDO_EXTENSION(DeviceExtension);
  3571. PDEVICE_OBJECT lowerDevice = NULL;
  3572. CM_EISA_SLOT_INFORMATION slotInformation;
  3573. //
  3574. // If this is in a virtualized slot then setup the lower device object
  3575. // pointer to go to the PDO
  3576. //
  3577. if(fdoExtension->IsInVirtualSlot) {
  3578. //
  3579. // Make sure the bus and slot number are correct
  3580. //
  3581. if(SlotNumber != fdoExtension->VirtualSlotNumber.u.AsULONG) {
  3582. ASSERT(BusDataType == PCIConfiguration);
  3583. return 2;
  3584. }
  3585. lowerDevice = fdoExtension->CommonExtension.LowerDeviceObject;
  3586. }
  3587. //
  3588. // If the length is nonzero, retrieve the requested data.
  3589. //
  3590. if (Length != 0) {
  3591. return SpGetBusData(fdoExtension,
  3592. lowerDevice,
  3593. BusDataType,
  3594. SystemIoBusNumber,
  3595. SlotNumber,
  3596. Buffer,
  3597. Length);
  3598. }
  3599. //
  3600. // Free any previously allocated data.
  3601. //
  3602. if (fdoExtension->MapRegisterBase != NULL) {
  3603. ExFreePool(fdoExtension->MapRegisterBase);
  3604. fdoExtension->MapRegisterBase = NULL;
  3605. }
  3606. if (BusDataType == EisaConfiguration) {
  3607. //
  3608. // Determine the length to allocate based on the number of functions
  3609. // for the slot.
  3610. //
  3611. Length = SpGetBusData( fdoExtension,
  3612. lowerDevice,
  3613. BusDataType,
  3614. SystemIoBusNumber,
  3615. SlotNumber,
  3616. &slotInformation,
  3617. sizeof(CM_EISA_SLOT_INFORMATION));
  3618. if (Length < sizeof(CM_EISA_SLOT_INFORMATION)) {
  3619. //
  3620. // The data is messed up since this should never occur
  3621. //
  3622. return 0;
  3623. }
  3624. //
  3625. // Calculate the required length based on the number of functions.
  3626. //
  3627. Length = sizeof(CM_EISA_SLOT_INFORMATION) +
  3628. (sizeof(CM_EISA_FUNCTION_INFORMATION) * slotInformation.NumberFunctions);
  3629. } else if (BusDataType == PCIConfiguration) {
  3630. //
  3631. // Read only the header.
  3632. //
  3633. Length = PCI_COMMON_HDR_LENGTH;
  3634. } else {
  3635. Length = PAGE_SIZE;
  3636. }
  3637. fdoExtension->MapRegisterBase =
  3638. SpAllocatePool(NonPagedPool,
  3639. Length,
  3640. SCSIPORT_TAG_BUS_DATA,
  3641. fdoExtension->DeviceObject->DriverObject);
  3642. ASSERT_FDO(fdoExtension->DeviceObject);
  3643. if (fdoExtension->MapRegisterBase == NULL) {
  3644. return 0;
  3645. }
  3646. //
  3647. // Return the pointer to the miniport driver.
  3648. //
  3649. *((PVOID *)Buffer) = fdoExtension->MapRegisterBase;
  3650. return SpGetBusData(fdoExtension,
  3651. lowerDevice,
  3652. BusDataType,
  3653. SystemIoBusNumber,
  3654. SlotNumber,
  3655. fdoExtension->MapRegisterBase,
  3656. Length);
  3657. }
  3658. ULONG
  3659. SpGetBusData(
  3660. IN PADAPTER_EXTENSION Adapter,
  3661. IN PDEVICE_OBJECT Pdo OPTIONAL,
  3662. IN BUS_DATA_TYPE BusDataType,
  3663. IN ULONG BusNumber,
  3664. IN ULONG SlotNumber,
  3665. IN PVOID Buffer,
  3666. IN ULONG Length
  3667. )
  3668. /*++
  3669. Routine Description:
  3670. This routine will retrieve bus data from the specified slot and bus number
  3671. or from the supplied physical device object. If bus and slot number are
  3672. supplied it will tranlate into a call to HalGetBusData.
  3673. If a PDO is supplied instead this will issue an IRP_MN_READ_CONFIG to the
  3674. lower level driver.
  3675. This routine allocates memory and waits for irp completion - it should not
  3676. be called above passive level.
  3677. Arguments:
  3678. Pdo - if this is non-NULL then it should be a pointer to the top of the
  3679. device object stack for the PDO representing this adapter
  3680. BusNumber - if PDO is NULL then this should be the bus number the adapter
  3681. sits on - zero otherwise
  3682. SlotNumber - if PDO is NULL then this is the number of the slot the
  3683. adapter is installed into - zero otherwise
  3684. Buffer - location to store the returned data
  3685. Length - size of above
  3686. Return Value:
  3687. status
  3688. --*/
  3689. {
  3690. //
  3691. // if the user didn't specify a PDO to query then just throw this request
  3692. // to the HAL
  3693. //
  3694. if(Pdo == NULL) {
  3695. #if defined(NO_LEGACY_DRIVERS)
  3696. DebugPrint((1,"SpGetBusData: NULL PDO, not supported for 64-bits.\n"));
  3697. return STATUS_INVALID_PARAMETER;
  3698. #else
  3699. return HalGetBusData(BusDataType,
  3700. BusNumber,
  3701. SlotNumber,
  3702. Buffer,
  3703. Length);
  3704. #endif // NO_LEGACY_DRIVERS
  3705. } else {
  3706. ASSERT(Adapter->LowerBusInterfaceStandardRetrieved == TRUE);
  3707. return Adapter->LowerBusInterfaceStandard.GetBusData(
  3708. Adapter->LowerBusInterfaceStandard.Context,
  3709. BusDataType,
  3710. Buffer,
  3711. 0L,
  3712. Length);
  3713. }
  3714. }
  3715. NTSTATUS
  3716. SpInitializeSrbDataLookasideList(
  3717. IN PDEVICE_OBJECT AdapterObject
  3718. )
  3719. {
  3720. KIRQL oldIrql;
  3721. ULONG adapterTag;
  3722. PDEVICE_OBJECT *newAdapterList;
  3723. PDEVICE_OBJECT *oldAdapterList = NULL;
  3724. NTSTATUS status = STATUS_SUCCESS;
  3725. #ifdef ALLOC_PRAGMA
  3726. PVOID sectionHandle = MmLockPagableCodeSection(
  3727. SpInitializeSrbDataLookasideList);
  3728. InterlockedIncrement(&SpPAGELOCKLockCount);
  3729. #endif
  3730. //
  3731. // Add our device object to the global adapter list. This will require
  3732. // increasing the size of the list.
  3733. //
  3734. KeAcquireSpinLock(&ScsiGlobalAdapterListSpinLock, &oldIrql);
  3735. try {
  3736. adapterTag = ScsiGlobalAdapterListElements;
  3737. newAdapterList = SpAllocatePool(
  3738. NonPagedPool,
  3739. (sizeof(PDEVICE_OBJECT) * (adapterTag + 1)),
  3740. SCSIPORT_TAG_GLOBAL,
  3741. AdapterObject->DriverObject);
  3742. if(newAdapterList == NULL) {
  3743. status = STATUS_INSUFFICIENT_RESOURCES;
  3744. leave;
  3745. }
  3746. ScsiGlobalAdapterListElements += 1;
  3747. if(ScsiGlobalAdapterList != NULL) {
  3748. RtlCopyMemory(newAdapterList,
  3749. ScsiGlobalAdapterList,
  3750. (sizeof(PDEVICE_OBJECT) * adapterTag));
  3751. }
  3752. newAdapterList[adapterTag] = AdapterObject;
  3753. oldAdapterList = ScsiGlobalAdapterList;
  3754. ScsiGlobalAdapterList = newAdapterList;
  3755. if(oldAdapterList != NULL) {
  3756. ExFreePool(oldAdapterList);
  3757. }
  3758. } finally {
  3759. KeReleaseSpinLock(&ScsiGlobalAdapterListSpinLock, oldIrql);
  3760. }
  3761. #ifdef ALLOC_PRAGMA
  3762. MmUnlockPagableImageSection(sectionHandle);
  3763. InterlockedDecrement(&SpPAGELOCKLockCount);
  3764. #endif
  3765. if(NT_SUCCESS(status)) {
  3766. PADAPTER_EXTENSION adapterExtension = AdapterObject->DeviceExtension;
  3767. //
  3768. // Create the lookaside list for SRB_DATA blobs. Make sure there's
  3769. // enough space for a small scatter gather list allocated in the
  3770. // structure as well.
  3771. //
  3772. ExInitializeNPagedLookasideList(
  3773. &adapterExtension->SrbDataLookasideList,
  3774. (PALLOCATE_FUNCTION) SpAllocateSrbDataBackend,
  3775. (PFREE_FUNCTION) SpFreeSrbDataBackend,
  3776. 0L,
  3777. sizeof(SRB_DATA),
  3778. adapterTag,
  3779. SRB_LIST_DEPTH);
  3780. adapterExtension->SrbDataListInitialized = TRUE;
  3781. }
  3782. return status;
  3783. }
  3784. #define SP_KEY_VALUE_BUFFER_SIZE 255
  3785. NTSTATUS
  3786. SpAllocateDriverExtension(
  3787. IN PDRIVER_OBJECT DriverObject,
  3788. IN PUNICODE_STRING RegistryPath,
  3789. OUT PSCSIPORT_DRIVER_EXTENSION *DriverExtension
  3790. )
  3791. /*++
  3792. Routine Description:
  3793. This routine will determine the proper size for the scsiport driver
  3794. extension (based on the number of PnpInterface flags recorded in the
  3795. services key)
  3796. --*/
  3797. {
  3798. PSCSIPORT_DRIVER_EXTENSION driverExtension = NULL;
  3799. OBJECT_ATTRIBUTES objectAttributes;
  3800. UNICODE_STRING unicodeString;
  3801. HANDLE serviceKey = NULL;
  3802. HANDLE parametersKey = NULL;
  3803. HANDLE interfaceKey = NULL;
  3804. STORAGE_BUS_TYPE busType;
  3805. ULONG passes;
  3806. NTSTATUS status;
  3807. PAGED_CODE();
  3808. *DriverExtension = NULL;
  3809. DebugPrint((1, "SpAllocateDriverExtension: Allocating extension for "
  3810. "driver %wZ\n", &DriverObject->DriverName));
  3811. try {
  3812. //
  3813. // Try to open the services key first
  3814. //
  3815. InitializeObjectAttributes(
  3816. &objectAttributes,
  3817. RegistryPath,
  3818. OBJ_CASE_INSENSITIVE,
  3819. NULL,
  3820. NULL);
  3821. status = ZwOpenKey(&serviceKey, KEY_READ, &objectAttributes);
  3822. if(!NT_SUCCESS(status)) {
  3823. DebugPrint((1, "SpAllocateDriverExtension: Unable to open registry "
  3824. "key %wZ [%#08lx]\n",
  3825. RegistryPath,
  3826. status));
  3827. leave;
  3828. }
  3829. //
  3830. // Open the parameters key
  3831. //
  3832. RtlInitUnicodeString(&unicodeString, L"Parameters");
  3833. InitializeObjectAttributes(&objectAttributes,
  3834. &unicodeString,
  3835. OBJ_CASE_INSENSITIVE,
  3836. serviceKey,
  3837. NULL);
  3838. status = ZwOpenKey(&parametersKey, KEY_READ, &objectAttributes);
  3839. if(!NT_SUCCESS(status)) {
  3840. DebugPrint((1, "SpAllocateDriverExtension: Unable to open "
  3841. "parameters key of %wZ [%#08lx]\n",
  3842. RegistryPath,
  3843. status));
  3844. leave;
  3845. }
  3846. //
  3847. // Try to determine the bus type for this driver.
  3848. //
  3849. RtlInitUnicodeString(&(unicodeString), L"BusType");
  3850. {
  3851. ULONG tmp;
  3852. status = SpReadNumericValue(parametersKey,
  3853. NULL,
  3854. &unicodeString,
  3855. &tmp);
  3856. busType = (STORAGE_BUS_TYPE) tmp;
  3857. }
  3858. if(NT_SUCCESS(status)) {
  3859. switch(busType) {
  3860. case BusTypeScsi:
  3861. case BusTypeAtapi:
  3862. case BusTypeAta:
  3863. case BusTypeSsa:
  3864. case BusTypeFibre:
  3865. case BusTypeRAID: {
  3866. DebugPrint((1, "SpAllocateDriverExtension: Bus type set to %d\n", busType));
  3867. break;
  3868. }
  3869. default: {
  3870. busType = BusTypeScsi;
  3871. break;
  3872. }
  3873. }
  3874. } else {
  3875. busType = BusTypeScsi;
  3876. }
  3877. //
  3878. // got that one - now open the pnpinterface key.
  3879. //
  3880. RtlInitUnicodeString(&unicodeString, L"PnpInterface");
  3881. InitializeObjectAttributes(&objectAttributes,
  3882. &unicodeString,
  3883. OBJ_CASE_INSENSITIVE,
  3884. parametersKey,
  3885. NULL);
  3886. status = ZwOpenKey(&interfaceKey, KEY_READ, &objectAttributes);
  3887. if(!NT_SUCCESS(status)) {
  3888. DebugPrint((1, "SpAllocateDriverExtension: Unable to open "
  3889. "PnpInterface key of %wZ [%#08lx]\n",
  3890. &RegistryPath,
  3891. status));
  3892. leave;
  3893. }
  3894. //
  3895. // Now that we have the pnpinterface key open we enumerate the entries in
  3896. // two steps. The first is to count up the number of entries. We then
  3897. // allocate an appropriately sized driver object extension, zero it out,
  3898. // and copy the values into the PnpInterface section at the end.
  3899. //
  3900. for(passes = 0; passes < 2; passes++) {
  3901. ULONG count;
  3902. status = STATUS_SUCCESS;
  3903. for(count = 0; TRUE; count++) {
  3904. UCHAR buffer[SP_KEY_VALUE_BUFFER_SIZE];
  3905. PKEY_VALUE_FULL_INFORMATION keyValue =
  3906. (PKEY_VALUE_FULL_INFORMATION) buffer;
  3907. ULONG resultLength;
  3908. ASSERTMSG("ScsiPort configuration error - possibly too many "
  3909. "count entries: ",
  3910. count != MaximumInterfaceType);
  3911. RtlZeroMemory(buffer, sizeof(UCHAR) * SP_KEY_VALUE_BUFFER_SIZE);
  3912. status = ZwEnumerateValueKey(
  3913. interfaceKey,
  3914. count,
  3915. (passes == 0) ? KeyValueBasicInformation :
  3916. KeyValueFullInformation,
  3917. keyValue,
  3918. sizeof(buffer),
  3919. &resultLength);
  3920. if(status == STATUS_NO_MORE_ENTRIES) {
  3921. status = STATUS_SUCCESS;
  3922. break;
  3923. } else if(!NT_SUCCESS(status)) {
  3924. DebugPrint((1, "SpAllocateDriverExtension: Fatal error %#08lx "
  3925. "enumerating PnpInterface key under %wZ.",
  3926. status,
  3927. RegistryPath));
  3928. leave;
  3929. }
  3930. if(passes == 1) {
  3931. PSCSIPORT_INTERFACE_TYPE_DATA interface =
  3932. &(driverExtension->PnpInterface[count]);
  3933. UNICODE_STRING unicodeString;
  3934. ULONG t;
  3935. ASSERTMSG("ScsiPort internal error - too many pnpinterface "
  3936. "entries on second pass: ",
  3937. count <= driverExtension->PnpInterfaceCount);
  3938. //
  3939. // First turn the name of the entry into a numerical value
  3940. // so we can match it to an interface type.
  3941. //
  3942. RtlInitUnicodeString(&unicodeString, keyValue->Name);
  3943. if((keyValue->Type != REG_DWORD) &&
  3944. (keyValue->Type != REG_NONE)) {
  3945. DbgPrint("SpAllocateDriverExtension: Fatal error parsing "
  3946. "PnpInterface under %wZ - entry %wZ is not "
  3947. "a REG_DWORD or REG_NONE entry (%d instead)\n",
  3948. status,
  3949. RegistryPath,
  3950. &unicodeString);
  3951. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  3952. leave;
  3953. }
  3954. status = RtlUnicodeStringToInteger(
  3955. &unicodeString,
  3956. 0L,
  3957. &t);
  3958. if(!NT_SUCCESS(status)) {
  3959. DbgPrint("SpAllocateDriverExtension: Fatal error %#08lx "
  3960. "parsing PnpInterface under %wZ - entry %wZ is "
  3961. "not a valid interface type name\n",
  3962. status,
  3963. RegistryPath,
  3964. &unicodeString);
  3965. leave;
  3966. }
  3967. if(t > MaximumInterfaceType) {
  3968. DbgPrint("SpAllocateDriverExtension: Fatal error "
  3969. "parsing PnpInterface under %wZ - entry %wZ is "
  3970. "> MaximumInterfaceType (%d)\n",
  3971. status,
  3972. RegistryPath,
  3973. &unicodeString);
  3974. interface->InterfaceType = InterfaceTypeUndefined;
  3975. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  3976. leave;
  3977. }
  3978. interface->InterfaceType = (INTERFACE_TYPE) t;
  3979. if(keyValue->Type == REG_NONE) {
  3980. interface->Flags = 0L;
  3981. } else {
  3982. interface->Flags = *(((PUCHAR) keyValue) +
  3983. keyValue->DataOffset);
  3984. if(interface->Flags & SP_PNP_IS_SAFE) {
  3985. ASSERT(driverExtension != NULL);
  3986. driverExtension->SafeInterfaceCount++;
  3987. }
  3988. switch(interface->InterfaceType) {
  3989. case PCIBus: {
  3990. SET_FLAG(interface->Flags,
  3991. SP_PNP_NEEDS_LOCATION);
  3992. SET_FLAG(interface->Flags,
  3993. SP_PNP_INTERRUPT_REQUIRED);
  3994. CLEAR_FLAG(interface->Flags,
  3995. SP_PNP_NON_ENUMERABLE);
  3996. break;
  3997. }
  3998. case Internal:
  3999. case PNPISABus:
  4000. case PNPBus:
  4001. case PCMCIABus: {
  4002. //
  4003. // These buses don't ever do detection.
  4004. //
  4005. CLEAR_FLAG(interface->Flags,
  4006. SP_PNP_NON_ENUMERABLE);
  4007. break;
  4008. }
  4009. default: {
  4010. //
  4011. // The other bus types will always do detection
  4012. // if given the chance.
  4013. //
  4014. if(!TEST_FLAG(interface->Flags,
  4015. SP_PNP_NO_LEGACY_DETECTION)) {
  4016. SET_FLAG(interface->Flags,
  4017. SP_PNP_NON_ENUMERABLE);
  4018. }
  4019. break;
  4020. }
  4021. }
  4022. }
  4023. DebugPrint((1, "SpAllocateDriverExtension: Interface %d has "
  4024. "flags %#08lx\n",
  4025. interface->InterfaceType,
  4026. interface->Flags));
  4027. }
  4028. }
  4029. if(passes == 0) {
  4030. ULONG extensionSize;
  4031. //
  4032. // We know how much extra space we need so go ahead and allocate
  4033. // the extension.
  4034. //
  4035. DebugPrint((2, "SpAllocateDriverExtension: Driver has %d interface "
  4036. "entries\n",
  4037. count));
  4038. extensionSize = sizeof(SCSIPORT_DRIVER_EXTENSION) +
  4039. (sizeof(SCSIPORT_INTERFACE_TYPE_DATA) * count);
  4040. DebugPrint((2, "SpAllocateDriverExtension: Driver extension will "
  4041. "be %d bytes\n",
  4042. extensionSize));
  4043. status = IoAllocateDriverObjectExtension(DriverObject,
  4044. ScsiPortInitialize,
  4045. extensionSize,
  4046. &driverExtension);
  4047. if(!NT_SUCCESS(status)) {
  4048. DebugPrint((1, "SpAllocateDriverExtension: Fatal error %#08lx "
  4049. "allocating driver extension\n", status));
  4050. leave;
  4051. }
  4052. RtlZeroMemory(driverExtension, extensionSize);
  4053. driverExtension->PnpInterfaceCount = count;
  4054. }
  4055. }
  4056. ASSERTMSG("ScsiPortAllocateDriverExtension internal error: left first "
  4057. "section with non-success status: ",
  4058. NT_SUCCESS(status));
  4059. } finally {
  4060. //
  4061. // If the driver extension has not been allocated then go ahead and
  4062. // do that here.
  4063. //
  4064. if(driverExtension == NULL) {
  4065. DebugPrint((1, "SpAllocateDriverExtension: Driver has 0 interface "
  4066. "entries\n"));
  4067. DebugPrint((2, "SpAllocateDriverExtension: Driver extension will "
  4068. "be %d bytes\n",
  4069. sizeof(SCSIPORT_DRIVER_EXTENSION)));
  4070. status = IoAllocateDriverObjectExtension(DriverObject,
  4071. ScsiPortInitialize,
  4072. sizeof(SCSIPORT_DRIVER_EXTENSION),
  4073. &driverExtension);
  4074. if(!NT_SUCCESS(status)) {
  4075. DebugPrint((1, "SpAllocateDriverExtension: Fatal error %#08lx "
  4076. "allocating driver extension\n", status));
  4077. goto Finally_Cleanup;
  4078. }
  4079. RtlZeroMemory(driverExtension, sizeof(SCSIPORT_DRIVER_EXTENSION));
  4080. } else {
  4081. driverExtension->BusType = busType;
  4082. }
  4083. status = STATUS_SUCCESS;
  4084. Finally_Cleanup:;
  4085. }
  4086. if (status != STATUS_SUCCESS)
  4087. goto Cleanup;
  4088. //
  4089. // initialize the remaining fields in the driver object extension.
  4090. //
  4091. driverExtension->ReserveAllocFailureLogEntry = SpAllocateErrorLogEntry(DriverObject);
  4092. driverExtension->UnusedPage = NULL;
  4093. driverExtension->UnusedPageMdl = NULL;
  4094. driverExtension->InvalidPage = NULL;
  4095. driverExtension->DriverObject = DriverObject;
  4096. driverExtension->RegistryPath = *RegistryPath;
  4097. driverExtension->RegistryPath.MaximumLength += sizeof(WCHAR);
  4098. driverExtension->RegistryPath.Buffer =
  4099. SpAllocatePool(PagedPool,
  4100. driverExtension->RegistryPath.MaximumLength,
  4101. SCSIPORT_TAG_REGISTRY,
  4102. DriverObject);
  4103. if(driverExtension->RegistryPath.Buffer == NULL) {
  4104. DebugPrint((1, "SpAllocateDriverExtension: Fatal error "
  4105. "allocating copy of registry path\n"));
  4106. status = STATUS_INSUFFICIENT_RESOURCES;
  4107. goto Cleanup;
  4108. }
  4109. RtlCopyUnicodeString(&(driverExtension->RegistryPath),
  4110. RegistryPath);
  4111. //
  4112. // Now get the values of the LegacyAdapterDetection flags.
  4113. //
  4114. //
  4115. // Set it to a good default value in case we error out getting the flags
  4116. //
  4117. if(ScsiPortLegacyAdapterDetection) {
  4118. //
  4119. // Global flag breaks scissors
  4120. //
  4121. driverExtension->LegacyAdapterDetection = TRUE;
  4122. } else {
  4123. if(parametersKey != NULL) {
  4124. UNICODE_STRING valueName;
  4125. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  4126. PKEY_VALUE_PARTIAL_INFORMATION keyValueInformation =
  4127. (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  4128. ULONG length;
  4129. RtlInitUnicodeString(&valueName, L"LegacyAdapterDetection");
  4130. status = ZwQueryValueKey(parametersKey,
  4131. &valueName,
  4132. KeyValuePartialInformation,
  4133. keyValueInformation,
  4134. sizeof(buffer),
  4135. &length);
  4136. if(NT_SUCCESS(status) &&
  4137. (length >= sizeof(KEY_VALUE_PARTIAL_INFORMATION)) &&
  4138. (keyValueInformation->Type == REG_DWORD)) {
  4139. ULONG data = *((PULONG) keyValueInformation->Data);
  4140. driverExtension->LegacyAdapterDetection = (data == 1);
  4141. //
  4142. // Rewrite a zero in to the value.
  4143. //
  4144. data = 0;
  4145. status = ZwSetValueKey(parametersKey,
  4146. &valueName,
  4147. keyValueInformation->TitleIndex,
  4148. REG_DWORD,
  4149. &data,
  4150. sizeof(data));
  4151. if(!NT_SUCCESS(status)) {
  4152. DebugPrint((1, "SpAllocateDriverExtension: Error %#08lx "
  4153. "setting LegacyAdapterDetection value to "
  4154. "zero\n", status));
  4155. status = STATUS_SUCCESS;
  4156. }
  4157. } else {
  4158. driverExtension->LegacyAdapterDetection = FALSE;
  4159. }
  4160. }
  4161. if(driverExtension->LegacyAdapterDetection == FALSE) {
  4162. UNICODE_STRING unicodeKeyName;
  4163. UNICODE_STRING unicodeClassGuid;
  4164. HANDLE controlClassKey = NULL;
  4165. HANDLE scsiAdapterKey = NULL;
  4166. RtlInitUnicodeString(&unicodeClassGuid, NULL);
  4167. //
  4168. // Miniport doesn't want to do detection. Check to see if the
  4169. // global port driver flag has been switched on.
  4170. //
  4171. RtlInitUnicodeString(
  4172. &unicodeString,
  4173. L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Class");
  4174. RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES));
  4175. InitializeObjectAttributes(
  4176. &objectAttributes,
  4177. &unicodeString,
  4178. OBJ_CASE_INSENSITIVE,
  4179. NULL,
  4180. NULL);
  4181. try {
  4182. status = ZwOpenKey(&controlClassKey,
  4183. KEY_READ,
  4184. &objectAttributes);
  4185. if(!NT_SUCCESS(status)) {
  4186. DebugPrint((1, "SpAllocateDriverExtension: Error %#08lx "
  4187. "opening key %wZ\n",
  4188. status,
  4189. &unicodeString));
  4190. leave;
  4191. }
  4192. //
  4193. // Now open up the GUID key for our device.
  4194. //
  4195. status = RtlStringFromGUID(&GUID_DEVCLASS_SCSIADAPTER,
  4196. &unicodeClassGuid);
  4197. if(!NT_SUCCESS(status)) {
  4198. DebugPrint((1, "SpAllocateDriverExtension: Error %#08lx "
  4199. "converting GUID to unicode string\n",
  4200. status));
  4201. leave;
  4202. }
  4203. RtlZeroMemory(&objectAttributes, sizeof(OBJECT_ATTRIBUTES));
  4204. InitializeObjectAttributes(&objectAttributes,
  4205. &unicodeClassGuid,
  4206. OBJ_CASE_INSENSITIVE,
  4207. controlClassKey,
  4208. NULL);
  4209. status = ZwOpenKey(&scsiAdapterKey,
  4210. KEY_READ,
  4211. &objectAttributes);
  4212. if(!NT_SUCCESS(status)) {
  4213. DebugPrint((1, "SpAllocateDriverExtension: Error %#08lx "
  4214. "opening class key %wZ\n",
  4215. status,
  4216. &unicodeClassGuid));
  4217. leave;
  4218. } else {
  4219. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
  4220. sizeof(ULONG)];
  4221. PKEY_VALUE_PARTIAL_INFORMATION keyInfo =
  4222. (PKEY_VALUE_PARTIAL_INFORMATION) buffer;
  4223. ULONG infoLength;
  4224. RtlInitUnicodeString(&unicodeString,
  4225. L"LegacyAdapterDetection");
  4226. status = ZwQueryValueKey(scsiAdapterKey,
  4227. &unicodeString,
  4228. KeyValuePartialInformation,
  4229. keyInfo,
  4230. sizeof(buffer),
  4231. &infoLength);
  4232. if(!NT_SUCCESS(status)) {
  4233. DebugPrint((2, "SpAllocateDriverExtension: Error "
  4234. "%#08lx reading key %wZ\n",
  4235. status,
  4236. &unicodeString));
  4237. status = STATUS_SUCCESS;
  4238. leave;
  4239. }
  4240. if(*((PULONG) keyInfo->Data) == 0) {
  4241. driverExtension->LegacyAdapterDetection = FALSE;
  4242. } else {
  4243. driverExtension->LegacyAdapterDetection = TRUE;
  4244. }
  4245. }
  4246. } finally {
  4247. if(controlClassKey != NULL) {
  4248. ZwClose(controlClassKey);
  4249. }
  4250. if(scsiAdapterKey != NULL) {
  4251. ZwClose(scsiAdapterKey);
  4252. }
  4253. RtlFreeUnicodeString(&unicodeClassGuid);
  4254. }
  4255. }
  4256. status = STATUS_SUCCESS;
  4257. }
  4258. Cleanup:
  4259. //
  4260. // If we got out of everything above and didn't allocate a driver
  4261. // extension then
  4262. if(serviceKey) {
  4263. ZwClose(serviceKey);
  4264. }
  4265. if(parametersKey) {
  4266. ZwClose(parametersKey);
  4267. }
  4268. if(interfaceKey) {
  4269. ZwClose(interfaceKey);
  4270. }
  4271. if(NT_SUCCESS(status)) {
  4272. *DriverExtension = driverExtension;
  4273. }
  4274. return status;
  4275. }
  4276. extern ULONG ScsiPortVerifierInitialized;
  4277. NTSTATUS DllInitialize(
  4278. IN PUNICODE_STRING RegistryPath
  4279. )
  4280. {
  4281. HANDLE VerifierKey;
  4282. UNICODE_STRING Name;
  4283. OBJECT_ATTRIBUTES ObjectAttributes;
  4284. NTSTATUS Status;
  4285. ULONG ResultLength;
  4286. UCHAR buffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  4287. PKEY_VALUE_PARTIAL_INFORMATION ValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
  4288. //
  4289. // Check the verification level first; someone may have poked the value
  4290. // from the debugger to prevent us from doing any verifier initialization.
  4291. //
  4292. if (SpVrfyLevel == SP_VRFY_NONE) {
  4293. return STATUS_SUCCESS;
  4294. }
  4295. //
  4296. // Read the global verification level from the registry. If the value is
  4297. // not present or if the value indicates 'no verification', we don't want
  4298. // to do any verifier initialization at all.
  4299. //
  4300. RtlInitUnicodeString(&Name, SCSIPORT_CONTROL_KEY SCSIPORT_VERIFIER_KEY);
  4301. InitializeObjectAttributes(&ObjectAttributes,
  4302. &Name,
  4303. OBJ_CASE_INSENSITIVE,
  4304. NULL,
  4305. NULL);
  4306. Status = ZwOpenKey(&VerifierKey, KEY_READ, &ObjectAttributes);
  4307. if (NT_SUCCESS(Status)) {
  4308. RtlInitUnicodeString(&Name, L"VerifyLevel");
  4309. Status = ZwQueryValueKey(VerifierKey,
  4310. &Name,
  4311. KeyValuePartialInformation,
  4312. ValueInfo,
  4313. sizeof(buffer),
  4314. &ResultLength);
  4315. if (NT_SUCCESS(Status)) {
  4316. if (ValueInfo->Type == REG_DWORD) {
  4317. if (ResultLength >= sizeof(ULONG)) {
  4318. SpVrfyLevel |= ((PULONG)(ValueInfo->Data))[0];
  4319. if (SpVrfyLevel != SP_VRFY_NONE &&
  4320. ScsiPortVerifierInitialized == 0) {
  4321. //
  4322. // Ok, we found a verifier level and it did not tell us
  4323. // not to verify. Go ahead and initialize scsiport's
  4324. // verifier.
  4325. //
  4326. if (SpVerifierInitialization()) {
  4327. ScsiPortVerifierInitialized = 1;
  4328. }
  4329. }
  4330. }
  4331. }
  4332. }
  4333. ZwClose(VerifierKey);
  4334. }
  4335. return STATUS_SUCCESS;
  4336. }
  4337. VOID
  4338. SpInitializePowerParams(
  4339. IN PADAPTER_EXTENSION AdapterExtension
  4340. )
  4341. /*++
  4342. Routine Description:
  4343. This routine initializes per-adapter power parameters.
  4344. Arguments:
  4345. Adapter - Points to an adapter extension.
  4346. Return Value:
  4347. Notes:
  4348. --*/
  4349. {
  4350. NTSTATUS status;
  4351. ULONG needsShutdown;
  4352. PAGED_CODE();
  4353. //
  4354. // If this is not a pnp device, don't attempt to read registry info.
  4355. //
  4356. if (AdapterExtension->IsPnp == FALSE) {
  4357. AdapterExtension->NeedsShutdown = FALSE;
  4358. return;
  4359. }
  4360. status = SpReadNumericInstanceValue(AdapterExtension->LowerPdo,
  4361. L"NeedsSystemShutdownNotification",
  4362. &needsShutdown);
  4363. if (!NT_SUCCESS(status)) {
  4364. AdapterExtension->NeedsShutdown = 0;
  4365. } else {
  4366. AdapterExtension->NeedsShutdown = (needsShutdown == 0) ? FALSE : TRUE;
  4367. }
  4368. }
  4369. VOID
  4370. SpInitializePerformanceParams(
  4371. IN PADAPTER_EXTENSION AdapterExtension
  4372. )
  4373. /*++
  4374. Routine Description:
  4375. This routine initializes per-adapter tunable performance parameters.
  4376. Arguments:
  4377. Adapter - Points to an adapter extension.
  4378. Return Value:
  4379. Notes:
  4380. --*/
  4381. {
  4382. NTSTATUS status;
  4383. ULONG remainInReducedMaxQueueState;
  4384. PAGED_CODE();
  4385. //
  4386. // If this isn't a pnp device, don't attempt to get parameters.
  4387. //
  4388. if (AdapterExtension->IsPnp == FALSE) {
  4389. AdapterExtension->RemainInReducedMaxQueueState = 0xffffffff;
  4390. return;
  4391. }
  4392. status = SpReadNumericInstanceValue(AdapterExtension->LowerPdo,
  4393. L"RemainInReducedMaxQueueState",
  4394. &remainInReducedMaxQueueState);
  4395. if (!NT_SUCCESS(status)) {
  4396. AdapterExtension->RemainInReducedMaxQueueState = 0xffffffff;
  4397. } else {
  4398. AdapterExtension->RemainInReducedMaxQueueState = remainInReducedMaxQueueState;
  4399. }
  4400. }
  4401. VOID
  4402. SpInitializeRequestSenseParams(
  4403. IN PADAPTER_EXTENSION AdapterExtension
  4404. )
  4405. /*++
  4406. Routine Description:
  4407. This routine returns the number of additonal sense bytes supported
  4408. by the specified adapter. By default, an adapter will support
  4409. zero additional sense bytes. The default is overridden by
  4410. specifying an alternative via the registry.
  4411. Arguments:
  4412. Adapter - Points to an adapter extension.
  4413. Return Value:
  4414. Notes:
  4415. --*/
  4416. {
  4417. NTSTATUS status;
  4418. ULONG TotalSenseDataBytes;
  4419. ULONG RequestSenseTimeout;
  4420. PAGED_CODE();
  4421. //
  4422. // If this isn't a pnp device, don't attempt to determine
  4423. // if it supports additional sense data.
  4424. //
  4425. if (AdapterExtension->IsPnp == FALSE) {
  4426. AdapterExtension->AdditionalSenseBytes = 0;
  4427. AdapterExtension->RequestSenseTimeout = 2;
  4428. return;
  4429. }
  4430. status = SpReadNumericInstanceValue(AdapterExtension->LowerPdo,
  4431. L"TotalSenseDataBytes",
  4432. &TotalSenseDataBytes);
  4433. if (!NT_SUCCESS(status)) {
  4434. //
  4435. // Value is absent. No additional sense bytes.
  4436. //
  4437. AdapterExtension->AdditionalSenseBytes = 0;
  4438. } else {
  4439. //
  4440. // The acceptable range of values is [18..255].
  4441. //
  4442. if (TotalSenseDataBytes <= SENSE_BUFFER_SIZE) {
  4443. AdapterExtension->AdditionalSenseBytes = 0;
  4444. } else if (TotalSenseDataBytes >= MAX_SENSE_BUFFER_SIZE) {
  4445. AdapterExtension->AdditionalSenseBytes = MAX_ADDITIONAL_SENSE_BYTES;
  4446. } else {
  4447. //
  4448. // The value in the registry is valid. The number of additional
  4449. // sense bytes is TotalSize - StandardSize.
  4450. //
  4451. AdapterExtension->AdditionalSenseBytes =
  4452. (UCHAR)(TotalSenseDataBytes - SENSE_BUFFER_SIZE);
  4453. }
  4454. }
  4455. status = SpReadNumericInstanceValue(AdapterExtension->LowerPdo,
  4456. L"RequestSenseTimeout",
  4457. &RequestSenseTimeout);
  4458. if (!NT_SUCCESS(status)) {
  4459. //
  4460. // Value is absent. Use the default request sense timeout of 2 seconds.
  4461. //
  4462. AdapterExtension->RequestSenseTimeout = 2;
  4463. } else {
  4464. AdapterExtension->RequestSenseTimeout = (UCHAR) RequestSenseTimeout;
  4465. }
  4466. }