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

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