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.

1694 lines
46 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: crashdmp.c
  8. //
  9. //--------------------------------------------------------------------------
  10. //#include "stddef.h"
  11. //#include "stdarg.h"
  12. //#include "stdio.h"
  13. //#include <excpt.h>
  14. //#include <ntdef.h>
  15. //#include <ntstatus.h>
  16. //#include <bugcodes.h>
  17. //#include <exlevels.h>
  18. //#include <ntiologc.h>
  19. //#include <ntos.h>
  20. //#include <pci.h>
  21. //#include "io.h"
  22. //#include "scsi.h"
  23. //#include <ntddscsi.h>
  24. //#include <ntdddisk.h>
  25. //#include <string.h>
  26. //#include "stdio.h"
  27. //
  28. //#ifdef ACPI_CONTROL_METHOD_SUPPORT
  29. ////
  30. //// for ACPI
  31. ////
  32. //#include "acpiioct.h"
  33. //#endif // ACPI_CONTROL_METHOD_SUPPORT
  34. //
  35. //#include "ide.h"
  36. //
  37. ////
  38. //// predefine structure pointer type to prevent
  39. //// constant re-ordering of include files
  40. ////
  41. //typedef struct _FDO_EXTENSION * PFDO_EXTENSION;
  42. //typedef struct _PDO_EXTENSION * PPDO_EXTENSION;
  43. //typedef struct _DEVICE_SETTINGS * PDEVICE_SETTINGS;
  44. //
  45. //#include "acpiutil.h"
  46. //#include "port.h"
  47. //#include "chanfdo.h"
  48. //#include "detect.h"
  49. //#include "atapi.h"
  50. //#include "devpdo.h"
  51. //#include "regutils.h"
  52. //#include "atapinit.h"
  53. //#include "luext.h"
  54. //#include "fdopower.h"
  55. //#include "pdopower.h"
  56. //#include "hack.h"
  57. //#include "crashdmp.h"
  58. //#include "idedata.h"
  59. //
  60. //#include "ntddstor.h"
  61. #include <ntosp.h>
  62. #include "io.h"
  63. #include "ideport.h"
  64. NTSTATUS
  65. AtapiCrashDumpIdeWriteDMA (
  66. IN LONG Action,
  67. IN PLARGE_INTEGER DiskByteOffset,
  68. IN PMDL Mdl,
  69. IN PVOID LocalData
  70. );
  71. VOID
  72. AtapiCrashDumpBmCallback (
  73. IN PVOID Context
  74. );
  75. #ifdef ALLOC_PRAGMA
  76. //
  77. // All the crash dump code can be marked "INIT".
  78. // during crash dump or hibernate dump, a new copy
  79. // of this driver gets loaded and its INIT code
  80. // doesn't get thrown away when DriverEnry returns
  81. //
  82. #pragma alloc_text(INIT, AtapiCrashDumpDriverEntry)
  83. #pragma alloc_text(INIT, AtapiCrashDumpOpen)
  84. #pragma alloc_text(INIT, AtapiCrashDumpIdeWrite)
  85. #pragma alloc_text(INIT, AtapiCrashDumpFinish)
  86. #pragma alloc_text(INIT, AtapiCrashDumpBmCallback)
  87. #pragma alloc_text(INIT, AtapiCrashDumpIdeWriteDMA)
  88. #endif // ALLOC_PRAGMA
  89. ULONG
  90. AtapiCrashDumpDriverEntry (
  91. PVOID Context
  92. )
  93. /*++
  94. Routine Description:
  95. dump driver entry point
  96. Arguments:
  97. Context - PCRASHDUMP_INIT_DATA
  98. Return Value:
  99. NT Status
  100. --*/
  101. {
  102. PDUMP_INITIALIZATION_CONTEXT context = Context;
  103. DebugPrint ((DBG_CRASHDUMP, "ATAPI: Entering AtapiCrashDumpDriverEntry...\n"));
  104. //
  105. // Put away what we need later
  106. //
  107. DumpData.CrashInitData = (PCRASHDUMP_INIT_DATA) context->PortConfiguration;
  108. DumpData.StallRoutine = context->StallRoutine;
  109. //
  110. // return our dump interface
  111. //
  112. context->OpenRoutine = AtapiCrashDumpOpen;
  113. context->WriteRoutine = AtapiCrashDumpIdeWrite;
  114. context->FinishRoutine = AtapiCrashDumpFinish;
  115. context->WritePendingRoutine = AtapiCrashDumpIdeWriteDMA;
  116. DebugPrint ((DBG_CRASHDUMP, "ATAPI: Leaving AtapiCrashDumpDriverEntry...\n"));
  117. return STATUS_SUCCESS;
  118. }
  119. BOOLEAN
  120. AtapiCrashDumpOpen (
  121. IN LARGE_INTEGER PartitionOffset
  122. )
  123. {
  124. ULONG i;
  125. PHW_DEVICE_EXTENSION hwExtension;
  126. PPCIIDE_BUSMASTER_INTERFACE bmInterface;
  127. DebugPrint ((DBG_CRASHDUMP, "ATAPI: Entering AtapiCrashDumpOpen...PartitionOffset = 0x%x%08x...\n", PartitionOffset.HighPart, PartitionOffset.LowPart));
  128. // if we are crashdumping, reset the cotroller - Not necessary
  129. //
  130. // ISSUE 08/26/2000: Check for disk signature - Why?
  131. //
  132. DumpData.PartitionOffset = PartitionOffset;
  133. RtlMoveMemory (
  134. &DumpData.HwDeviceExtension,
  135. DumpData.CrashInitData->LiveHwDeviceExtension,
  136. sizeof (HW_DEVICE_EXTENSION)
  137. );
  138. // for (i=0; i<DumpData.HwDeviceExtension.MaxIdeDevice; i++) {
  139. //
  140. // AKadatch: we may use DMA and will use DMA if its available
  141. // Do it in AtapiCrashDumpIdeWrite instead
  142. // CLRMASK (DumpData.HwDeviceExtension.DeviceFlags[i], DFLAGS_USE_DMA);
  143. DumpData.HwDeviceExtension.CurrentSrb = NULL;
  144. DumpData.HwDeviceExtension.DataBuffer = NULL;
  145. DumpData.HwDeviceExtension.BytesLeft = 0;
  146. DumpData.HwDeviceExtension.ExpectingInterrupt = FALSE;
  147. DumpData.HwDeviceExtension.DMAInProgress = FALSE;
  148. DumpData.HwDeviceExtension.DriverMustPoll = TRUE;
  149. // }
  150. DumpData.BytesPerSector = 512;
  151. DumpData.MaxBlockSize = DumpData.BytesPerSector * 256;
  152. hwExtension = &DumpData.HwDeviceExtension;
  153. bmInterface = &(hwExtension->BusMasterInterface);
  154. if (bmInterface->BmCrashDumpInitialize) {
  155. bmInterface->BmCrashDumpInitialize(bmInterface->Context);
  156. } else {
  157. // Don't use DMA
  158. for (i=0; i<DumpData.HwDeviceExtension.MaxIdeDevice; i++) {
  159. CLRMASK (DumpData.HwDeviceExtension.DeviceFlags[i], DFLAGS_USE_DMA);
  160. CLRMASK (DumpData.HwDeviceExtension.DeviceFlags[i], DFLAGS_USE_UDMA);
  161. }
  162. }
  163. DebugPrint ((DBG_CRASHDUMP, "ATAPI: Leaving AtapiCrashDumpOpen...\n"));
  164. return TRUE;
  165. }
  166. NTSTATUS
  167. AtapiCrashDumpIdeWrite (
  168. IN PLARGE_INTEGER DiskByteOffset,
  169. IN PMDL Mdl
  170. )
  171. {
  172. SCSI_REQUEST_BLOCK SrbData; // Store Srb on stack, don't modify memory!
  173. ULONG retryCount;
  174. ULONG srbStatus;
  175. NTSTATUS status;
  176. PSCSI_REQUEST_BLOCK srb;
  177. PCDB cdb;
  178. ULONG blockOffset;
  179. ULONG blockCount;
  180. ULONG blockSize;
  181. ULONG bytesWritten;
  182. UCHAR ideStatus;
  183. ULONG i;
  184. ULONG writeMulitpleBlockSize;
  185. for (i=0; i<DumpData.HwDeviceExtension.MaxIdeDevice; i++) {
  186. CLRMASK (DumpData.HwDeviceExtension.DeviceFlags[i], DFLAGS_USE_DMA);
  187. }
  188. DebugPrint((DBG_CRASHDUMP,
  189. "AtapiCrashDumpWrite: Write memory at 0x%x for 0x%x bytes\n",
  190. Mdl->MappedSystemVa,
  191. Mdl->ByteCount));
  192. if (Mdl->ByteCount % DumpData.BytesPerSector) {
  193. //
  194. // must be complete sectors
  195. //
  196. DebugPrint ((DBG_ALWAYS, "AtapiCrashDumpWrite ERROR: not writing full sectors\n"));
  197. return STATUS_INVALID_PARAMETER;
  198. }
  199. if ((Mdl->ByteCount / DumpData.BytesPerSector) > 256) {
  200. //
  201. // need code to split request up
  202. //
  203. DebugPrint ((DBG_ALWAYS, "AtapiCrashDumpWrite ERROR: can't handle large write\n"));
  204. return STATUS_INVALID_PARAMETER;
  205. }
  206. //
  207. // get the WRITE MULTIPLE blocksize per interrupt for later use
  208. //
  209. if (DumpData.HwDeviceExtension.MaximumBlockXfer[DumpData.CrashInitData->TargetId]) {
  210. writeMulitpleBlockSize =
  211. DumpData.HwDeviceExtension.
  212. MaximumBlockXfer[DumpData.CrashInitData->TargetId] *
  213. DumpData.BytesPerSector;
  214. } else {
  215. writeMulitpleBlockSize = 1 * DumpData.BytesPerSector;
  216. }
  217. srb = &SrbData;
  218. cdb = (PCDB)srb->Cdb;
  219. //
  220. // Zero SRB.
  221. //
  222. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  223. //
  224. // Initialize SRB.
  225. //
  226. srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  227. srb->PathId = DumpData.CrashInitData->PathId;
  228. srb->TargetId = DumpData.CrashInitData->TargetId;
  229. srb->Lun = DumpData.CrashInitData->Lun;
  230. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  231. srb->SrbFlags = SRB_FLAGS_DATA_OUT |
  232. SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
  233. SRB_FLAGS_DISABLE_DISCONNECT |
  234. SRB_FLAGS_DISABLE_AUTOSENSE;
  235. srb->SrbStatus = srb->ScsiStatus = 0;
  236. srb->NextSrb = 0;
  237. srb->TimeOutValue = 10;
  238. srb->CdbLength = 10;
  239. //
  240. // Initialize CDB for write command.
  241. //
  242. cdb->CDB10.OperationCode = SCSIOP_WRITE;
  243. MARK_SRB_FOR_PIO(srb);
  244. bytesWritten = 0;
  245. do {
  246. if ((Mdl->ByteCount - bytesWritten) > DumpData.MaxBlockSize) {
  247. blockSize = DumpData.MaxBlockSize;
  248. DebugPrint ((DBG_CRASHDUMP, "ATAPI: AtapiCrashDumpWrite: can't do a single write...\n"));
  249. } else {
  250. blockSize = Mdl->ByteCount - bytesWritten;
  251. }
  252. blockCount = blockSize / DumpData.BytesPerSector;
  253. status = STATUS_UNSUCCESSFUL;
  254. for (retryCount=0; (retryCount<2) && !NT_SUCCESS(status); retryCount++) {
  255. srb->DataTransferLength = blockSize;
  256. srb->DataBuffer = ((PUCHAR) Mdl->MappedSystemVa) + bytesWritten;
  257. //
  258. // Convert disk byte offset to block offset.
  259. //
  260. blockOffset = (ULONG)((DumpData.PartitionOffset.QuadPart +
  261. (*DiskByteOffset).QuadPart +
  262. (ULONGLONG) bytesWritten) / DumpData.BytesPerSector);
  263. //
  264. // Fill in CDB block address.
  265. //
  266. cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&blockOffset)->Byte3;
  267. cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&blockOffset)->Byte2;
  268. cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&blockOffset)->Byte1;
  269. cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&blockOffset)->Byte0;
  270. cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&blockCount)->Byte1;
  271. cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&blockCount)->Byte0;
  272. status = AtapiCrashDumpIdeWritePio(srb);
  273. if (NT_SUCCESS(status)) {
  274. bytesWritten += blockSize;
  275. }
  276. }
  277. if (!NT_SUCCESS(status)) {
  278. IdeHardReset (
  279. &DumpData.HwDeviceExtension.BaseIoAddress1,
  280. &DumpData.HwDeviceExtension.BaseIoAddress2,
  281. TRUE,
  282. TRUE
  283. );
  284. //
  285. // model: WDC AC31000H
  286. // version: 19.19E22
  287. // serial #: DWW-2T27518018 6
  288. //
  289. // found out this device can't handle WRITE with more sectors than 16,
  290. // the blocks per interrupt setting in ID data word 59.
  291. //
  292. // Therefore, it we see an error, we will change to blocksize to it.
  293. // If it still fails, we will keep shrinking the blocksize by half
  294. // until it gets to zero. Then, we will return an error
  295. //
  296. //
  297. // last write fail, try a smaller block size
  298. //
  299. if (blockSize > writeMulitpleBlockSize) {
  300. blockSize = writeMulitpleBlockSize;
  301. } else {
  302. blockSize /= 2;
  303. }
  304. if (blockSize) {
  305. DebugPrint ((DBG_ALWAYS, "ATAPI: AtapiCrashDumpWrite max write block size is down to 0x%x\n", blockSize));
  306. DumpData.MaxBlockSize = blockSize;
  307. } else {
  308. break;
  309. }
  310. }
  311. } while (bytesWritten < Mdl->ByteCount);
  312. DebugPrint ((DBG_CRASHDUMP, "ATAPI: Leaving AtapiCrashDumpWrite...\n"));
  313. return status;
  314. }
  315. VOID
  316. AtapiCrashDumpFinish (
  317. VOID
  318. )
  319. {
  320. SCSI_REQUEST_BLOCK SrbData; // Store Srb on stack, don't modify memory!
  321. PSCSI_REQUEST_BLOCK srb = &SrbData;
  322. PCDB cdb;
  323. ULONG srbStatus;
  324. ATA_PASS_THROUGH ataPassThroughData;
  325. UCHAR flushCommand;
  326. UCHAR ideStatus = 0;
  327. DebugPrint ((DBG_CRASHDUMP, "ATAPI: Entering AtapiCrashDumpFinish...\n"));
  328. flushCommand =
  329. DumpData.HwDeviceExtension.DeviceParameters[DumpData.CrashInitData->TargetId].IdeFlushCommand;
  330. if (flushCommand != IDE_COMMAND_NO_FLUSH) {
  331. WaitOnBusy(&DumpData.HwDeviceExtension.BaseIoAddress1, ideStatus);
  332. //
  333. // Zero SRB and ATA_PASS_THROUGH
  334. //
  335. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  336. RtlZeroMemory(&ataPassThroughData, sizeof(ATA_PASS_THROUGH));
  337. //
  338. // Initialize SRB.
  339. //
  340. srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  341. srb->PathId = DumpData.CrashInitData->PathId;
  342. srb->TargetId = DumpData.CrashInitData->TargetId;
  343. srb->Lun = DumpData.CrashInitData->Lun;
  344. srb->Function = SRB_FUNCTION_ATA_PASS_THROUGH;
  345. srb->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
  346. SRB_FLAGS_DISABLE_DISCONNECT;
  347. srb->SrbStatus = srb->ScsiStatus = 0;
  348. srb->NextSrb = 0;
  349. srb->TimeOutValue = 10;
  350. srb->CdbLength = 10;
  351. srb->DataTransferLength = sizeof (ataPassThroughData);
  352. srb->DataBuffer = &ataPassThroughData;
  353. ataPassThroughData.IdeReg.bCommandReg = flushCommand;
  354. ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
  355. srbStatus = IdeSendPassThroughCommand(
  356. &DumpData.HwDeviceExtension,
  357. srb
  358. );
  359. if (srbStatus == SRB_STATUS_PENDING) {
  360. UCHAR ideStatus;
  361. WaitOnBusy(&DumpData.HwDeviceExtension.BaseIoAddress1, ideStatus);
  362. DebugPrint ((DBG_ALWAYS, "flush = 0x%x, status = 0x%x...\n", flushCommand, ideStatus));
  363. } else if (srbStatus != SRB_STATUS_SUCCESS) {
  364. DebugPrint ((DBG_ALWAYS, "AtapiCrashDumpFinish: flush failed...\n"));
  365. }
  366. }
  367. //
  368. // issue an standby to park the drive head
  369. //
  370. srb = &DumpData.Srb;
  371. //
  372. // Zero SRB and ATA_PASS_THROUGH
  373. //
  374. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  375. RtlZeroMemory(&ataPassThroughData, sizeof(ATA_PASS_THROUGH));
  376. //
  377. // Initialize SRB.
  378. //
  379. srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  380. srb->PathId = DumpData.CrashInitData->PathId;
  381. srb->TargetId = DumpData.CrashInitData->TargetId;
  382. srb->Lun = DumpData.CrashInitData->Lun;
  383. srb->Function = SRB_FUNCTION_ATA_PASS_THROUGH;
  384. srb->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
  385. SRB_FLAGS_DISABLE_DISCONNECT;
  386. srb->SrbStatus = srb->ScsiStatus = 0;
  387. srb->NextSrb = 0;
  388. srb->TimeOutValue = 10;
  389. srb->CdbLength = 10;
  390. srb->DataTransferLength = sizeof (ataPassThroughData);
  391. srb->DataBuffer = &ataPassThroughData;
  392. ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_STANDBY_IMMEDIATE;
  393. ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
  394. srbStatus = IdeSendPassThroughCommand(
  395. &DumpData.HwDeviceExtension,
  396. srb
  397. );
  398. if (srbStatus == SRB_STATUS_PENDING) {
  399. WaitOnBusy(&DumpData.HwDeviceExtension.BaseIoAddress1, ideStatus);
  400. WaitOnBusy(&DumpData.HwDeviceExtension.BaseIoAddress1, ideStatus);
  401. WaitOnBusy(&DumpData.HwDeviceExtension.BaseIoAddress1, ideStatus);
  402. } else if (srbStatus != SRB_STATUS_SUCCESS) {
  403. DebugPrint ((DBG_ALWAYS, "AtapiCrashDumpFinish: flush failed...\n"));
  404. }
  405. //
  406. //the disk will be powered off.
  407. //
  408. DebugPrint ((DBG_CRASHDUMP, "ATAPI: Leaving AtapiCrashDumpFinish...\n"));
  409. return;
  410. }
  411. /* ---------------------------- DMA --------------------------- */
  412. /* --- */
  413. VOID
  414. AtapiCrashDumpBmCallback (
  415. IN PVOID Context
  416. )
  417. {
  418. // Just to make BmSetup happy -- it must be supplied
  419. }
  420. // Local variables that needs to be preserved across the calls
  421. #define ENUM_DUMP_LOCALS(X) \
  422. X(LARGE_INTEGER, DiskByteOffset) \
  423. X(PSCSI_REQUEST_BLOCK, srb) \
  424. X(PCDB, cdb) \
  425. X(PMDL, Mdl) \
  426. X(ULONG, blockSize) \
  427. X(ULONG, bytesWritten)
  428. // States
  429. #define STATE_READY 0
  430. #define STATE_WAIT_DMA 1
  431. #define STATE_WAIT_IDE 2
  432. #define STATE_BAD_DMA 3
  433. #define STATE_IO_FAIL 4
  434. #define DMA_MAGIC 'XDma'
  435. typedef struct
  436. {
  437. UCHAR RegionDescriptorTablePage[PAGE_SIZE];
  438. LONG State;
  439. LONG Magic;
  440. SCSI_REQUEST_BLOCK Srb;
  441. PMDL Mdl;
  442. LARGE_INTEGER DiskByteOffset;
  443. ULONG BytesWritten;
  444. ULONG RetryCount;
  445. // Keep contents of BusMasterInterface.Context in safe place because
  446. // originally it's stored in memory that's saved by hibernation.
  447. // Unfortunately, BmSetup saves its arguments in PdoContext thus
  448. // constantly modifying memory. Special troubleshooting code in
  449. // po\hiber.c detects and reports such memory changes, and despite in this
  450. // case it's absolutely harmless it's better be avoided.
  451. PVOID BmContext;
  452. UCHAR BmContextBuffer[1024];
  453. }
  454. DUMP_LOCALS;
  455. BOOLEAN
  456. AtapiCrashDumpInterrupt(
  457. PVOID DeviceExtension
  458. )
  459. /*++
  460. Routine Description:
  461. This is the ISR for crashdump. Should be called in a polling mode and works
  462. only for DMA requests. Doesn't need any of the flags, since we get called
  463. in a synchronized manner.
  464. Arguments:
  465. DeviceExtension : The hardware device extension.
  466. Return Value:
  467. TRUE : if it is our interrupt.
  468. FALSE : if it is not our interrupt or if there are no pending requests.
  469. --*/
  470. {
  471. PHW_DEVICE_EXTENSION deviceExtension = DeviceExtension;
  472. PPCIIDE_BUSMASTER_INTERFACE bmInterface = &deviceExtension->BusMasterInterface;
  473. PIDE_REGISTERS_1 baseIoAddress1 = &DumpData.HwDeviceExtension.BaseIoAddress1;
  474. PIDE_REGISTERS_2 baseIoAddress2 = &DumpData.HwDeviceExtension.BaseIoAddress2;
  475. PSCSI_REQUEST_BLOCK srb;
  476. BMSTATUS bmStatus;
  477. UCHAR statusByte;
  478. ULONG i;
  479. ULONG status;
  480. //
  481. // This interface should exist
  482. //
  483. ASSERT(bmInterface->BmStatus);
  484. //
  485. // poll the bus master status register
  486. //
  487. bmStatus = bmInterface->BmStatus(bmInterface->Context);
  488. //
  489. // return false if it is not our interrupt
  490. //
  491. if (!(bmStatus & BMSTATUS_INTERRUPT)) {
  492. DebugPrint((DBG_CRASHDUMP,
  493. "Not our interrupt\n"
  494. ));
  495. return FALSE;
  496. }
  497. //
  498. // Some VIA motherboards do not work without it
  499. //
  500. KeStallExecutionProcessor (5);
  501. //
  502. // disarm DMA and clear bus master interrupt
  503. //
  504. bmInterface->BmDisarm(bmInterface->Context);
  505. //
  506. // Get the current request
  507. //
  508. srb = deviceExtension->CurrentSrb;
  509. //
  510. // we will return false if there are no pending requests
  511. //
  512. if (srb == NULL) {
  513. DebugPrint((DBG_CRASHDUMP,
  514. "No pending request\n"
  515. ));
  516. return FALSE;
  517. }
  518. //
  519. // ignore the dma active bit
  520. //
  521. if (bmInterface->IgnoreActiveBitForAtaDevice) {
  522. CLRMASK (bmStatus, BMSTATUS_NOT_REACH_END_OF_TRANSFER);
  523. }
  524. //
  525. // Select IDE line(Primary or Secondary).
  526. //
  527. SelectIdeLine(baseIoAddress1, srb->TargetId >> 1);
  528. //
  529. // Clear interrupt by reading status.
  530. //
  531. GetBaseStatus(baseIoAddress1, statusByte);
  532. //
  533. // should be an ATA device
  534. //
  535. ASSERT(!(deviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_ATAPI_DEVICE));
  536. //
  537. // Check for error conditions.
  538. //
  539. if (statusByte & IDE_STATUS_ERROR) {
  540. //
  541. // Fail this request.
  542. //
  543. status = SRB_STATUS_ERROR;
  544. goto CompleteRequest;
  545. }
  546. WaitOnBusyUntil(baseIoAddress1, statusByte, 500);
  547. ASSERT(!(statusByte & IDE_STATUS_BUSY));
  548. //
  549. // interrupt indicates that the dma engine has finished the transfer
  550. //
  551. deviceExtension->BytesLeft = 0;
  552. //
  553. // bmStatus is initalized eariler.
  554. //
  555. if (!BMSTATUS_SUCCESS(bmStatus)) {
  556. if (bmStatus & BMSTATUS_ERROR_TRANSFER) {
  557. status = SRB_STATUS_ERROR;
  558. }
  559. if (bmStatus & BMSTATUS_NOT_REACH_END_OF_TRANSFER){
  560. status = SRB_STATUS_DATA_OVERRUN;
  561. }
  562. } else {
  563. status = SRB_STATUS_SUCCESS;
  564. }
  565. CompleteRequest:
  566. //
  567. // should we translate the srb error
  568. // and a complicated retry mechanism.
  569. //
  570. //
  571. // check if drq is still up
  572. //
  573. i=0;
  574. while (statusByte & IDE_STATUS_DRQ) {
  575. GetStatus(baseIoAddress1,statusByte);
  576. i++;
  577. if (i > 5) {
  578. status = SRB_STATUS_BUSY;
  579. }
  580. KeStallExecutionProcessor(100);
  581. }
  582. //
  583. // check if the device is busy
  584. //
  585. if (statusByte & IDE_STATUS_BUSY) {
  586. status = SRB_STATUS_BUSY;
  587. }
  588. //
  589. // Set the srb status
  590. //
  591. srb->SrbStatus = (UCHAR)status;
  592. //
  593. // request is done.
  594. //
  595. deviceExtension->CurrentSrb = NULL;
  596. return TRUE;
  597. }
  598. NTSTATUS
  599. AtapiCrashDumpIdeWriteDMA (
  600. IN LONG Action,
  601. IN PLARGE_INTEGER ArgDiskByteOffset,
  602. IN PMDL ArgMdl,
  603. IN PVOID LocalData
  604. )
  605. /*++
  606. Routine Description:
  607. Asynchronous DMA write routine.
  608. Arguments:
  609. Action - one of following:
  610. IO_DUMP_WRITE_INIT - Initialize LocalData (must be first call)
  611. IO_DUMP_WRITE_FULFILL - Perform IO and wait until completion
  612. IO_DUMP_WRITE_START - Start IO and return ASAP
  613. IO_DUMP_WRITE_RESUME - Resume previousely started IO
  614. IO_DUMP_WRITE_FINISH - Complete previous IO request (wait if necessary)
  615. Attention! It is caller's responsibility to make sure that
  616. a) WriteDMA is always called with absolutely the same value of LocalData
  617. b) Contents of *ArgMdl will be preserved between Start/Resume/Finish
  618. c) Memory given by ArgMdl is not modified until the end of operation
  619. ArgDiskByteOffset - Offset on hard disk in bytes
  620. ArgMdl - MDL giving output memory layout
  621. Attn: for DMA the best IO size is 4 KB; for PIO the more the better
  622. LocalData - Memory region where WriteDMA will keep all the data
  623. that need to be preserved between Start/Resume/Finish.
  624. Attn: this region shall be of at least IO_DUMP_WRITE_DATA_SIZE bytes,
  625. and it must be page-aligned
  626. Return Value:
  627. STATUS_SUCCESS - operation completed successfully
  628. STATUS_PENDING - operation started but not completed yet
  629. STATUS_UNSUCCESSFUL - operation failed; use of WriteRoutine (PIO-based IO) adviced
  630. (however if user will keep on using WriteDMA it will redirect
  631. all requests to PIO itself)
  632. STATUS_INVALID_PARAMETER - previously started operation wasn't finished, or
  633. incorrect parameter indeed
  634. --*/
  635. {
  636. DUMP_LOCALS *Locals = LocalData;
  637. PHW_DEVICE_EXTENSION hwExtension = &DumpData.HwDeviceExtension;
  638. PPCIIDE_BUSMASTER_INTERFACE bmInterface = &hwExtension->BusMasterInterface;
  639. LONG targetId = DumpData.CrashInitData->TargetId;
  640. PSCSI_REQUEST_BLOCK srb;
  641. NTSTATUS status;
  642. ULONG srbStatus;
  643. BMSTATUS bmStatus;
  644. ULONG i;
  645. PCDB cdb;
  646. UCHAR statusByte;
  647. PMDL mdl;
  648. BOOLEAN interruptCleared;
  649. BOOLEAN usePio;
  650. if (IO_DUMP_WRITE_DATA_SIZE < sizeof (*Locals)) {
  651. DebugPrint ((DBG_CRASHDUMP, "AtapiCrashDumpIdeWriteDMA: IO_DUMP_WRITE_DATA_SIZE = %d, sizeof (*Locals) == %d\n",
  652. IO_DUMP_WRITE_DATA_SIZE, sizeof (*Locals)));
  653. return STATUS_INVALID_PARAMETER;
  654. }
  655. switch (Action) {
  656. case IO_DUMP_WRITE_INIT:
  657. //
  658. // initalize the state to bad_dma
  659. //
  660. Locals->State = STATE_BAD_DMA;
  661. Locals->Magic = 0;
  662. //
  663. // Check alignment
  664. //
  665. if (((ULONG_PTR) Locals) & (PAGE_SIZE-1)) {
  666. DebugPrint ((DBG_CRASHDUMP, "AtapiCrashDumpIdeWriteDMA: misaligned Locals = %p\n", Locals));
  667. return STATUS_UNSUCCESSFUL;
  668. }
  669. //
  670. // Make sure we may use UDMA; do not try to use pure DMA --
  671. // it won't work on some machines (e.g. Compaq Armada 7800)
  672. //
  673. if (!(hwExtension->DeviceFlags[targetId] & DFLAGS_DEVICE_PRESENT) ||
  674. !(hwExtension->DeviceParameters[targetId].TransferModeSupported & UDMA_SUPPORT) ||
  675. !(hwExtension->DeviceParameters[targetId].TransferModeSelected & UDMA_SUPPORT) ||
  676. !(hwExtension->DeviceFlags[targetId] & DFLAGS_USE_UDMA) ||
  677. bmInterface->MaxTransferByteSize <= 0
  678. ) {
  679. DebugPrint ((DBG_CRASHDUMP, "AtapiCrashDumpIdeWriteDMA: UDMA is not available\n"));
  680. return STATUS_UNSUCCESSFUL;
  681. }
  682. //
  683. // Copy contents of BusMasterInterface.Context to safe place and
  684. // substitute the pointer. Bm* functions change its contents
  685. //
  686. ASSERT(bmInterface->ContextSize > 0);
  687. ASSERT(bmInterface->ContextSize < sizeof(Locals->BmContextBuffer));
  688. //
  689. // make sure we can copy the context to the local buffer
  690. //
  691. if ((bmInterface->ContextSize <=0) ||
  692. (bmInterface->ContextSize > sizeof(Locals->BmContextBuffer))) {
  693. return STATUS_UNSUCCESSFUL;
  694. }
  695. //
  696. // Save BM context in modifyable memory:
  697. // Bm* functions change its contents
  698. //
  699. Locals->BmContext = bmInterface->Context;
  700. RtlCopyMemory (&Locals->BmContextBuffer, Locals->BmContext, bmInterface->ContextSize);
  701. //
  702. // Check version of PCIIDEX.SYS
  703. //
  704. ASSERT(bmInterface->BmSetupOnePage);
  705. //
  706. // OK, now we are ready to use DMA
  707. //
  708. Locals->Magic = DMA_MAGIC;
  709. Locals->State = STATE_READY;
  710. return STATUS_SUCCESS;
  711. case IO_DUMP_WRITE_START:
  712. case IO_DUMP_WRITE_FULFILL:
  713. //
  714. // Make sure it was properly initialized
  715. //
  716. if (Locals->Magic != DMA_MAGIC) {
  717. return STATUS_INVALID_PARAMETER;
  718. }
  719. //
  720. // Do not call DMA if it failed once -- use PIO
  721. //
  722. if (Locals->State == STATE_BAD_DMA) {
  723. return AtapiCrashDumpIdeWrite (ArgDiskByteOffset, ArgMdl);
  724. }
  725. //
  726. // Caller did not complete prev IO
  727. //
  728. if (Locals->State != STATE_READY) {
  729. return STATUS_INVALID_PARAMETER;
  730. }
  731. //
  732. // Copy arguments into local variables
  733. //
  734. Locals->DiskByteOffset = *ArgDiskByteOffset;
  735. Locals->Mdl = ArgMdl;
  736. Locals->RetryCount = 0;
  737. srb = &Locals->Srb;
  738. mdl = Locals->Mdl;
  739. //
  740. // must be complete sectors
  741. //
  742. if (mdl->ByteCount % DumpData.BytesPerSector) {
  743. DebugPrint ((DBG_CRASHDUMP,
  744. "AtapiCrashDumpWriteDMA ERROR: not writing full sectors\n"
  745. ));
  746. return STATUS_INVALID_PARAMETER;
  747. }
  748. //
  749. // need code to split request up
  750. //
  751. if ((mdl->ByteCount / DumpData.BytesPerSector) > 256) {
  752. DebugPrint ((DBG_CRASHDUMP,
  753. "AtapiCrashDumpWriteDMA ERROR: can't handle large write\n"
  754. ));
  755. return STATUS_INVALID_PARAMETER;
  756. }
  757. //
  758. // use modifiable memory
  759. //
  760. bmInterface->Context = &Locals->BmContextBuffer;
  761. //
  762. // Zero SRB.
  763. //
  764. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  765. //
  766. // Initialize SRB.
  767. //
  768. srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  769. srb->PathId = DumpData.CrashInitData->PathId;
  770. srb->TargetId = (UCHAR) targetId;
  771. srb->Lun = DumpData.CrashInitData->Lun;
  772. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  773. srb->SrbFlags = SRB_FLAGS_DATA_OUT |
  774. SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
  775. SRB_FLAGS_DISABLE_DISCONNECT |
  776. SRB_FLAGS_DISABLE_AUTOSENSE;
  777. srb->SrbStatus = srb->ScsiStatus = 0;
  778. srb->NextSrb = 0;
  779. srb->TimeOutValue = 10;
  780. srb->CdbLength = 10;
  781. cdb = (PCDB)srb->Cdb;
  782. //
  783. // Initialize CDB for write command.
  784. //
  785. cdb->CDB10.OperationCode = SCSIOP_WRITE;
  786. //
  787. // Mark it for DMA
  788. //
  789. MARK_SRB_FOR_DMA (srb);
  790. hwExtension->CurrentSrb = srb;
  791. break;
  792. case IO_DUMP_WRITE_RESUME:
  793. case IO_DUMP_WRITE_FINISH:
  794. //
  795. // Make sure it was properly initialized
  796. //
  797. if (Locals->Magic != DMA_MAGIC) {
  798. return STATUS_INVALID_PARAMETER;
  799. }
  800. //
  801. // restore the local variables from scratch memory
  802. //
  803. srb = &Locals->Srb;
  804. mdl = Locals->Mdl;
  805. //
  806. // Resume/finish operation
  807. //
  808. if (Locals->State == STATE_READY) {
  809. //
  810. // we are done. return success
  811. //
  812. return(STATUS_SUCCESS);
  813. }
  814. if (Locals->State == STATE_WAIT_DMA) {
  815. //
  816. // Restore CurrentSrb
  817. // (it should be reset back to NULL on return)
  818. //
  819. hwExtension->CurrentSrb = srb;
  820. bmInterface->Context = &Locals->BmContextBuffer;
  821. goto WaitDma;
  822. }
  823. //
  824. // if any of the DMA operations failed, we would have used
  825. // PIO. PIO would have completed the transfer, so just return
  826. // status success.
  827. //
  828. if (Locals->State == STATE_BAD_DMA) {
  829. return STATUS_SUCCESS;
  830. }
  831. //
  832. // wrong state
  833. //
  834. DebugPrint((DBG_ALWAYS,
  835. "Wrong local state 0x%x\n",
  836. Locals->State
  837. ));
  838. ASSERT(FALSE);
  839. return(STATUS_INVALID_PARAMETER);
  840. default:
  841. DebugPrint ((DBG_CRASHDUMP, "AtapiCrashDumpIdeWriteDMA: Wrong Action = %d\n", Action));
  842. return STATUS_INVALID_PARAMETER;
  843. }
  844. DebugPrint((DBG_CRASHDUMP,
  845. "AtapiCrashDumpWriteDMA: Write memory at 0x%x for 0x%x bytes\n",
  846. mdl->MappedSystemVa,
  847. mdl->ByteCount));
  848. Locals->BytesWritten = 0;
  849. usePio = FALSE;
  850. do {
  851. ULONG blockSize;
  852. ULONG blockCount;
  853. ULONG blockOffset;
  854. ULONG bytesWritten = Locals->BytesWritten;
  855. //
  856. // determine the block size
  857. //
  858. //
  859. // cannot be greater than the max block size
  860. //
  861. if ((mdl->ByteCount - bytesWritten) > DumpData.MaxBlockSize) {
  862. blockSize = DumpData.MaxBlockSize;
  863. DebugPrint ((DBG_CRASHDUMP, "AtapiCrashDumpWriteDMA: can't do a single write...\n"));
  864. } else {
  865. blockSize = mdl->ByteCount - bytesWritten;
  866. }
  867. //
  868. // Write page by page in order to avoid extra memory allocations in HAL
  869. //
  870. {
  871. ULONG Size = PAGE_SIZE - (((ULONG) ((ULONG_PTR) mdl->MappedSystemVa + bytesWritten)) & (PAGE_SIZE - 1));
  872. if (blockSize > Size) {
  873. blockSize = Size;
  874. }
  875. }
  876. //
  877. // Don't do more than DMA can
  878. //
  879. if (blockSize > bmInterface->MaxTransferByteSize) {
  880. blockSize = bmInterface->MaxTransferByteSize;
  881. }
  882. blockCount = blockSize / DumpData.BytesPerSector;
  883. //
  884. // initialize status
  885. //
  886. status = STATUS_UNSUCCESSFUL;
  887. //
  888. // fill in the fields in the srb
  889. //
  890. srb->SrbStatus = srb->ScsiStatus = 0;
  891. srb->DataTransferLength = blockSize;
  892. srb->DataBuffer = ((PUCHAR) mdl->MappedSystemVa) + bytesWritten;
  893. //
  894. // Convert disk byte offset to block offset.
  895. //
  896. blockOffset = (ULONG)((DumpData.PartitionOffset.QuadPart +
  897. (Locals->DiskByteOffset).QuadPart +
  898. (ULONGLONG) bytesWritten) / DumpData.BytesPerSector);
  899. cdb = (PCDB)srb->Cdb;
  900. //
  901. // Fill in CDB block address.
  902. //
  903. cdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&blockOffset)->Byte3;
  904. cdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&blockOffset)->Byte2;
  905. cdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&blockOffset)->Byte1;
  906. cdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&blockOffset)->Byte0;
  907. cdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&blockCount)->Byte1;
  908. cdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&blockCount)->Byte0;
  909. //
  910. // make sure device is not busy
  911. //
  912. WaitOnBusy(&hwExtension->BaseIoAddress1, statusByte);
  913. //
  914. // HACK: do PIO.
  915. // Complete this request with PIO. Further requests will not
  916. // use DMA.
  917. //
  918. if (usePio) {
  919. status = AtapiCrashDumpIdeWritePio(srb);
  920. goto CompleteIde;
  921. }
  922. //
  923. // Make sure DMA is not busy
  924. //
  925. bmStatus = bmInterface->BmStatus (bmInterface->Context);
  926. if (bmStatus & BMSTATUS_INTERRUPT) {
  927. //
  928. // Well, in absense of interrupts it means that DMA is ready
  929. // However extra disarming won't hurt
  930. //
  931. bmInterface->BmDisarm (bmInterface->Context);
  932. } else if (bmStatus != BMSTATUS_NO_ERROR) {
  933. ASSERT(bmStatus == BMSTATUS_NO_ERROR);
  934. status = STATUS_UNSUCCESSFUL;
  935. goto Return;
  936. }
  937. //
  938. // Flush cached data buffers
  939. //
  940. KeFlushIoBuffers(mdl, FALSE, TRUE);
  941. //
  942. // Start new DMA operation
  943. //
  944. if (bmInterface->BmSetupOnePage == NULL) {
  945. status = bmInterface->BmSetup (
  946. bmInterface->Context,
  947. srb->DataBuffer,
  948. srb->DataTransferLength,
  949. mdl,
  950. FALSE,
  951. AtapiCrashDumpBmCallback,
  952. NULL
  953. );
  954. } else {
  955. status = bmInterface->BmSetupOnePage (
  956. bmInterface->Context,
  957. srb->DataBuffer,
  958. srb->DataTransferLength,
  959. mdl,
  960. FALSE,
  961. Locals
  962. );
  963. }
  964. if (!NT_SUCCESS(status)) {
  965. ASSERT(NT_SUCCESS(status));
  966. goto Return;
  967. }
  968. //
  969. // make sure the device is not busy
  970. //
  971. WaitOnBusy(&DumpData.HwDeviceExtension.BaseIoAddress1, statusByte);
  972. //
  973. // srb should be marked for DMA
  974. //
  975. ASSERT(SRB_USES_DMA(srb));
  976. //
  977. // Start new IO
  978. //
  979. srbStatus = IdeReadWrite (hwExtension, srb);
  980. if (srbStatus != SRB_STATUS_PENDING) {
  981. DebugPrint ((DBG_CRASHDUMP,
  982. "AtapiCrashDumpWriteDMA: Wrong srbStatus = 0x%x\n",
  983. srbStatus
  984. ));
  985. //
  986. // reset and retry
  987. //
  988. srb->SrbStatus = (UCHAR)srbStatus;
  989. goto CompleteIde;
  990. }
  991. WaitDma:
  992. //
  993. // wait for the dma to finish and the controller to
  994. // interrupt. we will keep polling the bus master status
  995. // register
  996. //
  997. bmStatus = bmInterface->BmStatus(bmInterface->Context);
  998. //
  999. // if we have an interrupt or there is an error
  1000. // we are done
  1001. //
  1002. if (!((bmStatus & BMSTATUS_INTERRUPT) ||
  1003. (bmStatus & BMSTATUS_ERROR_TRANSFER))) {
  1004. //
  1005. // if we don't have to fulfill the request, just
  1006. // return pending. we will be called again.
  1007. //
  1008. if ((Action == IO_DUMP_WRITE_START) ||
  1009. (Action == IO_DUMP_WRITE_RESUME)) {
  1010. Locals->State = STATE_WAIT_DMA;
  1011. status = STATUS_PENDING;
  1012. goto Return;
  1013. }
  1014. //
  1015. // we have to finish the request. wait until the interrupt
  1016. // is set
  1017. //
  1018. i=0;
  1019. while (i++ < 10000) {
  1020. bmStatus = bmInterface->BmStatus(bmInterface->Context);
  1021. if ((bmStatus & BMSTATUS_INTERRUPT) ||
  1022. (bmStatus & BMSTATUS_ERROR_TRANSFER)) {
  1023. break;
  1024. }
  1025. KeStallExecutionProcessor (100);
  1026. }
  1027. //
  1028. // check if we received an interrupt.
  1029. //
  1030. if (i >= 10000) {
  1031. //
  1032. // reset and retry
  1033. //
  1034. ASSERT(FALSE);
  1035. //
  1036. // disarm the dma controller
  1037. //
  1038. bmInterface->BmDisarm (bmInterface->Context);
  1039. srb->SrbStatus = SRB_STATUS_ERROR;
  1040. goto CompleteIde;
  1041. }
  1042. }
  1043. if (bmStatus & BMSTATUS_ERROR_TRANSFER){
  1044. //
  1045. // Transfer Error. fail the transfer.
  1046. //
  1047. status = STATUS_UNSUCCESSFUL;
  1048. goto Return;
  1049. }
  1050. //
  1051. // wait for our ISR to finish its job
  1052. //
  1053. interruptCleared = AtapiCrashDumpInterrupt(hwExtension);
  1054. //
  1055. // it should be our interrupt
  1056. //
  1057. ASSERT(interruptCleared);
  1058. if (!interruptCleared) {
  1059. status = STATUS_DEVICE_BUSY;
  1060. goto Return;
  1061. }
  1062. //
  1063. // clear any spurious interrupts
  1064. //
  1065. i=0;
  1066. while (AtapiCrashDumpInterrupt(hwExtension)) {
  1067. i++;
  1068. if (i>=100) {
  1069. DebugPrint((0,
  1070. "AtapiCrashDump: InterruptStorm\n"
  1071. ));
  1072. status = STATUS_DEVICE_BUSY;
  1073. goto Return;
  1074. }
  1075. KeStallExecutionProcessor (100);
  1076. }
  1077. CompleteIde:
  1078. //
  1079. // Flush the adapter buffers
  1080. //
  1081. if (usePio) {
  1082. //
  1083. // don't do anything
  1084. //
  1085. } else if (bmInterface->BmSetupOnePage == NULL) {
  1086. bmInterface->BmFlush (bmInterface->Context);
  1087. } else {
  1088. status = bmInterface->BmFlushAdapterBuffers (
  1089. bmInterface->Context,
  1090. srb->DataBuffer,
  1091. srb->DataTransferLength,
  1092. mdl,
  1093. FALSE
  1094. );
  1095. }
  1096. //
  1097. // update the bytesWritten
  1098. //
  1099. if (srb->SrbStatus == SRB_STATUS_SUCCESS) {
  1100. //
  1101. // status success
  1102. //
  1103. status = STATUS_SUCCESS;
  1104. //
  1105. // update byteswritten
  1106. //
  1107. Locals->BytesWritten += srb->DataTransferLength;
  1108. //
  1109. // reset retry count
  1110. //
  1111. Locals->RetryCount = 0;
  1112. } else {
  1113. ASSERT(FALSE);
  1114. //
  1115. // reset the bus and retry the request
  1116. //
  1117. IdeHardReset (
  1118. &DumpData.HwDeviceExtension.BaseIoAddress1,
  1119. &DumpData.HwDeviceExtension.BaseIoAddress2,
  1120. TRUE,
  1121. TRUE
  1122. );
  1123. //
  1124. // we should probably look at the error code and
  1125. // decide on the retry appropriately. However, to
  1126. // minimize complexity, we would just blindly retry
  1127. // 4 times and then use PIO
  1128. //
  1129. Locals->RetryCount++;
  1130. //
  1131. // retry with PIO (dma timeout)
  1132. // Give dma a fair shot. Once we switch to PIO
  1133. // we would not use DMA for the rest of hibernation.
  1134. //
  1135. if (Locals->RetryCount == 5) {
  1136. usePio = TRUE;
  1137. }
  1138. //
  1139. // PIO failed. Return error.
  1140. //
  1141. if (Locals->RetryCount > 5) {
  1142. status = STATUS_IO_DEVICE_ERROR;
  1143. goto Return;
  1144. }
  1145. }
  1146. } while (Locals->BytesWritten < mdl->ByteCount);
  1147. Locals->State = STATE_READY;
  1148. status = STATUS_SUCCESS;
  1149. Return:
  1150. //
  1151. // if we used PIO this time, disable dma
  1152. // for the rest of hibernation
  1153. //
  1154. if (usePio) {
  1155. Locals->State = STATE_BAD_DMA;
  1156. }
  1157. if (!NT_SUCCESS(status)) {
  1158. ASSERT(FALSE);
  1159. Locals->State = STATE_IO_FAIL;
  1160. }
  1161. hwExtension->CurrentSrb = NULL;
  1162. bmInterface->Context = Locals->BmContext;
  1163. return status;
  1164. }
  1165. NTSTATUS
  1166. AtapiCrashDumpIdeWritePio (
  1167. IN PSCSI_REQUEST_BLOCK Srb
  1168. )
  1169. {
  1170. NTSTATUS status;
  1171. ULONG srbStatus;
  1172. UCHAR ideStatus;
  1173. ULONG i;
  1174. MARK_SRB_FOR_PIO(Srb);
  1175. //
  1176. // make sure it is not busy
  1177. //
  1178. WaitOnBusy(&DumpData.HwDeviceExtension.BaseIoAddress1, ideStatus);
  1179. //
  1180. // Send the srb to the device
  1181. //
  1182. srbStatus = IdeReadWrite(
  1183. &DumpData.HwDeviceExtension,
  1184. Srb
  1185. );
  1186. if (srbStatus == SRB_STATUS_PENDING) {
  1187. while (DumpData.HwDeviceExtension.BytesLeft) {
  1188. //
  1189. // ATA-2 spec requires a minimum of 400 ns stall here
  1190. //
  1191. KeStallExecutionProcessor (1);
  1192. //
  1193. // a quick wait
  1194. //
  1195. for (i=0; i<100; i++) {
  1196. GetStatus(&DumpData.HwDeviceExtension.BaseIoAddress1, ideStatus);
  1197. if (!(ideStatus & IDE_STATUS_BUSY)) {
  1198. break;
  1199. }
  1200. }
  1201. if (ideStatus & IDE_STATUS_BUSY) {
  1202. //
  1203. // go to a slower wait
  1204. //
  1205. WaitOnBusy(&DumpData.HwDeviceExtension.BaseIoAddress1, ideStatus);
  1206. }
  1207. if (ideStatus & (IDE_STATUS_BUSY | IDE_STATUS_ERROR)) {
  1208. status = STATUS_UNSUCCESSFUL;
  1209. DebugPrint ((DBG_ALWAYS, "AtapiCrashDumpIdeWrite: unexpected status 0x%x\n", ideStatus));
  1210. break;
  1211. } else {
  1212. ULONG byteCount;
  1213. //
  1214. // a quick wait On DRQ
  1215. //
  1216. for (i=0; i<100; i++) {
  1217. GetStatus(&DumpData.HwDeviceExtension.BaseIoAddress1, ideStatus);
  1218. if (ideStatus & IDE_STATUS_DRQ) {
  1219. break;
  1220. }
  1221. }
  1222. if (!(ideStatus & IDE_STATUS_DRQ)) {
  1223. WaitForDrq(&DumpData.HwDeviceExtension.BaseIoAddress1, ideStatus);
  1224. }
  1225. if (!(ideStatus & IDE_STATUS_DRQ)) {
  1226. status = STATUS_UNSUCCESSFUL;
  1227. DebugPrint ((DBG_ALWAYS, "AtapiCrashDumpIdeWrite: drq fails to assert, 0x%x\n", ideStatus));
  1228. break;
  1229. }
  1230. if (DumpData.HwDeviceExtension.BytesLeft <
  1231. DumpData.HwDeviceExtension.DeviceParameters[Srb->TargetId].MaxBytePerPioInterrupt) {
  1232. byteCount = DumpData.HwDeviceExtension.BytesLeft;
  1233. } else {
  1234. byteCount = DumpData.HwDeviceExtension.DeviceParameters[Srb->TargetId].MaxBytePerPioInterrupt;
  1235. }
  1236. WriteBuffer(&DumpData.HwDeviceExtension.BaseIoAddress1,
  1237. (PUSHORT)DumpData.HwDeviceExtension.DataBuffer,
  1238. byteCount / sizeof(USHORT));
  1239. DumpData.HwDeviceExtension.BytesLeft -= byteCount;
  1240. DumpData.HwDeviceExtension.DataBuffer += byteCount;
  1241. }
  1242. }
  1243. if (!DumpData.HwDeviceExtension.BytesLeft) {
  1244. //
  1245. // ATA-2 spec requires a minimum of 400 ns stall here
  1246. //
  1247. KeStallExecutionProcessor (1);
  1248. //
  1249. // a quick wait
  1250. //
  1251. for (i=0; i<100; i++) {
  1252. GetStatus(&DumpData.HwDeviceExtension.BaseIoAddress1, ideStatus);
  1253. if (!(ideStatus & IDE_STATUS_BUSY)) {
  1254. break;
  1255. }
  1256. }
  1257. if (ideStatus & IDE_STATUS_BUSY) {
  1258. //
  1259. // go to a slower wait
  1260. //
  1261. WaitOnBusy(&DumpData.HwDeviceExtension.BaseIoAddress1, ideStatus);
  1262. }
  1263. }
  1264. if (DumpData.HwDeviceExtension.BytesLeft) {
  1265. status = STATUS_UNSUCCESSFUL;
  1266. DebugPrint ((DBG_ALWAYS, "AtapiCrashDumpIdeWrite: write failed. idestatus = 0x%x\n", ideStatus));
  1267. } else {
  1268. Srb->SrbStatus = SRB_STATUS_SUCCESS;
  1269. status = STATUS_SUCCESS;
  1270. }
  1271. } else {
  1272. DebugPrint ((DBG_ALWAYS,
  1273. "atapi crash dump: IdeReadWrite failed with stautus = 0x%x\n",
  1274. srbStatus
  1275. ));
  1276. status = STATUS_UNSUCCESSFUL;
  1277. }
  1278. if (!NT_SUCCESS(status)) {
  1279. Srb->SrbStatus = SRB_STATUS_ERROR;
  1280. } else {
  1281. ASSERT(Srb->SrbStatus == SRB_STATUS_SUCCESS);
  1282. }
  1283. DumpData.HwDeviceExtension.BytesLeft = 0;
  1284. DumpData.HwDeviceExtension.DataBuffer = 0;
  1285. return status;
  1286. }