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.

874 lines
20 KiB

  1. /*++
  2. Copyright (C) 1991-5 Microsoft Corporation
  3. Module Name:
  4. stripe.cxx
  5. Abstract:
  6. This module contains the code specific to volume sets for the fault
  7. tolerance driver.
  8. Author:
  9. Bob Rinne (bobri) 2-Feb-1992
  10. Mike Glass (mglass)
  11. Norbert Kusters 2-Feb-1995
  12. Environment:
  13. kernel mode only
  14. Notes:
  15. Revision History:
  16. --*/
  17. extern "C" {
  18. #include <ntddk.h>
  19. }
  20. #include <ftdisk.h>
  21. #ifdef ALLOC_PRAGMA
  22. #pragma code_seg("PAGE")
  23. #endif
  24. NTSTATUS
  25. STRIPE::Initialize(
  26. IN OUT PROOT_EXTENSION RootExtension,
  27. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  28. IN OUT PFT_VOLUME* VolumeArray,
  29. IN USHORT ArraySize,
  30. IN PVOID ConfigInfo,
  31. IN PVOID StateInfo
  32. )
  33. /*++
  34. Routine Description:
  35. Initialize routine for FT_VOLUME of type STRIPE.
  36. Arguments:
  37. RootExtension - Supplies the root device extension.
  38. LogicalDiskId - Supplies the logical disk id for this volume.
  39. VolumeArray - Supplies the array of volumes for this volume set.
  40. ArraySize - Supplies the number of volumes in the volume array.
  41. ConfigInfo - Supplies the configuration information.
  42. StateInfo - Supplies the state information.
  43. Return Value:
  44. NTSTATUS
  45. --*/
  46. {
  47. BOOLEAN oneGood;
  48. USHORT i;
  49. NTSTATUS status;
  50. PFT_STRIPE_SET_CONFIGURATION_INFORMATION configInfo;
  51. LONGLONG newSize;
  52. if (ArraySize < 2) {
  53. return STATUS_INVALID_PARAMETER;
  54. }
  55. oneGood = FALSE;
  56. for (i = 0; i < ArraySize; i++) {
  57. if (VolumeArray[i]) {
  58. oneGood = TRUE;
  59. }
  60. }
  61. if (!oneGood) {
  62. return STATUS_INVALID_PARAMETER;
  63. }
  64. status = COMPOSITE_FT_VOLUME::Initialize(RootExtension, LogicalDiskId,
  65. VolumeArray, ArraySize,
  66. ConfigInfo, StateInfo);
  67. if (!NT_SUCCESS(status)) {
  68. return status;
  69. }
  70. configInfo = (PFT_STRIPE_SET_CONFIGURATION_INFORMATION) ConfigInfo;
  71. _stripeSize = configInfo->StripeSize;
  72. if (_stripeSize < QuerySectorSize()) {
  73. return STATUS_INVALID_PARAMETER;
  74. }
  75. for (i = 0; _stripeSize%2 == 0; i++) {
  76. _stripeSize /= 2;
  77. }
  78. if (_stripeSize != 1) {
  79. return STATUS_INVALID_PARAMETER;
  80. }
  81. _stripeSize = configInfo->StripeSize;
  82. _stripeShift = i;
  83. _stripeMask = _stripeSize - 1;
  84. for (i = 0; i < ArraySize; i++) {
  85. if (VolumeArray[i]) {
  86. _memberSize = VolumeArray[i]->QueryVolumeSize();
  87. break;
  88. }
  89. }
  90. for (; i < ArraySize; i++) {
  91. if (VolumeArray[i]) {
  92. newSize = VolumeArray[i]->QueryVolumeSize();
  93. if (_memberSize > newSize) {
  94. _memberSize = newSize;
  95. }
  96. }
  97. }
  98. _memberSize = _memberSize/_stripeSize*_stripeSize;
  99. _volumeSize = _memberSize*ArraySize;
  100. _ePacket = new STRIPE_TP;
  101. if (_ePacket && !_ePacket->AllocateMdl((PVOID) 1, _stripeSize)) {
  102. delete _ePacket;
  103. _ePacket = NULL;
  104. }
  105. if (!_ePacket) {
  106. return STATUS_INSUFFICIENT_RESOURCES;
  107. }
  108. _ePacketInUse = FALSE;
  109. InitializeListHead(&_ePacketQueue);
  110. return status;
  111. }
  112. FT_LOGICAL_DISK_TYPE
  113. STRIPE::QueryLogicalDiskType(
  114. )
  115. /*++
  116. Routine Description:
  117. This routine returns the type of the logical disk.
  118. Arguments:
  119. None.
  120. Return Value:
  121. The type of the logical disk.
  122. --*/
  123. {
  124. return FtStripeSet;
  125. }
  126. NTSTATUS
  127. STRIPE::CheckIo(
  128. OUT PBOOLEAN IsIoOk
  129. )
  130. /*++
  131. Routine Description:
  132. This routine returns whether or not IO is possible on the given
  133. logical disk.
  134. Arguments:
  135. IsIoOk - Returns the state of IO.
  136. Return Value:
  137. NTSTATUS
  138. --*/
  139. {
  140. USHORT n, i;
  141. PFT_VOLUME vol;
  142. NTSTATUS status;
  143. n = QueryNumMembers();
  144. for (i = 0; i < n; i++) {
  145. vol = GetMemberUnprotected(i);
  146. if (!vol) {
  147. *IsIoOk = FALSE;
  148. return STATUS_SUCCESS;
  149. }
  150. status = vol->CheckIo(IsIoOk);
  151. if (!NT_SUCCESS(status)) {
  152. return status;
  153. }
  154. if (!(*IsIoOk)) {
  155. return STATUS_SUCCESS;
  156. }
  157. }
  158. return STATUS_SUCCESS;
  159. }
  160. NTSTATUS
  161. STRIPE::QueryPhysicalOffsets(
  162. IN LONGLONG LogicalOffset,
  163. OUT PVOLUME_PHYSICAL_OFFSET* PhysicalOffsets,
  164. OUT PULONG NumberOfPhysicalOffsets
  165. )
  166. /*++
  167. Routine Description:
  168. This routine returns physical disk and offset for a given volume
  169. logical offset.
  170. Arguments:
  171. LogicalOffset - Supplies the logical offset
  172. PhysicalOffsets - Returns the physical offsets
  173. NumberOfPhysicalOffsets - Returns the number of physical offsets
  174. Return Value:
  175. NTSTATUS
  176. --*/
  177. {
  178. USHORT n, whichMember;
  179. LONGLONG whichStripe, whichRow, logicalOffsetInMember;
  180. PFT_VOLUME vol;
  181. if (LogicalOffset < 0 ||
  182. _volumeSize <= LogicalOffset) {
  183. return STATUS_INVALID_PARAMETER;
  184. }
  185. n = QueryNumMembers();
  186. ASSERT(n);
  187. ASSERT(_stripeSize);
  188. whichStripe = LogicalOffset/_stripeSize;
  189. whichMember = (USHORT) (whichStripe%n);
  190. vol = GetMember(whichMember);
  191. if (!vol) {
  192. return STATUS_INVALID_PARAMETER;
  193. }
  194. whichRow = whichStripe/n;
  195. logicalOffsetInMember = whichRow*_stripeSize + LogicalOffset%_stripeSize;
  196. return vol->QueryPhysicalOffsets(logicalOffsetInMember, PhysicalOffsets, NumberOfPhysicalOffsets);
  197. }
  198. NTSTATUS
  199. STRIPE::QueryLogicalOffset(
  200. IN PVOLUME_PHYSICAL_OFFSET PhysicalOffset,
  201. OUT PLONGLONG LogicalOffset
  202. )
  203. /*++
  204. Routine Description:
  205. This routine returns the volume logical offset for a given disk number
  206. and physical offset.
  207. Arguments:
  208. PhysicalOffset - Supplies the physical offset
  209. LogicalOffset - Returns the logical offset
  210. Return Value:
  211. NTSTATUS
  212. --*/
  213. {
  214. USHORT n, i;
  215. LONGLONG whichStripe, whichRow;
  216. LONGLONG logicalOffset, logicalOffsetInMember;
  217. NTSTATUS status;
  218. PFT_VOLUME vol;
  219. n = QueryNumMembers();
  220. ASSERT(_stripeSize);
  221. for (i = 0; i < n; i++) {
  222. vol = GetMember(i);
  223. if (!vol) {
  224. continue;
  225. }
  226. status = vol->QueryLogicalOffset(PhysicalOffset, &logicalOffsetInMember);
  227. if (NT_SUCCESS(status)) {
  228. whichRow = logicalOffsetInMember/_stripeSize;
  229. whichStripe = whichRow*n + i;
  230. logicalOffset = whichStripe*_stripeSize + logicalOffsetInMember%_stripeSize;
  231. if (_volumeSize <= logicalOffset) {
  232. return STATUS_INVALID_PARAMETER;
  233. }
  234. *LogicalOffset = logicalOffset;
  235. return status;
  236. }
  237. }
  238. return STATUS_INVALID_PARAMETER;
  239. }
  240. #ifdef ALLOC_PRAGMA
  241. #pragma code_seg("PAGELK")
  242. #endif
  243. STRIPE::~STRIPE(
  244. )
  245. {
  246. if (_ePacket) {
  247. delete _ePacket;
  248. _ePacket = NULL;
  249. }
  250. }
  251. VOID
  252. STRIPE::Transfer(
  253. IN OUT PTRANSFER_PACKET TransferPacket
  254. )
  255. /*++
  256. Routine Description:
  257. Transfer routine for STRIPE type FT_VOLUME. Figure out
  258. which volumes this request needs to be dispatched to.
  259. Arguments:
  260. TransferPacket - Supplies the transfer packet.
  261. Return Value:
  262. None.
  263. --*/
  264. {
  265. KIRQL irql;
  266. if (!LaunchParallel(TransferPacket)) {
  267. if (!TransferPacket->Mdl) {
  268. TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  269. TransferPacket->IoStatus.Information = 0;
  270. TransferPacket->CompletionRoutine(TransferPacket);
  271. return;
  272. }
  273. KeAcquireSpinLock(&_spinLock, &irql);
  274. if (_ePacketInUse) {
  275. InsertTailList(&_ePacketQueue, &TransferPacket->QueueEntry);
  276. KeReleaseSpinLock(&_spinLock, irql);
  277. return;
  278. }
  279. _ePacketInUse = TRUE;
  280. KeReleaseSpinLock(&_spinLock, irql);
  281. LaunchSequential(TransferPacket);
  282. }
  283. }
  284. VOID
  285. StripeReplaceCompletionRoutine(
  286. IN OUT PTRANSFER_PACKET TransferPacket
  287. )
  288. /*++
  289. Routine Description:
  290. This is the completion routine for a replace request.
  291. Arguments:
  292. TransferPacket - Supplies the transfer packet.
  293. Return Value:
  294. None.
  295. --*/
  296. {
  297. PSTRIPE_TP transferPacket = (PSTRIPE_TP) TransferPacket;
  298. PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
  299. masterPacket->IoStatus = transferPacket->IoStatus;
  300. delete transferPacket;
  301. masterPacket->CompletionRoutine(masterPacket);
  302. }
  303. VOID
  304. STRIPE::ReplaceBadSector(
  305. IN OUT PTRANSFER_PACKET TransferPacket
  306. )
  307. /*++
  308. Routine Description:
  309. This routine attempts to fix the given bad sector by routing
  310. the request to the appropriate sub-volume.
  311. Arguments:
  312. TransferPacket - Supplies the transfer packet.
  313. Return Value:
  314. None.
  315. --*/
  316. {
  317. USHORT n, whichMember;
  318. LONGLONG whichStripe, whichRow;
  319. PSTRIPE_TP p;
  320. n = QueryNumMembers();
  321. whichStripe = TransferPacket->Offset/_stripeSize;
  322. whichMember = (USHORT) (whichStripe%n);
  323. whichRow = whichStripe/n;
  324. p = new STRIPE_TP;
  325. if (!p) {
  326. TransferPacket->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  327. TransferPacket->IoStatus.Information = 0;
  328. TransferPacket->CompletionRoutine(TransferPacket);
  329. return;
  330. }
  331. p->Length = TransferPacket->Length;
  332. p->Offset = whichRow*_stripeSize + TransferPacket->Offset%_stripeSize;
  333. p->CompletionRoutine = StripeReplaceCompletionRoutine;
  334. p->TargetVolume = GetMemberUnprotected(whichMember);
  335. p->Thread = TransferPacket->Thread;
  336. p->IrpFlags = TransferPacket->IrpFlags;
  337. p->MasterPacket = TransferPacket;
  338. p->Stripe = this;
  339. p->WhichMember = whichMember;
  340. p->TargetVolume->ReplaceBadSector(p);
  341. }
  342. LONGLONG
  343. STRIPE::QueryVolumeSize(
  344. )
  345. /*++
  346. Routine Description:
  347. Returns the number of bytes on the entire volume.
  348. Arguments:
  349. None.
  350. Return Value:
  351. The volume size in bytes.
  352. --*/
  353. {
  354. return _volumeSize;
  355. }
  356. VOID
  357. StripeTransferParallelCompletionRoutine(
  358. IN PTRANSFER_PACKET TransferPacket
  359. )
  360. /*++
  361. Routine Description:
  362. Completion routine for STRIPE::Transfer function.
  363. Arguments:
  364. TransferPacket - Supplies the transfer packet.
  365. Return Value:
  366. None.
  367. --*/
  368. {
  369. PSTRIPE_TP transferPacket = (PSTRIPE_TP) TransferPacket;
  370. PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
  371. NTSTATUS status = transferPacket->IoStatus.Status;
  372. KIRQL irql;
  373. if (!NT_SUCCESS(status)) {
  374. KeAcquireSpinLock(&masterPacket->SpinLock, &irql);
  375. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  376. masterPacket->IoStatus.Status = status;
  377. }
  378. KeReleaseSpinLock(&masterPacket->SpinLock, irql);
  379. }
  380. delete transferPacket;
  381. if (!InterlockedDecrement(&masterPacket->RefCount)) {
  382. masterPacket->CompletionRoutine(masterPacket);
  383. }
  384. }
  385. VOID
  386. STRIPE::CompleteNotification(
  387. IN BOOLEAN IoPending
  388. )
  389. /*++
  390. Routine Description:
  391. This routine is called to notify the volume that it is complete and
  392. to therefore prepare for incoming requests.
  393. Arguments:
  394. IoPending - Supplies whether or not there is IO pending.
  395. Return Value:
  396. None.
  397. --*/
  398. {
  399. USHORT n, i;
  400. PFT_VOLUME vol;
  401. COMPOSITE_FT_VOLUME::CompleteNotification(IoPending);
  402. n = QueryNumMembers();
  403. for (i = 0; i < n; i++) {
  404. vol = GetMember(i);
  405. if (_memberSize > vol->QueryVolumeSize()) {
  406. _memberSize = vol->QueryVolumeSize()/_stripeSize*_stripeSize;
  407. }
  408. }
  409. _volumeSize = n*_memberSize;
  410. }
  411. BOOLEAN
  412. STRIPE::LaunchParallel(
  413. IN OUT PTRANSFER_PACKET TransferPacket
  414. )
  415. /*++
  416. Routine Description:
  417. This routine lauches the given transfer packet in parallel accross
  418. all members. If memory cannot be allocated to launch this request
  419. in parallel then a return value of FALSE will be returned.
  420. Arguments:
  421. TransferPacket - Supplies the transfer packet to launch.
  422. Return Value:
  423. FALSE - The packet was not launched because of insufficient resources.
  424. TRUE - Success.
  425. --*/
  426. {
  427. LONGLONG offset, whichStripe, whichRow, off;
  428. ULONG length, stripeOffset, stripeRemainder, numRequests, len;
  429. USHORT arraySize, whichMember;
  430. PSTRIPE_TP p;
  431. ULONG i;
  432. PCHAR vp;
  433. LIST_ENTRY q;
  434. PLIST_ENTRY l;
  435. offset = TransferPacket->Offset;
  436. length = TransferPacket->Length;
  437. stripeOffset = (ULONG) (offset&_stripeMask);
  438. stripeRemainder = _stripeSize - stripeOffset;
  439. if (length > stripeRemainder) {
  440. length -= stripeRemainder;
  441. numRequests = length>>_stripeShift;
  442. length -= numRequests<<_stripeShift;
  443. if (length) {
  444. numRequests += 2;
  445. } else {
  446. numRequests++;
  447. }
  448. } else {
  449. numRequests = 1;
  450. }
  451. KeInitializeSpinLock(&TransferPacket->SpinLock);
  452. TransferPacket->IoStatus.Status = STATUS_SUCCESS;
  453. TransferPacket->IoStatus.Information = TransferPacket->Length;
  454. TransferPacket->RefCount = numRequests;
  455. length = TransferPacket->Length;
  456. if (TransferPacket->Mdl && numRequests > 1) {
  457. vp = (PCHAR) MmGetMdlVirtualAddress(TransferPacket->Mdl);
  458. }
  459. whichStripe = offset>>_stripeShift;
  460. arraySize = QueryNumMembers();
  461. InitializeListHead(&q);
  462. for (i = 0; i < numRequests; i++, whichStripe++) {
  463. whichRow = whichStripe/arraySize;
  464. whichMember = (USHORT) (whichStripe%arraySize);
  465. if (i == 0) {
  466. off = (whichRow<<_stripeShift) + stripeOffset;
  467. len = stripeRemainder > length ? length : stripeRemainder;
  468. } else if (i == numRequests - 1) {
  469. off = whichRow<<_stripeShift;
  470. len = length;
  471. } else {
  472. off = whichRow<<_stripeShift;
  473. len = _stripeSize;
  474. }
  475. length -= len;
  476. p = new STRIPE_TP;
  477. if (p) {
  478. if (TransferPacket->Mdl && numRequests > 1) {
  479. if (p->AllocateMdl(vp, len)) {
  480. IoBuildPartialMdl(TransferPacket->Mdl, p->Mdl, vp, len);
  481. } else {
  482. delete p;
  483. p = NULL;
  484. }
  485. vp += len;
  486. } else {
  487. p->Mdl = TransferPacket->Mdl;
  488. p->OriginalIrp = TransferPacket->OriginalIrp;
  489. }
  490. }
  491. if (!p) {
  492. while (!IsListEmpty(&q)) {
  493. l = RemoveHeadList(&q);
  494. p = CONTAINING_RECORD(l, STRIPE_TP, QueueEntry);
  495. delete p;
  496. }
  497. return FALSE;
  498. }
  499. p->Length = len;
  500. p->Offset = off;
  501. p->CompletionRoutine = StripeTransferParallelCompletionRoutine;
  502. p->TargetVolume = GetMemberUnprotected(whichMember);
  503. p->Thread = TransferPacket->Thread;
  504. p->IrpFlags = TransferPacket->IrpFlags;
  505. p->ReadPacket = TransferPacket->ReadPacket;
  506. p->SpecialRead = TransferPacket->SpecialRead;
  507. p->MasterPacket = TransferPacket;
  508. p->Stripe = this;
  509. p->WhichMember = whichMember;
  510. InsertTailList(&q, &p->QueueEntry);
  511. }
  512. while (!IsListEmpty(&q)) {
  513. l = RemoveHeadList(&q);
  514. p = CONTAINING_RECORD(l, STRIPE_TP, QueueEntry);
  515. TRANSFER(p);
  516. }
  517. return TRUE;
  518. }
  519. VOID
  520. StripeSequentialTransferCompletionRoutine(
  521. IN PTRANSFER_PACKET TransferPacket
  522. )
  523. /*++
  524. Routine Description:
  525. Completion routine for STRIPE::Transfer function.
  526. Arguments:
  527. TransferPacket - Supplies the transfer packet.
  528. Return Value:
  529. None.
  530. --*/
  531. {
  532. PSTRIPE_TP transferPacket = (PSTRIPE_TP) TransferPacket;
  533. PTRANSFER_PACKET masterPacket = transferPacket->MasterPacket;
  534. NTSTATUS status = transferPacket->IoStatus.Status;
  535. PSTRIPE t = transferPacket->Stripe;
  536. LONGLONG rowNumber, stripeNumber, masterOffset;
  537. KIRQL irql;
  538. PLIST_ENTRY l;
  539. PTRANSFER_PACKET p;
  540. if (NT_SUCCESS(status)) {
  541. if (NT_SUCCESS(masterPacket->IoStatus.Status)) {
  542. masterPacket->IoStatus.Information +=
  543. transferPacket->IoStatus.Information;
  544. }
  545. } else {
  546. if (FtpIsWorseStatus(status, masterPacket->IoStatus.Status)) {
  547. masterPacket->IoStatus.Status = status;
  548. masterPacket->IoStatus.Information = 0;
  549. }
  550. }
  551. MmPrepareMdlForReuse(transferPacket->Mdl);
  552. rowNumber = transferPacket->Offset/t->_stripeSize;
  553. stripeNumber = rowNumber*t->QueryNumMembers() +
  554. transferPacket->WhichMember;
  555. masterOffset = stripeNumber*t->_stripeSize +
  556. transferPacket->Offset%t->_stripeSize;
  557. if (masterOffset + transferPacket->Length ==
  558. masterPacket->Offset + masterPacket->Length) {
  559. masterPacket->CompletionRoutine(masterPacket);
  560. for (;;) {
  561. KeAcquireSpinLock(&t->_spinLock, &irql);
  562. if (IsListEmpty(&t->_ePacketQueue)) {
  563. t->_ePacketInUse = FALSE;
  564. KeReleaseSpinLock(&t->_spinLock, irql);
  565. break;
  566. }
  567. l = RemoveHeadList(&t->_ePacketQueue);
  568. KeReleaseSpinLock(&t->_spinLock, irql);
  569. p = CONTAINING_RECORD(l, TRANSFER_PACKET, QueueEntry);
  570. if (!t->LaunchParallel(p)) {
  571. t->LaunchSequential(p);
  572. break;
  573. }
  574. }
  575. return;
  576. }
  577. transferPacket->WhichMember++;
  578. if (transferPacket->WhichMember == t->QueryNumMembers()) {
  579. transferPacket->WhichMember = 0;
  580. rowNumber++;
  581. }
  582. masterOffset += transferPacket->Length;
  583. transferPacket->Offset = rowNumber*t->_stripeSize;
  584. transferPacket->Length = t->_stripeSize;
  585. if (masterOffset + transferPacket->Length >
  586. masterPacket->Offset + masterPacket->Length) {
  587. transferPacket->Length = (ULONG) (masterPacket->Offset +
  588. masterPacket->Length - masterOffset);
  589. }
  590. transferPacket->TargetVolume =
  591. t->GetMemberUnprotected(transferPacket->WhichMember);
  592. IoBuildPartialMdl(masterPacket->Mdl, transferPacket->Mdl,
  593. (PCHAR) MmGetMdlVirtualAddress(masterPacket->Mdl) +
  594. (ULONG) (masterOffset - masterPacket->Offset),
  595. transferPacket->Length);
  596. TRANSFER(transferPacket);
  597. }
  598. VOID
  599. STRIPE::LaunchSequential(
  600. IN OUT PTRANSFER_PACKET TransferPacket
  601. )
  602. /*++
  603. Routine Description:
  604. This routine lauches the given transfer packet in sequence accross
  605. all members using the emergency stripe transfer packet.
  606. Arguments:
  607. TransferPacket - Supplies the transfer packet to launch.
  608. Return Value:
  609. FALSE - The packet was not launched because of insufficient resources.
  610. TRUE - Success.
  611. --*/
  612. {
  613. PSTRIPE_TP p;
  614. LONGLONG offset, whichStripe, whichRow;
  615. USHORT whichMember, arraySize;
  616. TransferPacket->IoStatus.Status = STATUS_SUCCESS;
  617. TransferPacket->IoStatus.Information = 0;
  618. offset = TransferPacket->Offset;
  619. p = _ePacket;
  620. arraySize = QueryNumMembers();
  621. whichStripe = offset/_stripeSize;
  622. whichRow = whichStripe/arraySize;
  623. whichMember = (USHORT) (whichStripe%arraySize);
  624. p->Length = _stripeSize - (ULONG) (offset%_stripeSize);
  625. if (p->Length > TransferPacket->Length) {
  626. p->Length = TransferPacket->Length;
  627. }
  628. IoBuildPartialMdl(TransferPacket->Mdl, p->Mdl,
  629. MmGetMdlVirtualAddress(TransferPacket->Mdl), p->Length);
  630. p->Offset = whichRow*_stripeSize + offset%_stripeSize;
  631. p->CompletionRoutine = StripeSequentialTransferCompletionRoutine;
  632. p->TargetVolume = GetMemberUnprotected(whichMember);
  633. p->Thread = TransferPacket->Thread;
  634. p->IrpFlags = TransferPacket->IrpFlags;
  635. p->ReadPacket = TransferPacket->ReadPacket;
  636. p->SpecialRead = TransferPacket->SpecialRead;
  637. p->MasterPacket = TransferPacket;
  638. p->Stripe = this;
  639. p->WhichMember = whichMember;
  640. TRANSFER(p);
  641. }