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.

2477 lines
67 KiB

  1. #include "mpio.h"
  2. #include <stdio.h>
  3. #include <ntddk.h>
  4. ULONG CheckState = 0;
  5. PDEVICE_OBJECT
  6. IoGetLowerDeviceObject(
  7. IN PDEVICE_OBJECT DeviceObject
  8. );
  9. PREAL_DEV_INFO
  10. MPIOGetTargetInfo(
  11. IN PMPDISK_EXTENSION DiskExtension,
  12. IN PVOID PathId,
  13. IN PDEVICE_OBJECT Filter
  14. )
  15. {
  16. PREAL_DEV_INFO targetInfo = DiskExtension->TargetInfo;
  17. ULONG i;
  18. MPDebugPrint((3,
  19. "MPIOGetTargetInfo: PathId(%x) Filter (%x) TargetInfo (%x)\n",
  20. PathId,
  21. Filter,
  22. targetInfo));
  23. //
  24. // If PathId was passed in, the caller is looking for
  25. // the targetInfo match based on Path.
  26. //
  27. if (PathId) {
  28. //
  29. // Check each of the targetInfo structs for the
  30. // appropriate PathId.
  31. //
  32. for (i = 0; i < DiskExtension->TargetInfoCount; i++) {
  33. if (targetInfo->PathId == PathId) {
  34. return targetInfo;
  35. }
  36. //
  37. // Go to the next targetInfo.
  38. //
  39. targetInfo++;
  40. }
  41. } else if (Filter) {
  42. //
  43. // Looking for a DsmId match.
  44. //
  45. for (i = 0; i < DiskExtension->TargetInfoCount; i++) {
  46. if (targetInfo->AdapterFilter == Filter) {
  47. return targetInfo;
  48. }
  49. targetInfo++;
  50. }
  51. } else {
  52. ASSERT(PathId || Filter);
  53. }
  54. ASSERT(FALSE);
  55. //
  56. // PathId and DsmId were not found.
  57. //
  58. return NULL;
  59. }
  60. PDISK_ENTRY
  61. MPIOGetDiskEntry(
  62. IN PDEVICE_OBJECT DeviceObject,
  63. IN ULONG DiskIndex
  64. )
  65. {
  66. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  67. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  68. PLIST_ENTRY entry;
  69. ULONG i;
  70. //
  71. // Ensure that the Index is in range.
  72. //
  73. if ((DiskIndex + 1) > controlExtension->NumberDevices) {
  74. return NULL;
  75. }
  76. //
  77. // Run the list of MPDisk entries up to DiskIndex.
  78. //
  79. entry = controlExtension->DeviceList.Flink;
  80. for (i = 0; i < DiskIndex; entry = entry->Flink, i++) {
  81. #if DBG
  82. PDISK_ENTRY diskEntry;
  83. diskEntry = CONTAINING_RECORD(entry, DISK_ENTRY, ListEntry);
  84. ASSERT(diskEntry);
  85. MPDebugPrint((2,
  86. "MPIOGetDiskEntry: Index (%x) diskEntry (%x)\n",
  87. i,
  88. diskEntry));
  89. #endif
  90. }
  91. //
  92. // Return the DISK_ENTRY
  93. //
  94. return CONTAINING_RECORD(entry, DISK_ENTRY, ListEntry);
  95. }
  96. BOOLEAN
  97. MPIOFindLowerDevice(
  98. IN PDEVICE_OBJECT MPDiskObject,
  99. IN PDEVICE_OBJECT LowerDevice
  100. )
  101. {
  102. PDEVICE_EXTENSION deviceExtension = MPDiskObject->DeviceExtension;
  103. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  104. ULONG i;
  105. //
  106. // Search for LowerDevice in array of underlying PDO's.
  107. //
  108. for (i = 0; i < diskExtension->TargetInfoCount; i++) {
  109. if (diskExtension->TargetInfo[i].PortPdo == LowerDevice) {
  110. return TRUE;
  111. }
  112. }
  113. return FALSE;
  114. }
  115. PDSM_ENTRY
  116. MPIOGetDsm(
  117. IN PDEVICE_OBJECT DeviceObject,
  118. IN ULONG DsmIndex
  119. )
  120. {
  121. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  122. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  123. PLIST_ENTRY entry;
  124. ULONG i;
  125. //
  126. // See if requested index is in range.
  127. //
  128. if ((DsmIndex + 1) > controlExtension->NumberDSMs) {
  129. return NULL;
  130. }
  131. //
  132. // Get the first entry.
  133. //
  134. entry = controlExtension->DsmList.Flink;
  135. //
  136. // Run the list to DsmIndex.
  137. //
  138. for (i = 0; i < DsmIndex; entry = entry->Flink, i++) {
  139. #if DBG
  140. PDSM_ENTRY dsmEntry;
  141. dsmEntry = CONTAINING_RECORD(entry, DSM_ENTRY, ListEntry);
  142. ASSERT(dsmEntry);
  143. MPDebugPrint((2,
  144. "MPIOGetDsm: Index (%x) dsmEntry (%x)\n",
  145. i,
  146. dsmEntry));
  147. #endif
  148. }
  149. //
  150. // Return the entry.
  151. //
  152. return CONTAINING_RECORD(entry, DSM_ENTRY, ListEntry);
  153. }
  154. PCONTROLLER_ENTRY
  155. MPIOFindController(
  156. IN PDEVICE_OBJECT DeviceObject,
  157. IN PDEVICE_OBJECT ControllerObject,
  158. IN ULONGLONG Id
  159. )
  160. {
  161. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  162. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  163. PCONTROLLER_ENTRY controllerEntry;
  164. PLIST_ENTRY entry;
  165. //
  166. // Run the list of controller entries looking
  167. //
  168. for (entry = controlExtension->ControllerList.Flink;
  169. entry != &controlExtension->ControllerList;
  170. entry = entry->Flink) {
  171. controllerEntry = CONTAINING_RECORD(entry, CONTROLLER_ENTRY, ListEntry);
  172. if ((controllerEntry->ControllerInfo->ControllerIdentifier == Id) &&
  173. (controllerEntry->ControllerInfo->DeviceObject == ControllerObject)){
  174. return controllerEntry;
  175. }
  176. }
  177. return NULL;
  178. }
  179. PFLTR_ENTRY
  180. MPIOGetFltrEntry(
  181. IN PDEVICE_OBJECT DeviceObject,
  182. IN PDEVICE_OBJECT PortFdo,
  183. IN PDEVICE_OBJECT AdapterFilter
  184. )
  185. {
  186. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  187. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  188. PFLTR_ENTRY fltrEntry;
  189. PLIST_ENTRY entry;
  190. for (entry = controlExtension->FilterList.Flink;
  191. entry != &controlExtension->FilterList;
  192. entry = entry->Flink) {
  193. fltrEntry = CONTAINING_RECORD(entry, FLTR_ENTRY, ListEntry);
  194. if (PortFdo) {
  195. if (fltrEntry->PortFdo == PortFdo) {
  196. return fltrEntry;
  197. }
  198. } else if (AdapterFilter) {
  199. if (fltrEntry->FilterObject == AdapterFilter) {
  200. return fltrEntry;
  201. }
  202. }
  203. }
  204. return NULL;
  205. }
  206. ULONG
  207. MPIOGetPathCount(
  208. IN PDEVICE_OBJECT DeviceObject,
  209. IN PVOID PathId
  210. )
  211. {
  212. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  213. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  214. PDEVICE_EXTENSION mpdiskExtension;
  215. PMPDISK_EXTENSION diskExtension;
  216. PREAL_DEV_INFO deviceInfo;
  217. PDEVICE_OBJECT diskObject;
  218. PDISK_ENTRY diskEntry;
  219. ULONG deviceCount = 0;
  220. ULONG i;
  221. ULONG j;
  222. //
  223. // Get each mpdisk in turn.
  224. //
  225. for (i = 0; i < controlExtension->NumberDevices; i++) {
  226. diskEntry = MPIOGetDiskEntry(DeviceObject,
  227. i);
  228. diskObject = diskEntry->PdoObject;
  229. mpdiskExtension = diskObject->DeviceExtension;
  230. diskExtension = mpdiskExtension->TypeExtension;
  231. deviceInfo = diskExtension->TargetInfo;
  232. //
  233. // Find the path on this disk.
  234. //
  235. for (j = 0; j < diskExtension->TargetInfoCount; j++) {
  236. if (deviceInfo->PathId == PathId) {
  237. //
  238. // Found it, bump the total.
  239. //
  240. deviceCount++;
  241. }
  242. //
  243. // Go to the next deviceInfo.
  244. //
  245. deviceInfo++;
  246. }
  247. }
  248. MPDebugPrint((1,
  249. "MPIOGetPathCount: %u devices on Path (%x)\n",
  250. deviceCount,
  251. PathId));
  252. return deviceCount;
  253. }
  254. NTSTATUS
  255. MPIOAddSingleDevice(
  256. IN PDEVICE_OBJECT ControlObject,
  257. IN PADP_DEVICE_INFO DeviceInfo,
  258. IN PDEVICE_OBJECT PortObject,
  259. IN PDEVICE_OBJECT FilterObject
  260. )
  261. {
  262. PDSM_ENTRY entry;
  263. ULONG i;
  264. PVOID dsmExtension;
  265. NTSTATUS status = STATUS_SUCCESS;
  266. BOOLEAN claimed = FALSE;
  267. //
  268. // Run through each of the registered DSMs. The DO and
  269. // associated info will be passed to each, where they have
  270. // the opportunity to claim ownership.
  271. //
  272. i = 0;
  273. do {
  274. //
  275. // Get the next DSM entry.
  276. //
  277. entry = MPIOGetDsm(ControlObject, i);
  278. if (entry) {
  279. //
  280. // See if the DSM wants this device.
  281. //
  282. status = entry->InquireDriver(entry->DsmContext,
  283. DeviceInfo->DeviceObject,
  284. PortObject,
  285. DeviceInfo->DeviceDescriptor,
  286. DeviceInfo->DeviceIdList,
  287. &dsmExtension);
  288. if (status == STATUS_SUCCESS) {
  289. //
  290. // Ensure the DSM returned something.
  291. //
  292. ASSERT(dsmExtension);
  293. //
  294. // The DSM has indicated that it wants control of this device.
  295. //
  296. claimed = TRUE;
  297. //
  298. // Get more DSM info and handle setting up the MPDisk
  299. //
  300. status = MPIOHandleNewDevice(ControlObject,
  301. FilterObject,
  302. PortObject,
  303. DeviceInfo,
  304. entry,
  305. dsmExtension);
  306. if (!NT_SUCCESS(status)) {
  307. //
  308. // LOG an error. TODO.
  309. //
  310. claimed = FALSE;
  311. }
  312. }
  313. }
  314. i++;
  315. } while ((claimed == FALSE) && entry);
  316. return status;
  317. }
  318. NTSTATUS
  319. MPIOHandleDeviceArrivals(
  320. IN PDEVICE_OBJECT DeviceObject,
  321. IN PADP_DEVICE_LIST DeviceList,
  322. IN PDEVICE_RELATIONS CachedRelations,
  323. IN PDEVICE_RELATIONS Relations,
  324. IN PDEVICE_OBJECT PortObject,
  325. IN PDEVICE_OBJECT FilterObject,
  326. IN BOOLEAN NewList
  327. )
  328. {
  329. NTSTATUS status;
  330. ULONG devicesAdded = 0;
  331. ULONG i;
  332. ULONG j;
  333. ULONG k;
  334. BOOLEAN matched = FALSE;
  335. ASSERT(DeviceList->NumberDevices == Relations->Count);
  336. //
  337. // The list in Relations and DeviceList contain the same objects
  338. // at this point. CachedRelations contains the state prior to this call.
  339. //
  340. if (NewList == FALSE) {
  341. //
  342. // Compare the two relations structs to find the added devices.
  343. //
  344. for (i = 0; i < Relations->Count; i++) {
  345. for (j = 0; j < CachedRelations->Count; j++) {
  346. if (Relations->Objects[i] == CachedRelations->Objects[j]) {
  347. matched = TRUE;
  348. break;
  349. }
  350. }
  351. if (matched == FALSE) {
  352. //
  353. // Find it in the DeviceList.
  354. //
  355. for (k = 0; k < DeviceList->NumberDevices; k++) {
  356. if (Relations->Objects[i] == DeviceList->DeviceList[k].DeviceObject) {
  357. //
  358. // Add this one.
  359. //
  360. status = MPIOAddSingleDevice(DeviceObject,
  361. &DeviceList->DeviceList[k],
  362. PortObject,
  363. FilterObject);
  364. devicesAdded++;
  365. break;
  366. }
  367. }
  368. } else {
  369. matched = FALSE;
  370. }
  371. }
  372. } else {
  373. //
  374. // All devices need to be added.
  375. //
  376. //
  377. for (i = 0; i < Relations->Count; i++) {
  378. //
  379. // Add this one.
  380. //
  381. status = MPIOAddSingleDevice(DeviceObject,
  382. &DeviceList->DeviceList[i],
  383. PortObject,
  384. FilterObject);
  385. devicesAdded++;
  386. }
  387. }
  388. MPDebugPrint((1,
  389. "HandleDeviceArrivals: Added (%u)\n", devicesAdded));
  390. return STATUS_SUCCESS;
  391. }
  392. PDEVICE_RELATIONS
  393. MPIOHandleDeviceRemovals(
  394. IN PDEVICE_OBJECT DeviceObject,
  395. IN PADP_DEVICE_LIST DeviceList,
  396. IN PDEVICE_RELATIONS Relations
  397. )
  398. {
  399. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  400. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  401. PDEVICE_RELATIONS newRelations;
  402. ULONG i;
  403. ULONG j;
  404. ULONG k;
  405. ULONG devicesRemoved = 0;
  406. BOOLEAN matched = FALSE;
  407. BOOLEAN removed = FALSE;
  408. PDISK_ENTRY diskEntry;
  409. NTSTATUS status;
  410. //
  411. // For each device in the device relations (the current list), try to
  412. // find it in the DeviceList (the new list)
  413. //
  414. for (i = 0; i < Relations->Count; i++) {
  415. for (j = 0; j < DeviceList->NumberDevices; j++) {
  416. if (Relations->Objects[i] == DeviceList->DeviceList[j].DeviceObject) {
  417. matched = TRUE;
  418. MPDebugPrint((1,
  419. "HandleDeviceRemoval: Found (%x)\n",
  420. Relations->Objects[i]));
  421. break;
  422. }
  423. }
  424. if (matched == FALSE) {
  425. //
  426. // Remove Relations->Objects[i].
  427. //
  428. MPDebugPrint((1,
  429. "HandleDeviceRemoval: Removing (%x)\n",
  430. Relations->Objects[i]));
  431. //
  432. // Find the correct mpdisk object.
  433. //
  434. for (k = 0; k < controlExtension->NumberDevices; k++) {
  435. diskEntry = MPIOGetDiskEntry(DeviceObject,
  436. k);
  437. if (MPIOFindLowerDevice(diskEntry->PdoObject,
  438. Relations->Objects[i])) {
  439. status = MPIORemoveSingleDevice(diskEntry->PdoObject,
  440. Relations->Objects[i]);
  441. if (status == STATUS_PENDING) {
  442. //
  443. // This indicates that the device has outstanding IO's.
  444. // It will be removed once these complete.
  445. //
  446. continue;
  447. }
  448. devicesRemoved++;
  449. removed = TRUE;
  450. }
  451. }
  452. if ((removed == FALSE) && (status != STATUS_PENDING)) {
  453. MPDebugPrint((0,"HandleDeviceRemoval: Device marked for removal wasn't (%x)\n",
  454. Relations->Objects[i]));
  455. ASSERT(removed);
  456. }
  457. }
  458. matched = FALSE;
  459. removed = FALSE;
  460. }
  461. MPDebugPrint((0,
  462. "HandleDeviceRemoval: Removed (%u) devices\n",
  463. devicesRemoved));
  464. newRelations = MPIOBuildRelations(DeviceList);
  465. return newRelations;
  466. }
  467. NTSTATUS
  468. MPIORemoveDeviceEntry(
  469. IN PDEVICE_OBJECT DeviceObject,
  470. IN PREAL_DEV_INFO TargetInfo
  471. )
  472. {
  473. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  474. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  475. PVOID pathId;
  476. ULONG count;
  477. ULONG moveCount;
  478. ULONG newMask;
  479. ULONG i;
  480. ULONG k;
  481. NTSTATUS status;
  482. MPDebugPrint((0,
  483. "RemoveDeviceEntry: Removing %x from %x\n",
  484. TargetInfo,
  485. DeviceObject));
  486. //
  487. // The caller should be holding the config spinlock.
  488. //
  489. //
  490. // Determine the array entry for this deviceInfo.
  491. //
  492. count = diskExtension->TargetInfoCount;
  493. for (i = 0; i < count; i++) {
  494. MPDebugPrint((1,
  495. "RemoveDeviceEntry: Checking %x vs. %x\n",
  496. diskExtension->TargetInfo[i].PortPdo,
  497. TargetInfo->PortPdo));
  498. if (diskExtension->TargetInfo[i].PortPdo == TargetInfo->PortPdo) {
  499. diskExtension->DeviceMap &= ~ (1 << i);
  500. //
  501. // Move only those AFTER the removed entry.
  502. //
  503. moveCount = count - i;
  504. moveCount -= 1;
  505. //
  506. // Collapse the targetInfo array.
  507. //
  508. RtlMoveMemory(&diskExtension->TargetInfo[i],
  509. &diskExtension->TargetInfo[i+1],
  510. (moveCount * sizeof(REAL_DEV_INFO)));
  511. //
  512. // Indicate that there is one less entry.
  513. //
  514. diskExtension->TargetInfoCount--;
  515. //
  516. // Update the device map to reflect the new state of the world.
  517. //
  518. for (k = 0, newMask = 0; k < diskExtension->TargetInfoCount; k++) {
  519. newMask |= (1 << k);
  520. }
  521. MPDebugPrint((1,
  522. "RemoveDeviceEntry: Old Mask (%x) new mask (%x)\n",
  523. diskExtension->DeviceMap,
  524. newMask));
  525. InterlockedExchange(&diskExtension->DeviceMap, newMask);
  526. //
  527. // Zero out the last vacated entry.
  528. //
  529. RtlZeroMemory(&diskExtension->TargetInfo[count - 1], sizeof(REAL_DEV_INFO));
  530. break;
  531. }
  532. }
  533. return STATUS_SUCCESS;
  534. }
  535. NTSTATUS
  536. MPIORemoveSingleDevice(
  537. IN PDEVICE_OBJECT DeviceObject,
  538. IN PDEVICE_OBJECT Pdo
  539. )
  540. {
  541. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  542. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  543. PREAL_DEV_INFO deviceInfo;
  544. PDEVICE_OBJECT diskObject;
  545. PDSM_ENTRY dsm;
  546. PVOID pathId = NULL;
  547. ULONG i;
  548. ULONG k;
  549. ULONG count;
  550. ULONG moveCount;
  551. ULONG removedIndex = (ULONG)-1;
  552. ULONG newMask;
  553. ULONG remainingDevices;
  554. NTSTATUS status;
  555. KIRQL irql;
  556. BOOLEAN matched = FALSE;
  557. dsm = &diskExtension->DsmInfo;
  558. //
  559. // Grab this disk's spinlock. The submit path does the same.
  560. //
  561. KeAcquireSpinLock(&diskExtension->SpinLock, &irql);
  562. //
  563. // Find the corresponding targetInfo.
  564. //
  565. count = diskExtension->TargetInfoCount;
  566. deviceInfo = diskExtension->TargetInfo;
  567. for (i = 0; i < count; i++) {
  568. //
  569. // If this deviceInfo has Pdo, then break.
  570. //
  571. if (deviceInfo->PortPdo == Pdo) {
  572. matched = TRUE;
  573. break;
  574. } else {
  575. deviceInfo++;
  576. }
  577. }
  578. ASSERT(matched == TRUE);
  579. if ((deviceInfo == NULL) || (matched == FALSE)) {
  580. MPDebugPrint((0,
  581. "RemoveSingleDevice: Device not found\n"));
  582. //
  583. // For some reason, the device has already been removed.
  584. //
  585. KeReleaseSpinLock(&diskExtension->SpinLock, irql);
  586. return STATUS_DEVICE_NOT_CONNECTED;
  587. }
  588. MPDebugPrint((0,
  589. "RemoveSingleDevice: Removing %x from %x. DsmID %x\n",
  590. deviceInfo,
  591. DeviceObject,
  592. deviceInfo->DsmID));
  593. //
  594. // Tell the DSM that this device is about to go away.
  595. //
  596. status = dsm->RemovePending(dsm->DsmContext,
  597. deviceInfo->DsmID);
  598. //
  599. // Collapse our DsmId list so that we are in sync with the dsm.
  600. // Do this even though we may not remove the targetInfo entry.
  601. //
  602. count = diskExtension->DsmIdList.Count;
  603. for (i = 0; i < count; i++) {
  604. if (diskExtension->DsmIdList.IdList[i] == deviceInfo->DsmID) {
  605. //
  606. // Set the index. This is used if we can actually remove the device from
  607. // our and the DSM's lists.
  608. //
  609. removedIndex = i;
  610. //
  611. // One less DsmId in the list.
  612. //
  613. diskExtension->DsmIdList.Count--;
  614. //
  615. // Determine the number of entries to move in order to collapse
  616. // all the entries after this one.
  617. //
  618. moveCount = count - i;
  619. moveCount -= 1;
  620. //
  621. // Collapse the array.
  622. //
  623. RtlMoveMemory(&diskExtension->DsmIdList.IdList[i],
  624. &diskExtension->DsmIdList.IdList[i + 1],
  625. (moveCount * sizeof(PVOID)));
  626. diskExtension->DsmIdList.IdList[count - 1] = NULL;
  627. break;
  628. }
  629. }
  630. //
  631. // The DSM ID has to have been in the list.
  632. //
  633. ASSERT(removedIndex != (ULONG)-1);
  634. //
  635. // If there are any outstanding IO's, then we can't remove this yet.
  636. //
  637. if (deviceInfo->Requests) {
  638. MPDebugPrint((0,
  639. "RemoveSingleDevice: Pending removal for DeviceInfo (%x). DsmID (%x)\n",
  640. deviceInfo,
  641. deviceInfo->DsmID));
  642. //
  643. // The completion path will check this if outstanding requests go to zero and
  644. // handle the removal there.
  645. //
  646. deviceInfo->NeedsRemoval = TRUE;
  647. KeReleaseSpinLock(&diskExtension->SpinLock, irql);
  648. return STATUS_PENDING;
  649. }
  650. MPDebugPrint((1,
  651. "RemoveSingleDevice: Removing (%x). DeviceInfo (%x). DsmID (%x)\n",
  652. Pdo,
  653. deviceInfo,
  654. deviceInfo->DsmID));
  655. //
  656. // Call the DSM to remove this DsmID.
  657. //
  658. dsm = &diskExtension->DsmInfo;
  659. status = dsm->RemoveDevice(dsm->DsmContext,
  660. deviceInfo->DsmID,
  661. deviceInfo->PathId);
  662. if (!NT_SUCCESS(status)) {
  663. //
  664. // LOG
  665. //
  666. }
  667. //
  668. // Save off the pathId.
  669. //
  670. pathId = deviceInfo->PathId;
  671. //
  672. // Remove the deviceInfo element.
  673. //
  674. status = MPIORemoveDeviceEntry(DeviceObject,
  675. deviceInfo);
  676. //
  677. // Release the config spinlock.
  678. //
  679. KeReleaseSpinLock(&diskExtension->SpinLock, irql);
  680. //
  681. // Determine whether pathId needs to be removed.
  682. //
  683. remainingDevices = MPIOGetPathCount(diskExtension->ControlObject,
  684. pathId);
  685. if (remainingDevices == 0) {
  686. //
  687. // Can't remove the path if we aren't in a steady-state condition.
  688. // If not normal or degraded, mark the remove as pending.
  689. // queue a work-item and the state transition logic will fire the remove
  690. // when it's OK.
  691. //
  692. //if ((deviceExtension->State == MPIO_STATE_NORMAL) ||
  693. // (deviceExtension->State == MPIO_STATE_DEGRADED)) {
  694. if (FALSE) {
  695. MPDebugPrint((0,
  696. "RemoveSingleDevice: Removing path (%x). Disk (%x) in State (%x)\n",
  697. pathId,
  698. DeviceObject,
  699. deviceExtension->State));
  700. //
  701. // All devices on this path have been removed,
  702. // Go ahead and remove the path.
  703. //
  704. dsm->RemovePath(dsm->DsmContext,
  705. pathId);
  706. } else {
  707. PMPIO_REQUEST_INFO requestInfo;
  708. MPDebugPrint((0,
  709. "RemoveSingle: Queuing removal of path (%x). Disk (%x) in State (%x)\n",
  710. pathId,
  711. DeviceObject,
  712. deviceExtension->State));
  713. //
  714. // Allocate a work item
  715. // Fill it in to indicate a path removal.
  716. //
  717. requestInfo = ExAllocatePool(NonPagedPool, sizeof(MPIO_REQUEST_INFO));
  718. requestInfo->RequestComplete = NULL;
  719. requestInfo->Operation = PATH_REMOVAL;
  720. //
  721. // Set the Path that should be removed.
  722. //
  723. requestInfo->OperationSpecificInfo = pathId;
  724. requestInfo->ErrorMask = 0;
  725. ExInterlockedInsertTailList(&diskExtension->PendingWorkList,
  726. &requestInfo->ListEntry,
  727. &diskExtension->WorkListLock);
  728. //
  729. // Indicate that an item is in the pending list.
  730. //
  731. diskExtension->PendingItems++;
  732. }
  733. }
  734. return STATUS_SUCCESS;
  735. }
  736. NTSTATUS
  737. MPIOHandleRemoveAsync(
  738. IN PDEVICE_OBJECT DeviceObject,
  739. IN PREAL_DEV_INFO TargetInfo
  740. )
  741. {
  742. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  743. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  744. PMPIO_REQUEST_INFO requestInfo;
  745. PMPIO_DEVICE_REMOVAL deviceRemoval;
  746. //
  747. // Allocate the request packet and the removal info struct.
  748. //
  749. requestInfo = ExAllocatePool(NonPagedPool, sizeof(MPIO_REQUEST_INFO));
  750. deviceRemoval = ExAllocatePool(NonPagedPool, sizeof(MPIO_DEVICE_REMOVAL));
  751. //
  752. // No completion callback necessary.
  753. //
  754. requestInfo->RequestComplete = NULL;
  755. //
  756. // Indicate that this is a remove operation.
  757. //
  758. requestInfo->Operation = DEVICE_REMOVAL;
  759. //
  760. // Setup the removal info.
  761. //
  762. deviceRemoval->DeviceObject = DeviceObject;
  763. deviceRemoval->TargetInfo = TargetInfo;
  764. //
  765. // Set the removal info as SpecificInfo
  766. //
  767. requestInfo->OperationSpecificInfo = deviceRemoval;
  768. requestInfo->ErrorMask = 0;
  769. //
  770. // Queue it to the pending work list. The tick handler will put this
  771. // on the thread's work queue.
  772. //
  773. ExInterlockedInsertTailList(&diskExtension->PendingWorkList,
  774. &requestInfo->ListEntry,
  775. &diskExtension->WorkListLock);
  776. //
  777. // Tell the tick handler that there is work to do.
  778. //
  779. diskExtension->PendingItems++;
  780. return STATUS_SUCCESS;
  781. }
  782. NTSTATUS
  783. MPIORemoveDeviceAsync(
  784. IN PDEVICE_OBJECT DeviceObject,
  785. IN PREAL_DEV_INFO TargetInfo
  786. )
  787. {
  788. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  789. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  790. PDSM_ENTRY dsm;
  791. KIRQL irql;
  792. NTSTATUS status;
  793. PVOID dsmId;
  794. PVOID pathId;
  795. ULONG remainingDevices;
  796. //
  797. // BUGBUG: Need to document fully that RemoveDevice will be called
  798. // at DPC. If there is push-back from IHV's, then this will need to
  799. // be put on a thread.
  800. //
  801. //
  802. // Capture the dsm and path ID's as the call to RemoveDeviceEntry
  803. // will invalidate the TargetInfo structure.
  804. //
  805. dsmId = TargetInfo->DsmID;
  806. pathId = TargetInfo->PathId;
  807. KeAcquireSpinLock(&diskExtension->SpinLock, &irql);
  808. //
  809. // Remove our info structure.
  810. //
  811. MPIORemoveDeviceEntry(DeviceObject,
  812. TargetInfo);
  813. KeReleaseSpinLock(&diskExtension->SpinLock, irql);
  814. //
  815. // Call the DSM to remove this DsmID.
  816. //
  817. dsm = &diskExtension->DsmInfo;
  818. status = dsm->RemoveDevice(dsm->DsmContext,
  819. dsmId,
  820. pathId);
  821. //
  822. // Determine whether pathId needs to be removed.
  823. //
  824. remainingDevices = MPIOGetPathCount(diskExtension->ControlObject,
  825. pathId);
  826. if (remainingDevices == 0) {
  827. PMPIO_REQUEST_INFO requestInfo;
  828. MPDebugPrint((0,
  829. "RemoveSingleAsync: Queuing removal of path (%x). Disk (%x) in State (%x)\n",
  830. pathId,
  831. DeviceObject,
  832. deviceExtension->State));
  833. //
  834. // Allocate a work item
  835. // Fill it in to indicate a path removal.
  836. //
  837. requestInfo = ExAllocatePool(NonPagedPool, sizeof(MPIO_REQUEST_INFO));
  838. requestInfo->RequestComplete = NULL;
  839. requestInfo->Operation = PATH_REMOVAL;
  840. //
  841. // Set the Path that should be removed.
  842. //
  843. requestInfo->OperationSpecificInfo = pathId;
  844. requestInfo->ErrorMask = 0;
  845. ExInterlockedInsertTailList(&diskExtension->PendingWorkList,
  846. &requestInfo->ListEntry,
  847. &diskExtension->WorkListLock);
  848. //
  849. // Indicate that an item is in the pending list.
  850. //
  851. diskExtension->PendingItems++;
  852. #if 0
  853. //
  854. // All devices on this path have been removed,
  855. // Go ahead and remove the path.
  856. //
  857. dsm->RemovePath(dsm->DsmContext,
  858. pathId);
  859. #endif
  860. }
  861. return status;
  862. }
  863. NTSTATUS
  864. MPIOHandleNewDevice(
  865. IN PDEVICE_OBJECT DeviceObject,
  866. IN PDEVICE_OBJECT FilterObject,
  867. IN PDEVICE_OBJECT PortObject,
  868. IN PADP_DEVICE_INFO DeviceInfo,
  869. IN PDSM_ENTRY DsmEntry,
  870. IN PVOID DsmExtension
  871. )
  872. {
  873. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  874. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  875. PDEVICE_OBJECT diskObject;
  876. PDISK_ENTRY diskEntry;
  877. NTSTATUS status;
  878. ULONG i;
  879. BOOLEAN matched = FALSE;
  880. //
  881. // Run the list of MPDisk PDO's to see whether the new
  882. // device corresponds to an already existing one.
  883. //
  884. for (i = 0; i < controlExtension->NumberDevices; i++) {
  885. //
  886. // Get the next disk entry.
  887. //
  888. diskEntry = MPIOGetDiskEntry(DeviceObject,
  889. i);
  890. if (diskEntry) {
  891. //
  892. // Feed the MPDisk object to this routine, which will call
  893. // the DSMCompareRoutine to see if an MP state is present.
  894. //
  895. if (MPIOFindMatchingDevice(diskEntry->PdoObject,
  896. DeviceInfo,
  897. DsmEntry,
  898. DsmExtension)) {
  899. matched = TRUE;
  900. //
  901. // Got a match. Update the MPDisk.
  902. // PdoObject IS the mpdisk D.O.
  903. //
  904. status = MPIOUpdateDevice(diskEntry->PdoObject,
  905. FilterObject,
  906. PortObject,
  907. DeviceInfo,
  908. DsmExtension);
  909. return status;
  910. }
  911. } else {
  912. MPDebugPrint((1,
  913. "MPIOHandleNew: Some error.\n"));
  914. DbgBreakPoint();
  915. //
  916. // This certainly shouldn't happen, unless the internal
  917. // state is hosed.
  918. //
  919. // Log Error. TODO
  920. //
  921. status = STATUS_UNSUCCESSFUL;
  922. }
  923. }
  924. if (matched == FALSE) {
  925. //
  926. // Didn't match up any. Build a new PDO.
  927. //
  928. status = MPIOCreateDevice(DeviceObject,
  929. FilterObject,
  930. PortObject,
  931. DeviceInfo,
  932. DsmEntry,
  933. DsmExtension,
  934. &diskObject);
  935. if (status == STATUS_SUCCESS) {
  936. //
  937. // Indicate that one more multi-path disk
  938. // has been created.
  939. //
  940. controlExtension->NumberDevices++;
  941. //
  942. // Build a disk entry
  943. //
  944. diskEntry = ExAllocatePool(NonPagedPool, sizeof(DISK_ENTRY));
  945. ASSERT(diskEntry);
  946. RtlZeroMemory(diskEntry, sizeof(DISK_ENTRY));
  947. //
  948. // Set the new mp disk's DO.
  949. //
  950. diskEntry->PdoObject = diskObject;
  951. //
  952. // Add it to the list of mpdisks
  953. //
  954. ExInterlockedInsertTailList(&controlExtension->DeviceList,
  955. &diskEntry->ListEntry,
  956. &controlExtension->SpinLock);
  957. IoInvalidateDeviceRelations(deviceExtension->Pdo, BusRelations);
  958. }
  959. } else {
  960. MPDebugPrint((2,
  961. "MPIOHandleNew: Not creating a disk.\n"));
  962. }
  963. return status;
  964. }
  965. NTSTATUS
  966. MPIOForwardRequest(
  967. IN PDEVICE_OBJECT DeviceObject,
  968. IN PIRP Irp
  969. )
  970. /*++
  971. Routine Description:
  972. This routine sends the Irp to the next driver in line
  973. when the Irp is not processed by this driver.
  974. Arguments:
  975. DeviceObject
  976. Irp
  977. Return Value:
  978. NTSTATUS
  979. --*/
  980. {
  981. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  982. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  983. IoSkipCurrentIrpStackLocation(Irp);
  984. return IoCallDriver(deviceExtension->LowerDevice, Irp);
  985. }
  986. NTSTATUS
  987. MPIOSyncCompletion(
  988. IN PDEVICE_OBJECT DeviceObject,
  989. IN PIRP Irp,
  990. IN PVOID Context
  991. )
  992. /*++
  993. Routine Description:
  994. General-purpose completion routine, used for handling 'sync' requests
  995. such as PnP.
  996. Arguments:
  997. DeviceObject
  998. Irp
  999. Context - The event on which the caller is waiting.
  1000. Return Value:
  1001. NTSTATUS
  1002. --*/
  1003. {
  1004. PKEVENT event = Context;
  1005. MPDebugPrint((2,
  1006. "MPIOSyncCompletion: Irp %x\n",
  1007. Irp));
  1008. if (Irp->PendingReturned) {
  1009. IoMarkIrpPending(Irp);
  1010. }
  1011. KeSetEvent(event, 0, FALSE);
  1012. return STATUS_MORE_PROCESSING_REQUIRED;
  1013. }
  1014. NTSTATUS
  1015. MPIOGetScsiAddress(
  1016. IN PDEVICE_OBJECT DeviceObject,
  1017. OUT PSCSI_ADDRESS *ScsiAddress
  1018. )
  1019. /*++
  1020. Routine Description:
  1021. This routine issues the appropriate IOCTL to get the scsi address of DeviceObject.
  1022. The storage allocated becomes the responsibility of the caller.
  1023. Arguments:
  1024. DeviceObject - Device Object for a scsiport pdo returned in QDR.
  1025. ScsiAddress - pointer for the scsi address buffer.
  1026. Return Value:
  1027. Status of the request
  1028. --*/
  1029. {
  1030. PSCSI_ADDRESS scsiAddress;
  1031. PIO_STATUS_BLOCK ioStatus;
  1032. PIRP irp;
  1033. NTSTATUS status;
  1034. //
  1035. // Initialize the return values. This routine will only return success or
  1036. // insufficient resources.
  1037. //
  1038. *ScsiAddress = NULL;
  1039. status = STATUS_INSUFFICIENT_RESOURCES;
  1040. //
  1041. // Allocate storage. It's the caller's responsibility to free
  1042. // it.
  1043. //
  1044. scsiAddress = ExAllocatePool(NonPagedPool, sizeof(SCSI_ADDRESS));
  1045. if (scsiAddress) {
  1046. //
  1047. // Don't use a stack variable, as we could switch to a different
  1048. // thread.
  1049. //
  1050. ioStatus = ExAllocatePool(NonPagedPool, sizeof(IO_STATUS_BLOCK));
  1051. //
  1052. // Send the request
  1053. //
  1054. MPLIBSendDeviceIoControlSynchronous(IOCTL_SCSI_GET_ADDRESS,
  1055. DeviceObject,
  1056. NULL,
  1057. scsiAddress,
  1058. 0,
  1059. sizeof(SCSI_ADDRESS),
  1060. FALSE,
  1061. ioStatus);
  1062. status = ioStatus->Status;
  1063. if (status == STATUS_SUCCESS) {
  1064. //
  1065. // Update the caller's pointer with the returned
  1066. // information.
  1067. //
  1068. *ScsiAddress = scsiAddress;
  1069. }
  1070. }
  1071. ExFreePool(ioStatus);
  1072. return status;
  1073. }
  1074. PMPIO_CONTEXT
  1075. MPIOAllocateContext(
  1076. IN PDEVICE_EXTENSION DeviceExtension
  1077. )
  1078. {
  1079. PMPIO_CONTEXT context;
  1080. ULONG freeIndex;
  1081. ULONG i;
  1082. KIRQL irql;
  1083. //
  1084. // Try to get the context structure from the list.
  1085. //
  1086. context = ExAllocateFromNPagedLookasideList(&DeviceExtension->ContextList);
  1087. if (context == NULL) {
  1088. //
  1089. // No/Low memory condition. Use one of the emergency buffers.
  1090. //
  1091. KeAcquireSpinLock(&DeviceExtension->EmergencySpinLock,
  1092. &irql);
  1093. //
  1094. // Find a clear bit. Never use '0', as the check in the FreeContext
  1095. // routine keys off the value of EmergencyIndex;
  1096. //
  1097. for (i = 1; i < MAX_EMERGENCY_CONTEXT; i++) {
  1098. if (!(DeviceExtension->EmergencyContextMap & (1 << i))) {
  1099. //
  1100. // Set the bit to indicate that this buffer is being used.
  1101. //
  1102. DeviceExtension->EmergencyContextMap |= (1 << i);
  1103. freeIndex = i;
  1104. break;
  1105. }
  1106. }
  1107. if (i == MAX_EMERGENCY_CONTEXT) {
  1108. //
  1109. // LOG something.
  1110. //
  1111. } else {
  1112. //
  1113. // Pull one from the reserved buffer.
  1114. //
  1115. context = DeviceExtension->EmergencyContext[freeIndex];
  1116. context->EmergencyIndex = freeIndex;
  1117. }
  1118. KeReleaseSpinLock(&DeviceExtension->EmergencySpinLock,
  1119. irql);
  1120. } else {
  1121. //
  1122. // Indicate that this came from the Lookaside List.
  1123. //
  1124. context->EmergencyIndex = 0;
  1125. }
  1126. return context;
  1127. }
  1128. VOID
  1129. MPIOFreeContext(
  1130. IN PDEVICE_EXTENSION DeviceExtension,
  1131. IN PMPIO_CONTEXT Context
  1132. )
  1133. {
  1134. KIRQL irql;
  1135. if (Context->Freed) {
  1136. MPDebugPrint((0,
  1137. "FreeContext: Trying to free already freed context (%x)\n",
  1138. Context));
  1139. DbgBreakPoint();
  1140. }
  1141. Context->Freed = TRUE;
  1142. //
  1143. // Determine is this came from the emergency list or from the lookaside list
  1144. //
  1145. if (Context->EmergencyIndex == 0) {
  1146. ExFreeToNPagedLookasideList(&DeviceExtension->ContextList,
  1147. Context);
  1148. } else {
  1149. KeAcquireSpinLock(&DeviceExtension->EmergencySpinLock,
  1150. &irql);
  1151. //
  1152. // Indicate that the buffer is now available.
  1153. //
  1154. DeviceExtension->EmergencyContextMap &= ~(1 << Context->EmergencyIndex);
  1155. KeReleaseSpinLock(&DeviceExtension->EmergencySpinLock,
  1156. irql);
  1157. }
  1158. return;
  1159. }
  1160. VOID
  1161. MPIOCopyMemory(
  1162. IN PVOID Destination,
  1163. IN PVOID Source,
  1164. IN ULONG Length
  1165. )
  1166. {
  1167. MPDebugPrint((0,
  1168. "MPIOCopyMemory: Dest %x, Src %x, Length %x\n",
  1169. Destination,
  1170. Source,
  1171. Length));
  1172. RtlCopyMemory(Destination,
  1173. Source,
  1174. Length);
  1175. }
  1176. NTSTATUS
  1177. MPIOQueueRequest(
  1178. IN PDEVICE_OBJECT DeviceObject,
  1179. IN PIRP Irp,
  1180. IN PMPIO_CONTEXT Context,
  1181. IN PMP_QUEUE Queue
  1182. )
  1183. {
  1184. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1185. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  1186. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1187. PSCSI_REQUEST_BLOCK srb;
  1188. PMPQUEUE_ENTRY queueEntry;
  1189. NTSTATUS status;
  1190. KIRQL irql;
  1191. //
  1192. // Get a queue entry to package the request.
  1193. // BUGBUG: Use LookAsideList, backed by pre-allocated entries.
  1194. //
  1195. queueEntry = ExAllocatePool(NonPagedPool, sizeof(MPQUEUE_ENTRY));
  1196. if (queueEntry == NULL) {
  1197. return STATUS_INSUFFICIENT_RESOURCES;
  1198. }
  1199. RtlZeroMemory(queueEntry, sizeof(MPQUEUE_ENTRY));
  1200. //
  1201. // If this was a scsi request (vs. DeviceIoControl), the srb
  1202. // was saved in the context.
  1203. //
  1204. if (irpStack->MajorFunction == IRP_MJ_SCSI) {
  1205. //
  1206. // Rebuild the srb using the saved request in the context.
  1207. //
  1208. srb = irpStack->Parameters.Scsi.Srb;
  1209. RtlCopyMemory(srb,
  1210. &Context->Srb,
  1211. sizeof(SCSI_REQUEST_BLOCK));
  1212. }
  1213. //
  1214. // Indicate the Queue.
  1215. //
  1216. Context->QueuedInto = Queue->QueueIndicator;
  1217. Irp->IoStatus.Status = 0;
  1218. Irp->IoStatus.Information = 0;
  1219. //
  1220. // Save the irp address.
  1221. //
  1222. queueEntry->Irp = Irp;
  1223. //
  1224. // Jam onto the queue.
  1225. //
  1226. MPIOInsertQueue(Queue,
  1227. queueEntry);
  1228. return STATUS_SUCCESS;
  1229. }
  1230. PMPIO_FAILOVER_INFO
  1231. MPIODequeueFailPacket(
  1232. IN PDEVICE_OBJECT DeviceObject,
  1233. IN PVOID PathId
  1234. )
  1235. {
  1236. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1237. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  1238. PMPIO_FAILOVER_INFO failPacket = NULL;
  1239. PLIST_ENTRY entry;
  1240. KIRQL irql;
  1241. KeAcquireSpinLock(&controlExtension->SpinLock, &irql);
  1242. for (entry = controlExtension->FailPacketList.Flink;
  1243. entry != &controlExtension->FailPacketList;
  1244. entry = entry->Flink) {
  1245. failPacket = CONTAINING_RECORD(entry, MPIO_FAILOVER_INFO, ListEntry);
  1246. if (failPacket->PathId == PathId) {
  1247. break;
  1248. } else {
  1249. failPacket = NULL;
  1250. }
  1251. }
  1252. if (failPacket) {
  1253. //
  1254. // Yank it out of the queue.
  1255. //
  1256. RemoveEntryList(entry);
  1257. //
  1258. // Dec the number of entries.
  1259. //
  1260. InterlockedDecrement(&controlExtension->NumberFOPackets);
  1261. }
  1262. KeReleaseSpinLock(&controlExtension->SpinLock, irql);
  1263. MPDebugPrint((1,
  1264. "DequeueFailPacket: Returning (%x). CurrentCount (%x)\n",
  1265. failPacket,
  1266. controlExtension->NumberFOPackets));
  1267. return failPacket;
  1268. }
  1269. PVOID CurrentFailurePath = NULL;
  1270. VOID
  1271. MPIOFailOverCallBack(
  1272. IN PDEVICE_OBJECT DeviceObject,
  1273. IN ULONG Operation,
  1274. IN NTSTATUS Status
  1275. )
  1276. {
  1277. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1278. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  1279. PREAL_DEV_INFO targetInfo;
  1280. NTSTATUS status;
  1281. PDEVICE_OBJECT failDevice;
  1282. PDEVICE_EXTENSION failDevExt;
  1283. PMPDISK_EXTENSION failDiskExt;
  1284. PMPIO_FAILOVER_INFO failPacket;
  1285. ULONG state;
  1286. ULONG numberPackets = 0;
  1287. PLIST_ENTRY listEntry;
  1288. WCHAR componentName[32];
  1289. //
  1290. // The thread successfully handled the fail-over and we are in WAIT1
  1291. // or it was unsuccessfull and we are still IN_FO.
  1292. // TODO: Handle failure case.
  1293. //
  1294. ASSERT(Status == STATUS_SUCCESS);
  1295. ASSERT(Operation == INITIATE_FAILOVER);
  1296. ASSERT(diskExtension->CurrentPath);
  1297. MPDebugPrint((0,
  1298. "FailOverCallBack: Fail-Over on (%x) complete.\n",
  1299. DeviceObject));
  1300. //
  1301. // TODO remove hack.
  1302. //
  1303. CurrentFailurePath = NULL;
  1304. //
  1305. // Check to see whether the F.O. was successful.
  1306. //
  1307. if ((Status != STATUS_SUCCESS) || (diskExtension->CurrentPath == NULL)) {
  1308. //
  1309. // Need to flush all of the queues and update State to STATE_FULL_FAILURE.
  1310. // TODO BUGBUG.
  1311. //
  1312. MPDebugPrint((0,
  1313. "FailOverCallBack: Status (%x). Path (%x)\n",
  1314. Status,
  1315. diskExtension->CurrentPath));
  1316. DbgBreakPoint();
  1317. }
  1318. //
  1319. // Run through the failOver list and extract all entries that match "PathId"
  1320. //
  1321. // For each one, run the code below.
  1322. //
  1323. do {
  1324. failPacket = MPIODequeueFailPacket(diskExtension->ControlObject,
  1325. diskExtension->FailedPath);
  1326. if (failPacket) {
  1327. failDevice = failPacket->DeviceObject;
  1328. failDevExt = failDevice->DeviceExtension;
  1329. failDiskExt = failDevExt->TypeExtension;
  1330. numberPackets++;
  1331. state = MPIOHandleStateTransition(failDevice);
  1332. MPDebugPrint((0,
  1333. "FailOverCallBack: Handling (%x). CurrentState (%x)\n",
  1334. failDevice,
  1335. state));
  1336. //
  1337. // Get the target based on the new path that the fail-over handler
  1338. // setup.
  1339. //
  1340. targetInfo = MPIOGetTargetInfo(failDiskExt,
  1341. failDiskExt->CurrentPath,
  1342. NULL);
  1343. if (state == MPIO_STATE_WAIT2) {
  1344. //
  1345. // Queue a request for the timer to run rescans after the fail-back
  1346. // period expires.
  1347. //
  1348. failDiskExt->RescanCount = 15;
  1349. //
  1350. // Issue all requests down the new path.
  1351. //
  1352. status = MPIOIssueQueuedRequests(targetInfo,
  1353. &failDiskExt->ResubmitQueue,
  1354. MPIO_STATE_WAIT2,
  1355. &failDiskExt->OutstandingRequests);
  1356. } else if (state == MPIO_STATE_WAIT3) {
  1357. //
  1358. // Issue all requests down the new path.
  1359. //
  1360. status = MPIOIssueQueuedRequests(targetInfo,
  1361. &failDiskExt->FailOverQueue,
  1362. MPIO_STATE_WAIT3,
  1363. &failDiskExt->OutstandingRequests);
  1364. } else if (state == MPIO_STATE_DEGRADED) {
  1365. status = STATUS_SUCCESS;
  1366. } else {
  1367. ASSERT(state == MPIO_STATE_WAIT1);
  1368. ASSERT(failDiskExt->OutstandingRequests);
  1369. status = STATUS_SUCCESS;
  1370. }
  1371. ASSERT((status == STATUS_SUCCESS) || (status == STATUS_PENDING));
  1372. swprintf(componentName, L"MPIO Disk(%02d)", failDiskExt->DeviceOrdinal);
  1373. status = MPIOFireEvent(failDevice,
  1374. componentName,
  1375. L"Fail-Over Complete",
  1376. MPIO_INFORMATION);
  1377. ExFreePool(failPacket);
  1378. }
  1379. } while (failPacket);
  1380. if (numberPackets == 0) {
  1381. MPDebugPrint((0,
  1382. "FailoverCallBack: No fail-over packets for %x\n",
  1383. diskExtension->FailedPath));
  1384. ASSERT(FALSE);
  1385. }
  1386. #if 0
  1387. //
  1388. // Check for any pending work items to start.
  1389. //
  1390. if (failDiskExt->PendingItems) {
  1391. //
  1392. // Yank the packet from the pending list...
  1393. //
  1394. listEntry = ExInterlockedRemoveHeadList(&diskExtension->PendingWorkList,
  1395. &diskExtension->WorkListLock);
  1396. //
  1397. // ...and jam it on the work list.
  1398. //
  1399. ExInterlockedInsertTailList(&failDiskExt->WorkList,
  1400. listEntry,
  1401. &failDiskExt->WorkListLock);
  1402. InterlockedDecrement(&failDiskExt->PendingItems);
  1403. //
  1404. // Signal the thread to initiate the F.O.
  1405. //
  1406. KeSetEvent(&diskExtension->ThreadEvent,
  1407. 8,
  1408. FALSE);
  1409. }
  1410. #endif
  1411. return;
  1412. }
  1413. BOOLEAN
  1414. MPIOPathInFailOver(
  1415. IN PVOID PathId,
  1416. IN BOOLEAN Query
  1417. )
  1418. {
  1419. //
  1420. // REDO THIS HACK. TODO.
  1421. //
  1422. if (Query) {
  1423. return (PathId == CurrentFailurePath);
  1424. } else {
  1425. CurrentFailurePath = PathId;
  1426. }
  1427. return TRUE;
  1428. }
  1429. NTSTATUS
  1430. MPIOQueueFailPacket(
  1431. IN PDEVICE_OBJECT DeviceObject,
  1432. IN PDEVICE_OBJECT FailingDevice,
  1433. IN PVOID PathId
  1434. )
  1435. {
  1436. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1437. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  1438. PMPIO_FAILOVER_INFO failPacket;
  1439. //
  1440. // Allocate a fail-over packet.
  1441. //
  1442. failPacket = ExAllocatePool(NonPagedPool, sizeof(MPIO_FAILOVER_INFO));
  1443. if (failPacket == NULL) {
  1444. return STATUS_INSUFFICIENT_RESOURCES;
  1445. }
  1446. //
  1447. // Set the path, the d.o.
  1448. //
  1449. failPacket->DeviceObject = FailingDevice;
  1450. failPacket->PathId = PathId;
  1451. //
  1452. // Inc the number of entries.
  1453. //
  1454. InterlockedIncrement(&controlExtension->NumberFOPackets);
  1455. //
  1456. // Put it on the list.
  1457. //
  1458. ExInterlockedInsertTailList(&controlExtension->FailPacketList,
  1459. &failPacket->ListEntry,
  1460. &controlExtension->SpinLock);
  1461. return STATUS_SUCCESS;
  1462. }
  1463. NTSTATUS
  1464. MPIOFailOverHandler(
  1465. IN PDEVICE_OBJECT DeviceObject,
  1466. IN ULONG ErrorMask,
  1467. IN PREAL_DEV_INFO FailingDevice
  1468. )
  1469. {
  1470. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1471. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  1472. PMPIO_REQUEST_INFO requestInfo;
  1473. NTSTATUS status;
  1474. ULONG i;
  1475. PFLTR_ENTRY fltrEntry;
  1476. WCHAR componentName[32];
  1477. ASSERT(FailingDevice->PathFailed == FALSE);
  1478. //
  1479. // Mark it as failed. TODO - Ensure if it's
  1480. // brought back alive to update that.
  1481. //
  1482. FailingDevice->PathFailed = TRUE;
  1483. diskExtension->FailedPath = FailingDevice->PathId;
  1484. //
  1485. // Check to see whether there is only one path.
  1486. // It's not necessarily a bad thing, the DSM could be controlling
  1487. // hardware that hides the alternate path until a fail-over.
  1488. // BUT, this is currently not supported.
  1489. //
  1490. // Alternatively, one or more devices could have already been removed.
  1491. // In this case, allow the FailOver to happen.
  1492. // TODO: Figure out how to best handle this. Perhaps always allow a single path
  1493. // fail-over and handle the error on the other side...
  1494. //
  1495. if (diskExtension->DsmIdList.Count <= 1) {
  1496. MPDebugPrint((0,
  1497. "MPIOFailOverHandler: Initiating F.O. on single path\n"));
  1498. //
  1499. // LOG
  1500. //
  1501. }
  1502. //
  1503. // Put this on the fail-over list. All of these devices will get notified
  1504. // once the first F.O. completes. They will then start running the state-machine
  1505. // to get any queued requests issued.
  1506. //
  1507. status = MPIOQueueFailPacket(diskExtension->ControlObject,
  1508. DeviceObject,
  1509. FailingDevice->PathId);
  1510. if (!NT_SUCCESS(status)) {
  1511. //
  1512. // LOG the failure.
  1513. //
  1514. return status;
  1515. }
  1516. //
  1517. // If the fail-over on this path has already been started,
  1518. // don't do it again. There is a window where state is set by the first
  1519. // failing device, but this one is in the completion routine.
  1520. //
  1521. if (MPIOPathInFailOver(FailingDevice->PathId, 1)) {
  1522. return STATUS_SUCCESS;
  1523. }
  1524. MPDebugPrint((0,
  1525. "MPIOFailOverHandler: Failing Device (%x) on (%x). Failing Path (%x)\n",
  1526. FailingDevice,
  1527. DeviceObject,
  1528. FailingDevice->PathId));
  1529. //
  1530. // Set this as the current failing path.
  1531. //
  1532. MPIOPathInFailOver(FailingDevice->PathId, 0);
  1533. //
  1534. // Get all of the fltrEntry's for this disk.
  1535. //
  1536. for (i = 0; i < diskExtension->TargetInfoCount; i++) {
  1537. fltrEntry = MPIOGetFltrEntry(diskExtension->ControlObject,
  1538. diskExtension->TargetInfo[i].PortFdo,
  1539. NULL);
  1540. if (fltrEntry) {
  1541. fltrEntry->Flags |= FLTR_FLAGS_NEED_RESCAN;
  1542. fltrEntry->Flags &= ~(FLTR_FLAGS_QDR_COMPLETE | FLTR_FLAGS_QDR);
  1543. }
  1544. }
  1545. //
  1546. // Log the failure. TODO: Build a request and submit to thread.
  1547. //
  1548. #if 0
  1549. swprintf(componentName, L"MPIO Disk(%02d)", diskExtension->DeviceOrdinal);
  1550. status = MPIOFireEvent(DeviceObject,
  1551. componentName,
  1552. L"Fail-Over Initiated",
  1553. MPIO_FATAL_ERROR);
  1554. MPDebugPrint((0,
  1555. "MPIOFailOver: Failing Device (%x) Path (%x) Status of Event (%x)\n",
  1556. FailingDevice,
  1557. FailingDevice->PathId,
  1558. status));
  1559. #endif
  1560. //
  1561. // Allocate a work item
  1562. // Fill it in to indicate a fail-over.
  1563. //
  1564. requestInfo = ExAllocatePool(NonPagedPool, sizeof(MPIO_REQUEST_INFO));
  1565. requestInfo->RequestComplete = MPIOFailOverCallBack;
  1566. requestInfo->Operation = INITIATE_FAILOVER;
  1567. //
  1568. // Set the Path that should be failed.
  1569. //
  1570. requestInfo->OperationSpecificInfo = FailingDevice->PathId;
  1571. requestInfo->ErrorMask = ErrorMask;
  1572. ExInterlockedInsertTailList(&diskExtension->WorkList,
  1573. &requestInfo->ListEntry,
  1574. &diskExtension->WorkListLock);
  1575. //
  1576. // Signal the thread to initiate the F.O.
  1577. //
  1578. KeSetEvent(&diskExtension->ThreadEvent,
  1579. 8,
  1580. FALSE);
  1581. return STATUS_SUCCESS;
  1582. }
  1583. VOID
  1584. MPIOSetRequestBusy(
  1585. IN PSCSI_REQUEST_BLOCK Srb
  1586. )
  1587. {
  1588. PSENSE_DATA senseBuffer;
  1589. //
  1590. // Ensure that there is a sense buffer.
  1591. //
  1592. Srb->SrbStatus = SRB_STATUS_ERROR;
  1593. Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
  1594. if ((Srb->SenseInfoBufferLength) && (Srb->SenseInfoBuffer)) {
  1595. //
  1596. // Build a sense buffer that will coerce the class drivers
  1597. // into setting a delay, and retrying the request.
  1598. //
  1599. senseBuffer = Srb->SenseInfoBuffer;
  1600. senseBuffer->ErrorCode = 0x70;
  1601. senseBuffer->Valid = 1;
  1602. senseBuffer->AdditionalSenseLength = 0xb;
  1603. senseBuffer->SenseKey = SCSI_SENSE_NOT_READY;
  1604. senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_LUN_NOT_READY;
  1605. senseBuffer->AdditionalSenseCodeQualifier = SCSI_SENSEQ_BECOMING_READY;
  1606. Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
  1607. } else {
  1608. //
  1609. // Hack based on class driver interpretation of errors. Returning this
  1610. // will allow a retry interval.
  1611. //
  1612. Srb->ScsiStatus = SCSISTAT_BUSY;
  1613. }
  1614. return;
  1615. }
  1616. NTSTATUS
  1617. MPIOSetNewPath(
  1618. IN PDEVICE_OBJECT DeviceObject,
  1619. IN PVOID PathId
  1620. )
  1621. {
  1622. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1623. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  1624. PDEVICE_EXTENSION diskExtension;
  1625. PMPDISK_EXTENSION mpdiskExt;
  1626. PDEVICE_OBJECT diskObject;
  1627. PDISK_ENTRY diskEntry;
  1628. NTSTATUS status;
  1629. ULONG i;
  1630. //
  1631. // Go through each of the mpdisks and notify them that FailingPath
  1632. // is considered dead.
  1633. //
  1634. for (i = 0; i < controlExtension->NumberDevices; i++) {
  1635. diskEntry = MPIOGetDiskEntry(DeviceObject,
  1636. i);
  1637. diskObject = diskEntry->PdoObject;
  1638. diskExtension = diskObject->DeviceExtension;
  1639. mpdiskExt = diskExtension->TypeExtension;
  1640. mpdiskExt->NewPathSet = TRUE;
  1641. InterlockedExchange(&(ULONG)mpdiskExt->CurrentPath, (ULONG)PathId);
  1642. }
  1643. return STATUS_SUCCESS;
  1644. }
  1645. NTSTATUS
  1646. MPIOGetAdapterAddress(
  1647. IN PDEVICE_OBJECT DeviceObject,
  1648. IN OUT PMPIO_ADDRESS Address
  1649. )
  1650. {
  1651. ULONG bus = 0;
  1652. ULONG deviceFunction = 0;
  1653. NTSTATUS status;
  1654. ULONG bytesReturned;
  1655. status = IoGetDeviceProperty(DeviceObject,
  1656. DevicePropertyBusNumber,
  1657. sizeof(ULONG),
  1658. &bus,
  1659. &bytesReturned);
  1660. if (NT_SUCCESS(status)) {
  1661. status = IoGetDeviceProperty(DeviceObject,
  1662. DevicePropertyAddress,
  1663. sizeof(ULONG),
  1664. &deviceFunction,
  1665. &bytesReturned);
  1666. }
  1667. if (NT_SUCCESS(status)) {
  1668. Address->Bus = (UCHAR)bus;
  1669. Address->Device = (UCHAR)(deviceFunction >> 16);
  1670. Address->Function = (UCHAR)(deviceFunction & 0x0000FFFF);
  1671. Address->Pad = 0;
  1672. }
  1673. return status;
  1674. }
  1675. NTSTATUS
  1676. MPIOCreatePathEntry(
  1677. IN PDEVICE_OBJECT DeviceObject,
  1678. IN PDEVICE_OBJECT FilterObject,
  1679. IN PDEVICE_OBJECT PortFdo,
  1680. IN PVOID PathID
  1681. )
  1682. {
  1683. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1684. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  1685. PLIST_ENTRY entry;
  1686. PID_ENTRY id;
  1687. MPIO_ADDRESS address;
  1688. ULONG bytesReturned;
  1689. NTSTATUS status;
  1690. PDEVICE_OBJECT tempDO;
  1691. //
  1692. // See whether the pathId already exists.
  1693. //
  1694. for (entry = controlExtension->IdList.Flink;
  1695. entry != &controlExtension->IdList;
  1696. entry = entry->Flink) {
  1697. id = CONTAINING_RECORD(entry, ID_ENTRY, ListEntry);
  1698. if (id->PathID == PathID) {
  1699. //
  1700. // Already have an entry. Just return.
  1701. //
  1702. return STATUS_SUCCESS;
  1703. }
  1704. }
  1705. //
  1706. // Didn't find it. Allocate an entry.
  1707. //
  1708. id = ExAllocatePool(NonPagedPool, sizeof(ID_ENTRY));
  1709. if (id == NULL) {
  1710. return STATUS_INSUFFICIENT_RESOURCES;
  1711. }
  1712. RtlZeroMemory(id, sizeof(ID_ENTRY));
  1713. id->AdapterName.Buffer = ExAllocatePool(NonPagedPool, FDO_NAME_LENGTH);
  1714. RtlZeroMemory(id->AdapterName.Buffer, FDO_NAME_LENGTH);
  1715. //
  1716. // Set the max. length of the name.
  1717. //
  1718. id->AdapterName.MaximumLength = FDO_NAME_LENGTH;
  1719. //
  1720. // Capture the rest of the values.
  1721. //
  1722. id->PathID = PathID;
  1723. id->AdapterFilter = FilterObject;
  1724. id->PortFdo = PortFdo;
  1725. tempDO = IoGetLowerDeviceObject(PortFdo);
  1726. //
  1727. // Get the name.
  1728. //
  1729. status = IoGetDeviceProperty(tempDO,
  1730. DevicePropertyDeviceDescription,
  1731. id->AdapterName.MaximumLength,
  1732. id->AdapterName.Buffer,
  1733. &bytesReturned);
  1734. //
  1735. // Set the length - the terminating NULL.
  1736. //
  1737. id->AdapterName.Length = (USHORT)(bytesReturned - sizeof(UNICODE_NULL));
  1738. //
  1739. // Get the address.
  1740. //
  1741. status = MPIOGetAdapterAddress(tempDO,
  1742. &id->Address);
  1743. //
  1744. //
  1745. // Jam this into the list.
  1746. //
  1747. ExInterlockedInsertTailList(&controlExtension->IdList,
  1748. &id->ListEntry,
  1749. &controlExtension->SpinLock);
  1750. //
  1751. // Indicate the number of entries.
  1752. //
  1753. InterlockedIncrement(&controlExtension->NumberPaths);
  1754. return STATUS_SUCCESS;
  1755. }
  1756. LONGLONG
  1757. MPIOCreateUID(
  1758. IN PDEVICE_OBJECT DeviceObject,
  1759. IN PVOID PathID
  1760. )
  1761. {
  1762. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1763. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  1764. PLIST_ENTRY entry;
  1765. PID_ENTRY id;
  1766. UUID uuid;
  1767. PUCHAR index;
  1768. NTSTATUS status;
  1769. LONGLONG collapsedUID;
  1770. ULONG retryCount = 10;
  1771. for ( entry = controlExtension->IdList.Flink;
  1772. entry != &controlExtension->IdList;
  1773. entry = entry->Flink) {
  1774. id = CONTAINING_RECORD(entry, ID_ENTRY, ListEntry);
  1775. if (id->PathID == PathID) {
  1776. if (id->UID == 0) {
  1777. //
  1778. // Wasn't found. Create a new one.
  1779. //
  1780. status = ExUuidCreate(&uuid);
  1781. if (status == STATUS_SUCCESS) {
  1782. //
  1783. // Collapse this down into a 64-bit value.
  1784. //
  1785. index = (PUCHAR)&uuid;
  1786. collapsedUID = (*((PLONGLONG) index)) ^ (*((PLONGLONG)(index + sizeof(LONGLONG))));
  1787. //
  1788. // Set the value.
  1789. //
  1790. id->UID = collapsedUID;
  1791. id->UIDValid = TRUE;
  1792. }
  1793. }
  1794. return id->UID;
  1795. }
  1796. }
  1797. return 0;
  1798. }
  1799. ULONGLONG
  1800. MPIOBuildControllerInfo(
  1801. IN PDEVICE_OBJECT ControlObject,
  1802. IN PDSM_ENTRY Dsm,
  1803. IN PVOID DsmID
  1804. )
  1805. {
  1806. PDEVICE_EXTENSION deviceExtension = ControlObject->DeviceExtension;
  1807. PCONTROL_EXTENSION controlExtension = deviceExtension->TypeExtension;
  1808. PCONTROLLER_INFO controllerInfo;
  1809. PCONTROLLER_ENTRY tmpInfo;
  1810. PCONTROLLER_ENTRY controllerEntry;
  1811. ULONGLONG id = 0;
  1812. NTSTATUS status;
  1813. ASSERT(Dsm->GetControllerInfo);
  1814. status = Dsm->GetControllerInfo(Dsm->DsmContext,
  1815. DsmID,
  1816. DSM_CNTRL_FLAGS_ALLOCATE | DSM_CNTRL_FLAGS_CHECK_STATE,
  1817. &controllerInfo);
  1818. if (NT_SUCCESS(status)) {
  1819. ASSERT(controllerInfo);
  1820. //
  1821. // grab the ID.
  1822. //
  1823. id = controllerInfo->ControllerIdentifier;
  1824. //
  1825. // See whether the controller ID is part of the list.
  1826. //
  1827. tmpInfo = MPIOFindController(ControlObject,
  1828. controllerInfo->DeviceObject,
  1829. controllerInfo->ControllerIdentifier);
  1830. if (tmpInfo) {
  1831. //
  1832. // The entry already exists so just update the state.
  1833. //
  1834. tmpInfo->ControllerInfo->State = controllerInfo->State;
  1835. //
  1836. // Free the DSM's allocation.
  1837. //
  1838. ExFreePool(controllerInfo);
  1839. } else {
  1840. //
  1841. // Allocate an entry.
  1842. //
  1843. controllerEntry = ExAllocatePool(NonPagedPool, sizeof(CONTROLLER_ENTRY));
  1844. if (controllerEntry) {
  1845. RtlZeroMemory(controllerEntry, sizeof(CONTROLLER_ENTRY));
  1846. //
  1847. // Save this copy.
  1848. //
  1849. controllerEntry->ControllerInfo = controllerInfo;
  1850. //
  1851. // Save the dsm entry. It will be used in the WMI
  1852. // handling routines to get it's name.
  1853. //
  1854. controllerEntry->Dsm = Dsm;
  1855. //
  1856. // Jam it into the list.
  1857. //
  1858. ExInterlockedInsertTailList(&controlExtension->ControllerList,
  1859. &controllerEntry->ListEntry,
  1860. &controlExtension->SpinLock);
  1861. //
  1862. // Indicate the additional entry.
  1863. //
  1864. InterlockedIncrement(&controlExtension->NumberControllers);
  1865. } else {
  1866. id = 0;
  1867. }
  1868. }
  1869. }
  1870. return id;
  1871. }
  1872. ULONG
  1873. MPIOHandleStateTransition(
  1874. IN PDEVICE_OBJECT DeviceObject
  1875. )
  1876. {
  1877. PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1878. PMPDISK_EXTENSION diskExtension = deviceExtension->TypeExtension;
  1879. ULONG currentState;
  1880. ULONG requests;
  1881. KIRQL irql;
  1882. BOOLEAN complete = FALSE;
  1883. KeAcquireSpinLock(&diskExtension->SpinLock, &irql);
  1884. //
  1885. // Capture the current state.
  1886. //
  1887. currentState = deviceExtension->State;
  1888. //
  1889. // Run the state machine until there are no more 'events'.
  1890. //
  1891. do {
  1892. switch (currentState) {
  1893. case MPIO_STATE_IN_FO:
  1894. //
  1895. // See if the new path has been indicated.
  1896. //
  1897. if (diskExtension->NewPathSet) {
  1898. MPDebugPrint((0,
  1899. "HandleStateTransition: IN_FO moving to WAIT1\n"));
  1900. //
  1901. // Can now go to WAIT1
  1902. //
  1903. currentState = MPIO_STATE_WAIT1;
  1904. //
  1905. // Reset the flags.
  1906. //
  1907. diskExtension->NewPathSet = FALSE;
  1908. diskExtension->FailOver = FALSE;
  1909. } else {
  1910. complete = TRUE;
  1911. }
  1912. break;
  1913. case MPIO_STATE_WAIT1:
  1914. //
  1915. // The DSM has set the new path. See if all of the outstanding
  1916. // requests have come back (and are on the resubmit queue).
  1917. //
  1918. if (diskExtension->OutstandingRequests == 0) {
  1919. MPDebugPrint((0,
  1920. "HandleStateTransition: WAIT1 moving to WAIT2\n"));
  1921. //
  1922. // Go to WAIT2
  1923. //
  1924. currentState = MPIO_STATE_WAIT2;
  1925. diskExtension->ResubmitRequests = diskExtension->ResubmitQueue.QueuedItems;
  1926. } else {
  1927. complete = TRUE;
  1928. }
  1929. break;
  1930. case MPIO_STATE_WAIT2:
  1931. //
  1932. // Resubmit queue is being handled in this state.
  1933. // Check to see if it's empty.
  1934. //
  1935. requests = diskExtension->ResubmitRequests;
  1936. if (requests == 0) {
  1937. MPDebugPrint((0,
  1938. "HandleStateTransition: WAIT2 moving to WAIT3\n"));
  1939. //
  1940. // Can go to WAIT3
  1941. //
  1942. currentState = MPIO_STATE_WAIT3;
  1943. diskExtension->FailOverRequests = diskExtension->FailOverQueue.QueuedItems;
  1944. } else {
  1945. //
  1946. // Still draining the resubmit queue.
  1947. //
  1948. complete = TRUE;
  1949. }
  1950. break;
  1951. case MPIO_STATE_WAIT3:
  1952. //
  1953. // The fail-over queue is being handled in WAIT3
  1954. //
  1955. requests = diskExtension->FailOverRequests;
  1956. if (requests == 0) {
  1957. MPDebugPrint((0,
  1958. "HandleStateTransition: WAIT3 moving to DEGRADED\n"));
  1959. //
  1960. // Can go to DEGRADED.
  1961. //
  1962. currentState = MPIO_STATE_DEGRADED;
  1963. } else {
  1964. //
  1965. // Still have requests in the fail-over queue.
  1966. //
  1967. complete = TRUE;
  1968. }
  1969. break;
  1970. case MPIO_STATE_DEGRADED:
  1971. //
  1972. // This indicates that we are minus at least one path.
  1973. // Check to see whether it's been repaired.
  1974. //
  1975. if (diskExtension->PathBackOnLine) {
  1976. //
  1977. // Reset the flag.
  1978. //
  1979. diskExtension->PathBackOnLine = FALSE;
  1980. //
  1981. // See if that puts us back to where we were.
  1982. //
  1983. if (diskExtension->TargetInfoCount == diskExtension->MaxPaths) {
  1984. //
  1985. // Go to NORMAL.
  1986. //
  1987. currentState = MPIO_STATE_NORMAL;
  1988. }
  1989. } else {
  1990. //
  1991. // Stay in DEGRADED.
  1992. //
  1993. complete = TRUE;
  1994. }
  1995. break;
  1996. case MPIO_STATE_NORMAL:
  1997. //
  1998. // Check the Fail-Over flag.
  1999. //
  2000. if (diskExtension->FailOver) {
  2001. //
  2002. // Go to FAIL-OVER.
  2003. //
  2004. currentState = MPIO_STATE_IN_FO;
  2005. } else {
  2006. complete = TRUE;
  2007. }
  2008. break;
  2009. default:
  2010. ASSERT(currentState == MPIO_STATE_NORMAL);
  2011. complete = TRUE;
  2012. break;
  2013. }
  2014. } while (complete == FALSE);
  2015. //
  2016. // Update the state.
  2017. //
  2018. deviceExtension->LastState = deviceExtension->State;
  2019. deviceExtension->State = currentState;
  2020. KeReleaseSpinLock(&diskExtension->SpinLock, irql);
  2021. return currentState;
  2022. }
  2023. NTSTATUS
  2024. MPIOForceRescan(
  2025. IN PDEVICE_OBJECT AdapterFilter
  2026. )
  2027. {
  2028. IO_STATUS_BLOCK ioStatus;
  2029. MPDebugPrint((0,
  2030. "ForceRescan: Issueing rescan to (%x)\n",
  2031. AdapterFilter));
  2032. MPLIBSendDeviceIoControlSynchronous(IOCTL_SCSI_RESCAN_BUS,
  2033. AdapterFilter,
  2034. NULL,
  2035. NULL,
  2036. 0,
  2037. 0,
  2038. FALSE,
  2039. &ioStatus);
  2040. MPDebugPrint((0,
  2041. "ForceRescan: Rescan on (%x) status (%x)\n",
  2042. AdapterFilter,
  2043. ioStatus.Status));
  2044. return ioStatus.Status;
  2045. }