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.

2949 lines
81 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1990 - 1999
  3. Module Name:
  4. pnp.c
  5. Abstract:
  6. This is the NT SCSI port driver. This file contains the self-contained plug
  7. and play code.
  8. Authors:
  9. Peter Wieland
  10. Environment:
  11. kernel mode only
  12. Notes:
  13. This module is a driver dll for scsi miniports.
  14. Revision History:
  15. --*/
  16. #include "port.h"
  17. #include <wdmguid.h>
  18. #define __FILE_ID__ 'pnp '
  19. #if DBG
  20. static const char *__file__ = __FILE__;
  21. #endif
  22. #define NUM_DEVICE_TYPE_INFO_ENTRIES 18
  23. extern SCSIPORT_DEVICE_TYPE DeviceTypeInfo[];
  24. ULONG SpAdapterStopRemoveSupported = TRUE;
  25. NTSTATUS
  26. SpQueryCapabilities(
  27. IN PADAPTER_EXTENSION Adapter
  28. );
  29. PWCHAR
  30. ScsiPortAddGenericControllerId(
  31. IN PDRIVER_OBJECT DriverObject,
  32. IN PWCHAR IdList
  33. );
  34. VOID
  35. CopyField(
  36. IN PUCHAR Destination,
  37. IN PUCHAR Source,
  38. IN ULONG Count,
  39. IN UCHAR Change
  40. );
  41. NTSTATUS
  42. ScsiPortInitPnpAdapter(
  43. IN PDEVICE_OBJECT Fdo
  44. );
  45. NTSTATUS
  46. SpStartLowerDevice(
  47. IN PDEVICE_OBJECT DeviceObject,
  48. IN PIRP Irp
  49. );
  50. VOID
  51. SpGetSlotNumber(
  52. IN PDEVICE_OBJECT Fdo,
  53. IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  54. IN PCM_RESOURCE_LIST ResourceList
  55. );
  56. BOOLEAN
  57. SpGetInterrupt(
  58. IN PCM_RESOURCE_LIST FullResourceList,
  59. OUT ULONG *Irql,
  60. OUT ULONG *Vector,
  61. OUT KAFFINITY *Affinity
  62. );
  63. VOID
  64. SpQueryDeviceRelationsCompletion(
  65. IN PADAPTER_EXTENSION Adapter,
  66. IN PSP_ENUMERATION_REQUEST Request,
  67. IN NTSTATUS Status
  68. );
  69. NTSTATUS
  70. ScsiPortDetermineGenId(
  71. IN PDRIVER_OBJECT DriverObject,
  72. IN PINQUIRYDATA InquiryData,
  73. OUT PUCHAR GenericId
  74. );
  75. //
  76. // Routines start
  77. //
  78. #ifdef ALLOC_PRAGMA
  79. #pragma alloc_text(PAGE, ScsiPortAddDevice)
  80. #pragma alloc_text(PAGE, ScsiPortUnload)
  81. #pragma alloc_text(PAGE, ScsiPortFdoPnp)
  82. #pragma alloc_text(PAGE, ScsiPortStartAdapter)
  83. #pragma alloc_text(PAGE, ScsiPortGetDeviceId)
  84. #pragma alloc_text(PAGE, ScsiPortGetInstanceId)
  85. #pragma alloc_text(PAGE, ScsiPortGetHardwareIds)
  86. #pragma alloc_text(PAGE, ScsiPortGetCompatibleIds)
  87. #pragma alloc_text(PAGE, ScsiPortDetermineGenId)
  88. #pragma alloc_text(PAGE, CopyField)
  89. #pragma alloc_text(PAGE, SpFindInitData)
  90. #pragma alloc_text(PAGE, SpStartLowerDevice)
  91. #pragma alloc_text(PAGE, SpGetSlotNumber)
  92. #pragma alloc_text(PAGE, SpGetDeviceTypeInfo)
  93. #pragma alloc_text(PAGE, ScsiPortAddGenericControllerId)
  94. #pragma alloc_text(PAGE, SpQueryCapabilities)
  95. #pragma alloc_text(PAGE, SpGetInterrupt)
  96. #pragma alloc_text(PAGE, SpQueryDeviceRelationsCompletion)
  97. #pragma alloc_text(PAGELOCK, ScsiPortInitPnpAdapter)
  98. #endif
  99. #ifdef ALLOC_PRAGMA
  100. #pragma code_seg("PAGE")
  101. #endif
  102. SCSIPORT_DEVICE_TYPE DeviceTypeInfo[NUM_DEVICE_TYPE_INFO_ENTRIES] = {
  103. {"Disk", "GenDisk", L"DiskPeripheral", TRUE},
  104. {"Sequential", "", L"TapePeripheral", TRUE},
  105. {"Printer", "GenPrinter", L"PrinterPeripheral", FALSE},
  106. {"Processor", "", L"OtherPeripheral", FALSE},
  107. {"Worm", "GenWorm", L"WormPeripheral", TRUE},
  108. {"CdRom", "GenCdRom", L"CdRomPeripheral", TRUE},
  109. {"Scanner", "GenScanner", L"ScannerPeripheral", FALSE},
  110. {"Optical", "GenOptical", L"OpticalDiskPeripheral", TRUE},
  111. {"Changer", "ScsiChanger", L"MediumChangerPeripheral", TRUE},
  112. {"Net", "ScsiNet", L"CommunicationsPeripheral", FALSE},
  113. {"ASCIT8", "ScsiASCIT8", L"ASCPrePressGraphicsPeripheral", FALSE},
  114. {"ASCIT8", "ScsiASCIT8", L"ASCPrePressGraphicsPeripheral", FALSE},
  115. {"Array", "ScsiArray", L"ArrayPeripheral", FALSE},
  116. {"Enclosure", "ScsiEnclosure", L"EnclosurePeripheral", FALSE},
  117. {"RBC", "ScsiRBC", L"RBCPeripheral", TRUE},
  118. {"CardReader", "ScsiCardReader", L"CardReaderPeripheral", FALSE},
  119. {"Bridge", "ScsiBridge", L"BridgePeripheral", FALSE},
  120. {"Other", "ScsiOther", L"OtherPeripheral", FALSE}
  121. };
  122. #ifdef ALLOC_PRAGMA
  123. #pragma code_seg()
  124. #endif
  125. NTSTATUS
  126. ScsiPortAddDevice(
  127. IN PDRIVER_OBJECT DriverObject,
  128. IN PDEVICE_OBJECT PhysicalDeviceObject
  129. )
  130. /*++
  131. Routine Description:
  132. This routine handles add-device requests for the scsi port driver
  133. Arguments:
  134. DriverObject - a pointer to the driver object for this device
  135. PhysicalDeviceObject - a pointer to the PDO we are being added to
  136. Return Value:
  137. STATUS_SUCCESS
  138. --*/
  139. {
  140. PSCSIPORT_DRIVER_EXTENSION driverExtension;
  141. PDEVICE_OBJECT newFdo;
  142. NTSTATUS status;
  143. PAGED_CODE();
  144. status = SpCreateAdapter(DriverObject, &newFdo);
  145. if(newFdo != NULL) {
  146. PADAPTER_EXTENSION adapter;
  147. PCOMMON_EXTENSION commonExtension;
  148. PDEVICE_OBJECT newStack;
  149. adapter = newFdo->DeviceExtension;
  150. commonExtension = &(adapter->CommonExtension);
  151. adapter->IsMiniportDetected = FALSE;
  152. adapter->IsPnp = TRUE;
  153. driverExtension = IoGetDriverObjectExtension(DriverObject,
  154. ScsiPortInitialize);
  155. switch(driverExtension->BusType) {
  156. #if 0
  157. case BusTypeFibre: {
  158. adapter->DisablePower = TRUE;
  159. adapter->DisableStop = TRUE;
  160. break;
  161. }
  162. #endif
  163. default: {
  164. adapter->DisablePower = FALSE;
  165. adapter->DisableStop = FALSE;
  166. break;
  167. }
  168. }
  169. newStack = IoAttachDeviceToDeviceStack(newFdo, PhysicalDeviceObject);
  170. adapter->CommonExtension.LowerDeviceObject = newStack;
  171. adapter->LowerPdo = PhysicalDeviceObject;
  172. if(newStack == NULL) {
  173. status = STATUS_UNSUCCESSFUL;
  174. } else {
  175. status = STATUS_SUCCESS;
  176. }
  177. }
  178. return status;
  179. }
  180. VOID
  181. ScsiPortUnload(
  182. IN PDRIVER_OBJECT DriverObject
  183. )
  184. /*++
  185. Routine Description:
  186. This routine will shut down all device objects for this miniport and
  187. clean up all allocated resources
  188. Arguments:
  189. DriverObject - the driver being unloaded
  190. Return Value:
  191. none
  192. --*/
  193. {
  194. PVOID Packet;
  195. PSCSIPORT_DRIVER_EXTENSION DriverExtension;
  196. PVOID CurrentValue;
  197. PVOID InvalidPage;
  198. PAGED_CODE();
  199. //
  200. // See if there is a driver extension for this driver. It is possible
  201. // that one has not been created yet, so this may fail, in which case
  202. // we give up and return.
  203. //
  204. DriverExtension = IoGetDriverObjectExtension(
  205. DriverObject,
  206. ScsiPortInitialize
  207. );
  208. if (DriverExtension == NULL) {
  209. return;
  210. }
  211. //
  212. // Get the reserve event in the driver extension. The reserve event
  213. // may not have already been used, so it's possible that it is NULL. If
  214. // this is the case, we give up and return.
  215. //
  216. Packet = DriverExtension->ReserveAllocFailureLogEntry;
  217. if (Packet != NULL) {
  218. //
  219. // We have to ensure that we are the only instance to use this
  220. // event. To do so, we attempt to NULL the event in the driver
  221. // extension. If somebody else beats us to it, they own the
  222. // event and we have to give up.
  223. //
  224. CurrentValue = InterlockedCompareExchangePointer(
  225. &(DriverExtension->ReserveAllocFailureLogEntry),
  226. NULL,
  227. Packet);
  228. if (Packet == CurrentValue) {
  229. IoFreeErrorLogEntry(Packet);
  230. }
  231. }
  232. //
  233. // Free the invalid page we created to catch misbehaving miniports.
  234. //
  235. InvalidPage = DriverExtension->InvalidPage;
  236. if (InvalidPage != NULL) {
  237. CurrentValue = InterlockedCompareExchangePointer(
  238. &(DriverExtension->InvalidPage),
  239. NULL,
  240. InvalidPage);
  241. if (InvalidPage == CurrentValue) {
  242. MmProtectMdlSystemAddress(DriverExtension->UnusedPageMdl, PAGE_READWRITE);
  243. MmUnlockPages(DriverExtension->UnusedPageMdl);
  244. IoFreeMdl(DriverExtension->UnusedPageMdl);
  245. ExFreePool(DriverExtension->UnusedPage);
  246. }
  247. }
  248. #ifdef ALLOC_PRAGMA
  249. if (VerifierApiCodeSectionHandle != NULL) {
  250. PVOID Handle = VerifierApiCodeSectionHandle;
  251. CurrentValue = InterlockedCompareExchangePointer(
  252. &VerifierApiCodeSectionHandle,
  253. NULL,
  254. Handle);
  255. if (CurrentValue == Handle) {
  256. MmUnlockPagableImageSection(Handle);
  257. }
  258. }
  259. #endif
  260. return;
  261. }
  262. NTSTATUS
  263. ScsiPortFdoPnp(
  264. IN PDEVICE_OBJECT DeviceObject,
  265. IN PIRP Irp
  266. )
  267. {
  268. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  269. PADAPTER_EXTENSION adapter = DeviceObject->DeviceExtension;
  270. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  271. NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST;
  272. ULONG isRemoved;
  273. BOOLEAN sendDown = TRUE;
  274. PAGED_CODE();
  275. isRemoved = SpAcquireRemoveLock(DeviceObject, Irp);
  276. DebugPrint((2, "ScsiPortFdoPnp: FDO %p IRP %p MinorFunction %x isRemoved %d\n",
  277. DeviceObject,
  278. Irp,
  279. irpStack->MinorFunction,
  280. isRemoved));
  281. switch (irpStack->MinorFunction) {
  282. case IRP_MN_QUERY_PNP_DEVICE_STATE: {
  283. //
  284. // Extract the address of the device state buffer from the IRP.
  285. //
  286. PPNP_DEVICE_STATE deviceState;
  287. deviceState = (PPNP_DEVICE_STATE) &(Irp->IoStatus.Information);
  288. //
  289. // Copy our saved device state into the supplied address.
  290. //
  291. *deviceState = adapter->DeviceState;
  292. //
  293. // If the device is in the paging path, mark it as not-disableable.
  294. //
  295. if (commonExtension->PagingPathCount != 0) {
  296. SET_FLAG((*deviceState), PNP_DEVICE_NOT_DISABLEABLE);
  297. }
  298. //
  299. // Leave sendDown set to TRUE so request will be forwarded to
  300. // lower driver below.
  301. //
  302. break;
  303. }
  304. case IRP_MN_START_DEVICE: {
  305. PSCSIPORT_DRIVER_EXTENSION driverExtension =
  306. IoGetDriverObjectExtension(DeviceObject->DriverObject,
  307. ScsiPortInitialize);
  308. PCM_RESOURCE_LIST allocatedResources =
  309. irpStack->Parameters.StartDevice.AllocatedResources;
  310. PCM_RESOURCE_LIST translatedResources =
  311. irpStack->Parameters.StartDevice.AllocatedResourcesTranslated;
  312. ULONG interfaceFlags;
  313. irpStack = IoGetCurrentIrpStackLocation(Irp);
  314. //
  315. // Override sendDown so we complete this request below instead of
  316. // forwarding it to the lower driver.
  317. //
  318. sendDown = FALSE;
  319. //
  320. // Make sure this device was created by an add rather than the
  321. // one that was found by port or miniport.
  322. //
  323. if(adapter->IsPnp == FALSE) {
  324. DebugPrint((1, "ScsiPortFdoPnp - asked to start non-pnp "
  325. "adapter\n"));
  326. status = STATUS_UNSUCCESSFUL;
  327. break;
  328. }
  329. if(commonExtension->CurrentPnpState == IRP_MN_START_DEVICE) {
  330. DebugPrint((1, "ScsiPortFdoPnp - already started - nothing "
  331. "to do\n"));
  332. status = STATUS_SUCCESS;
  333. break;
  334. }
  335. //
  336. // Now make sure that pnp handed us some resources. It may not
  337. // if this is a phantom of a PCI device which we reported on a
  338. // previous boot. In that case pnp thinks we'll allocate the
  339. // resources ourselves.
  340. //
  341. if(allocatedResources == NULL) {
  342. //
  343. // This happens with reported devices when PCI moves them from
  344. // boot to boot.
  345. //
  346. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  347. break;
  348. }
  349. ASSERT(allocatedResources->Count);
  350. //
  351. // Make sure that adapters with this interface type can be
  352. // initialized as pnp drivers.
  353. //
  354. interfaceFlags = SpQueryPnpInterfaceFlags(
  355. driverExtension,
  356. allocatedResources->List[0].InterfaceType);
  357. if(interfaceFlags == SP_PNP_NOT_SAFE) {
  358. //
  359. // Nope - not safe. We cannot start this device so return
  360. // failure.
  361. //
  362. DebugPrint((1, "ScsiPortFdoPnp - Miniport cannot be run in "
  363. "pnp mode for interface type %#08lx\n",
  364. allocatedResources->List[0].InterfaceType));
  365. //
  366. // Mark the device as not being pnp - that way we won't get
  367. // removed.
  368. //
  369. adapter->IsPnp = FALSE;
  370. status = STATUS_UNSUCCESSFUL;
  371. break;
  372. }
  373. //
  374. // Check to see if this interface requires slot/function numbers.
  375. // If not then zero out the virtual slot number.
  376. //
  377. if(!TEST_FLAG(interfaceFlags, SP_PNP_NEEDS_LOCATION)) {
  378. adapter->VirtualSlotNumber.u.AsULONG = 0;
  379. }
  380. //
  381. // Determine if we should have found this device during
  382. // our detection scan. We do this by checking to see if the pdo
  383. // has a pnp bus type. If not and the detection flag is set then
  384. // assume duplicate detection has failed and don't start this
  385. // device.
  386. //
  387. {
  388. status = SpGetBusTypeGuid(adapter);
  389. if((status == STATUS_OBJECT_NAME_NOT_FOUND) &&
  390. ((driverExtension->LegacyAdapterDetection == TRUE) &&
  391. (interfaceFlags & SP_PNP_NON_ENUMERABLE))) {
  392. DbgPrint("ScsiPortFdoPnp: device has no pnp bus type but "
  393. "was not found as a duplicate during "
  394. "detection\n");
  395. status = STATUS_UNSUCCESSFUL;
  396. //
  397. // make sure this one doesn't get removed though - if it's
  398. // removed then the resources may be disabled for the
  399. // ghost.
  400. //
  401. adapter->IsPnp = FALSE;
  402. break;
  403. }
  404. }
  405. //
  406. // Finally, if this is a PCI adapter make sure we were given
  407. // an interrupt. The current assumption is that there aren't
  408. // any polled-mode PCI SCSI adapters in the market.
  409. //
  410. if(TEST_FLAG(interfaceFlags, SP_PNP_INTERRUPT_REQUIRED)) {
  411. ULONG irql, vector;
  412. KAFFINITY affinity;
  413. if(SpGetInterrupt(allocatedResources,
  414. &irql,
  415. &vector,
  416. &affinity) == FALSE) {
  417. PIO_ERROR_LOG_PACKET error =
  418. IoAllocateErrorLogEntry(DeviceObject,
  419. sizeof(IO_ERROR_LOG_PACKET));
  420. status = STATUS_DEVICE_CONFIGURATION_ERROR;
  421. if(error != NULL) {
  422. error->MajorFunctionCode = IRP_MJ_PNP;
  423. error->UniqueErrorValue = 0x418;
  424. error->ErrorCode = IO_ERR_INCORRECT_IRQL;
  425. IoWriteErrorLogEntry(error);
  426. }
  427. break;
  428. }
  429. }
  430. status = SpStartLowerDevice(DeviceObject, Irp);
  431. if(NT_SUCCESS(status)) {
  432. //
  433. // If we haven't allocated a HwDeviceExtension for this thing
  434. // yet then we'll need to set it up
  435. //
  436. if(commonExtension->IsInitialized == FALSE) {
  437. DebugPrint((1, "ScsiPortFdoPnp - find and init adapter %#p\n",
  438. DeviceObject));
  439. if(allocatedResources == NULL) {
  440. status = STATUS_INVALID_PARAMETER;
  441. } else {
  442. adapter->AllocatedResources =
  443. RtlDuplicateCmResourceList(
  444. DeviceObject->DriverObject,
  445. NonPagedPool,
  446. allocatedResources,
  447. SCSIPORT_TAG_RESOURCE_LIST);
  448. adapter->TranslatedResources =
  449. RtlDuplicateCmResourceList(
  450. DeviceObject->DriverObject,
  451. NonPagedPool,
  452. translatedResources,
  453. SCSIPORT_TAG_RESOURCE_LIST);
  454. commonExtension->IsInitialized = TRUE;
  455. status = ScsiPortInitPnpAdapter(DeviceObject);
  456. }
  457. if(!NT_SUCCESS(status)) {
  458. DebugPrint((1, "ScsiPortInitializeAdapter failed "
  459. "%#08lx\n", status));
  460. break;
  461. }
  462. }
  463. //
  464. // Start up the adapter.
  465. //
  466. status = ScsiPortStartAdapter(DeviceObject);
  467. if(NT_SUCCESS(status)) {
  468. commonExtension->PreviousPnpState = 0xff;
  469. commonExtension->CurrentPnpState = IRP_MN_START_DEVICE;
  470. }
  471. }
  472. break;
  473. }
  474. case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: {
  475. PIO_RESOURCE_REQUIREMENTS_LIST requirements;
  476. //
  477. // Grab the bus and slot numbers out of the resource requirements
  478. // list.
  479. //
  480. requirements = irpStack->Parameters.FilterResourceRequirements.
  481. IoResourceRequirementList;
  482. if (requirements != NULL) {
  483. adapter->RealBusNumber = requirements->BusNumber;
  484. adapter->RealSlotNumber = requirements->SlotNumber;
  485. }
  486. //
  487. // Leave sendDown in its default TRUE state so we will forward
  488. // this request to the lower driver.
  489. //
  490. break;
  491. }
  492. case IRP_MN_CANCEL_STOP_DEVICE: {
  493. sendDown = TRUE;
  494. Irp->IoStatus.Status = STATUS_SUCCESS;
  495. if(commonExtension->CurrentPnpState == IRP_MN_QUERY_STOP_DEVICE) {
  496. commonExtension->CurrentPnpState =
  497. commonExtension->PreviousPnpState;
  498. commonExtension->PreviousPnpState = 0xff;
  499. }
  500. break;
  501. }
  502. case IRP_MN_CANCEL_REMOVE_DEVICE: {
  503. sendDown = TRUE;
  504. Irp->IoStatus.Status = STATUS_SUCCESS;
  505. if(commonExtension->CurrentPnpState == IRP_MN_QUERY_REMOVE_DEVICE) {
  506. commonExtension->CurrentPnpState =
  507. commonExtension->PreviousPnpState;
  508. commonExtension->PreviousPnpState = 0xff;
  509. }
  510. break;
  511. }
  512. case IRP_MN_QUERY_STOP_DEVICE: {
  513. //
  514. // If stop has been disabled, fail the IRP and override sendDown
  515. // so we complete the request instead of forwarding it.
  516. //
  517. if (adapter->DisableStop) {
  518. status = STATUS_NOT_SUPPORTED;
  519. sendDown = FALSE;
  520. break;
  521. }
  522. //
  523. // Fall through.
  524. //
  525. }
  526. case IRP_MN_QUERY_REMOVE_DEVICE: {
  527. //
  528. // No problem with this request on our part. Just send it down
  529. // to the next driver.
  530. //
  531. if (SpAdapterStopRemoveSupported) {
  532. if((adapter->IsPnp) &&
  533. SpIsAdapterControlTypeSupported(adapter,
  534. ScsiStopAdapter)) {
  535. Irp->IoStatus.Status = STATUS_SUCCESS;
  536. sendDown = TRUE;
  537. } else {
  538. status = STATUS_UNSUCCESSFUL;
  539. sendDown = FALSE;
  540. }
  541. if(NT_SUCCESS(status)) {
  542. commonExtension->PreviousPnpState =
  543. commonExtension->CurrentPnpState;
  544. commonExtension->CurrentPnpState = irpStack->MinorFunction;
  545. }
  546. } else {
  547. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  548. status = STATUS_UNSUCCESSFUL;
  549. sendDown = FALSE;
  550. }
  551. break;
  552. }
  553. case IRP_MN_SURPRISE_REMOVAL: {
  554. PDEVICE_OBJECT lowerDevice = commonExtension->LowerDeviceObject;
  555. //
  556. // First mark the device as REMOVE_PENDING - this should keep
  557. // us from starting up any new i/o requests.
  558. //
  559. commonExtension->IsRemoved = REMOVE_PENDING;
  560. //
  561. // Terminate the device. This shuts down the miniport as quickly
  562. // as possible and aborts all i/o requests.
  563. //
  564. if(commonExtension->CurrentPnpState == IRP_MN_START_DEVICE) {
  565. SpTerminateAdapter(adapter);
  566. }
  567. //
  568. // Release the remove lock and wait for any in-flight requests to
  569. // complete.
  570. //
  571. SpReleaseRemoveLock(DeviceObject, Irp);
  572. SpWaitForRemoveLock(DeviceObject, DeviceObject);
  573. //
  574. // Go do the surprise remove portion of removing the adapter.
  575. //
  576. ScsiPortRemoveAdapter(DeviceObject, TRUE);
  577. //
  578. // Save the new state of this device.
  579. //
  580. commonExtension->PreviousPnpState = commonExtension->CurrentPnpState;
  581. commonExtension->CurrentPnpState = IRP_MN_SURPRISE_REMOVAL;
  582. //
  583. // Since we have already released the adapter remove lock, we
  584. // the request here instead of doing it at the bottom of the
  585. // function.
  586. //
  587. IoCopyCurrentIrpStackLocationToNext(Irp);
  588. return IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  589. }
  590. case IRP_MN_REMOVE_DEVICE:
  591. //
  592. // Asked to remove the adapter. We'll ask the port driver to
  593. // stop it's adapter and release it's resources. We can
  594. // detach and delete our device object as the lower driver
  595. // completes the remove request.
  596. //
  597. ASSERT(isRemoved != REMOVE_COMPLETE);
  598. //
  599. // If the device has been started then make sure we've got the
  600. // necessary code to disable it. If it isn't currently started
  601. // then either it's got the code we need or it's never been
  602. // started - in either case we can just tear it down.
  603. //
  604. if((adapter->IsPnp == FALSE) ||
  605. ((commonExtension->CurrentPnpState == IRP_MN_START_DEVICE) &&
  606. (!SpIsAdapterControlTypeSupported(adapter,
  607. ScsiStopAdapter)))) {
  608. //
  609. // the miniport needs to be stopped but we cannot do it.
  610. // Fail the request.
  611. //
  612. status = STATUS_UNSUCCESSFUL;
  613. sendDown = FALSE;
  614. break;
  615. }
  616. //
  617. // Clear the interface if it exists.
  618. //
  619. if(adapter->InterfaceName.Buffer != NULL) {
  620. IoSetDeviceInterfaceState(
  621. &(adapter->InterfaceName),
  622. FALSE);
  623. RtlFreeUnicodeString(&(adapter->InterfaceName));
  624. RtlInitUnicodeString(&(adapter->InterfaceName), NULL);
  625. }
  626. SpReleaseRemoveLock(DeviceObject, Irp);
  627. ScsiPortRemoveAdapter(DeviceObject, FALSE);
  628. //
  629. // The adapter's been removed. Set the new state now.
  630. //
  631. commonExtension->CurrentPnpState = IRP_MN_REMOVE_DEVICE;
  632. commonExtension->PreviousPnpState = 0xff;
  633. //
  634. // Forward the request down and wait for it to complete.
  635. //
  636. status = SpSendIrpSynchronous(
  637. commonExtension->LowerDeviceObject,
  638. Irp);
  639. //
  640. // Indicate the the adapter is fully removed.
  641. //
  642. commonExtension->IsRemoved = REMOVE_COMPLETE;
  643. //
  644. // Complete the IRP.
  645. //
  646. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  647. //
  648. // Detach and delete the FDO.
  649. //
  650. IoDetachDevice(commonExtension->LowerDeviceObject);
  651. IoDeleteDevice(DeviceObject);
  652. return status;
  653. case IRP_MN_STOP_DEVICE: {
  654. sendDown = TRUE;
  655. ASSERT(adapter->IsPnp);
  656. ASSERT(adapter->HwAdapterControl != NULL);
  657. status = ScsiPortStopAdapter(DeviceObject, Irp);
  658. Irp->IoStatus.Status = status;
  659. Irp->IoStatus.Information = 0L;
  660. if(!NT_SUCCESS(status)) {
  661. sendDown = FALSE;
  662. } else {
  663. commonExtension->PreviousPnpState = commonExtension->CurrentPnpState;
  664. commonExtension->CurrentPnpState = IRP_MN_STOP_DEVICE;
  665. }
  666. break;
  667. }
  668. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  669. DEVICE_RELATION_TYPE type =
  670. irpStack->Parameters.QueryDeviceRelations.Type;
  671. DebugPrint((1, "ScsiPortFdoPnp - got "
  672. "IRP_MJ_QUERY_DEVICE_RELATIONS\n"));
  673. DebugPrint((1, "\ttype is %d\n", type));
  674. if (type == BusRelations) {
  675. PSP_ENUMERATION_REQUEST request;
  676. request = InterlockedCompareExchangePointer(
  677. &adapter->PnpEnumRequestPtr,
  678. NULL,
  679. &(adapter->PnpEnumerationRequest));
  680. if (request != NULL) {
  681. RtlZeroMemory(request, sizeof(SP_ENUMERATION_REQUEST));
  682. request->CompletionRoutine = SpQueryDeviceRelationsCompletion;
  683. request->Context = Irp;
  684. request->CompletionStatus = &(Irp->IoStatus.Status);
  685. IoMarkIrpPending(Irp);
  686. SpEnumerateAdapterAsynchronous(adapter, request, FALSE);
  687. return STATUS_PENDING;
  688. } else {
  689. ASSERT(FALSE && "Unexpected!! Concurrent QDR requests");
  690. Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  691. Irp->IoStatus.Information = 0L;
  692. sendDown = FALSE;
  693. }
  694. }
  695. break;
  696. }
  697. case IRP_MN_DEVICE_USAGE_NOTIFICATION:
  698. //
  699. // Send the irp down to the device below us.
  700. // Since there's a remove lock outstanding on the PDO we can release
  701. // the lock on the FDO before sending this down.
  702. //
  703. Irp->IoStatus.Status = STATUS_SUCCESS;
  704. break;
  705. case IRP_MN_QUERY_ID: {
  706. PWCHAR newIdList;
  707. //
  708. // We add the id GEN_SCSIADAPTER to the compatible ID's for any
  709. // adapters controlled by scsiport.
  710. //
  711. DebugPrint((2, "ScsiPortFdoPnp: got IRP_MN_QUERY_ID\n"));
  712. if(irpStack->Parameters.QueryId.IdType != BusQueryCompatibleIDs) {
  713. sendDown = TRUE;
  714. break;
  715. }
  716. status = SpSendIrpSynchronous(commonExtension->LowerDeviceObject,
  717. Irp);
  718. newIdList = ScsiPortAddGenericControllerId(
  719. DeviceObject->DriverObject,
  720. (PWCHAR) (Irp->IoStatus.Information));
  721. if(newIdList == NULL) {
  722. status = STATUS_INSUFFICIENT_RESOURCES;
  723. } else {
  724. status = STATUS_SUCCESS;
  725. if(Irp->IoStatus.Information != 0L) {
  726. ExFreePool((PVOID) Irp->IoStatus.Information);
  727. }
  728. Irp->IoStatus.Information = (ULONG_PTR) newIdList;
  729. }
  730. sendDown = FALSE;
  731. break;
  732. }
  733. default: {
  734. PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
  735. DebugPrint((1, "ScsiPortFdoPnp: Unimplemented PNP/POWER minor "
  736. "code %d\n", irpStack->MinorFunction));
  737. break;
  738. }
  739. }
  740. if (sendDown) {
  741. IoCopyCurrentIrpStackLocationToNext(Irp);
  742. SpReleaseRemoveLock(DeviceObject, Irp);
  743. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  744. } else {
  745. SpReleaseRemoveLock(DeviceObject, Irp);
  746. Irp->IoStatus.Status = status;
  747. SpCompleteRequest(DeviceObject, Irp, NULL, IO_NO_INCREMENT);
  748. }
  749. return status;
  750. }
  751. NTSTATUS
  752. ScsiPortStartAdapter(
  753. IN PDEVICE_OBJECT Adapter
  754. )
  755. /*++
  756. Routine Descripion:
  757. This routine will start an adapter.
  758. It is illegal to start the device if it has already been started.
  759. Arguments:
  760. Adapter - a pointer to the functional device object (adapter) being started
  761. Return Value:
  762. STATUS_SUCCESS if the device was properly started and enumeration was
  763. attempted - or if the device had previously been started.
  764. error value indicating the cause of the failure otherwise
  765. --*/
  766. {
  767. PSCSIPORT_DRIVER_EXTENSION
  768. driverExtension = IoGetDriverObjectExtension(Adapter->DriverObject,
  769. ScsiPortInitialize);
  770. PADAPTER_EXTENSION adapterExtension = Adapter->DeviceExtension;
  771. PCOMMON_EXTENSION commonExtension = Adapter->DeviceExtension;
  772. UCHAR pathId;
  773. PAGED_CODE();
  774. ASSERT(driverExtension != NULL);
  775. ASSERT_FDO(Adapter);
  776. ASSERT(commonExtension->CurrentPnpState != IRP_MN_START_DEVICE);
  777. ASSERT(commonExtension->IsInitialized);
  778. ASSERT(((Adapter->Flags & DO_DEVICE_INITIALIZING) == 0));
  779. DebugPrint((1, "ScsiPortStartAdapter - starting adapter %#p\n", Adapter));
  780. //
  781. // Start timer. Request timeout counters
  782. // in the logical units have already been
  783. // initialized.
  784. //
  785. adapterExtension->TickCount = 0;
  786. IoStartTimer(Adapter);
  787. //
  788. // Initialize WMI support.
  789. //
  790. if (adapterExtension->CommonExtension.WmiInitialized == FALSE) {
  791. //
  792. // Build the SCSIPORT WMI registration information buffer for this FDO.
  793. //
  794. SpWmiInitializeSpRegInfo(Adapter);
  795. //
  796. // Register this device object only if the miniport supports WMI and/or
  797. // SCSIPORT will support certain WMI GUIDs on behalf of the miniport.
  798. //
  799. if (adapterExtension->CommonExtension.WmiScsiPortRegInfoBuf != NULL) {
  800. //
  801. // Register this functional device object as a WMI data provider,
  802. // instructing WMI that it is ready to receive WMI IRPs.
  803. //
  804. DebugPrint((1, "ScsiPortStartAdapter: REGISTER FDO:%p\n", Adapter));
  805. IoWMIRegistrationControl(Adapter, WMIREG_ACTION_REGISTER);
  806. adapterExtension->CommonExtension.WmiInitialized = TRUE;
  807. }
  808. //
  809. // Allocate several WMI_MINIPORT_REQUEST_ITEM blocks to satisfy a
  810. // potential onslaught of WMIEvent notifications by the miniport.
  811. //
  812. if (adapterExtension->CommonExtension.WmiMiniPortSupport) {
  813. //
  814. // Currently, we only allocate two per new adapter (FDO).
  815. //
  816. SpWmiInitializeFreeRequestList(Adapter, 2);
  817. }
  818. }
  819. //
  820. // Create a well known name for this device object by making a symbolic
  821. // link to the PDO. Even if this fails, the start should still succeed.
  822. //
  823. if(adapterExtension->PortNumber == -1) {
  824. NTSTATUS status;
  825. UNICODE_STRING unicodePdoName;
  826. ULONG number;
  827. UNICODE_STRING interfaceName;
  828. RtlInitUnicodeString(&unicodePdoName, adapterExtension->DeviceName);
  829. //
  830. // Start at zero and keep going through all the possible numbers
  831. // until we find a hole. This is an unfortunate requirement for
  832. // legacy support since most old class drivers will give up if
  833. // they find a hole in the scsiport numbers.
  834. //
  835. number = 0;
  836. do {
  837. WCHAR wideLinkName[64];
  838. UNICODE_STRING unicodeLinkName;
  839. //
  840. // Create the well known name string first.
  841. //
  842. swprintf(wideLinkName, L"\\Device\\ScsiPort%d", number);
  843. RtlInitUnicodeString(&unicodeLinkName, wideLinkName);
  844. status = IoCreateSymbolicLink(&unicodeLinkName, &unicodePdoName);
  845. if(NT_SUCCESS(status)) {
  846. //
  847. // Found a spot - mark this one as named so we don't go
  848. // through this trouble again and save the port number
  849. //
  850. adapterExtension->PortNumber = number;
  851. //
  852. // Create the dos port driver name. If there's a collision
  853. // then just forget it.
  854. //
  855. swprintf(wideLinkName, L"\\DosDevices\\Scsi%d:", number);
  856. RtlInitUnicodeString(&unicodeLinkName, wideLinkName);
  857. IoCreateSymbolicLink(&unicodeLinkName, &unicodePdoName);
  858. } else {
  859. number++;
  860. }
  861. } while (status == STATUS_OBJECT_NAME_COLLISION);
  862. //
  863. // Increment the count of scsiport device
  864. //
  865. IoGetConfigurationInformation()->ScsiPortCount++;
  866. //
  867. // Create a device map entry for this adapter.
  868. //
  869. SpBuildDeviceMapEntry(commonExtension);
  870. //
  871. // Register our device interface.
  872. //
  873. status = IoRegisterDeviceInterface(adapterExtension->LowerPdo,
  874. &StoragePortClassGuid,
  875. NULL,
  876. &interfaceName);
  877. if(NT_SUCCESS(status)) {
  878. adapterExtension->InterfaceName = interfaceName;
  879. status = IoSetDeviceInterfaceState(&interfaceName, TRUE);
  880. if(!NT_SUCCESS(status)) {
  881. RtlFreeUnicodeString(&interfaceName);
  882. RtlInitUnicodeString(&(adapterExtension->InterfaceName), NULL);
  883. }
  884. }
  885. }
  886. //
  887. // Set the force next bus scan bit.
  888. //
  889. adapterExtension->ForceNextBusScan = TRUE;
  890. return STATUS_SUCCESS;
  891. }
  892. NTSTATUS
  893. ScsiPortGetDeviceId(
  894. IN PDEVICE_OBJECT Pdo,
  895. OUT PUNICODE_STRING UnicodeString
  896. )
  897. /*++
  898. Routine Description:
  899. This routine will allocate space for and fill in a device id string for
  900. the specified Pdo. This string is generated from the bus type (scsi) and
  901. the type of the device.
  902. Arguments:
  903. Pdo - a pointer to the physical device object being queried
  904. UnicodeString - a pointer to an already allocated unicode string structure.
  905. This routine will allocate and fill in the buffer of this
  906. structure
  907. Returns:
  908. status
  909. --*/
  910. {
  911. PLOGICAL_UNIT_EXTENSION physicalExtension = Pdo->DeviceExtension;
  912. PINQUIRYDATA inquiryData = &(physicalExtension->InquiryData);
  913. UCHAR buffer[256];
  914. PUCHAR rawIdString = buffer;
  915. ANSI_STRING ansiIdString;
  916. ULONG whichString;
  917. PAGED_CODE();
  918. ASSERT(UnicodeString != NULL);
  919. RtlZeroMemory(buffer, sizeof(buffer));
  920. sprintf(rawIdString,
  921. "SCSI\\%s",
  922. SpGetDeviceTypeInfo(inquiryData->DeviceType)->DeviceTypeString);
  923. rawIdString += strlen(rawIdString);
  924. ASSERT(*rawIdString == '\0');
  925. for(whichString = 0; whichString < 3; whichString++) {
  926. PUCHAR headerString;
  927. PUCHAR sourceString;
  928. ULONG sourceStringLength;
  929. ULONG i;
  930. switch(whichString) {
  931. //
  932. // Vendor Id
  933. //
  934. case 0: {
  935. sourceString = inquiryData->VendorId;
  936. sourceStringLength = sizeof(inquiryData->VendorId);
  937. headerString = "Ven";
  938. break;
  939. }
  940. //
  941. // Product Id
  942. //
  943. case 1: {
  944. sourceString = inquiryData->ProductId;
  945. sourceStringLength = sizeof(inquiryData->ProductId);
  946. headerString = "Prod";
  947. break;
  948. }
  949. //
  950. // Product Revision Level
  951. //
  952. case 2: {
  953. sourceString = inquiryData->ProductRevisionLevel;
  954. sourceStringLength = sizeof(inquiryData->ProductRevisionLevel);
  955. headerString = "Rev";
  956. break;
  957. }
  958. }
  959. //
  960. // Start at the end of the source string and back up until we find a
  961. // non-space, non-null character.
  962. //
  963. for(; sourceStringLength > 0; sourceStringLength--) {
  964. if((sourceString[sourceStringLength - 1] != ' ') &&
  965. (sourceString[sourceStringLength - 1] != '\0')) {
  966. break;
  967. }
  968. }
  969. //
  970. // Throw the header string into the block
  971. //
  972. sprintf(rawIdString, "&%s_", headerString);
  973. rawIdString += strlen(headerString) + 2;
  974. //
  975. // Spew the string into the device id
  976. //
  977. for(i = 0; i < sourceStringLength; i++) {
  978. *rawIdString = (sourceString[i] != ' ') ? (sourceString[i]) :
  979. ('_');
  980. rawIdString++;
  981. }
  982. ASSERT(*rawIdString == '\0');
  983. }
  984. RtlInitAnsiString(&ansiIdString, buffer);
  985. DebugPrint((1, "DeviceId for logical unit %#p is %Z\n",
  986. Pdo, &ansiIdString));
  987. return RtlAnsiStringToUnicodeString(UnicodeString, &ansiIdString, TRUE);
  988. }
  989. NTSTATUS
  990. ScsiPortGetInstanceId(
  991. IN PDEVICE_OBJECT Pdo,
  992. OUT PUNICODE_STRING UnicodeString
  993. )
  994. /*++
  995. Routine Description:
  996. This routine will allocate space for and fill in an instance id string for
  997. the specified Pdo. This string will be generated either from the device
  998. type + serial number of the device (if it has a serial number) or from
  999. the address of the device.
  1000. Arguments:
  1001. Pdo - a pointer to the physical device object being queried
  1002. UnicodeString - a pointer to an already allocated unicode string structure.
  1003. This routine will allocate and fill in the buffer of this
  1004. structure
  1005. Returns:
  1006. status
  1007. --*/
  1008. {
  1009. PLOGICAL_UNIT_EXTENSION physicalExtension = Pdo->DeviceExtension;
  1010. PDRIVER_OBJECT driverObject = Pdo->DriverObject;
  1011. PSCSIPORT_DEVICE_TYPE deviceTypeInfo;
  1012. UCHAR idStringBuffer[64];
  1013. ANSI_STRING ansiIdString;
  1014. PAGED_CODE();
  1015. ASSERT(UnicodeString != NULL);
  1016. //
  1017. // can't use serial number even if it exists since a device which is
  1018. // multiply connected to the same bus (dual-ported device) will have
  1019. // the same serial number at each connection and would confuse the PNP.
  1020. //
  1021. sprintf(idStringBuffer,
  1022. "%x%x%x",
  1023. physicalExtension->PathId,
  1024. physicalExtension->TargetId,
  1025. physicalExtension->Lun
  1026. );
  1027. RtlInitAnsiString(&ansiIdString, idStringBuffer);
  1028. return RtlAnsiStringToUnicodeString(UnicodeString, &ansiIdString, TRUE);
  1029. }
  1030. NTSTATUS
  1031. ScsiPortGetCompatibleIds(
  1032. IN PDRIVER_OBJECT DriverObject,
  1033. IN PINQUIRYDATA InquiryData,
  1034. OUT PUNICODE_STRING UnicodeString
  1035. )
  1036. /*++
  1037. Routine Description:
  1038. This routine will allocate space for and fill in a compatible id multi
  1039. string for the specified Pdo. This string is generated using the bus and
  1040. device types for the device
  1041. Arguments:
  1042. InquiryData - the inquiry data to generate compatible ids from.
  1043. UnicodeString - a pointer to an already allocated unicode string structure.
  1044. This routine will allocate and fill in the buffer of this
  1045. structure
  1046. Returns:
  1047. status
  1048. --*/
  1049. {
  1050. UCHAR s[sizeof("SCSI\\DEVICE_TYPE_GOES_HERE")];
  1051. PSTR stringBuffer[] = {
  1052. s,
  1053. "SCSI\\RAW",
  1054. NULL};
  1055. //
  1056. // Fill in the scsi specific string
  1057. //
  1058. sprintf(stringBuffer[0],
  1059. "SCSI\\%s",
  1060. SpGetDeviceTypeInfo(InquiryData->DeviceType)->DeviceTypeString);
  1061. //
  1062. // Set up the first id string
  1063. //
  1064. return ScsiPortStringArrayToMultiString(
  1065. DriverObject,
  1066. UnicodeString,
  1067. stringBuffer);
  1068. }
  1069. #define MPIO_DEVICE_LIST L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\MPDEV"
  1070. NTSTATUS
  1071. ScsiPortDetermineGenId(
  1072. IN PDRIVER_OBJECT DriverObject,
  1073. IN PINQUIRYDATA InquiryData,
  1074. OUT PUCHAR GenericId
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. This routine will return the correct Compatible ID for the device in the caller
  1079. supplied 'CompatibleId'.
  1080. The value will either be a GenXXX or MPIODisk, depending upon results from routines
  1081. exported by portlib.lib
  1082. Arguments:
  1083. DriverObject - The port-driver's DriverObject.
  1084. InquiryData - The inquiry data of the device for which a compatID is being built.
  1085. GenericId - Storage for the NULL-terminated buffer that will contain the correct ID.
  1086. Returns:
  1087. SUCCESS or some error status from the library routines - (INSUFFICIENT_RESOURCES or some
  1088. registry access error).
  1089. --*/
  1090. {
  1091. PSCSIPORT_DEVICE_TYPE devTypeInfo;
  1092. PSCSIPORT_DRIVER_EXTENSION driverExtension;
  1093. UNICODE_STRING mpioRegistryPath;
  1094. UCHAR vendorId[9];
  1095. UCHAR productId[17];
  1096. UCHAR genericId[40];
  1097. BOOLEAN mpio = FALSE;
  1098. NTSTATUS status = STATUS_SUCCESS;
  1099. PAGED_CODE();
  1100. //
  1101. // Init compatibleId, as it will always contain something.
  1102. //
  1103. RtlZeroMemory(genericId, 40);
  1104. //
  1105. // Get the type info for this device.
  1106. //
  1107. devTypeInfo = SpGetDeviceTypeInfo(InquiryData->DeviceType);
  1108. //
  1109. // Default to the GenXXX of the device. If it's not a disk, errors occur
  1110. // in this routine, or it's a non-mpio supported disk, then this value
  1111. // will be returned.
  1112. //
  1113. RtlCopyMemory(genericId,
  1114. devTypeInfo->GenericTypeString,
  1115. strlen(devTypeInfo->GenericTypeString));
  1116. //
  1117. // Check whether this is a disk or not. If not, the generic id
  1118. // built earlier will be used.
  1119. //
  1120. if (InquiryData->DeviceType == DIRECT_ACCESS_DEVICE) {
  1121. NTSTATUS status2;
  1122. //
  1123. // Get the driverObject extension. This contains storage for the
  1124. // supported device list.
  1125. //
  1126. driverExtension = IoGetDriverObjectExtension(
  1127. DriverObject,
  1128. ScsiPortInitialize);
  1129. ASSERT(driverExtension != NULL);
  1130. //
  1131. // Determine whether this contains the list, or is uninitialised.
  1132. //
  1133. if (driverExtension->MPIOSupportedDeviceList.Buffer == NULL) {
  1134. //
  1135. // Build the registry path string.
  1136. //
  1137. RtlInitUnicodeString(&mpioRegistryPath, MPIO_DEVICE_LIST);
  1138. //
  1139. // Call into the port-driver library to get the list.
  1140. // Any failures here will be dealt with below.
  1141. //
  1142. status2 = PortGetMPIODeviceList(
  1143. &mpioRegistryPath,
  1144. &driverExtension->MPIOSupportedDeviceList);
  1145. } else {
  1146. //
  1147. // Buffer is there, so load up 'success'.
  1148. //
  1149. status2 = STATUS_SUCCESS;
  1150. }
  1151. if (NT_SUCCESS(status2)) {
  1152. //
  1153. // Get NULL terminated copies of Vendor and Product ID from the
  1154. // passed-in inquiry data.
  1155. //
  1156. RtlZeroMemory(vendorId, 9);
  1157. RtlZeroMemory(productId, 17);
  1158. RtlCopyMemory(vendorId, InquiryData->VendorId, 8);
  1159. RtlCopyMemory(productId, InquiryData->ProductId, 16);
  1160. //
  1161. // Call into the port-driver library to determine whether this
  1162. // device is supported under multipath.
  1163. //
  1164. mpio = PortIsDeviceMPIOSupported(
  1165. &driverExtension->MPIOSupportedDeviceList,
  1166. vendorId,
  1167. productId);
  1168. if (mpio) {
  1169. //
  1170. // Build MPIODisk instead of GenDisk. Mpdev.sys loads against
  1171. // this.
  1172. //
  1173. RtlCopyMemory(genericId,
  1174. "MPIODisk",
  1175. 8);
  1176. }
  1177. }
  1178. }
  1179. if (NT_SUCCESS(status)) {
  1180. //
  1181. // Copy the built ID into the caller's buffer.
  1182. //
  1183. RtlCopyMemory(GenericId,
  1184. genericId,
  1185. strlen(genericId));
  1186. }
  1187. return status;
  1188. }
  1189. NTSTATUS
  1190. ScsiPortGetHardwareIds(
  1191. IN PDRIVER_OBJECT DriverObject,
  1192. IN PINQUIRYDATA InquiryData,
  1193. OUT PUNICODE_STRING UnicodeString
  1194. )
  1195. /*++
  1196. Routine Description:
  1197. This routine will allocate space for and fill in a hardware id multi
  1198. string for the specified Pdo. This string is generated using the device
  1199. type and the inquiry data.
  1200. Arguments:
  1201. InquiryData - the inquiry data to be converted into id strings.
  1202. UnicodeString - a pointer to an already allocated unicode string structure.
  1203. This routine will allocate and fill in the buffer of this
  1204. structure
  1205. Returns:
  1206. status
  1207. --*/
  1208. #define NUMBER_HARDWARE_STRINGS 6
  1209. {
  1210. PSCSIPORT_DEVICE_TYPE devTypeInfo =
  1211. SpGetDeviceTypeInfo(InquiryData->DeviceType);
  1212. ULONG i;
  1213. PSTR strings[NUMBER_HARDWARE_STRINGS + 1];
  1214. UCHAR scratch[64];
  1215. UCHAR genericId[40];
  1216. NTSTATUS status;
  1217. SIZE_T len;
  1218. PAGED_CODE();
  1219. //
  1220. // Zero out the string buffer
  1221. //
  1222. RtlZeroMemory(strings, sizeof(strings));
  1223. RtlZeroMemory(genericId, 40);
  1224. //
  1225. // Build the compatible ID for this device.
  1226. //
  1227. status = ScsiPortDetermineGenId(DriverObject,
  1228. InquiryData,
  1229. genericId);
  1230. if (!NT_SUCCESS(status)) {
  1231. return status;
  1232. }
  1233. try {
  1234. for(i = 0; i < NUMBER_HARDWARE_STRINGS; i++) {
  1235. RtlZeroMemory(scratch, sizeof(scratch));
  1236. //
  1237. // Build each of the hardware id's
  1238. //
  1239. switch(i) {
  1240. //
  1241. // Bus + Dev Type + Vendor + Product + Revision
  1242. //
  1243. case 0: {
  1244. sprintf(scratch, "SCSI\\%s", devTypeInfo->DeviceTypeString);
  1245. CopyField(scratch + strlen(scratch),
  1246. InquiryData->VendorId,
  1247. 8,
  1248. '_');
  1249. CopyField(scratch + strlen(scratch),
  1250. InquiryData->ProductId,
  1251. 16,
  1252. '_');
  1253. CopyField(scratch + strlen(scratch),
  1254. InquiryData->ProductRevisionLevel,
  1255. 4,
  1256. '_');
  1257. break;
  1258. }
  1259. //
  1260. // bus + device + vendor + product
  1261. //
  1262. case 1: {
  1263. sprintf(scratch, "SCSI\\%s", devTypeInfo->DeviceTypeString);
  1264. CopyField(scratch + strlen(scratch),
  1265. InquiryData->VendorId,
  1266. 8,
  1267. '_');
  1268. CopyField(scratch + strlen(scratch),
  1269. InquiryData->ProductId,
  1270. 16,
  1271. '_');
  1272. break;
  1273. }
  1274. //
  1275. // bus + device + vendor
  1276. //
  1277. case 2: {
  1278. sprintf(scratch, "SCSI\\%s", devTypeInfo->DeviceTypeString);
  1279. CopyField(scratch + strlen(scratch),
  1280. InquiryData->VendorId,
  1281. 8,
  1282. '_');
  1283. break;
  1284. }
  1285. //
  1286. // bus \ vendor + product + revision[0]
  1287. //
  1288. case 3: {
  1289. sprintf(scratch, "SCSI\\");
  1290. //
  1291. // Fall through to the next set.
  1292. //
  1293. }
  1294. //
  1295. // vendor + product + revision[0] (win9x)
  1296. //
  1297. case 4: {
  1298. CopyField(scratch + strlen(scratch),
  1299. InquiryData->VendorId,
  1300. 8,
  1301. '_');
  1302. CopyField(scratch + strlen(scratch),
  1303. InquiryData->ProductId,
  1304. 16,
  1305. '_');
  1306. CopyField(scratch + strlen(scratch),
  1307. InquiryData->ProductRevisionLevel,
  1308. 1,
  1309. '_');
  1310. break;
  1311. }
  1312. case 5: {
  1313. //
  1314. // Copy over the previously built generic id.
  1315. //
  1316. RtlCopyMemory(scratch,
  1317. genericId,
  1318. strlen(genericId));
  1319. break;
  1320. }
  1321. default: {
  1322. ASSERT(FALSE);
  1323. break;
  1324. }
  1325. }
  1326. len = strlen(scratch);
  1327. if(len != 0) {
  1328. strings[i] =
  1329. SpAllocatePool(PagedPool,
  1330. strlen(scratch) + sizeof(UCHAR),
  1331. SCSIPORT_TAG_PNP_ID,
  1332. DriverObject);
  1333. if(strings[i] == NULL) {
  1334. status = STATUS_INSUFFICIENT_RESOURCES;
  1335. leave;
  1336. }
  1337. RtlCopyMemory(strings[i], scratch, len+1);
  1338. } else {
  1339. break;
  1340. }
  1341. }
  1342. status = ScsiPortStringArrayToMultiString(DriverObject,
  1343. UnicodeString,
  1344. strings);
  1345. leave;
  1346. } finally {
  1347. for(i = 0; i < NUMBER_HARDWARE_STRINGS; i++) {
  1348. if(strings[i]) {
  1349. ExFreePool(strings[i]);
  1350. }
  1351. }
  1352. }
  1353. return status;
  1354. }
  1355. #undef NUMBER_HARDWARE_STRINGS
  1356. VOID
  1357. CopyField(
  1358. IN PUCHAR Destination,
  1359. IN PUCHAR Source,
  1360. IN ULONG Count,
  1361. IN UCHAR Change
  1362. )
  1363. /*++
  1364. Routine Description:
  1365. This routine will copy Count string bytes from Source to Destination. If
  1366. it finds a nul byte in the Source it will translate that and any subsequent
  1367. bytes into Change. It will also replace spaces with the specified character.
  1368. Arguments:
  1369. Destination - the location to copy bytes
  1370. Source - the location to copy bytes from
  1371. Count - the number of bytes to be copied
  1372. Return Value:
  1373. none
  1374. --*/
  1375. {
  1376. ULONG i = 0;
  1377. BOOLEAN pastEnd = FALSE;
  1378. PAGED_CODE();
  1379. for(i = 0; i < Count; i++) {
  1380. if(!pastEnd) {
  1381. if(Source[i] == 0) {
  1382. pastEnd = TRUE;
  1383. Destination[i] = Change;
  1384. } else if(Source[i] == ' ') {
  1385. Destination[i] = Change;
  1386. } else {
  1387. Destination[i] = Source[i];
  1388. }
  1389. } else {
  1390. Destination[i] = Change;
  1391. }
  1392. }
  1393. return;
  1394. }
  1395. NTSTATUS
  1396. ScsiPortInitPnpAdapter(
  1397. IN PDEVICE_OBJECT Fdo
  1398. )
  1399. /*++
  1400. Routine Description:
  1401. This routine will find and (if found) initialize a specific adapter. The
  1402. adapter is specified by the ResourceList passed in.
  1403. This routine will initialize a port configuration structure using the
  1404. information provided in the resource list and call the miniport's find
  1405. adapter routine to locate the adapter. If that completes successfully, the
  1406. miniport's initialize routine will be called. This will connect the
  1407. interrupts and initialize the timers and DPCs as well as allocating
  1408. common buffers and request data structures.
  1409. Arguments:
  1410. Fdo - the device object for the adapter being initialized
  1411. Return Value:
  1412. status
  1413. --*/
  1414. {
  1415. PADAPTER_EXTENSION adapter = Fdo->DeviceExtension;
  1416. PSCSIPORT_DRIVER_EXTENSION
  1417. driverExtension = IoGetDriverObjectExtension(Fdo->DriverObject,
  1418. ScsiPortInitialize);
  1419. INTERFACE_TYPE interfaceType;
  1420. ULONG resultLength;
  1421. PHW_INITIALIZATION_DATA hwInitializationData = NULL;
  1422. CONFIGURATION_CONTEXT configurationContext;
  1423. PPORT_CONFIGURATION_INFORMATION configInfo = NULL;
  1424. BOOLEAN callAgain;
  1425. OBJECT_ATTRIBUTES objectAttributes;
  1426. ULONG uniqueId;
  1427. PHW_DEVICE_EXTENSION hwDeviceExtension;
  1428. ULONG hwDeviceExtensionSize;
  1429. PUNICODE_STRING registryPath = &(driverExtension->RegistryPath);
  1430. NTSTATUS status;
  1431. PAGED_CODE();
  1432. //
  1433. // Find the init data for this interface type
  1434. //
  1435. interfaceType = SpGetPdoInterfaceType(adapter->LowerPdo);
  1436. hwInitializationData = SpFindInitData(driverExtension, interfaceType);
  1437. if(hwInitializationData == NULL) {
  1438. //
  1439. // Hmmm. The miniport never reported this adapter type. We can't
  1440. // start the device since we don't know what the correct entry points
  1441. // are. Pretend it doesn't exist
  1442. //
  1443. return STATUS_NO_SUCH_DEVICE;
  1444. }
  1445. hwDeviceExtensionSize = hwInitializationData->DeviceExtensionSize +
  1446. sizeof(HW_DEVICE_EXTENSION);
  1447. RtlZeroMemory(&configurationContext, sizeof(configurationContext));
  1448. if(hwInitializationData->NumberOfAccessRanges != 0) {
  1449. configurationContext.AccessRanges =
  1450. SpAllocatePool(PagedPool,
  1451. (hwInitializationData->NumberOfAccessRanges *
  1452. sizeof(ACCESS_RANGE)),
  1453. SCSIPORT_TAG_ACCESS_RANGE,
  1454. Fdo->DriverObject);
  1455. if(configurationContext.AccessRanges == NULL) {
  1456. return STATUS_INSUFFICIENT_RESOURCES;
  1457. }
  1458. }
  1459. try {
  1460. ULONG portConfigSize;
  1461. //
  1462. // Allocate the HwDeviceExtension first - it's easier to deallocate :)
  1463. //
  1464. hwDeviceExtension = SpAllocatePool(NonPagedPool,
  1465. hwDeviceExtensionSize,
  1466. SCSIPORT_TAG_DEV_EXT,
  1467. Fdo->DriverObject);
  1468. if(hwDeviceExtension == NULL) {
  1469. DebugPrint((1, "ScsiPortInitialize: Could not allocate "
  1470. "HwDeviceExtension\n"));
  1471. status = STATUS_INSUFFICIENT_RESOURCES;
  1472. uniqueId = __LINE__;
  1473. leave;
  1474. }
  1475. RtlZeroMemory(hwDeviceExtension, hwDeviceExtensionSize);
  1476. //
  1477. // Setup device extension pointers
  1478. //
  1479. SpInitializeAdapterExtension(adapter,
  1480. hwInitializationData,
  1481. hwDeviceExtension);
  1482. //
  1483. // initialize the miniport config info buffer
  1484. //
  1485. status = SpInitializeConfiguration(
  1486. adapter,
  1487. registryPath,
  1488. hwInitializationData,
  1489. &configurationContext);
  1490. if(!NT_SUCCESS(status)) {
  1491. uniqueId = __LINE__;
  1492. leave;
  1493. }
  1494. //
  1495. // Allocate a config-info structure and access ranges for the
  1496. // miniport drivers to use
  1497. //
  1498. portConfigSize = sizeof(PORT_CONFIGURATION_INFORMATION);
  1499. portConfigSize += hwInitializationData->NumberOfAccessRanges *
  1500. sizeof(ACCESS_RANGE);
  1501. portConfigSize += 7;
  1502. portConfigSize &= ~7;
  1503. configInfo = SpAllocatePool(NonPagedPool,
  1504. portConfigSize,
  1505. SCSIPORT_TAG_PORT_CONFIG,
  1506. Fdo->DriverObject);
  1507. if(configInfo == NULL) {
  1508. status = STATUS_INSUFFICIENT_RESOURCES;
  1509. uniqueId = __LINE__;
  1510. leave;
  1511. }
  1512. adapter->PortConfig = configInfo;
  1513. //
  1514. // Copy the current structure to the writable copy
  1515. //
  1516. RtlCopyMemory(configInfo,
  1517. &configurationContext.PortConfig,
  1518. sizeof(PORT_CONFIGURATION_INFORMATION));
  1519. //
  1520. // Copy the SrbExtensionSize from device extension to ConfigInfo.
  1521. // A check will be made later to determine if the miniport updated
  1522. // this value
  1523. //
  1524. configInfo->SrbExtensionSize = adapter->SrbExtensionSize;
  1525. configInfo->SpecificLuExtensionSize = adapter->HwLogicalUnitExtensionSize;
  1526. //
  1527. // initialize the access range array
  1528. //
  1529. if(hwInitializationData->NumberOfAccessRanges != 0) {
  1530. configInfo->AccessRanges = (PVOID) (configInfo + 1);
  1531. //
  1532. // Quadword align this
  1533. //
  1534. (ULONG_PTR) (configInfo->AccessRanges) += 7;
  1535. (ULONG_PTR) (configInfo->AccessRanges) &= ~7;
  1536. RtlCopyMemory(configInfo->AccessRanges,
  1537. configurationContext.AccessRanges,
  1538. (hwInitializationData->NumberOfAccessRanges *
  1539. sizeof(ACCESS_RANGE)));
  1540. }
  1541. //
  1542. // Set the adapter interface type.
  1543. //
  1544. configInfo->AdapterInterfaceType = interfaceType;
  1545. //
  1546. // Since we've been handed resources we need to build a config info
  1547. // structure before we can call the find adapter routine
  1548. //
  1549. SpBuildConfiguration(adapter,
  1550. hwInitializationData,
  1551. configInfo);
  1552. SpGetSlotNumber(Fdo, configInfo, adapter->AllocatedResources);
  1553. //
  1554. // Get the miniport configuration inofmraiton
  1555. //
  1556. status = SpCallHwFindAdapter(Fdo,
  1557. hwInitializationData,
  1558. NULL,
  1559. &configurationContext,
  1560. configInfo,
  1561. &callAgain);
  1562. if(status == STATUS_DEVICE_DOES_NOT_EXIST) {
  1563. adapter->PortConfig = NULL;
  1564. ExFreePool(configInfo);
  1565. } else if(NT_SUCCESS(status)) {
  1566. status = SpAllocateAdapterResources(Fdo);
  1567. if(NT_SUCCESS(status)) {
  1568. PCOMMON_EXTENSION commonExtension = Fdo->DeviceExtension;
  1569. BOOLEAN stopped;
  1570. //
  1571. // If the device's previous state is IRP_MN_STOP_DEVICE then
  1572. // it should have a disable count of 1. Clear the disabled
  1573. // state.
  1574. //
  1575. stopped =
  1576. ((commonExtension->CurrentPnpState == IRP_MN_STOP_DEVICE) ?
  1577. TRUE :
  1578. FALSE);
  1579. if(stopped) {
  1580. ASSERT(adapter->CommonExtension.PreviousPnpState == IRP_MN_START_DEVICE);
  1581. ASSERT(adapter->DisableCount == 1);
  1582. adapter->DisableCount = 0;
  1583. CLEAR_FLAG(adapter->InterruptData.InterruptFlags,
  1584. PD_DISABLE_INTERRUPTS);
  1585. }
  1586. status = SpCallHwInitialize(Fdo);
  1587. if(stopped) {
  1588. KIRQL oldIrql;
  1589. PVOID sectionHandle;
  1590. //
  1591. // Restart i/o processing.
  1592. //
  1593. sectionHandle =
  1594. MmLockPagableCodeSection(ScsiPortInitPnpAdapter);
  1595. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  1596. IoStartNextPacket(Fdo, FALSE);
  1597. KeLowerIrql(oldIrql);
  1598. MmUnlockPagableImageSection(sectionHandle);
  1599. }
  1600. }
  1601. }
  1602. } finally {
  1603. if(!NT_SUCCESS(status)) {
  1604. PIO_ERROR_LOG_PACKET errorLogEntry;
  1605. //
  1606. // An error occured - log it.
  1607. //
  1608. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  1609. IoAllocateErrorLogEntry(
  1610. Fdo,
  1611. sizeof(IO_ERROR_LOG_PACKET));
  1612. if(errorLogEntry != NULL) {
  1613. errorLogEntry->ErrorCode = IO_ERR_DRIVER_ERROR;
  1614. errorLogEntry->UniqueErrorValue = uniqueId;
  1615. errorLogEntry->FinalStatus = status;
  1616. errorLogEntry->DumpDataSize = 0;
  1617. IoWriteErrorLogEntry(errorLogEntry);
  1618. }
  1619. //
  1620. // Clean up the last device object which is not used.
  1621. //
  1622. SpDestroyAdapter(adapter, FALSE);
  1623. if (configurationContext.AccessRanges != NULL) {
  1624. ExFreePool(configurationContext.AccessRanges);
  1625. }
  1626. if (configurationContext.Parameter != NULL) {
  1627. ExFreePool(configurationContext.Parameter);
  1628. }
  1629. } else {
  1630. //
  1631. // Determine which adapter control functions this miniport will
  1632. // support for the adapter.
  1633. //
  1634. SpGetSupportedAdapterControlFunctions(adapter);
  1635. }
  1636. }
  1637. return status;
  1638. }
  1639. PHW_INITIALIZATION_DATA
  1640. SpFindInitData(
  1641. IN PSCSIPORT_DRIVER_EXTENSION DriverExtension,
  1642. IN INTERFACE_TYPE InterfaceType
  1643. )
  1644. /*++
  1645. Routine Description:
  1646. This routine will search the list of chained init structures looking for
  1647. the first one that matches the interface type in the resource list.
  1648. Arguments:
  1649. DriverExtension - The driver extension to be searched
  1650. ResourceList - this resource list describes the (interface) type of the
  1651. adapter we are looking for
  1652. Return Value:
  1653. a pointer to the HW_INITIALIZATION_DATA structure for this interface type
  1654. NULL if none was found
  1655. --*/
  1656. {
  1657. PSP_INIT_CHAIN_ENTRY chainEntry = DriverExtension->InitChain;
  1658. PAGED_CODE();
  1659. while(chainEntry != NULL) {
  1660. if(chainEntry->InitData.AdapterInterfaceType == InterfaceType) {
  1661. return &(chainEntry->InitData);
  1662. }
  1663. chainEntry = chainEntry->NextEntry;
  1664. }
  1665. return NULL;
  1666. }
  1667. NTSTATUS
  1668. SpStartLowerDevice(
  1669. IN PDEVICE_OBJECT DeviceObject,
  1670. IN PIRP Irp
  1671. )
  1672. /*++
  1673. Routine Description:
  1674. This routine will forward the start request to the next lower device and
  1675. block until it's completion.
  1676. Arguments:
  1677. DeviceObject - the device to which the start request was issued.
  1678. Irp - the start request
  1679. Return Value:
  1680. status
  1681. --*/
  1682. {
  1683. PADAPTER_EXTENSION adapter = DeviceObject->DeviceExtension;
  1684. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  1685. PKEVENT event;
  1686. NTSTATUS status;
  1687. PAGED_CODE();
  1688. event = SpAllocatePool(NonPagedPool,
  1689. sizeof(KEVENT),
  1690. SCSIPORT_TAG_EVENT,
  1691. DeviceObject->DriverObject);
  1692. if(event == NULL) {
  1693. return STATUS_INSUFFICIENT_RESOURCES;
  1694. }
  1695. KeInitializeEvent(event, SynchronizationEvent, FALSE);
  1696. IoCopyCurrentIrpStackLocationToNext(Irp);
  1697. IoSetCompletionRoutine(Irp,
  1698. SpSignalCompletion,
  1699. event,
  1700. TRUE,
  1701. TRUE,
  1702. TRUE);
  1703. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  1704. if(status == STATUS_PENDING) {
  1705. KeWaitForSingleObject(event, Executive, KernelMode, FALSE, NULL);
  1706. status = Irp->IoStatus.Status;
  1707. }
  1708. if(NT_SUCCESS(status)) {
  1709. PIO_STACK_LOCATION irpStack;
  1710. //
  1711. // Now go and retrieve any interfaces we need from the lower device.
  1712. //
  1713. Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1714. irpStack = IoGetNextIrpStackLocation(Irp);
  1715. irpStack->Parameters.QueryInterface.InterfaceType =
  1716. (LPGUID) &GUID_BUS_INTERFACE_STANDARD;
  1717. irpStack->Parameters.QueryInterface.Size =
  1718. sizeof(BUS_INTERFACE_STANDARD);
  1719. irpStack->Parameters.QueryInterface.Version = 1;
  1720. irpStack->Parameters.QueryInterface.Interface =
  1721. (PINTERFACE) &(adapter->LowerBusInterfaceStandard);
  1722. irpStack->MajorFunction = IRP_MJ_PNP;
  1723. irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
  1724. KeResetEvent(event);
  1725. IoSetCompletionRoutine(Irp,
  1726. SpSignalCompletion,
  1727. event,
  1728. TRUE,
  1729. TRUE,
  1730. TRUE);
  1731. IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  1732. KeWaitForSingleObject(event, Executive, KernelMode, FALSE, NULL);
  1733. if(NT_SUCCESS(Irp->IoStatus.Status)) {
  1734. adapter->LowerBusInterfaceStandardRetrieved = TRUE;
  1735. } else {
  1736. DebugPrint((1, "LowerBusInterfaceStandard request returned "
  1737. "%#08lx\n", Irp->IoStatus.Status));
  1738. adapter->LowerBusInterfaceStandardRetrieved = FALSE;
  1739. }
  1740. Irp->IoStatus.Status = status;
  1741. }
  1742. ExFreePool(event);
  1743. return status;
  1744. }
  1745. VOID
  1746. SpGetSlotNumber(
  1747. IN PDEVICE_OBJECT Fdo,
  1748. IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
  1749. IN PCM_RESOURCE_LIST ResourceList
  1750. )
  1751. /*++
  1752. Routine Description:
  1753. This routine will open the registry key for the associated Pdo and try
  1754. to retrieve the bus, slot and function numbers that will be stored there
  1755. if this was a device we detected or one that the user has configured by
  1756. hand. These values will be stored in the ConfigInfo structure for the
  1757. adapter.
  1758. If this information does not exist then the values will be filled with
  1759. zeros and the IsVirtualSlot flag will be set in the Fdo for use by other
  1760. routines.
  1761. Arguments:
  1762. Fdo - a pointer to the functional device object for this adapter
  1763. ConfigInfo - the ConfigInfo structure to be changed
  1764. Return Value:
  1765. None
  1766. --*/
  1767. {
  1768. PADAPTER_EXTENSION adapter = Fdo->DeviceExtension;
  1769. HANDLE instanceHandle = NULL;
  1770. HANDLE parametersHandle = NULL;
  1771. NTSTATUS status;
  1772. PAGED_CODE();
  1773. adapter->IsInVirtualSlot = FALSE;
  1774. try {
  1775. OBJECT_ATTRIBUTES objectAttributes;
  1776. UNICODE_STRING unicodeKeyName;
  1777. status = IoOpenDeviceRegistryKey(adapter->LowerPdo,
  1778. PLUGPLAY_REGKEY_DEVICE,
  1779. KEY_READ,
  1780. &instanceHandle);
  1781. if(!NT_SUCCESS(status)) {
  1782. leave;
  1783. }
  1784. RtlInitUnicodeString(&unicodeKeyName, L"Scsiport");
  1785. InitializeObjectAttributes(
  1786. &objectAttributes,
  1787. &unicodeKeyName,
  1788. OBJ_CASE_INSENSITIVE,
  1789. instanceHandle,
  1790. NULL);
  1791. status = ZwOpenKey(&parametersHandle,
  1792. KEY_READ,
  1793. &objectAttributes);
  1794. if(!NT_SUCCESS(status)) {
  1795. leave;
  1796. } else {
  1797. RTL_QUERY_REGISTRY_TABLE queryTable[3];
  1798. ULONG busNumber;
  1799. ULONG slotNumber;
  1800. ULONG negativeOne = 0xffffffff;
  1801. RtlZeroMemory(queryTable, sizeof(queryTable));
  1802. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1803. queryTable[0].Name = L"SlotNumber";
  1804. queryTable[0].EntryContext = &slotNumber;
  1805. queryTable[0].DefaultType = REG_DWORD;
  1806. queryTable[0].DefaultData = &negativeOne;
  1807. queryTable[0].DefaultLength = sizeof(ULONG);
  1808. queryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
  1809. queryTable[1].Name = L"BusNumber";
  1810. queryTable[1].EntryContext = &busNumber;
  1811. queryTable[1].DefaultType = REG_DWORD;
  1812. queryTable[1].DefaultData = &negativeOne;
  1813. queryTable[1].DefaultLength = sizeof(ULONG);
  1814. status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE,
  1815. (PWSTR) parametersHandle,
  1816. queryTable,
  1817. NULL,
  1818. NULL);
  1819. if(!NT_SUCCESS(status)) {
  1820. leave;
  1821. }
  1822. if((busNumber == negativeOne) || (slotNumber == negativeOne)) {
  1823. ConfigInfo->SystemIoBusNumber = ResourceList->List[0].BusNumber;
  1824. ConfigInfo->SlotNumber = 0;
  1825. adapter->IsInVirtualSlot = TRUE;
  1826. } else {
  1827. ConfigInfo->SystemIoBusNumber = busNumber;
  1828. ConfigInfo->SlotNumber = slotNumber;
  1829. adapter->IsInVirtualSlot = FALSE;
  1830. }
  1831. }
  1832. } finally {
  1833. //
  1834. // If an error occurred then we'll need to try virtualizing this
  1835. // adapter
  1836. //
  1837. if(!NT_SUCCESS(status)) {
  1838. //
  1839. // Send ourself a query capabilities IRP so that we can retrieve
  1840. // slot and function numbers from PCI.
  1841. //
  1842. status = SpQueryCapabilities(adapter);
  1843. if(NT_SUCCESS(status)) {
  1844. ConfigInfo->SystemIoBusNumber = ResourceList->List[0].BusNumber;
  1845. ConfigInfo->SlotNumber = adapter->VirtualSlotNumber.u.AsULONG;
  1846. adapter->IsInVirtualSlot = TRUE;
  1847. }
  1848. }
  1849. if(instanceHandle != NULL) {
  1850. ZwClose(instanceHandle);
  1851. }
  1852. if(parametersHandle != NULL) {
  1853. ZwClose(parametersHandle);
  1854. }
  1855. }
  1856. return;
  1857. }
  1858. PSCSIPORT_DEVICE_TYPE
  1859. SpGetDeviceTypeInfo(
  1860. IN UCHAR DeviceType
  1861. )
  1862. {
  1863. PAGED_CODE();
  1864. if(DeviceType >= NUM_DEVICE_TYPE_INFO_ENTRIES) {
  1865. return &(DeviceTypeInfo[NUM_DEVICE_TYPE_INFO_ENTRIES - 1]);
  1866. } else {
  1867. return &(DeviceTypeInfo[DeviceType]);
  1868. }
  1869. };
  1870. PWCHAR
  1871. ScsiPortAddGenericControllerId(
  1872. IN PDRIVER_OBJECT DriverObject,
  1873. IN PWCHAR IdList
  1874. )
  1875. /*++
  1876. Routine Description:
  1877. This routine will attempt to add the id GEN_SCSIADAPTER to the provided
  1878. list of compatible id's.
  1879. Arguments:
  1880. Pdo - a pointer to the physical device object being queried
  1881. UnicodeString - a pointer to an already allocated unicode string structure.
  1882. This routine will allocate and fill in the buffer of this
  1883. structure
  1884. Returns:
  1885. status
  1886. --*/
  1887. {
  1888. ULONG stringLength = 0;
  1889. ULONG i = 0;
  1890. PWCHAR addedString = L"GEN_SCSIADAPTER";
  1891. PWCHAR newList;
  1892. PWCHAR p;
  1893. PAGED_CODE();
  1894. //
  1895. // If strings were provided then count them to determine a length for the
  1896. // new id list.
  1897. //
  1898. if(IdList != NULL) {
  1899. i = 0;
  1900. while((IdList[i] != UNICODE_NULL) || (IdList[i+1] != UNICODE_NULL)) {
  1901. i++;
  1902. }
  1903. //
  1904. // Compensate for the fact that we stopped counting just before the
  1905. // first byte of the double-null.
  1906. //
  1907. i += 2;
  1908. stringLength = i;
  1909. }
  1910. stringLength += wcslen(L"GEN_SCSIADAPTER");
  1911. //
  1912. // We'll need to add in yet another NULL to terminate the current ending
  1913. // string.
  1914. //
  1915. stringLength += 2;
  1916. //
  1917. // Allocate a new string list to replace the existing one with.
  1918. //
  1919. newList = SpAllocatePool(PagedPool,
  1920. (stringLength * sizeof(WCHAR)),
  1921. SCSIPORT_TAG_PNP_ID,
  1922. DriverObject);
  1923. if(newList == NULL) {
  1924. return NULL;
  1925. }
  1926. RtlFillMemory(newList, (stringLength * sizeof(WCHAR)), '@');
  1927. //
  1928. // If we were provided with a string then copy it into the buffer we just
  1929. // allocated.
  1930. //
  1931. if(ARGUMENT_PRESENT(IdList)) {
  1932. i = 0;
  1933. while((IdList[i] != UNICODE_NULL) || (IdList[i+1] != UNICODE_NULL)) {
  1934. newList[i] = IdList[i];
  1935. i++;
  1936. }
  1937. //
  1938. // Terminate the string we just wrote.
  1939. //
  1940. newList[i] = UNICODE_NULL;
  1941. p = &(newList[i+1]);
  1942. } else {
  1943. p = newList;
  1944. }
  1945. //
  1946. // Copy the new id string into the buffer.
  1947. //
  1948. for(i = 0; addedString[i] != UNICODE_NULL; i++) {
  1949. *p = addedString[i];
  1950. p++;
  1951. }
  1952. //
  1953. // Write two unicode nulls to the string to terminate it.
  1954. //
  1955. *p = UNICODE_NULL;
  1956. p++;
  1957. *p = UNICODE_NULL;
  1958. //
  1959. // Set up the first id string
  1960. //
  1961. return newList;
  1962. }
  1963. NTSTATUS
  1964. SpQueryCapabilities(
  1965. IN PADAPTER_EXTENSION Adapter
  1966. )
  1967. {
  1968. DEVICE_CAPABILITIES capabilities;
  1969. PIRP irp;
  1970. PIO_STACK_LOCATION irpStack;
  1971. KEVENT event;
  1972. NTSTATUS status;
  1973. PAGED_CODE();
  1974. //
  1975. // Initialize the capabilities structure.
  1976. //
  1977. RtlZeroMemory(&capabilities, sizeof(DEVICE_CAPABILITIES));
  1978. capabilities.Size = sizeof(DEVICE_CAPABILITIES);
  1979. capabilities.Version = 1;
  1980. capabilities.Address = capabilities.UINumber = (ULONG)-1;
  1981. //
  1982. // Initialize the event we're going to wait on.
  1983. //
  1984. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1985. //
  1986. // Allocate a new irp.
  1987. //
  1988. irp = SpAllocateIrp((CCHAR) (Adapter->DeviceObject->StackSize + 1),
  1989. FALSE,
  1990. Adapter->DeviceObject->DriverObject);
  1991. if(irp == NULL) {
  1992. return STATUS_INSUFFICIENT_RESOURCES;
  1993. }
  1994. irpStack = IoGetNextIrpStackLocation(irp);
  1995. irpStack->MajorFunction = IRP_MJ_PNP;
  1996. irpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
  1997. irpStack->Parameters.DeviceCapabilities.Capabilities = &capabilities;
  1998. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1999. IoSetCompletionRoutine(irp,
  2000. SpSignalCompletion,
  2001. &event,
  2002. TRUE,
  2003. TRUE,
  2004. TRUE);
  2005. //
  2006. // Send the irp to ourself ... just in case we ever start modifying
  2007. // the contents of the capabilities in our PNP dispatch routine.
  2008. //
  2009. IoCallDriver(Adapter->DeviceObject, irp);
  2010. KeWaitForSingleObject(&event,
  2011. Executive,
  2012. KernelMode,
  2013. FALSE,
  2014. NULL);
  2015. status = irp->IoStatus.Status;
  2016. if(NT_SUCCESS(status)) {
  2017. USHORT device;
  2018. USHORT function;
  2019. device = (USHORT) (capabilities.Address >> 0x10);
  2020. function = (USHORT) (capabilities.Address & 0x0000ffff);
  2021. Adapter->VirtualSlotNumber.u.bits.DeviceNumber = device;
  2022. Adapter->VirtualSlotNumber.u.bits.FunctionNumber = function;
  2023. } else {
  2024. Adapter->VirtualSlotNumber.u.AsULONG = 0;
  2025. }
  2026. IoFreeIrp(irp);
  2027. return status;
  2028. }
  2029. BOOLEAN
  2030. SpGetInterrupt(
  2031. IN PCM_RESOURCE_LIST FullResourceList,
  2032. OUT ULONG *Irql,
  2033. OUT ULONG *Vector,
  2034. OUT KAFFINITY *Affinity
  2035. )
  2036. /*++
  2037. Routine Description:
  2038. Given a full resource list returns the interrupt.
  2039. Arguments:
  2040. FullResourceList - the resource list.
  2041. Irql - returns the irql for the interrupt.
  2042. Vector - returns the vector for the interrupt.
  2043. Affinity - returns the affinity for the interrupt.
  2044. Return Value:
  2045. TRUE if an interrupt is found.
  2046. FALSE if none was found (in which case the output parameters are not valid.
  2047. --*/
  2048. {
  2049. ULONG rangeNumber;
  2050. ULONG index;
  2051. PCM_FULL_RESOURCE_DESCRIPTOR resourceList;
  2052. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialData;
  2053. PAGED_CODE();
  2054. rangeNumber = 0;
  2055. resourceList = FullResourceList->List;
  2056. for (index = 0; index < resourceList->PartialResourceList.Count; index++) {
  2057. partialData = &resourceList->PartialResourceList.PartialDescriptors[index];
  2058. if(partialData->Type == CmResourceTypeInterrupt) {
  2059. *Irql = partialData->u.Interrupt.Level;
  2060. *Vector = partialData->u.Interrupt.Vector;
  2061. *Affinity = partialData->u.Interrupt.Affinity;
  2062. return TRUE;
  2063. }
  2064. }
  2065. return FALSE;
  2066. }
  2067. VOID
  2068. SpQueryDeviceRelationsCompletion(
  2069. IN PADAPTER_EXTENSION Adapter,
  2070. IN PSP_ENUMERATION_REQUEST Request,
  2071. IN NTSTATUS Unused
  2072. )
  2073. {
  2074. PIRP irp = (PIRP) Request->Context;
  2075. PDEVICE_RELATIONS deviceRelations;
  2076. PDEVICE_OBJECT lowerDevice = Adapter->CommonExtension.LowerDeviceObject;
  2077. NTSTATUS status;
  2078. PAGED_CODE();
  2079. ASSERT_FDO(Adapter->DeviceObject);
  2080. //
  2081. // Pnp is done in a system thread - we shouldn't get a user-mode APC to this
  2082. // thread.
  2083. //
  2084. ASSERT(Unused != STATUS_USER_APC);
  2085. //
  2086. // Return the list of devices on the bus
  2087. //
  2088. status = SpExtractDeviceRelations(Adapter, BusRelations, &deviceRelations);
  2089. if(NT_SUCCESS(status)) {
  2090. ULONG i;
  2091. DebugPrint((2, "SpQueryDeviceRelationsCompletion: Found %d devices "
  2092. "on adapter %#p\n",
  2093. deviceRelations->Count,
  2094. Adapter));
  2095. for(i = 0; i < deviceRelations->Count; i++) {
  2096. DebugPrint((2, "/t#%2d: device %#p\n",
  2097. i,
  2098. deviceRelations->Objects[i]));
  2099. }
  2100. }
  2101. //
  2102. // Put the pointer to the enumeration request object back.
  2103. //
  2104. Request = InterlockedCompareExchangePointer(
  2105. &Adapter->PnpEnumRequestPtr,
  2106. &(Adapter->PnpEnumerationRequest),
  2107. NULL);
  2108. ASSERT(Request == NULL);
  2109. //
  2110. // Store the status and the return information in the IRP.
  2111. //
  2112. irp->IoStatus.Status = status;
  2113. if(NT_SUCCESS(status)) {
  2114. irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  2115. } else {
  2116. irp->IoStatus.Information = (ULONG_PTR) NULL;
  2117. }
  2118. return;
  2119. }