Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1889 lines
53 KiB

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