Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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