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.

1162 lines
31 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. pdo.c
  5. Abstract:
  6. This module contains the dispatch routines for scsiport's physical device
  7. objects
  8. Authors:
  9. Peter Wieland
  10. Environment:
  11. Kernel mode only
  12. Notes:
  13. Revision History:
  14. --*/
  15. #include "port.h"
  16. #if DBG
  17. static const char *__file__ = __FILE__;
  18. #endif
  19. VOID
  20. SpAdapterCleanup(
  21. IN PADAPTER_EXTENSION DeviceExtension
  22. );
  23. VOID
  24. SpReapChildren(
  25. IN PADAPTER_EXTENSION Adapter
  26. );
  27. BOOLEAN
  28. SpTerminateAdapterSynchronized (
  29. IN PADAPTER_EXTENSION Adapter
  30. );
  31. BOOLEAN
  32. SpRemoveAdapterSynchronized(
  33. IN PADAPTER_EXTENSION Adapter
  34. );
  35. VOID
  36. SpFlushAllRequests(
  37. IN PVOID HwDeviceExtension,
  38. IN UCHAR PathId,
  39. IN UCHAR TargetId,
  40. IN UCHAR Lun,
  41. IN UCHAR SrbStatus
  42. );
  43. #ifdef ALLOC_PRAGMA
  44. #pragma alloc_text(PAGE, SpDeleteLogicalUnit)
  45. #pragma alloc_text(PAGE, SpRemoveLogicalUnit)
  46. #pragma alloc_text(PAGE, SpWaitForRemoveLock)
  47. #pragma alloc_text(PAGE, SpAdapterCleanup)
  48. #pragma alloc_text(PAGE, SpReapChildren)
  49. #pragma alloc_text(PAGELOCK, ScsiPortRemoveAdapter)
  50. #endif
  51. BOOLEAN
  52. SpRemoveLogicalUnit(
  53. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  54. IN UCHAR RemoveType
  55. )
  56. {
  57. PADAPTER_EXTENSION adapterExtension = LogicalUnit->AdapterExtension;
  58. ULONG isRemoved;
  59. ULONG oldDebugLevel;
  60. PAGED_CODE();
  61. if(LogicalUnit->CommonExtension.IsRemoved != REMOVE_COMPLETE) {
  62. if(RemoveType == IRP_MN_REMOVE_DEVICE) {
  63. SpWaitForRemoveLock(LogicalUnit->DeviceObject, SP_BASE_REMOVE_LOCK );
  64. //
  65. // If the device was claimed we should release it now.
  66. //
  67. if(LogicalUnit->IsClaimed) {
  68. LogicalUnit->IsClaimed = FALSE;
  69. LogicalUnit->IsLegacyClaim = FALSE;
  70. }
  71. }
  72. DebugPrint((1, "SpRemoveLogicalUnit - %sremoving device %#p\n",
  73. (RemoveType == IRP_MN_SURPRISE_REMOVAL) ? "surprise " : "",
  74. LogicalUnit));
  75. //
  76. // If the lun isn't marked as missing yet or is marked as missing but
  77. // PNP hasn't been informed yet then we cannot delete it. Set it back
  78. // to the NO_REMOVE state so that we'll be able to attempt a rescan.
  79. //
  80. // Likewise if the lun is invisible then just swallow the remove
  81. // operation now that we've cleared any existing claims.
  82. //
  83. if(RemoveType == IRP_MN_REMOVE_DEVICE) {
  84. //
  85. // If the device is not missing or is missing but is still
  86. // enumerated then don't finish destroying it.
  87. //
  88. if((LogicalUnit->IsMissing == TRUE) &&
  89. (LogicalUnit->IsEnumerated == FALSE)) {
  90. // do nothing here - fall through and destroy the device.
  91. } else {
  92. DebugPrint((1, "SpRemoveLogicalUnit - device is not missing "
  93. "and will not be destroyed\n"));
  94. SpAcquireRemoveLock(LogicalUnit->DeviceObject, SP_BASE_REMOVE_LOCK);
  95. LogicalUnit->CommonExtension.IsRemoved = NO_REMOVE;
  96. return FALSE;
  97. }
  98. } else if((LogicalUnit->IsVisible == FALSE) &&
  99. (LogicalUnit->IsMissing == FALSE)) {
  100. //
  101. // The surprise remove came because the device is no longer
  102. // visible. We don't want to destroy it.
  103. //
  104. return FALSE;
  105. }
  106. //
  107. // Mark the device as uninitialized so that we'll go back and
  108. // recreate all the necessary stuff if it gets restarted.
  109. //
  110. LogicalUnit->CommonExtension.IsInitialized = FALSE;
  111. //
  112. // Delete the device map entry for this one (if any).
  113. //
  114. SpDeleteDeviceMapEntry(&(LogicalUnit->CommonExtension));
  115. if(RemoveType == IRP_MN_REMOVE_DEVICE) {
  116. ASSERT(LogicalUnit->RequestTimeoutCounter == -1);
  117. ASSERT(LogicalUnit->ReadyLogicalUnit == NULL);
  118. ASSERT(LogicalUnit->PendingRequest == NULL);
  119. ASSERT(LogicalUnit->BusyRequest == NULL);
  120. ASSERT(LogicalUnit->QueueCount == 0);
  121. LogicalUnit->CommonExtension.IsRemoved = REMOVE_COMPLETE;
  122. //
  123. // Yank this out of the logical unit list.
  124. //
  125. SpRemoveLogicalUnitFromBin(LogicalUnit->AdapterExtension,
  126. LogicalUnit);
  127. LogicalUnit->PathId = 0xff;
  128. LogicalUnit->TargetId = 0xff;
  129. LogicalUnit->Lun = 0xff;
  130. //
  131. // If this device wasn't temporary then delete it.
  132. //
  133. if(LogicalUnit->IsTemporary == FALSE) {
  134. SpDeleteLogicalUnit(LogicalUnit);
  135. }
  136. }
  137. }
  138. return TRUE;
  139. }
  140. VOID
  141. SpDeleteLogicalUnit(
  142. IN PLOGICAL_UNIT_EXTENSION LogicalUnit
  143. )
  144. /*++
  145. Routine Description:
  146. This routine will release any resources held for the logical unit, mark the
  147. device extension as deleted, and call the io system to actually delete
  148. the object. The device object will be deleted once it's reference count
  149. drops to zero.
  150. Arguments:
  151. LogicalUnit - the device object for the logical unit to be deleted.
  152. Return Value:
  153. none
  154. --*/
  155. {
  156. PAGED_CODE();
  157. ASSERT(LogicalUnit->ReadyLogicalUnit == NULL);
  158. ASSERT(LogicalUnit->PendingRequest == NULL);
  159. ASSERT(LogicalUnit->BusyRequest == NULL);
  160. ASSERT(LogicalUnit->QueueCount == 0);
  161. ASSERT(LogicalUnit->PathId == 0xff);
  162. ASSERT(LogicalUnit->TargetId == 0xff);
  163. ASSERT(LogicalUnit->Lun == 0xff);
  164. //
  165. // Unregister with WMI.
  166. //
  167. if(LogicalUnit->CommonExtension.WmiInitialized == TRUE) {
  168. //
  169. // Destroy all our WMI resources and unregister with WMI.
  170. //
  171. IoWMIRegistrationControl(LogicalUnit->DeviceObject,
  172. WMIREG_ACTION_DEREGISTER);
  173. //
  174. // We should be asking the WmiFreeRequestList of remove some
  175. // free cells.
  176. LogicalUnit->CommonExtension.WmiInitialized = FALSE;
  177. SpWmiDestroySpRegInfo(LogicalUnit->DeviceObject);
  178. }
  179. #if DBG
  180. // ASSERT(LogicalUnit->CommonExtension.RemoveTrackingList == NULL);
  181. ExDeleteNPagedLookasideList(
  182. &(LogicalUnit->CommonExtension.RemoveTrackingLookasideList));
  183. #endif
  184. //
  185. // If the request sense irp still exists, delete it.
  186. //
  187. if(LogicalUnit->RequestSenseIrp != NULL) {
  188. IoFreeIrp(LogicalUnit->RequestSenseIrp);
  189. LogicalUnit->RequestSenseIrp = NULL;
  190. }
  191. if(LogicalUnit->HwLogicalUnitExtension != NULL) {
  192. ExFreePool(LogicalUnit->HwLogicalUnitExtension);
  193. LogicalUnit->HwLogicalUnitExtension = NULL;
  194. }
  195. if(LogicalUnit->SerialNumber.Buffer != NULL) {
  196. ExFreePool(LogicalUnit->SerialNumber.Buffer);
  197. RtlInitAnsiString(&(LogicalUnit->SerialNumber), NULL);
  198. }
  199. if(LogicalUnit->DeviceIdentifierPage != NULL) {
  200. ExFreePool(LogicalUnit->DeviceIdentifierPage);
  201. LogicalUnit->DeviceIdentifierPage = NULL;
  202. }
  203. //
  204. // If this lun is temporary then clear the RescanLun field in the adapter.
  205. //
  206. if(LogicalUnit->IsTemporary) {
  207. ASSERT(LogicalUnit->AdapterExtension->RescanLun = LogicalUnit);
  208. LogicalUnit->AdapterExtension->RescanLun = NULL;
  209. } else {
  210. ASSERT(LogicalUnit->AdapterExtension->RescanLun != LogicalUnit);
  211. }
  212. IoDeleteDevice(LogicalUnit->DeviceObject);
  213. return;
  214. }
  215. VOID
  216. ScsiPortRemoveAdapter(
  217. IN PDEVICE_OBJECT AdapterObject,
  218. IN BOOLEAN Surprise
  219. )
  220. {
  221. PADAPTER_EXTENSION adapter = AdapterObject->DeviceExtension;
  222. PCOMMON_EXTENSION commonExtension = AdapterObject->DeviceExtension;
  223. NTSTATUS status = STATUS_SUCCESS;
  224. PAGED_CODE();
  225. ASSERT_FDO(AdapterObject);
  226. ASSERT(adapter->IsPnp);
  227. //
  228. // Set the flag PD_ADAPTER_REMOVED to keep scsiport from calling into the
  229. // miniport after we've started this teardown.
  230. //
  231. if(Surprise == FALSE) {
  232. PVOID sectionHandle;
  233. KIRQL oldIrql;
  234. //
  235. // Wait until all outstanding requests have been completed. If the
  236. // adapter was surprise removed, we don't need to wait on the remove
  237. // lock again, since we already waited for it in the surprise remove
  238. // path.
  239. //
  240. if (commonExtension->CurrentPnpState != IRP_MN_SURPRISE_REMOVAL) {
  241. SpWaitForRemoveLock(AdapterObject, AdapterObject);
  242. }
  243. //
  244. // If the device is started we should uninitialize the miniport and
  245. // release it's resources. Fortunately this is exactly what stop does.
  246. //
  247. if((commonExtension->CurrentPnpState != IRP_MN_SURPRISE_REMOVAL) &&
  248. ((commonExtension->CurrentPnpState == IRP_MN_START_DEVICE) ||
  249. (commonExtension->PreviousPnpState == IRP_MN_START_DEVICE))) {
  250. //
  251. // Okay. If this adapter can't support remove then we're dead
  252. //
  253. ASSERT(SpIsAdapterControlTypeSupported(adapter, ScsiStopAdapter) == TRUE);
  254. //
  255. // Stop the miniport now that it's safe.
  256. //
  257. SpEnableDisableAdapter(adapter, FALSE);
  258. //
  259. // Mark the adapter as removed.
  260. //
  261. #ifdef ALLOC_PRAGMA
  262. sectionHandle = MmLockPagableCodeSection(ScsiPortRemoveAdapter);
  263. InterlockedIncrement(&SpPAGELOCKLockCount);
  264. #endif
  265. KeAcquireSpinLock(&(adapter->SpinLock), &oldIrql);
  266. adapter->SynchronizeExecution(adapter->InterruptObject,
  267. SpRemoveAdapterSynchronized,
  268. adapter);
  269. KeReleaseSpinLock(&(adapter->SpinLock), oldIrql);
  270. #ifdef ALLOC_PRAGMA
  271. InterlockedDecrement(&SpPAGELOCKLockCount);
  272. MmUnlockPagableImageSection(sectionHandle);
  273. #endif
  274. }
  275. SpReapChildren(adapter);
  276. }
  277. if(commonExtension->WmiInitialized == TRUE) {
  278. //
  279. // Destroy all our WMI resources and unregister with WMI.
  280. //
  281. IoWMIRegistrationControl(AdapterObject, WMIREG_ACTION_DEREGISTER);
  282. SpWmiRemoveFreeMiniPortRequestItems(adapter);
  283. commonExtension->WmiInitialized = FALSE;
  284. commonExtension->WmiMiniPortInitialized = FALSE;
  285. }
  286. //
  287. // If we are surprise removed, the following gets executed twice, but
  288. // it's safe to do so.
  289. //
  290. SpDeleteDeviceMapEntry(commonExtension);
  291. SpDestroyAdapter(adapter, Surprise);
  292. return;
  293. }
  294. VOID
  295. SpWaitForRemoveLock(
  296. IN PDEVICE_OBJECT DeviceObject,
  297. IN PVOID LockTag
  298. )
  299. {
  300. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  301. PAGED_CODE();
  302. //
  303. // Mark the thing as removing
  304. //
  305. commonExtension->IsRemoved = REMOVE_PENDING;
  306. //
  307. // Release our outstanding lock.
  308. //
  309. SpReleaseRemoveLock(DeviceObject, LockTag);
  310. DebugPrint((4, "SpWaitForRemoveLock - Reference count is now %d\n",
  311. commonExtension->RemoveLock));
  312. KeWaitForSingleObject(&(commonExtension->RemoveEvent),
  313. Executive,
  314. KernelMode,
  315. FALSE,
  316. NULL);
  317. DebugPrint((4, "SpWaitForRemoveLock - removing device %#p\n",
  318. DeviceObject));
  319. return;
  320. }
  321. VOID
  322. SpDestroyAdapter(
  323. IN PADAPTER_EXTENSION Adapter,
  324. IN BOOLEAN Surprise
  325. )
  326. {
  327. SpReleaseAdapterResources(Adapter, FALSE, Surprise);
  328. SpAdapterCleanup(Adapter);
  329. return;
  330. }
  331. VOID
  332. SpAdapterCleanup(
  333. IN PADAPTER_EXTENSION Adapter
  334. )
  335. /*++
  336. Routine Description:
  337. This routine cleans up the names associated with the specified adapter
  338. and the i/o system counts.
  339. Arguments:
  340. Adapter - Supplies a pointer to the device extension to be deleted.
  341. Return Value:
  342. None.
  343. --*/
  344. {
  345. PCOMMON_EXTENSION commonExtension = &(Adapter->CommonExtension);
  346. PAGED_CODE();
  347. //
  348. // If we assigned a port number to this adapter then attempt to delete the
  349. // symbolic links we created to it.
  350. //
  351. if(Adapter->PortNumber != -1) {
  352. PWCHAR wideNameStrings[] = {L"\\Device\\ScsiPort%d",
  353. L"\\DosDevices\\Scsi%d:"};
  354. ULONG i;
  355. for(i = 0; i < (sizeof(wideNameStrings) / sizeof(PWCHAR)); i++) {
  356. WCHAR wideLinkName[64];
  357. UNICODE_STRING unicodeLinkName;
  358. swprintf(wideLinkName, wideNameStrings[i], Adapter->PortNumber);
  359. RtlInitUnicodeString(&unicodeLinkName, wideLinkName);
  360. IoDeleteSymbolicLink(&unicodeLinkName);
  361. }
  362. Adapter->PortNumber = -1;
  363. //
  364. // Decrement the scsiport count.
  365. //
  366. IoGetConfigurationInformation()->ScsiPortCount--;
  367. }
  368. return;
  369. }
  370. VOID
  371. SpReleaseAdapterResources(
  372. IN PADAPTER_EXTENSION Adapter,
  373. IN BOOLEAN Stop,
  374. IN BOOLEAN Surprise
  375. )
  376. /*++
  377. Routine Description:
  378. This function deletes all of the storage associated with a device
  379. extension, disconnects from the timers and interrupts and then deletes the
  380. object. This function can be called at any time during the initialization.
  381. Arguments:
  382. Adapter - Supplies a pointer to the device extesnion to be deleted.
  383. Surprise - This is redundant, but is used by stop, remove and surprise-remove
  384. SurpriseRemoved - Indicates that the adapter has been surprise-removed
  385. Return Value:
  386. None.
  387. --*/
  388. {
  389. PCOMMON_EXTENSION commonExtension = &(Adapter->CommonExtension);
  390. ULONG j;
  391. PVOID tempPointer;
  392. PAGED_CODE();
  393. #if DBG
  394. if(!Surprise && !Stop) {
  395. //
  396. // Free the Remove tracking lookaside list.
  397. //
  398. ExDeleteNPagedLookasideList(&(commonExtension->RemoveTrackingLookasideList));
  399. }
  400. #endif
  401. //
  402. // Stop the time and disconnect the interrupt if they have been
  403. // initialized. The interrupt object is connected after
  404. // timer has been initialized, and the interrupt object is connected, but
  405. // before the timer is started.
  406. //
  407. if(Adapter->DeviceObject->Timer != NULL) {
  408. IoStopTimer(Adapter->DeviceObject);
  409. KeCancelTimer(&(Adapter->MiniPortTimer));
  410. }
  411. if(Adapter->SynchronizeExecution != SpSynchronizeExecution) {
  412. if (Adapter->InterruptObject) {
  413. IoDisconnectInterrupt(Adapter->InterruptObject);
  414. }
  415. if (Adapter->InterruptObject2) {
  416. IoDisconnectInterrupt(Adapter->InterruptObject2);
  417. Adapter->InterruptObject2 = NULL;
  418. }
  419. //
  420. // SpSynchronizeExecution expects to get a pointer to the
  421. // adapter extension as the "interrupt" parameter.
  422. //
  423. Adapter->InterruptObject = (PVOID) Adapter;
  424. Adapter->SynchronizeExecution = SpSynchronizeExecution;
  425. }
  426. //
  427. // Delete the miniport's device extension
  428. //
  429. if (Adapter->HwDeviceExtension != NULL) {
  430. PHW_DEVICE_EXTENSION devExt =
  431. CONTAINING_RECORD(Adapter->HwDeviceExtension,
  432. HW_DEVICE_EXTENSION,
  433. HwDeviceExtension);
  434. ExFreePool(devExt);
  435. Adapter->HwDeviceExtension = NULL;
  436. }
  437. //
  438. // Free the configuration information structure.
  439. //
  440. if (Adapter->PortConfig) {
  441. ExFreePool(Adapter->PortConfig);
  442. Adapter->PortConfig = NULL;
  443. }
  444. //
  445. // Deallocate SCSIPORT WMI REGINFO information, if any.
  446. //
  447. SpWmiDestroySpRegInfo(Adapter->DeviceObject);
  448. //
  449. // Free the common buffer.
  450. //
  451. if (SpVerifyingCommonBuffer(Adapter)) {
  452. SpFreeCommonBufferVrfy(Adapter);
  453. } else {
  454. if (Adapter->SrbExtensionBuffer != NULL &&
  455. Adapter->CommonBufferSize != 0) {
  456. if (Adapter->DmaAdapterObject == NULL) {
  457. //
  458. // Since there is no adapter just free the non-paged pool.
  459. //
  460. ExFreePool(Adapter->SrbExtensionBuffer);
  461. } else {
  462. if(Adapter->UncachedExtensionIsCommonBuffer == FALSE) {
  463. MmFreeContiguousMemorySpecifyCache(Adapter->SrbExtensionBuffer,
  464. Adapter->CommonBufferSize,
  465. MmCached);
  466. } else {
  467. FreeCommonBuffer(
  468. Adapter->DmaAdapterObject,
  469. Adapter->CommonBufferSize,
  470. Adapter->PhysicalCommonBuffer,
  471. Adapter->SrbExtensionBuffer,
  472. FALSE);
  473. }
  474. }
  475. Adapter->SrbExtensionBuffer = NULL;
  476. }
  477. }
  478. //
  479. // Get rid of our dma adapter.
  480. //
  481. if(Adapter->DmaAdapterObject != NULL) {
  482. PutDmaAdapter(Adapter->DmaAdapterObject);
  483. Adapter->DmaAdapterObject = NULL;
  484. }
  485. //
  486. // Free the SRB data array, if this is not a surprise remove. We should
  487. // not free the lookaside list in case of a surprise remove, as some
  488. // requests might have allocated SRB_DATA blocks w/o holding the adapter
  489. // remove lock. All other resources are required only if we ere able to
  490. // acquire the adapter remove lock, which we guarantee we won't at this point.
  491. // It is safe to free the array during remove, because we delete all the LUN's
  492. // before realeasing adapters resources
  493. if( !Surprise ){
  494. if (Adapter->SrbDataListInitialized) {
  495. if(Adapter->EmergencySrbData != NULL) {
  496. ExFreeToNPagedLookasideList(
  497. &Adapter->SrbDataLookasideList,
  498. Adapter->EmergencySrbData);
  499. Adapter->EmergencySrbData = NULL;
  500. }
  501. ExDeleteNPagedLookasideList(&Adapter->SrbDataLookasideList);
  502. Adapter->SrbDataListInitialized = FALSE;
  503. }
  504. }
  505. if (Adapter->InquiryBuffer != NULL) {
  506. ExFreePool(Adapter->InquiryBuffer);
  507. Adapter->InquiryBuffer = NULL;
  508. }
  509. if (Adapter->InquirySenseBuffer != NULL) {
  510. ExFreePool(Adapter->InquirySenseBuffer);
  511. Adapter->InquirySenseBuffer = NULL;
  512. }
  513. if (Adapter->InquiryIrp != NULL) {
  514. IoFreeIrp(Adapter->InquiryIrp);
  515. Adapter->InquiryIrp = NULL;
  516. }
  517. if (Adapter->InquiryMdl != NULL) {
  518. IoFreeMdl(Adapter->InquiryMdl);
  519. Adapter->InquiryMdl = NULL;
  520. }
  521. //
  522. // Unmap any mapped areas.
  523. //
  524. SpReleaseMappedAddresses(Adapter);
  525. //
  526. // If we've got any resource lists allocated still we should free them
  527. // now.
  528. //
  529. if(Adapter->AllocatedResources != NULL) {
  530. ExFreePool(Adapter->AllocatedResources);
  531. Adapter->AllocatedResources = NULL;
  532. }
  533. if(Adapter->TranslatedResources != NULL) {
  534. ExFreePool(Adapter->TranslatedResources);
  535. Adapter->TranslatedResources = NULL;
  536. }
  537. //
  538. // Cleanup verifier resources.
  539. //
  540. if (SpVerifierActive(Adapter)) {
  541. SpDoVerifierCleanup(Adapter);
  542. }
  543. #if defined(FORWARD_PROGRESS)
  544. //
  545. // Cleanup the adapter's reserved pages.
  546. //
  547. if (Adapter->ReservedPages != NULL) {
  548. MmFreeMappingAddress(Adapter->ReservedPages,
  549. SCSIPORT_TAG_MAPPING_LIST);
  550. Adapter->ReservedPages = NULL;
  551. }
  552. if (Adapter->ReservedMdl != NULL) {
  553. IoFreeMdl(Adapter->ReservedMdl);
  554. Adapter->ReservedMdl = NULL;
  555. }
  556. #endif
  557. Adapter->CommonExtension.IsInitialized = FALSE;
  558. return;
  559. }
  560. VOID
  561. SpReapChildren(
  562. IN PADAPTER_EXTENSION Adapter
  563. )
  564. {
  565. ULONG j;
  566. PAGED_CODE();
  567. //
  568. // Run through the logical unit bins and remove any child devices which
  569. // remain.
  570. //
  571. for(j = 0; j < NUMBER_LOGICAL_UNIT_BINS; j++) {
  572. while(Adapter->LogicalUnitList[j].List != NULL) {
  573. PLOGICAL_UNIT_EXTENSION lun =
  574. Adapter->LogicalUnitList[j].List;
  575. lun->IsMissing = TRUE;
  576. lun->IsEnumerated = FALSE;
  577. SpRemoveLogicalUnit(lun, IRP_MN_REMOVE_DEVICE);
  578. }
  579. }
  580. //
  581. // Remove the initiator LUs.
  582. //
  583. for (j = 0; j < 8; j++) {
  584. PLOGICAL_UNIT_EXTENSION lu = Adapter->InitiatorLU[j];
  585. if (lu != NULL) {
  586. Adapter->InitiatorLU[j] = NULL;
  587. }
  588. }
  589. return;
  590. }
  591. VOID
  592. SpTerminateAdapter(
  593. IN PADAPTER_EXTENSION Adapter
  594. )
  595. /*++
  596. Routine Description:
  597. This routine will terminate the miniport's control of the adapter. It
  598. does not cleanly shutdown the miniport and should only be called when
  599. scsiport is notified that the adapter has been surprise removed.
  600. This works by synchronizing with the miniport and setting flags to
  601. disable any new calls into the miniport. Once this has been done it can
  602. run through and complete any i/o requests which may still be inside
  603. the miniport.
  604. Arguments:
  605. Adapter - the adapter to terminate.
  606. Return Value:
  607. none
  608. --*/
  609. {
  610. KIRQL oldIrql;
  611. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  612. KeAcquireSpinLockAtDpcLevel(&(Adapter->SpinLock));
  613. if (Adapter->CommonExtension.CurrentPnpState == IRP_MN_START_DEVICE) {
  614. //
  615. // TA synchronized will stop all calls into the miniport and complete
  616. // all active requests.
  617. //
  618. Adapter->SynchronizeExecution(Adapter->InterruptObject,
  619. SpTerminateAdapterSynchronized,
  620. Adapter);
  621. Adapter->CommonExtension.PreviousPnpState = 0xff;
  622. SpFlushAllRequests(Adapter->HwDeviceExtension,
  623. 0xff,
  624. 0xff,
  625. 0xff,
  626. SRB_STATUS_NO_HBA);
  627. //
  628. // Stop the miniport timer
  629. //
  630. KeCancelTimer(&(Adapter->MiniPortTimer));
  631. //
  632. // We keep the device object timer running so that any held, busy or
  633. // otherwise deferred requests will have a chance to get flushed out.
  634. // We can give the whole process a boost by setting the adapter timeout
  635. // counter to 1 (it will go to zero in the tick handler) and running
  636. // the tick handler by hand here.
  637. //
  638. Adapter->PortTimeoutCounter = 1;
  639. ScsiPortTickHandler(Adapter->DeviceObject, NULL);
  640. } else {
  641. KeReleaseSpinLockFromDpcLevel(&(Adapter->SpinLock));
  642. }
  643. KeLowerIrql(oldIrql);
  644. return;
  645. }
  646. BOOLEAN
  647. SpTerminateAdapterSynchronized(
  648. IN PADAPTER_EXTENSION Adapter
  649. )
  650. {
  651. //
  652. // Disable the interrupt from coming in.
  653. //
  654. SET_FLAG(Adapter->InterruptData.InterruptFlags, PD_ADAPTER_REMOVED);
  655. ScsiPortCompleteRequest(Adapter->HwDeviceExtension,
  656. 0xff,
  657. 0xff,
  658. 0xff,
  659. SRB_STATUS_NO_HBA);
  660. //
  661. //This needs to be done to start the next request sitting in the adapter
  662. //queue, otherwise surprise remove will wait forever for the remove
  663. //lockcount to be zero.
  664. //
  665. ScsiPortNotification(NextRequest,
  666. Adapter->HwDeviceExtension);
  667. //
  668. // Run the completion DPC.
  669. //
  670. if(TEST_FLAG(Adapter->InterruptData.InterruptFlags,
  671. PD_NOTIFICATION_REQUIRED)) {
  672. SpRequestCompletionDpc(Adapter->DeviceObject);
  673. }
  674. return TRUE;
  675. }
  676. BOOLEAN
  677. SpRemoveAdapterSynchronized(
  678. PADAPTER_EXTENSION Adapter
  679. )
  680. {
  681. //
  682. // Disable the interrupt from coming in.
  683. //
  684. SET_FLAG(Adapter->InterruptData.InterruptFlags, PD_ADAPTER_REMOVED);
  685. return TRUE;
  686. }
  687. VOID
  688. SpFlushAllRequests(
  689. IN PVOID HwDeviceExtension,
  690. IN UCHAR PathId,
  691. IN UCHAR TargetId,
  692. IN UCHAR Lun,
  693. IN UCHAR SrbStatus
  694. )
  695. /*++
  696. Routine Description:
  697. Flushes all requests in all the Lun device queues, busy and pending
  698. requests on all Luns. The request stuck in the adapter's CurrentIrp
  699. field of the adapter due to PD_RESET_HELD will be taken care of by
  700. the tick handler. In short all the requests stuck anywhere in ScsiPort
  701. will be flushed. Unfortunately this is not enough to handle Surprise
  702. Remove. We also need a small check in Startio so that we flush all
  703. requests on the lun for which we got a request.
  704. Arguments:
  705. DeviceExtenson - Supplies the HBA miniport driver's adapter data storage.
  706. TargetId, Lun and PathId - specify device address on a SCSI bus.
  707. SrbStatus - Status to be returned in each completed SRB.
  708. Return Value:
  709. None.
  710. Note: This routine must be called with the Adapter SpinLock held, and
  711. the lock would be released by this routine.
  712. --*/
  713. {
  714. PADAPTER_EXTENSION deviceExtension = GET_FDO_EXTENSION(HwDeviceExtension);
  715. ULONG binNumber;
  716. PIRP listIrp = NULL;
  717. PIRP nextIrp;
  718. PKDEVICE_QUEUE_ENTRY packet;
  719. PIO_STACK_LOCATION irpStack;
  720. PSCSI_REQUEST_BLOCK srb;
  721. for (binNumber = 0; binNumber < NUMBER_LOGICAL_UNIT_BINS; binNumber++) {
  722. PLOGICAL_UNIT_BIN bin = &deviceExtension->LogicalUnitList[binNumber];
  723. PLOGICAL_UNIT_EXTENSION LogicalUnit;
  724. ULONG limit = 0;
  725. LogicalUnit = bin->List;
  726. DebugPrint((2, "ScsiPortCompleteRequest: Completing requests in "
  727. "bin %d [%#p]\n",
  728. binNumber, bin));
  729. for(LogicalUnit = bin->List;
  730. LogicalUnit != NULL;
  731. LogicalUnit = LogicalUnit->NextLogicalUnit) {
  732. PLIST_ENTRY entry;
  733. ASSERT(limit++ < 1000);
  734. //
  735. // See if this logical unit matches the pattern. Check for -1
  736. // first since this seems to be the most popular way to complete
  737. // requests.
  738. //
  739. if (((PathId == SP_UNTAGGED) || (PathId == LogicalUnit->PathId)) &&
  740. ((TargetId == SP_UNTAGGED) ||
  741. (TargetId == LogicalUnit->TargetId)) &&
  742. ((Lun == SP_UNTAGGED) || (Lun == LogicalUnit->Lun))) {
  743. //
  744. // The queue may not be busy so we have to use the IfBusy variant.
  745. // Use a zero key to pull items from the head of it (if any are there)
  746. //
  747. while ((packet =
  748. KeRemoveByKeyDeviceQueueIfBusy(
  749. &(LogicalUnit->DeviceObject->DeviceQueue),
  750. 0))
  751. != NULL) {
  752. nextIrp = CONTAINING_RECORD(packet,
  753. IRP,
  754. Tail.Overlay.DeviceQueueEntry);
  755. //
  756. // Get the srb.
  757. //
  758. irpStack = IoGetCurrentIrpStackLocation(nextIrp);
  759. srb = irpStack->Parameters.Scsi.Srb;
  760. //
  761. // Set the status code.
  762. //
  763. srb->SrbStatus = SrbStatus;
  764. nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  765. //
  766. // Link the requests. They will be completed after the
  767. // spinlock is released.
  768. //
  769. nextIrp->Tail.Overlay.ListEntry.Flink =
  770. (PLIST_ENTRY)listIrp;
  771. listIrp = nextIrp;
  772. }
  773. //
  774. // If there is a pending request on the LU, add it to the list so it
  775. // gets flushed along with the queued requests.
  776. //
  777. if (LogicalUnit->PendingRequest != NULL) {
  778. PIRP irp = LogicalUnit->PendingRequest->CurrentIrp;
  779. srb = LogicalUnit->PendingRequest->CurrentSrb;
  780. DebugPrint((1, "SpFlushReleaseQueue: flushing pending request irp:%p srb:%p\n", irp, srb));
  781. srb->SrbStatus = SrbStatus;
  782. irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  783. irp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY) listIrp;
  784. listIrp = irp;
  785. LogicalUnit->PendingRequest = NULL;
  786. ASSERT(LogicalUnit->LuFlags | LU_PENDING_LU_REQUEST);
  787. CLEAR_FLAG(LogicalUnit->LuFlags, LU_PENDING_LU_REQUEST);
  788. }
  789. //
  790. // If there is a busy request on the LU, add it to the list so it
  791. // gets flushed along with the queued requests.
  792. //
  793. if ( LogicalUnit->BusyRequest ) {
  794. PIRP irp = LogicalUnit->BusyRequest->CurrentIrp;
  795. srb = LogicalUnit->BusyRequest->CurrentSrb;
  796. DebugPrint((1, "SpFlushReleaseQueue: flushing busy request irp:%\
  797. p srb:%p\n", irp, srb));
  798. srb->SrbStatus = SrbStatus;
  799. irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  800. irp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY) listIrp;
  801. listIrp = irp;
  802. LogicalUnit->BusyRequest = NULL;
  803. ASSERT((LU_LOGICAL_UNIT_IS_BUSY | LU_QUEUE_IS_FULL));
  804. CLEAR_FLAG(LogicalUnit->LuFlags,
  805. (LU_LOGICAL_UNIT_IS_BUSY | LU_QUEUE_IS_FULL));
  806. }
  807. }
  808. }
  809. }
  810. KeReleaseSpinLockFromDpcLevel(&(deviceExtension->SpinLock));
  811. //
  812. // Complete the flushed requests.
  813. //
  814. while (listIrp != NULL) {
  815. PSRB_DATA srbData;
  816. nextIrp = listIrp;
  817. listIrp = (PIRP) nextIrp->Tail.Overlay.ListEntry.Flink;
  818. //
  819. // Get the srb.
  820. //
  821. irpStack = IoGetCurrentIrpStackLocation(nextIrp);
  822. srb = irpStack->Parameters.Scsi.Srb;
  823. srbData = srb->OriginalRequest;
  824. srb->OriginalRequest = nextIrp;
  825. SpReleaseRemoveLock(deviceExtension->DeviceObject, nextIrp);
  826. SpCompleteRequest(deviceExtension->DeviceObject,
  827. nextIrp,
  828. srbData,
  829. IO_NO_INCREMENT);
  830. }
  831. return;
  832. }