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.

7474 lines
195 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1990 - 1999
  3. Module Name:
  4. internal.c
  5. Abstract:
  6. This is the NT SCSI port driver. This file contains the internal
  7. code.
  8. Authors:
  9. Mike Glass
  10. Jeff Havens
  11. Environment:
  12. kernel mode only
  13. Notes:
  14. This module is a driver dll for scsi miniports.
  15. Revision History:
  16. --*/
  17. #include "ideport.h"
  18. NTSTATUS
  19. IdeSendMiniPortIoctl(
  20. IN PFDO_EXTENSION DeviceExtension,
  21. IN PIRP RequestIrp
  22. );
  23. NTSTATUS
  24. IdeSendPassThrough (
  25. IN PFDO_EXTENSION DeviceExtension,
  26. IN PIRP RequestIrp
  27. );
  28. NTSTATUS
  29. IdeGetInquiryData(
  30. IN PFDO_EXTENSION DeviceExtension,
  31. IN PIRP Irp
  32. );
  33. NTSTATUS
  34. IdeClaimLogicalUnit(
  35. IN PFDO_EXTENSION DeviceExtension,
  36. IN PIRP Irp
  37. );
  38. NTSTATUS
  39. IdeRemoveDevice(
  40. IN PFDO_EXTENSION DeviceExtension,
  41. IN PIRP Irp
  42. );
  43. VOID
  44. IdeLogResetError(
  45. IN PFDO_EXTENSION DeviceExtension,
  46. IN PSCSI_REQUEST_BLOCK Srb,
  47. IN ULONG UniqueId
  48. );
  49. #ifdef ALLOC_PRAGMA
  50. #pragma alloc_text(NONPAGE, IdePortDeviceControl)
  51. #pragma alloc_text(PAGE, IdeSendMiniPortIoctl)
  52. #pragma alloc_text(PAGE, IdeGetInquiryData)
  53. #pragma alloc_text(PAGE, IdeSendPassThrough)
  54. #pragma alloc_text(PAGE, IdeClaimLogicalUnit)
  55. #pragma alloc_text(PAGE, IdeRemoveDevice)
  56. #endif
  57. #if DBG
  58. #define CheckIrql() {\
  59. if (saveIrql != KeGetCurrentIrql()){\
  60. DebugPrint((1, "saveIrql=%x, current=%x\n", saveIrql, KeGetCurrentIrql()));\
  61. ASSERT(FALSE);}\
  62. }
  63. #else
  64. #define CheckIrql()
  65. #endif
  66. //
  67. // Routines start
  68. //
  69. NTSTATUS
  70. IdePortDispatch(
  71. IN PDEVICE_OBJECT DeviceObject,
  72. IN PIRP Irp
  73. )
  74. /*++
  75. Routine Description:
  76. Arguments:
  77. DeviceObject - Address of device object.
  78. Irp - Address of I/O request packet.
  79. Return Value:
  80. Status.
  81. --*/
  82. {
  83. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  84. PDEVICE_EXTENSION_HEADER doExtension;
  85. PFDO_EXTENSION deviceExtension;
  86. PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
  87. PLOGICAL_UNIT_EXTENSION logicalUnit;
  88. NTSTATUS status;
  89. RESET_CONTEXT resetContext;
  90. KIRQL currentIrql;
  91. KIRQL saveIrql=KeGetCurrentIrql();
  92. #if DBG
  93. UCHAR savedCdb[16];
  94. ULONG ki;
  95. #endif
  96. doExtension = DeviceObject->DeviceExtension;
  97. if (doExtension->AttacheeDeviceObject == NULL) {
  98. //
  99. // This is a PDO
  100. //
  101. PPDO_EXTENSION pdoExtension = (PPDO_EXTENSION) doExtension;
  102. srb->PathId = (UCHAR) pdoExtension->PathId;
  103. srb->TargetId = (UCHAR) pdoExtension->TargetId;
  104. srb->Lun = (UCHAR) pdoExtension->Lun;
  105. ((PCDB) (srb->Cdb))->CDB6GENERIC.LogicalUnitNumber = srb->Lun;
  106. CheckIrql();
  107. return IdePortDispatch(
  108. pdoExtension->ParentDeviceExtension->DeviceObject,
  109. Irp
  110. );
  111. } else {
  112. //
  113. // This is a FDO;
  114. //
  115. deviceExtension = (PFDO_EXTENSION) doExtension;
  116. }
  117. //
  118. // Init SRB Flags for IDE
  119. //
  120. INIT_IDE_SRB_FLAGS (srb);
  121. //
  122. // get the target device object extension
  123. //
  124. logicalUnit = RefLogicalUnitExtensionWithTag(
  125. deviceExtension,
  126. srb->PathId,
  127. srb->TargetId,
  128. srb->Lun,
  129. TRUE,
  130. Irp
  131. );
  132. if (logicalUnit == NULL) {
  133. DebugPrint((1, "IdePortDispatch: Bad logical unit address.\n"));
  134. //
  135. // Fail the request. Set status in Irp and complete it.
  136. //
  137. srb->SrbStatus = SRB_STATUS_NO_DEVICE;
  138. Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  139. CheckIrql();
  140. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  141. CheckIrql();
  142. return STATUS_NO_SUCH_DEVICE;
  143. }
  144. //
  145. // special flag for tape device
  146. //
  147. TEST_AND_SET_SRB_FOR_RDP(logicalUnit->ScsiDeviceType, srb);
  148. //
  149. // hang the logUnitExtension off the Irp
  150. //
  151. IDEPORT_PUT_LUNEXT_IN_IRP (irpStack, logicalUnit);
  152. //
  153. // check for DMA candidate
  154. // default (0) is DMA candidate
  155. //
  156. if (SRB_IS_DMA_CANDIDATE(srb)) {
  157. if (srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) {
  158. ULONG deviceFlags = deviceExtension->HwDeviceExtension->DeviceFlags[srb->TargetId];
  159. if (deviceFlags & DFLAGS_ATAPI_DEVICE) {
  160. if (srb->Cdb[0] == SCSIOP_MODE_SENSE) {
  161. if (!(deviceFlags & DFLAGS_TAPE_DEVICE)) {
  162. CheckIrql();
  163. return DeviceAtapiModeSense(logicalUnit, Irp);
  164. }
  165. //
  166. // we should do PIO for mode sense/select
  167. //
  168. MARK_SRB_AS_PIO_CANDIDATE(srb);
  169. } else if (srb->Cdb[0] == SCSIOP_MODE_SELECT) {
  170. if (!(deviceFlags & DFLAGS_TAPE_DEVICE)) {
  171. CheckIrql();
  172. return DeviceAtapiModeSelect(logicalUnit, Irp);
  173. }
  174. MARK_SRB_AS_PIO_CANDIDATE(srb);
  175. } else if (srb->Cdb[0] == SCSIOP_REQUEST_SENSE) {
  176. //
  177. // SCSIOP_REQUEST_SENSE
  178. // ALi can't handle odd word udma xfer
  179. // safest thing to do is do pio
  180. //
  181. MARK_SRB_AS_PIO_CANDIDATE(srb);
  182. } else if ((srb->Function == SRB_FUNCTION_ATA_POWER_PASS_THROUGH) ||
  183. (srb->Function == SRB_FUNCTION_ATA_PASS_THROUGH)) {
  184. MARK_SRB_AS_PIO_CANDIDATE(srb);
  185. } else if ((srb->Cdb[0] == ATAPI_MODE_SENSE) ||
  186. (srb->Cdb[0] == ATAPI_MODE_SELECT) ||
  187. (srb->Cdb[0] == SCSIOP_INQUIRY) ||
  188. (srb->Cdb[0] == SCSIOP_GET_EVENT_STATUS)) {
  189. MARK_SRB_AS_PIO_CANDIDATE(srb);
  190. }
  191. } else { // ATA deivce
  192. if ((srb->Cdb[0] != SCSIOP_READ) && (srb->Cdb[0] != SCSIOP_WRITE)) {
  193. //
  194. // for ATA device, we can only DMA with SCSIOP_READ and SCSIOP_WRITE
  195. //
  196. MARK_SRB_AS_PIO_CANDIDATE(srb);
  197. if (srb->Cdb[0] == SCSIOP_READ_CAPACITY) {
  198. CheckIrql();
  199. return DeviceIdeReadCapacity (logicalUnit, Irp);
  200. } else if (srb->Cdb[0] == SCSIOP_MODE_SENSE) {
  201. CheckIrql();
  202. return DeviceIdeModeSense (logicalUnit, Irp);
  203. } else if (srb->Cdb[0] == SCSIOP_MODE_SELECT) {
  204. CheckIrql();
  205. return DeviceIdeModeSelect (logicalUnit, Irp);
  206. }
  207. }
  208. }
  209. //
  210. //Check with the miniport (Special cases)
  211. //
  212. ASSERT (doExtension->AttacheeDeviceObject);
  213. ASSERT (srb->TargetId >=0);
  214. #if DBG
  215. for (ki=0;ki<srb->CdbLength;ki++) {
  216. savedCdb[ki]=srb->Cdb[ki];
  217. }
  218. #endif
  219. //Check for NULL.
  220. if (deviceExtension->TransferModeInterface.UseDma){
  221. if (!((deviceExtension->TransferModeInterface.UseDma)
  222. (deviceExtension->TransferModeInterface.VendorSpecificDeviceExtension,
  223. (PVOID)(srb->Cdb), srb->TargetId))) {
  224. MARK_SRB_AS_PIO_CANDIDATE(srb);
  225. }
  226. }
  227. #if DBG
  228. for (ki=0;ki<srb->CdbLength;ki++) {
  229. if (savedCdb[ki] != srb->Cdb[ki]) {
  230. DebugPrint((DBG_ALWAYS,
  231. "Miniport modified the Cdb\n"));
  232. ASSERT(FALSE);
  233. }
  234. }
  235. #endif
  236. if ((logicalUnit->DmaTransferTimeoutCount >= PDO_DMA_TIMEOUT_LIMIT) ||
  237. (logicalUnit->CrcErrorCount >= PDO_UDMA_CRC_ERROR_LIMIT)) {
  238. //
  239. // broken hardware
  240. //
  241. MARK_SRB_AS_PIO_CANDIDATE(srb);
  242. }
  243. } else {
  244. MARK_SRB_AS_PIO_CANDIDATE(srb);
  245. }
  246. }
  247. switch (srb->Function) {
  248. case SRB_FUNCTION_SHUTDOWN:
  249. DebugPrint((1, "IdePortDispatch: SRB_FUNCTION_SHUTDOWN...\n"));
  250. // ISSUE: 08/30/2000: disable/restore MSN settings
  251. case SRB_FUNCTION_FLUSH:
  252. {
  253. ULONG dFlags = deviceExtension->HwDeviceExtension->DeviceFlags[srb->TargetId];
  254. //
  255. // for IDE devices, complete the request with status success if
  256. // the device doesn't support the flush cache command
  257. //
  258. if (!(dFlags & DFLAGS_ATAPI_DEVICE) &&
  259. ((logicalUnit->FlushCacheTimeoutCount >= PDO_FLUSH_TIMEOUT_LIMIT) ||
  260. (logicalUnit->
  261. ParentDeviceExtension->
  262. HwDeviceExtension->
  263. DeviceParameters[logicalUnit->TargetId].IdeFlushCommand
  264. == IDE_COMMAND_NO_FLUSH))) {
  265. srb->SrbStatus = SRB_STATUS_SUCCESS;
  266. status = STATUS_SUCCESS;
  267. CheckIrql();
  268. break;
  269. }
  270. DebugPrint((1,
  271. "IdePortDispatch: SRB_FUNCTION_%x to target %x\n",
  272. srb->Function,
  273. srb->TargetId
  274. ));
  275. //
  276. // Fall thru to execute_scsi
  277. //
  278. }
  279. case SRB_FUNCTION_ATA_POWER_PASS_THROUGH:
  280. case SRB_FUNCTION_ATA_PASS_THROUGH:
  281. case SRB_FUNCTION_IO_CONTROL:
  282. case SRB_FUNCTION_EXECUTE_SCSI:
  283. if (logicalUnit->PdoState & PDOS_DEADMEAT) {
  284. //
  285. // Fail the request. Set status in Irp and complete it.
  286. //
  287. srb->SrbStatus = SRB_STATUS_NO_DEVICE;
  288. status = STATUS_NO_SUCH_DEVICE;
  289. CheckIrql();
  290. break;
  291. }
  292. if (srb->SrbFlags & SRB_FLAGS_NO_KEEP_AWAKE) {
  293. if (logicalUnit->DevicePowerState != PowerDeviceD0) {
  294. DebugPrint ((DBG_POWER, "0x%x powered down. failing SRB_FLAGS_NO_KEEP_AWAKE srb 0x%x\n", logicalUnit, srb));
  295. srb->SrbStatus = SRB_STATUS_NOT_POWERED;
  296. status = STATUS_NO_SUCH_DEVICE;
  297. CheckIrql();
  298. break;
  299. }
  300. }
  301. //
  302. // Mark Irp status pending.
  303. //
  304. IoMarkIrpPending(Irp);
  305. if (srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) {
  306. //
  307. // Call start io directly. This will by-pass the
  308. // frozen queue.
  309. //
  310. DebugPrint((DBG_READ_WRITE,
  311. "IdePortDispatch: Bypass frozen queue, IRP %lx\n",
  312. Irp));
  313. IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
  314. CheckIrql();
  315. return STATUS_PENDING;
  316. } else {
  317. BOOLEAN inserted;
  318. //
  319. // Queue the packet normally.
  320. //
  321. status = IdePortInsertByKeyDeviceQueue (
  322. logicalUnit,
  323. Irp,
  324. srb->QueueSortKey,
  325. &inserted
  326. );
  327. if (NT_SUCCESS(status) && inserted) {
  328. //
  329. // irp is queued
  330. //
  331. } else {
  332. //
  333. // irp is ready to go
  334. //
  335. //
  336. // Clear the active flag. If there is another request, the flag will be
  337. // set again when the request is passed to the miniport.
  338. //
  339. CLRMASK (logicalUnit->LuFlags, PD_LOGICAL_UNIT_IS_ACTIVE);
  340. //
  341. // Clear the retry count.
  342. //
  343. logicalUnit->RetryCount = 0;
  344. //
  345. // Queue is empty; start request.
  346. //
  347. IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
  348. }
  349. CheckIrql();
  350. return STATUS_PENDING;
  351. }
  352. case SRB_FUNCTION_RELEASE_QUEUE:
  353. DebugPrint((2,"IdePortDispatch: SCSI unfreeze queue TID %d\n",
  354. srb->TargetId));
  355. //
  356. // Acquire the spinlock to protect the flags structure and the saved
  357. // interrupt context.
  358. //
  359. KeRaiseIrql(DISPATCH_LEVEL, &currentIrql);
  360. KeAcquireSpinLockAtDpcLevel(&deviceExtension->SpinLock);
  361. //
  362. // Make sure the queue is frozen.
  363. //
  364. if (!(logicalUnit->LuFlags & PD_QUEUE_FROZEN)) {
  365. DebugPrint((DBG_WARNING,
  366. "IdePortDispatch: Request to unfreeze an unfrozen queue!\n"
  367. ));
  368. KeReleaseSpinLock(&deviceExtension->SpinLock, currentIrql);
  369. srb->SrbStatus = SRB_STATUS_SUCCESS;
  370. status = STATUS_SUCCESS;
  371. CheckIrql();
  372. break;
  373. }
  374. CLRMASK (logicalUnit->LuFlags, PD_QUEUE_FROZEN);
  375. //
  376. // If there is not an untagged request running then start the
  377. // next request for this logical unit. Otherwise free the
  378. // spin lock.
  379. //
  380. if (logicalUnit->SrbData.CurrentSrb == NULL) {
  381. //
  382. // GetNextLuRequest frees the spinlock.
  383. //
  384. GetNextLuRequest(deviceExtension, logicalUnit);
  385. KeLowerIrql(currentIrql);
  386. } else {
  387. DebugPrint((DBG_WARNING,
  388. "IdePortDispatch: Request to unfreeze queue with active request\n"
  389. ));
  390. KeReleaseSpinLock(&deviceExtension->SpinLock, currentIrql);
  391. }
  392. srb->SrbStatus = SRB_STATUS_SUCCESS;
  393. status = STATUS_SUCCESS;
  394. CheckIrql();
  395. break;
  396. case SRB_FUNCTION_RESET_BUS: {
  397. PATA_PASS_THROUGH ataPassThroughData;
  398. ataPassThroughData = ExAllocatePool(NonPagedPool, sizeof(ATA_PASS_THROUGH));
  399. if (ataPassThroughData == NULL) {
  400. srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  401. srb->InternalStatus=STATUS_INSUFFICIENT_RESOURCES;
  402. status=STATUS_INSUFFICIENT_RESOURCES;
  403. IdeLogNoMemoryError(deviceExtension,
  404. logicalUnit->TargetId,
  405. NonPagedPool,
  406. sizeof(ATA_PASS_THROUGH),
  407. IDEPORT_TAG_DISPATCH_RESET
  408. );
  409. CheckIrql();
  410. break;
  411. }
  412. RtlZeroMemory (ataPassThroughData, sizeof (*ataPassThroughData));
  413. ataPassThroughData->IdeReg.bReserved = ATA_PTFLAGS_BUS_RESET;
  414. status = IssueSyncAtaPassThroughSafe (
  415. logicalUnit->ParentDeviceExtension,
  416. logicalUnit,
  417. ataPassThroughData,
  418. FALSE,
  419. FALSE,
  420. 30,
  421. FALSE
  422. );
  423. if (NT_SUCCESS(status)) {
  424. IdeLogResetError(deviceExtension,
  425. srb,
  426. ('R'<<24) | 256);
  427. srb->SrbStatus = SRB_STATUS_SUCCESS;
  428. } else {
  429. //
  430. // fail to send ata pass through
  431. //
  432. srb->SrbStatus = SRB_STATUS_ERROR;
  433. if (status==STATUS_INSUFFICIENT_RESOURCES) {
  434. srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  435. srb->InternalStatus=STATUS_INSUFFICIENT_RESOURCES;
  436. }
  437. }
  438. CheckIrql();
  439. break;
  440. }
  441. //
  442. // Acquire the spinlock to protect the flags structure and the saved
  443. // interrupt context.
  444. //
  445. /*++
  446. KeAcquireSpinLock(&deviceExtension->SpinLock, &currentIrql);
  447. resetContext.DeviceExtension = deviceExtension;
  448. resetContext.PathId = srb->PathId;
  449. resetContext.NewResetSequence = TRUE;
  450. resetContext.ResetSrb = NULL;
  451. if (!KeSynchronizeExecution(deviceExtension->InterruptObject,
  452. IdeResetBusSynchronized,
  453. &resetContext)) {
  454. DebugPrint((1,"IdePortDispatch: Reset failed\n"));
  455. srb->SrbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
  456. status = STATUS_IO_DEVICE_ERROR;
  457. } else {
  458. IdeLogResetError(deviceExtension,
  459. srb,
  460. ('R'<<24) | 256);
  461. srb->SrbStatus = SRB_STATUS_SUCCESS;
  462. status = STATUS_SUCCESS;
  463. }
  464. KeReleaseSpinLock(&deviceExtension->SpinLock, currentIrql);
  465. CheckIrql();
  466. break;
  467. --*/
  468. case SRB_FUNCTION_ABORT_COMMAND:
  469. DebugPrint((1, "IdePortDispatch: SCSI Abort or Reset command\n"));
  470. //
  471. // Mark Irp status pending.
  472. //
  473. IoMarkIrpPending(Irp);
  474. //
  475. // Don't queue these requests in the logical unit
  476. // queue, rather queue them to the adapter queue.
  477. //
  478. KeRaiseIrql(DISPATCH_LEVEL, &currentIrql);
  479. IoStartPacket(DeviceObject, Irp, (PULONG)NULL, NULL);
  480. KeLowerIrql(currentIrql);
  481. CheckIrql();
  482. return STATUS_PENDING;
  483. break;
  484. case SRB_FUNCTION_FLUSH_QUEUE:
  485. DebugPrint((1, "IdePortDispatch: SCSI flush queue command\n"));
  486. status = IdePortFlushLogicalUnit (
  487. deviceExtension,
  488. logicalUnit,
  489. FALSE
  490. );
  491. CheckIrql();
  492. break;
  493. case SRB_FUNCTION_ATTACH_DEVICE:
  494. case SRB_FUNCTION_CLAIM_DEVICE:
  495. case SRB_FUNCTION_RELEASE_DEVICE:
  496. status = IdeClaimLogicalUnit(deviceExtension, Irp);
  497. CheckIrql();
  498. break;
  499. case SRB_FUNCTION_REMOVE_DEVICE:
  500. //
  501. // decrement the refcount before remove the device
  502. //
  503. UnrefLogicalUnitExtensionWithTag(
  504. deviceExtension,
  505. logicalUnit,
  506. Irp
  507. );
  508. status = IdeRemoveDevice(deviceExtension, Irp);
  509. Irp->IoStatus.Status = status;
  510. CheckIrql();
  511. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  512. CheckIrql();
  513. return status;
  514. default:
  515. //
  516. // Found unsupported SRB function.
  517. //
  518. DebugPrint((1,"IdePortDispatch: Unsupported function, SRB %lx\n",
  519. srb));
  520. srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
  521. status = STATUS_INVALID_DEVICE_REQUEST;
  522. CheckIrql();
  523. break;
  524. }
  525. //
  526. // Set status in Irp.
  527. //
  528. Irp->IoStatus.Status = status;
  529. //
  530. // Decrement the logUnitExtension reference count
  531. //
  532. CheckIrql();
  533. UnrefLogicalUnitExtensionWithTag(
  534. deviceExtension,
  535. logicalUnit,
  536. Irp
  537. );
  538. IDEPORT_PUT_LUNEXT_IN_IRP (irpStack, NULL);
  539. //
  540. // Complete request at raised IRQ.
  541. //
  542. CheckIrql();
  543. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  544. CheckIrql();
  545. return status;
  546. } // end IdePortDispatch()
  547. VOID
  548. IdePortStartIo (
  549. IN PDEVICE_OBJECT DeviceObject,
  550. IN PIRP Irp
  551. )
  552. /*++
  553. Routine Description:
  554. Arguments:
  555. DeviceObject - Supplies pointer to Adapter device object.
  556. Irp - Supplies a pointer to an IRP.
  557. Return Value:
  558. Nothing.
  559. --*/
  560. {
  561. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  562. PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
  563. PFDO_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  564. PSRB_DATA srbData;
  565. PLOGICAL_UNIT_EXTENSION logicalUnit;
  566. LONG interlockResult;
  567. NTSTATUS status;
  568. ULONG deviceFlags = deviceExtension->HwDeviceExtension->DeviceFlags[srb->TargetId];
  569. PCDB cdb;
  570. LARGE_INTEGER timer;
  571. LogStartTime(TimeStartIo, &timer);
  572. DebugPrint((3,"IdePortStartIo: Enter routine\n"));
  573. //
  574. // Set the default flags in the SRB.
  575. //
  576. srb->SrbFlags |= deviceExtension->SrbFlags;
  577. //
  578. // Get logical unit extension.
  579. //
  580. logicalUnit = IDEPORT_GET_LUNEXT_IN_IRP (irpStack);
  581. if (!(srb->SrbFlags & SRB_FLAGS_NO_KEEP_AWAKE) &&
  582. (srb->Function != SRB_FUNCTION_ATA_POWER_PASS_THROUGH) &&
  583. (logicalUnit->IdleCounter)) {
  584. //
  585. // Tell Po that we are busy
  586. //
  587. PoSetDeviceBusy (logicalUnit->IdleCounter);
  588. }
  589. DebugPrint((2,"IdePortStartIo: Irp 0x%8x Srb 0x%8x DataBuf 0x%8x Len 0x%8x\n", Irp, srb, srb->DataBuffer, srb->DataTransferLength));
  590. //
  591. // No special resources are required. Set the SRB data to the
  592. // structure in the logical unit extension, set the queue tag value
  593. // to the untagged value, and clear the SRB extension.
  594. //
  595. srbData = &logicalUnit->SrbData;
  596. //
  597. // Update the sequence number for this request if there is not already one
  598. // assigned.
  599. //
  600. if (!srbData->SequenceNumber) {
  601. //
  602. // Assign a sequence number to the request and store it in the logical
  603. // unit.
  604. //
  605. srbData->SequenceNumber = deviceExtension->SequenceNumber++;
  606. }
  607. //
  608. // If this is not an ABORT request the set the current srb.
  609. // NOTE: Lock should be held here!
  610. //
  611. if (srb->Function != SRB_FUNCTION_ABORT_COMMAND) {
  612. ASSERT(srbData->CurrentSrb == NULL);
  613. srbData->CurrentSrb = srb;
  614. ASSERT(srbData->CurrentSrb);
  615. if ((deviceExtension->HwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_USE_DMA) &&
  616. SRB_IS_DMA_CANDIDATE(srb)) {
  617. MARK_SRB_FOR_DMA(srb);
  618. } else {
  619. MARK_SRB_FOR_PIO(srb);
  620. }
  621. } else {
  622. //
  623. // Only abort requests can be started when there is a current request
  624. // active.
  625. //
  626. ASSERT(logicalUnit->AbortSrb == NULL);
  627. logicalUnit->AbortSrb = srb;
  628. }
  629. //
  630. // Log the command
  631. //
  632. IdeLogStartCommandLog(srbData);
  633. //
  634. // Flush the data buffer if necessary.
  635. //
  636. if (srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) {
  637. //
  638. // Save the MDL virtual address.
  639. //
  640. srbData->SrbDataOffset = MmGetMdlVirtualAddress(Irp->MdlAddress);
  641. do {
  642. //
  643. // Determine if the adapter needs mapped memory.
  644. //
  645. if (!SRB_USES_DMA(srb)) { // PIO
  646. if (Irp->MdlAddress) {
  647. //
  648. // Get the mapped system address and
  649. // calculate offset into MDL.
  650. //
  651. srbData->SrbDataOffset = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
  652. if ((srbData->SrbDataOffset == NULL) &&
  653. (deviceExtension->ReservedPages != NULL)) {
  654. KeAcquireSpinLockAtDpcLevel(&deviceExtension->SpinLock);
  655. //
  656. // this would set the appropriate flags in the device extension
  657. // and srbData only when the call succeeds.
  658. //
  659. srbData->SrbDataOffset = IdeMapLockedPagesWithReservedMapping(deviceExtension,
  660. srbData,
  661. Irp->MdlAddress
  662. );
  663. //
  664. // if there is another active request using the reserved pages
  665. // mark this one pending. When the active request completes this
  666. // one will be picked up
  667. //
  668. if (srbData->SrbDataOffset == (PVOID)-1) {
  669. DebugPrint ((1,
  670. "Irp 0x%x marked pending\n",
  671. Irp
  672. ));
  673. //
  674. // remove the current Srb
  675. //
  676. srbData->CurrentSrb = NULL;
  677. ASSERT(DeviceObject->CurrentIrp == Irp);
  678. SETMASK(deviceExtension->Flags, PD_PENDING_DEVICE_REQUEST);
  679. KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
  680. return;
  681. }
  682. KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
  683. }
  684. if (srbData->SrbDataOffset == NULL) {
  685. deviceExtension->LastMemoryFailure += IDEPORT_TAG_STARTIO_MDL;
  686. srbData->CurrentSrb = NULL;
  687. //
  688. // This is the correct status for insufficient resources
  689. //
  690. srb->SrbStatus=SRB_STATUS_INTERNAL_ERROR;
  691. srb->InternalStatus=STATUS_INSUFFICIENT_RESOURCES;
  692. Irp->IoStatus.Status=STATUS_INSUFFICIENT_RESOURCES;
  693. IdeLogNoMemoryError(deviceExtension,
  694. logicalUnit->TargetId,
  695. NonPagedPool,
  696. sizeof(MDL),
  697. IDEPORT_TAG_STARTIO_MDL
  698. );
  699. //
  700. // Clear the device busy flag
  701. //
  702. IoStartNextPacket(DeviceObject, FALSE);
  703. //
  704. // Acquire spin lock to protect the flags
  705. //
  706. KeAcquireSpinLockAtDpcLevel(&deviceExtension->SpinLock);
  707. //
  708. // Get the next request, if this request does not
  709. // bypass frozen queue. We don't want to start the
  710. // next request, if the queue is frozen.
  711. //
  712. if (!(srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)) {
  713. //
  714. // This flag needs to be set for getnextlu to work
  715. //
  716. logicalUnit->LuFlags |= PD_LOGICAL_UNIT_IS_ACTIVE;
  717. //
  718. // Retrieve the next request and give it to the fdo
  719. // This releases the spinlock
  720. //
  721. GetNextLuRequest(deviceExtension, logicalUnit);
  722. }
  723. else {
  724. KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
  725. }
  726. //
  727. // Decrement the logUnitExtension reference count
  728. //
  729. UnrefLogicalUnitExtensionWithTag(
  730. deviceExtension,
  731. logicalUnit,
  732. Irp
  733. );
  734. //
  735. // Complete the request
  736. //
  737. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  738. return;
  739. }
  740. srb->DataBuffer = srbData->SrbDataOffset +
  741. (ULONG)((PUCHAR)srb->DataBuffer -
  742. (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
  743. }
  744. IdePortAllocateAccessToken (DeviceObject);
  745. status = STATUS_SUCCESS;
  746. } else { // DMA
  747. //
  748. // If the buffer is not mapped then the I/O buffer must be flushed.
  749. //
  750. KeFlushIoBuffers(Irp->MdlAddress,
  751. (BOOLEAN) (srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE),
  752. TRUE);
  753. #if defined (FAKE_BMSETUP_FAILURE)
  754. if (!(FailBmSetupCount++ % FAKE_BMSETUP_FAILURE)) {
  755. status = STATUS_UNSUCCESSFUL;
  756. } else {
  757. #endif // FAKE_BMSETUP_FAILURE
  758. status = deviceExtension->HwDeviceExtension->BusMasterInterface.BmSetup (
  759. deviceExtension->HwDeviceExtension->BusMasterInterface.Context,
  760. srb->DataBuffer,
  761. srb->DataTransferLength,
  762. Irp->MdlAddress,
  763. (BOOLEAN) (srb->SrbFlags & SRB_FLAGS_DATA_IN),
  764. IdePortAllocateAccessToken,
  765. DeviceObject
  766. );
  767. #if defined (FAKE_BMSETUP_FAILURE)
  768. }
  769. #endif // FAKE_BMSETUP_FAILURE
  770. if (!NT_SUCCESS(status)) {
  771. DebugPrint((1,
  772. "IdePortStartIo: IoAllocateAdapterChannel failed(%x). try pio for srb %x\n",
  773. status, srb));
  774. //
  775. // out of resource for DMA, try PIO
  776. //
  777. MARK_SRB_FOR_PIO(srb);
  778. }
  779. }
  780. } while (!NT_SUCCESS(status));
  781. } else {
  782. IdePortAllocateAccessToken (DeviceObject);
  783. }
  784. LogStopTime(TimeStartIo, &timer, 0);
  785. return;
  786. } // end IdePortStartIO()
  787. BOOLEAN
  788. IdePortInterrupt(
  789. IN PKINTERRUPT Interrupt,
  790. IN PDEVICE_OBJECT DeviceObject
  791. )
  792. /*++
  793. Routine Description:
  794. Arguments:
  795. Interrupt
  796. Device Object
  797. Return Value:
  798. Returns TRUE if interrupt expected.
  799. --*/
  800. {
  801. PFDO_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  802. BOOLEAN returnValue;
  803. LARGE_INTEGER timer;
  804. UNREFERENCED_PARAMETER(Interrupt);
  805. #ifdef ENABLE_ATAPI_VERIFIER
  806. ViAtapiInterrupt(deviceExtension);
  807. #endif
  808. LogStartTime(TimeIsr, &timer);
  809. returnValue = AtapiInterrupt(deviceExtension->HwDeviceExtension);
  810. LogStopTime(TimeIsr, &timer, 100);
  811. //
  812. // Check to see if a DPC needs to be queued.
  813. //
  814. if (deviceExtension->InterruptData.InterruptFlags & PD_NOTIFICATION_REQUIRED) {
  815. IoRequestDpc(deviceExtension->DeviceObject, NULL, NULL);
  816. }
  817. return(returnValue);
  818. } // end IdePortInterrupt()
  819. VOID
  820. IdePortCompletionDpc(
  821. IN PKDPC Dpc,
  822. IN PDEVICE_OBJECT DeviceObject,
  823. IN PIRP Irp,
  824. IN PVOID Context
  825. )
  826. /*++
  827. Routine Description:
  828. Arguments:
  829. Dpc
  830. DeviceObject
  831. Irp - not used
  832. // Context - not used
  833. Return Value:
  834. None.
  835. --*/
  836. {
  837. PFDO_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  838. INTERRUPT_CONTEXT interruptContext;
  839. INTERRUPT_DATA savedInterruptData;
  840. BOOLEAN callStartIo;
  841. PLOGICAL_UNIT_EXTENSION logicalUnit;
  842. PSRB_DATA srbData;
  843. LONG interlockResult;
  844. LARGE_INTEGER timeValue;
  845. PMDL mdl;
  846. LARGE_INTEGER timer;
  847. LogStartTime(TimeDpc, &timer);
  848. UNREFERENCED_PARAMETER(Dpc);
  849. //
  850. // Acquire the spinlock to protect flush adapter buffers information.
  851. //
  852. KeAcquireSpinLockAtDpcLevel(&deviceExtension->SpinLock);
  853. //
  854. // Get the interrupt state. This copies the interrupt state to the
  855. // saved state where it can be processed. It also clears the interrupt
  856. // flags.
  857. //
  858. interruptContext.DeviceExtension = deviceExtension;
  859. interruptContext.SavedInterruptData = &savedInterruptData;
  860. if (!KeSynchronizeExecution(deviceExtension->InterruptObject,
  861. IdeGetInterruptState,
  862. &interruptContext)) {
  863. //
  864. // There is no work to do so just return.
  865. //
  866. KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
  867. LogStopTime(TimeDpc, &timer, 0);
  868. return;
  869. }
  870. //
  871. // We only support one request at a time, so we can just check
  872. // the first completed request to determine whether we use DMA
  873. // and whether we need to flush DMA
  874. //
  875. if (savedInterruptData.CompletedRequests != NULL) {
  876. PSCSI_REQUEST_BLOCK srb;
  877. srbData = savedInterruptData.CompletedRequests;
  878. ASSERT(srbData->CurrentSrb);
  879. srb = srbData->CurrentSrb;
  880. if (srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) {
  881. if (SRB_USES_DMA(srb)) {
  882. deviceExtension->HwDeviceExtension->BusMasterInterface.BmFlush (
  883. deviceExtension->HwDeviceExtension->BusMasterInterface.Context
  884. );
  885. }
  886. }
  887. }
  888. //
  889. // check for empty channels
  890. //
  891. if (savedInterruptData.InterruptFlags & PD_ALL_DEVICE_MISSING) {
  892. PPDO_EXTENSION pdoExtension;
  893. IDE_PATH_ID pathId;
  894. ULONG errorCount;
  895. BOOLEAN rescanActive = FALSE;
  896. pathId.l = 0;
  897. while (pdoExtension = NextLogUnitExtensionWithTag (
  898. deviceExtension,
  899. &pathId,
  900. TRUE,
  901. IdePortCompletionDpc
  902. )) {
  903. KeAcquireSpinLockAtDpcLevel(&pdoExtension->PdoSpinLock);
  904. SETMASK (pdoExtension->PdoState, PDOS_DEADMEAT);
  905. IdeLogDeadMeatReason( pdoExtension->DeadmeatRecord.Reason,
  906. reportedMissing
  907. );
  908. if (pdoExtension->LuFlags & PD_RESCAN_ACTIVE) {
  909. rescanActive = TRUE;
  910. }
  911. KeReleaseSpinLockFromDpcLevel(&pdoExtension->PdoSpinLock);
  912. UnrefPdoWithTag(
  913. pdoExtension,
  914. IdePortCompletionDpc
  915. );
  916. }
  917. //
  918. // Don't ask for a rescan if you are in the middle of one.
  919. //
  920. if (!rescanActive) {
  921. IoInvalidateDeviceRelations (
  922. deviceExtension->AttacheePdo,
  923. BusRelations
  924. );
  925. } else {
  926. DebugPrint((1,
  927. "The device marked deadmeat during enumeration\n"
  928. ));
  929. }
  930. }
  931. //
  932. // Check for timer requests.
  933. //
  934. if (savedInterruptData.InterruptFlags & PD_TIMER_CALL_REQUEST) {
  935. //
  936. // The miniport wants a timer request. Save the timer parameters.
  937. //
  938. deviceExtension->HwTimerRequest = savedInterruptData.HwTimerRequest;
  939. //
  940. // If the requested timer value is zero, then cancel the timer.
  941. //
  942. if (savedInterruptData.MiniportTimerValue == 0) {
  943. KeCancelTimer(&deviceExtension->MiniPortTimer);
  944. } else {
  945. //
  946. // Convert the timer value from mircoseconds to a negative 100
  947. // nanoseconds.
  948. //
  949. timeValue.QuadPart = Int32x32To64(
  950. savedInterruptData.MiniportTimerValue,
  951. -10);
  952. //
  953. // Set the timer.
  954. //
  955. KeSetTimer(&deviceExtension->MiniPortTimer,
  956. timeValue,
  957. &deviceExtension->MiniPortTimerDpc);
  958. }
  959. }
  960. if (savedInterruptData.InterruptFlags & PD_RESET_REQUEST) {
  961. RESET_CONTEXT resetContext;
  962. //
  963. // clear the reset request
  964. //
  965. CLRMASK (savedInterruptData.InterruptFlags, PD_RESET_REQUEST);
  966. //
  967. // Request timed out.
  968. //
  969. resetContext.DeviceExtension = deviceExtension;
  970. resetContext.PathId = 0;
  971. resetContext.NewResetSequence = TRUE;
  972. resetContext.ResetSrb = NULL;
  973. if (!KeSynchronizeExecution(deviceExtension->InterruptObject,
  974. IdeResetBusSynchronized,
  975. &resetContext)) {
  976. DebugPrint((DBG_WARNING,"IdePortCompletionDpc: Reset failed\n"));
  977. }
  978. }
  979. //
  980. // Verify that the ready for next request is ok.
  981. //
  982. if (savedInterruptData.InterruptFlags & PD_READY_FOR_NEXT_REQUEST) {
  983. //
  984. // If the device busy bit is not set, then this is a duplicate request.
  985. // If a no disconnect request is executing, then don't call start I/O.
  986. // This can occur when the miniport does a NextRequest followed by
  987. // a NextLuRequest.
  988. //
  989. if ((deviceExtension->Flags & (PD_DEVICE_IS_BUSY | PD_DISCONNECT_RUNNING))
  990. == (PD_DEVICE_IS_BUSY | PD_DISCONNECT_RUNNING)) {
  991. //
  992. // Clear the device busy flag. This flag is set by
  993. // IdeStartIoSynchonized.
  994. //
  995. CLRMASK (deviceExtension->Flags, PD_DEVICE_IS_BUSY);
  996. if (!(savedInterruptData.InterruptFlags & PD_RESET_HOLD)) {
  997. //
  998. // The miniport is ready for the next request and there is
  999. // not a pending reset hold, so clear the port timer.
  1000. //
  1001. deviceExtension->PortTimeoutCounter = PD_TIMER_STOPPED;
  1002. }
  1003. } else {
  1004. //
  1005. // If a no disconnect request is executing, then clear the
  1006. // busy flag. When the disconnect request completes an
  1007. // IoStartNextPacket will be done.
  1008. //
  1009. CLRMASK (deviceExtension->Flags, PD_DEVICE_IS_BUSY);
  1010. //
  1011. // Clear the ready for next request flag.
  1012. //
  1013. CLRMASK (savedInterruptData.InterruptFlags, PD_READY_FOR_NEXT_REQUEST);
  1014. }
  1015. }
  1016. KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
  1017. //
  1018. // Free Access Token
  1019. //
  1020. if ((savedInterruptData.CompletedRequests != NULL) &&
  1021. (deviceExtension->SyncAccessInterface.FreeAccessToken)) {
  1022. (*deviceExtension->SyncAccessInterface.FreeAccessToken) (
  1023. deviceExtension->SyncAccessInterface.Token
  1024. );
  1025. }
  1026. //
  1027. // Check for a ready for next packet.
  1028. //
  1029. if (savedInterruptData.InterruptFlags & PD_READY_FOR_NEXT_REQUEST) {
  1030. //
  1031. // Start the next request.
  1032. //
  1033. IoStartNextPacket(deviceExtension->DeviceObject, FALSE);
  1034. }
  1035. //
  1036. // Check for an error log requests.
  1037. //
  1038. if (savedInterruptData.InterruptFlags & PD_LOG_ERROR) {
  1039. //
  1040. // Process the request.
  1041. //
  1042. LogErrorEntry(deviceExtension,
  1043. &savedInterruptData.LogEntry);
  1044. }
  1045. //
  1046. // Process any completed requests.
  1047. //
  1048. callStartIo = FALSE;
  1049. while (savedInterruptData.CompletedRequests != NULL) {
  1050. //
  1051. // Remove the request from the linked-list.
  1052. //
  1053. srbData = savedInterruptData.CompletedRequests;
  1054. savedInterruptData.CompletedRequests = srbData->CompletedRequests;
  1055. srbData->CompletedRequests = NULL;
  1056. //
  1057. // We only supports one request at a time
  1058. //
  1059. ASSERT (savedInterruptData.CompletedRequests == NULL);
  1060. //
  1061. // Stop the command log. The request sense will be logged as the next request.
  1062. //
  1063. IdeLogStopCommandLog(srbData);
  1064. IdeProcessCompletedRequest(deviceExtension,
  1065. srbData,
  1066. &callStartIo);
  1067. }
  1068. //
  1069. // Process any completed abort requests.
  1070. //
  1071. while (savedInterruptData.CompletedAbort != NULL) {
  1072. logicalUnit = savedInterruptData.CompletedAbort;
  1073. //
  1074. // Remove request from the completed abort list.
  1075. //
  1076. savedInterruptData.CompletedAbort = logicalUnit->CompletedAbort;
  1077. //
  1078. // Acquire the spinlock to protect the flags structure,
  1079. // and the free of the srb extension.
  1080. //
  1081. KeAcquireSpinLockAtDpcLevel(&deviceExtension->SpinLock);
  1082. //
  1083. // Note the timer which was started for the abort request is not
  1084. // stopped by the get interrupt routine. Rather the timer is stopped.
  1085. // when the aborted request completes.
  1086. //
  1087. Irp = logicalUnit->AbortSrb->OriginalRequest;
  1088. //
  1089. // Set IRP status. Class drivers will reset IRP status based
  1090. // on request sense if error.
  1091. //
  1092. if (SRB_STATUS(logicalUnit->AbortSrb->SrbStatus) == SRB_STATUS_SUCCESS) {
  1093. Irp->IoStatus.Status = STATUS_SUCCESS;
  1094. } else {
  1095. Irp->IoStatus.Status = IdeTranslateSrbStatus(logicalUnit->AbortSrb);
  1096. }
  1097. Irp->IoStatus.Information = 0;
  1098. //
  1099. // Clear the abort request pointer.
  1100. //
  1101. logicalUnit->AbortSrb = NULL;
  1102. KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
  1103. UnrefLogicalUnitExtensionWithTag(
  1104. deviceExtension,
  1105. IDEPORT_GET_LUNEXT_IN_IRP(IoGetCurrentIrpStackLocation(Irp)),
  1106. Irp
  1107. );
  1108. IoCompleteRequest(Irp, IO_DISK_INCREMENT);
  1109. }
  1110. //
  1111. // Call the start I/O routine if necessary.
  1112. //
  1113. if (callStartIo) {
  1114. ASSERT(DeviceObject->CurrentIrp != NULL);
  1115. IdePortStartIo(DeviceObject, DeviceObject->CurrentIrp);
  1116. }
  1117. //
  1118. // Check for reset
  1119. //
  1120. if (savedInterruptData.InterruptFlags & PD_RESET_REPORTED) {
  1121. //
  1122. // we had a bus reset. everyone on the bus should be in PowerDeviceD0
  1123. //
  1124. IDE_PATH_ID pathId;
  1125. PPDO_EXTENSION pdoExtension;
  1126. POWER_STATE powerState;
  1127. pathId.l = 0;
  1128. powerState.DeviceState = PowerDeviceD0;
  1129. while (pdoExtension = NextLogUnitExtensionWithTag (
  1130. deviceExtension,
  1131. &pathId,
  1132. FALSE,
  1133. IdePortCompletionDpc
  1134. )) {
  1135. //
  1136. // If rescan is active, the pdo might go away
  1137. //
  1138. if (pdoExtension != savedInterruptData.PdoExtensionResetBus &&
  1139. !(pdoExtension->LuFlags & PD_RESCAN_ACTIVE)) {
  1140. PoRequestPowerIrp (
  1141. pdoExtension->DeviceObject,
  1142. IRP_MN_SET_POWER,
  1143. powerState,
  1144. NULL,
  1145. NULL,
  1146. NULL
  1147. );
  1148. }
  1149. UnrefLogicalUnitExtensionWithTag (
  1150. deviceExtension,
  1151. pdoExtension,
  1152. IdePortCompletionDpc
  1153. );
  1154. }
  1155. }
  1156. LogStopTime(TimeDpc, &timer, 0);
  1157. return;
  1158. } // end IdePortCompletionDpc()
  1159. #ifdef IDEDEBUG_TEST_START_STOP_DEVICE
  1160. typedef enum {
  1161. IdeDebugStartStop_Idle=0,
  1162. IdeDebugStartStop_StopPending,
  1163. IdeDebugStartStop_Stopped,
  1164. IdeDebugStartStop_StartPending,
  1165. IdeDebugStartStop_Started,
  1166. IdeDebugStartStop_LastState
  1167. } IDEDEBUG_STARTSTOP_STATE;
  1168. PDEVICE_OBJECT IdeDebugStartStopDeviceObject=NULL;
  1169. IDEDEBUG_STARTSTOP_STATE IdeDebugStartStopState = IdeDebugStartStop_Idle;
  1170. IDEDEBUG_STARTSTOP_STATE IdeDebugStartStopTimer = 0;
  1171. PDEVICE_OBJECT
  1172. IoGetAttachedDevice(
  1173. IN PDEVICE_OBJECT DeviceObject
  1174. );
  1175. NTSTATUS
  1176. IdeDebugSynchronousCallCompletionRoutine(
  1177. IN PDEVICE_OBJECT DeviceObject,
  1178. IN OUT PIRP Irp,
  1179. IN OUT PVOID Context
  1180. )
  1181. {
  1182. PKEVENT event = Context;
  1183. *(Irp->UserIosb) = Irp->IoStatus;
  1184. KeSetEvent( event, IO_NO_INCREMENT, FALSE );
  1185. IoFreeIrp (Irp);
  1186. return STATUS_MORE_PROCESSING_REQUIRED;
  1187. }
  1188. NTSTATUS
  1189. IdeDebugSynchronousCall(
  1190. IN PDEVICE_OBJECT DeviceObject,
  1191. IN PIO_STACK_LOCATION TopStackLocation
  1192. )
  1193. /*++
  1194. Routine Description:
  1195. This function sends a synchronous irp to the top level device
  1196. object which roots on DeviceObject.
  1197. Parameters:
  1198. DeviceObject - Supplies the device object of the device being removed.
  1199. TopStackLocation - Supplies a pointer to the parameter block for the irp.
  1200. Return Value:
  1201. NTSTATUS code.
  1202. --*/
  1203. {
  1204. PIRP irp;
  1205. PIO_STACK_LOCATION irpSp;
  1206. IO_STATUS_BLOCK statusBlock;
  1207. KEVENT event;
  1208. NTSTATUS status;
  1209. PDEVICE_OBJECT deviceObject;
  1210. PAGED_CODE();
  1211. //
  1212. // Get a pointer to the topmost device object in the stack of devices,
  1213. // beginning with the deviceObject.
  1214. //
  1215. deviceObject = IoGetAttachedDevice(DeviceObject);
  1216. //
  1217. // Begin by allocating the IRP for this request. Do not charge quota to
  1218. // the current process for this IRP.
  1219. //
  1220. irp = IoAllocateIrp(deviceObject->StackSize, FALSE);
  1221. if (irp == NULL){
  1222. return STATUS_INSUFFICIENT_RESOURCES;
  1223. }
  1224. //
  1225. // Initialize it to failure.
  1226. //
  1227. irp->IoStatus.Status = statusBlock.Status = STATUS_NOT_SUPPORTED;
  1228. irp->IoStatus.Information = statusBlock.Information = 0;
  1229. irp->UserIosb = &statusBlock;
  1230. //
  1231. // Set the pointer to the status block and initialized event.
  1232. //
  1233. KeInitializeEvent( &event,
  1234. SynchronizationEvent,
  1235. FALSE );
  1236. //
  1237. // Set the address of the current thread
  1238. //
  1239. irp->Tail.Overlay.Thread = PsGetCurrentThread();
  1240. //
  1241. // Get a pointer to the stack location of the first driver which will be
  1242. // invoked. This is where the function codes and parameters are set.
  1243. //
  1244. irpSp = IoGetNextIrpStackLocation(irp);
  1245. //
  1246. // Copy in the caller-supplied stack location contents
  1247. //
  1248. *irpSp = *TopStackLocation;
  1249. IoSetCompletionRoutine(
  1250. irp,
  1251. IdeDebugSynchronousCallCompletionRoutine,
  1252. &event,
  1253. TRUE,
  1254. TRUE,
  1255. TRUE
  1256. );
  1257. //
  1258. // Call the driver
  1259. //
  1260. status = IoCallDriver(DeviceObject, irp);
  1261. //
  1262. // If a driver returns STATUS_PENDING, we will wait for it to complete
  1263. //
  1264. if (status == STATUS_PENDING) {
  1265. (VOID) KeWaitForSingleObject( &event,
  1266. Executive,
  1267. KernelMode,
  1268. FALSE,
  1269. (PLARGE_INTEGER) NULL );
  1270. status = statusBlock.Status;
  1271. }
  1272. return status;
  1273. }
  1274. NTSTATUS
  1275. IdeDebugStartStopWorkRoutine (
  1276. IN PDEVICE_OBJECT DeviceObject,
  1277. IN PIO_WORKITEM WorkItem
  1278. )
  1279. {
  1280. NTSTATUS status;
  1281. IO_STACK_LOCATION irpSp;
  1282. PVOID dummy;
  1283. RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
  1284. irpSp.MajorFunction = IRP_MJ_PNP;
  1285. //
  1286. // release resource for this worker item
  1287. //
  1288. IoFreeWorkItem(WorkItem);
  1289. if (IdeDebugStartStopDeviceObject) {
  1290. if (IdeDebugStartStopState == IdeDebugStartStop_StopPending) {
  1291. irpSp.MinorFunction = IRP_MN_STOP_DEVICE;
  1292. status = IdeDebugSynchronousCall(DeviceObject, &irpSp);
  1293. if (!NT_SUCCESS(status)) {
  1294. DbgBreakPoint();
  1295. }
  1296. IdeDebugStartStopTimer = 0;
  1297. IdeDebugStartStopState = IdeDebugStartStop_Stopped;
  1298. } else if (IdeDebugStartStopState == IdeDebugStartStop_StartPending) {
  1299. // this will only work with legacy ide channels enmerated by pciidex.sys
  1300. irpSp.MinorFunction = IRP_MN_START_DEVICE;
  1301. status =IdeDebugSynchronousCall(DeviceObject, &irpSp);
  1302. if (!NT_SUCCESS(status)) {
  1303. DbgBreakPoint();
  1304. }
  1305. IdeDebugStartStopTimer = 0;
  1306. IdeDebugStartStopState = IdeDebugStartStop_Started;
  1307. } else {
  1308. DbgBreakPoint();
  1309. }
  1310. }
  1311. return STATUS_SUCCESS;
  1312. }
  1313. #endif //IDEDEBUG_TEST_START_STOP_DEVICE
  1314. #ifdef DPC_FOR_EMPTY_CHANNEL
  1315. BOOLEAN
  1316. IdeCheckEmptyChannel(
  1317. IN PVOID ServiceContext
  1318. )
  1319. {
  1320. ULONG status;
  1321. PSCSI_REQUEST_BLOCK Srb;
  1322. PDEVICE_OBJECT deviceObject = ServiceContext;
  1323. PFDO_EXTENSION deviceExtension = deviceObject->DeviceExtension;
  1324. PHW_DEVICE_EXTENSION hwDeviceExtension = deviceExtension->HwDeviceExtension;
  1325. if ((status=IdePortChannelEmptyQuick(&hwDeviceExtension->BaseIoAddress1, &hwDeviceExtension->BaseIoAddress2,
  1326. hwDeviceExtension->MaxIdeDevice, &hwDeviceExtension->CurrentIdeDevice,
  1327. &hwDeviceExtension->MoreWait, &hwDeviceExtension->NoRetry))!= STATUS_RETRY) {
  1328. //
  1329. // Clear current SRB.
  1330. //
  1331. Srb=hwDeviceExtension->CurrentSrb;
  1332. hwDeviceExtension->CurrentSrb = NULL;
  1333. //
  1334. // Set status in SRB.
  1335. //
  1336. if (status == 1) {
  1337. Srb->SrbStatus = (UCHAR) SRB_STATUS_SUCCESS;
  1338. } else {
  1339. Srb->SrbStatus = (UCHAR) SRB_STATUS_ERROR;
  1340. }
  1341. //
  1342. // Clear all the variables
  1343. //
  1344. hwDeviceExtension->MoreWait=0;
  1345. hwDeviceExtension->CurrentIdeDevice=0;
  1346. hwDeviceExtension->NoRetry=0;
  1347. //
  1348. // Indicate command complete.
  1349. //
  1350. IdePortNotification(IdeRequestComplete,
  1351. hwDeviceExtension,
  1352. Srb);
  1353. //
  1354. // Indicate ready for next request.
  1355. //
  1356. IdePortNotification(IdeNextRequest,
  1357. hwDeviceExtension,
  1358. NULL);
  1359. IoRequestDpc(deviceObject, NULL, NULL);
  1360. return TRUE;
  1361. }
  1362. return FALSE;
  1363. }
  1364. #endif
  1365. VOID
  1366. IdePortTickHandler(
  1367. IN PDEVICE_OBJECT DeviceObject,
  1368. IN PVOID Context
  1369. )
  1370. /*++
  1371. Routine Description:
  1372. Arguments:
  1373. Return Value:
  1374. None.
  1375. --*/
  1376. {
  1377. PFDO_EXTENSION deviceExtension =
  1378. (PFDO_EXTENSION) DeviceObject->DeviceExtension;
  1379. PLOGICAL_UNIT_EXTENSION logicalUnit;
  1380. PIRP irp;
  1381. ULONG target;
  1382. IDE_PATH_ID pathId;
  1383. UNREFERENCED_PARAMETER(Context);
  1384. #if DBG
  1385. if (IdeDebugRescanBusFreq) {
  1386. IdeDebugRescanBusCounter++;
  1387. if (IdeDebugRescanBusCounter == IdeDebugRescanBusFreq) {
  1388. IoInvalidateDeviceRelations (
  1389. deviceExtension->AttacheePdo,
  1390. BusRelations
  1391. );
  1392. IdeDebugRescanBusCounter = 0;
  1393. }
  1394. }
  1395. #endif //DBG
  1396. #ifdef IDEDEBUG_TEST_START_STOP_DEVICE
  1397. if (deviceExtension->LogicalUnitList[0] &&
  1398. (IdeDebugStartStopDeviceObject == deviceExtension->LogicalUnitList[0]->DeviceObject)) {
  1399. PIO_WORKITEM workItem;
  1400. if (IdeDebugStartStopState == IdeDebugStartStop_Idle) {
  1401. IdeDebugStartStopState = IdeDebugStartStop_StopPending;
  1402. workItem = IoAllocateWorkItem(IdeDebugStartStopDeviceObject);
  1403. IoQueueWorkItem(
  1404. workItem,
  1405. IdeDebugStartStopWorkRoutine,
  1406. DelayedWorkQueue,
  1407. workItem
  1408. );
  1409. } else if (IdeDebugStartStopState == IdeDebugStartStop_Stopped) {
  1410. if (IdeDebugStartStopTimer > 5) {
  1411. IdeDebugStartStopState = IdeDebugStartStop_StartPending;
  1412. workItem = IoAllocateWorkItem(IdeDebugStartStopDeviceObject);
  1413. IoQueueWorkItem(
  1414. workItem,
  1415. IdeDebugStartStopWorkRoutine,
  1416. HyperCriticalWorkQueue,
  1417. workItem
  1418. );
  1419. } else {
  1420. IdeDebugStartStopTimer++;
  1421. }
  1422. } else if (IdeDebugStartStopState == IdeDebugStartStop_Started) {
  1423. if (IdeDebugStartStopTimer > 10) {
  1424. IdeDebugStartStopState = IdeDebugStartStop_Idle;
  1425. } else {
  1426. IdeDebugStartStopTimer++;
  1427. }
  1428. }
  1429. }
  1430. #endif // IDEDEBUG_TEST_START_STOP_DEVICE
  1431. //
  1432. // Acquire the spinlock to protect the flags structure.
  1433. //
  1434. KeAcquireSpinLockAtDpcLevel(&deviceExtension->SpinLock);
  1435. #ifdef DPC_FOR_EMPTY_CHANNEL
  1436. //
  1437. //Holding the lock is OK.
  1438. //The empty channel check is quick
  1439. //
  1440. if (deviceExtension->HwDeviceExtension->MoreWait) {
  1441. if (!KeSynchronizeExecution (
  1442. deviceExtension->InterruptObject,
  1443. IdeCheckEmptyChannel,
  1444. DeviceObject
  1445. )) {
  1446. DebugPrint((0,"ATAPI: ChannelEmpty check- device busy after 1sec\n"));
  1447. }
  1448. KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
  1449. return;
  1450. }
  1451. #endif
  1452. //
  1453. // Check for port timeouts.
  1454. //
  1455. if (deviceExtension->ResetCallAgain) {
  1456. RESET_CONTEXT resetContext;
  1457. //
  1458. // Request timed out.
  1459. //
  1460. resetContext.DeviceExtension = deviceExtension;
  1461. resetContext.PathId = 0;
  1462. resetContext.NewResetSequence = FALSE;
  1463. resetContext.ResetSrb = NULL;
  1464. if (!KeSynchronizeExecution(deviceExtension->InterruptObject,
  1465. IdeResetBusSynchronized,
  1466. &resetContext)) {
  1467. DebugPrint((0,"IdePortTickHanlder: Reset failed\n"));
  1468. }
  1469. KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
  1470. return;
  1471. }
  1472. if (deviceExtension->PortTimeoutCounter > 0) {
  1473. if (--deviceExtension->PortTimeoutCounter == 0) {
  1474. //
  1475. // Process the port timeout.
  1476. //
  1477. if (deviceExtension->InterruptObject) {
  1478. if (KeSynchronizeExecution(deviceExtension->InterruptObject,
  1479. IdeTimeoutSynchronized,
  1480. deviceExtension->DeviceObject)){
  1481. //
  1482. // Log error if IdeTimeoutSynchonized indicates this was an error
  1483. // timeout.
  1484. //
  1485. if (deviceExtension->DeviceObject->CurrentIrp) {
  1486. IdeLogTimeoutError(deviceExtension,
  1487. deviceExtension->DeviceObject->CurrentIrp,
  1488. 256);
  1489. }
  1490. }
  1491. } else {
  1492. PIRP irp = deviceExtension->DeviceObject->CurrentIrp;
  1493. DebugPrint((0,
  1494. "The device was suprise removed with an active request\n"
  1495. ));
  1496. //
  1497. // the device was probably surprise removed. Complete
  1498. // the request with status_no_such_device
  1499. //
  1500. if (irp) {
  1501. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(irp);
  1502. PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
  1503. srb->SrbStatus = SRB_STATUS_NO_DEVICE;
  1504. irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  1505. UnrefLogicalUnitExtensionWithTag (
  1506. deviceExtension,
  1507. IDEPORT_GET_LUNEXT_IN_IRP(irpStack),
  1508. irp
  1509. );
  1510. IoCompleteRequest(irp, IO_NO_INCREMENT);
  1511. }
  1512. }
  1513. }
  1514. //
  1515. // check for busy Luns and restart its request
  1516. //
  1517. pathId.l = 0;
  1518. while (logicalUnit = NextLogUnitExtensionWithTag(
  1519. deviceExtension,
  1520. &pathId,
  1521. TRUE,
  1522. IdePortTickHandler
  1523. )) {
  1524. AtapiRestartBusyRequest(deviceExtension, logicalUnit);
  1525. UnrefLogicalUnitExtensionWithTag (
  1526. deviceExtension,
  1527. logicalUnit,
  1528. IdePortTickHandler
  1529. );
  1530. }
  1531. KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
  1532. //
  1533. // Since a port timeout has been done. Skip the rest of the
  1534. // processing.
  1535. //
  1536. return;
  1537. }
  1538. //
  1539. // Scan each of the logical units. If it has an active request then
  1540. // decrement the timeout value and process a timeout if it is zero.
  1541. //
  1542. pathId.l = 0;
  1543. while (logicalUnit = NextLogUnitExtensionWithTag(
  1544. deviceExtension,
  1545. &pathId,
  1546. TRUE,
  1547. IdePortTickHandler
  1548. )) {
  1549. //
  1550. // Check for busy requests.
  1551. //
  1552. if (AtapiRestartBusyRequest (deviceExtension, logicalUnit)) {
  1553. //
  1554. // this lun was marked busy
  1555. // skip all other checks
  1556. //
  1557. } else if (logicalUnit->RequestTimeoutCounter == 0) {
  1558. RESET_CONTEXT resetContext;
  1559. //
  1560. // Request timed out.
  1561. //
  1562. logicalUnit->RequestTimeoutCounter = PD_TIMER_STOPPED;
  1563. DebugPrint((1,"IdePortTickHandler: Request timed out\n"));
  1564. resetContext.DeviceExtension = deviceExtension;
  1565. resetContext.PathId = logicalUnit->PathId;
  1566. resetContext.NewResetSequence = TRUE;
  1567. resetContext.ResetSrb = NULL;
  1568. if (deviceExtension->InterruptObject) {
  1569. if (!KeSynchronizeExecution(deviceExtension->InterruptObject,
  1570. IdeResetBusSynchronized,
  1571. &resetContext)) {
  1572. DebugPrint((1,"IdePortTickHanlder: Reset failed\n"));
  1573. } else {
  1574. //
  1575. // Log the reset.
  1576. //
  1577. IdeLogResetError( deviceExtension,
  1578. logicalUnit->SrbData.CurrentSrb,
  1579. ('P'<<24) | 257);
  1580. }
  1581. }
  1582. } else if (logicalUnit->RequestTimeoutCounter > 0) {
  1583. //
  1584. // Decrement timeout count.
  1585. //
  1586. logicalUnit->RequestTimeoutCounter--;
  1587. }
  1588. UnrefLogicalUnitExtensionWithTag (
  1589. deviceExtension,
  1590. logicalUnit,
  1591. IdePortTickHandler
  1592. );
  1593. }
  1594. KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
  1595. return;
  1596. } // end IdePortTickHandler()
  1597. BOOLEAN
  1598. AtapiRestartBusyRequest (
  1599. PFDO_EXTENSION DeviceExtension,
  1600. PPDO_EXTENSION LogicalUnit
  1601. )
  1602. {
  1603. PIRP irp;
  1604. PIO_STACK_LOCATION irpStack;
  1605. PSCSI_REQUEST_BLOCK srb;
  1606. //
  1607. // Check for busy requests.
  1608. //
  1609. if (LogicalUnit->LuFlags & PD_LOGICAL_UNIT_IS_BUSY) {
  1610. //
  1611. // If a request sense is needed or the queue is
  1612. // frozen, defer processing this busy request until
  1613. // that special processing has completed. This prevents
  1614. // a random busy request from being started when a REQUEST
  1615. // SENSE needs to be sent.
  1616. //
  1617. if (!(LogicalUnit->LuFlags &
  1618. (PD_NEED_REQUEST_SENSE | PD_QUEUE_FROZEN))) {
  1619. DebugPrint((1,"IdePortTickHandler: Retrying busy status request\n"));
  1620. //
  1621. // Clear the busy flag and retry the request. Release the
  1622. // spinlock while the call to IoStartPacket is made.
  1623. //
  1624. CLRMASK (LogicalUnit->LuFlags, PD_LOGICAL_UNIT_IS_BUSY | PD_QUEUE_IS_FULL);
  1625. irp = LogicalUnit->BusyRequest;
  1626. //
  1627. // Clear the busy request.
  1628. //
  1629. LogicalUnit->BusyRequest = NULL;
  1630. //
  1631. // check if the device is gone
  1632. //
  1633. if (LogicalUnit->PdoState & (PDOS_SURPRISE_REMOVED | PDOS_REMOVED)) {
  1634. irpStack = IoGetCurrentIrpStackLocation(irp);
  1635. srb = irpStack->Parameters.Scsi.Srb;
  1636. srb->SrbStatus = SRB_STATUS_NO_DEVICE;
  1637. irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  1638. //
  1639. // Decrement the logUnitExtension reference count
  1640. //
  1641. UnrefLogicalUnitExtensionWithTag(
  1642. DeviceExtension,
  1643. LogicalUnit,
  1644. irp
  1645. );
  1646. IoCompleteRequest(irp, IO_NO_INCREMENT);
  1647. return TRUE;
  1648. }
  1649. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  1650. IoStartPacket(DeviceExtension->DeviceObject, irp, (PULONG)NULL, NULL);
  1651. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  1652. }
  1653. return TRUE;
  1654. } else {
  1655. return FALSE;
  1656. }
  1657. }
  1658. NTSTATUS
  1659. IdePortDeviceControl(
  1660. IN PDEVICE_OBJECT DeviceObject,
  1661. IN PIRP Irp
  1662. )
  1663. /*++
  1664. Routine Description:
  1665. This routine is the device control dispatcher.
  1666. Arguments:
  1667. DeviceObject
  1668. Irp
  1669. Return Value:
  1670. NTSTATUS
  1671. --*/
  1672. {
  1673. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1674. PFDO_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
  1675. UCHAR scsiBus;
  1676. NTSTATUS status;
  1677. ULONG j;
  1678. //
  1679. // Initialize the information field.
  1680. //
  1681. Irp->IoStatus.Information = 0;
  1682. switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
  1683. //
  1684. // Get adapter capabilities.
  1685. //
  1686. case IOCTL_SCSI_GET_CAPABILITIES:
  1687. //
  1688. // If the output buffer is equal to the size of the a PVOID then just
  1689. // return a pointer to the buffer.
  1690. //
  1691. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength
  1692. == sizeof(PVOID)) {
  1693. *((PVOID *)Irp->AssociatedIrp.SystemBuffer)
  1694. = &deviceExtension->Capabilities;
  1695. Irp->IoStatus.Information = sizeof(PVOID);
  1696. status = STATUS_SUCCESS;
  1697. break;
  1698. }
  1699. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength
  1700. < sizeof(IO_SCSI_CAPABILITIES)) {
  1701. status = STATUS_BUFFER_TOO_SMALL;
  1702. break;
  1703. }
  1704. //
  1705. // this is dynamic
  1706. //
  1707. deviceExtension->Capabilities.AdapterUsesPio = FALSE;
  1708. for (j=0; j<deviceExtension->HwDeviceExtension->MaxIdeDevice; j++) {
  1709. deviceExtension->Capabilities.AdapterUsesPio |=
  1710. !(deviceExtension->HwDeviceExtension->DeviceFlags[j] & DFLAGS_USE_DMA);
  1711. }
  1712. RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer,
  1713. &deviceExtension->Capabilities,
  1714. sizeof(IO_SCSI_CAPABILITIES));
  1715. Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
  1716. status = STATUS_SUCCESS;
  1717. break;
  1718. case IOCTL_SCSI_PASS_THROUGH:
  1719. case IOCTL_SCSI_PASS_THROUGH_DIRECT:
  1720. status = IdeSendPassThrough(deviceExtension, Irp);
  1721. break;
  1722. #ifdef GET_DISK_GEOMETRY_DEFINED
  1723. case IOCTL_DISK_GET_DRIVE_GEOMETRY:
  1724. DebugPrint((DBG_ALWAYS, "ERROR: Fdo received IOCTL=%x\n",
  1725. irpStack->Parameters.DeviceIoControl.IoControlCode));
  1726. //
  1727. // Don't know what to do.
  1728. //pass it to the lower device object
  1729. //
  1730. IoCopyCurrentIrpStackLocationToNext(Irp);
  1731. return IoCallDriver (deviceExtension->AttacheeDeviceObject, Irp);
  1732. break;
  1733. #endif
  1734. case IOCTL_SCSI_MINIPORT:
  1735. status = IdeSendMiniPortIoctl( deviceExtension, Irp);
  1736. break;
  1737. case IOCTL_SCSI_GET_INQUIRY_DATA:
  1738. //
  1739. // Return the inquiry data.
  1740. //
  1741. status = IdeGetInquiryData(deviceExtension, Irp);
  1742. break;
  1743. case IOCTL_SCSI_RESCAN_BUS:
  1744. //
  1745. // should return only after we get the device relation irp
  1746. // this will be fixed if needed.
  1747. //
  1748. IoInvalidateDeviceRelations (
  1749. deviceExtension->AttacheePdo,
  1750. BusRelations
  1751. );
  1752. status = STATUS_SUCCESS;
  1753. break;
  1754. default:
  1755. return ChannelDeviceIoControl (DeviceObject, Irp);
  1756. break;
  1757. } // end switch
  1758. //
  1759. // Set status in Irp.
  1760. //
  1761. Irp->IoStatus.Status = status;
  1762. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1763. return status;
  1764. } // end IdePortDeviceControl()
  1765. BOOLEAN
  1766. IdeStartIoSynchronized (
  1767. PVOID ServiceContext
  1768. )
  1769. /*++
  1770. Routine Description:
  1771. This routine calls the dependent driver start io routine.
  1772. It also starts the request timer for the logical unit if necesary and
  1773. inserts the SRB data structure in to the requset list.
  1774. Arguments:
  1775. ServiceContext - Supplies the pointer to the device object.
  1776. Return Value:
  1777. Returns the value returned by the dependent start I/O routine.
  1778. Notes:
  1779. The port driver spinlock must be held when this routine is called.
  1780. --*/
  1781. {
  1782. PDEVICE_OBJECT deviceObject = ServiceContext;
  1783. PFDO_EXTENSION deviceExtension = deviceObject->DeviceExtension;
  1784. PIO_STACK_LOCATION irpStack;
  1785. PLOGICAL_UNIT_EXTENSION logicalUnit;
  1786. PSCSI_REQUEST_BLOCK srb;
  1787. PSRB_DATA srbData;
  1788. BOOLEAN timerStarted;
  1789. BOOLEAN returnValue;
  1790. BOOLEAN resetRequest;
  1791. DebugPrint((3, "IdePortStartIoSynchronized: Enter routine\n"));
  1792. irpStack = IoGetCurrentIrpStackLocation(deviceObject->CurrentIrp);
  1793. srb = irpStack->Parameters.Scsi.Srb;
  1794. //
  1795. // Get the logical unit extension.
  1796. //
  1797. logicalUnit = IDEPORT_GET_LUNEXT_IN_IRP (irpStack);
  1798. //
  1799. // Check for a reset hold. If one is in progress then flag it and return.
  1800. // The timer will reset the current request. This check should be made
  1801. // before anything else is done.
  1802. //
  1803. if (deviceExtension->InterruptData.InterruptFlags & PD_RESET_HOLD) {
  1804. DebugPrint ((1, "IdeStartIoSynchronized: PD_RESET_HOLD set...request is held for later..\n"));
  1805. deviceExtension->InterruptData.InterruptFlags |= PD_HELD_REQUEST;
  1806. return(TRUE);
  1807. }
  1808. if ((((srb->Function == SRB_FUNCTION_ATA_PASS_THROUGH) ||
  1809. (srb->Function == SRB_FUNCTION_ATA_POWER_PASS_THROUGH)) &&
  1810. (((PATA_PASS_THROUGH) (srb->DataBuffer))->IdeReg.bReserved & ATA_PTFLAGS_BUS_RESET))) {
  1811. resetRequest = TRUE;
  1812. } else {
  1813. resetRequest = FALSE;
  1814. }
  1815. //
  1816. // Start the port timer. This ensures that the miniport asks for
  1817. // the next request in a resonable amount of time. Set the device
  1818. // busy flag to indicate it is ok to start the next request.
  1819. //
  1820. deviceExtension->PortTimeoutCounter = srb->TimeOutValue;
  1821. deviceExtension->Flags |= PD_DEVICE_IS_BUSY;
  1822. //
  1823. // Start the logical unit timer if it is not currently running.
  1824. //
  1825. if (logicalUnit->RequestTimeoutCounter == PD_TIMER_STOPPED) {
  1826. //
  1827. // Set request timeout value from Srb SCSI extension in Irp.
  1828. //
  1829. logicalUnit->RequestTimeoutCounter = srb->TimeOutValue;
  1830. timerStarted = TRUE;
  1831. } else {
  1832. timerStarted = FALSE;
  1833. }
  1834. //
  1835. // Indicate that there maybe more requests queued, if this is not a bypass
  1836. // request.
  1837. //
  1838. if (!(srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)) {
  1839. if (srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) {
  1840. //
  1841. // This request does not allow disconnects. Remember that so
  1842. // no more requests are started until this one completes.
  1843. //
  1844. CLRMASK (deviceExtension->Flags, PD_DISCONNECT_RUNNING);
  1845. }
  1846. logicalUnit->LuFlags |= PD_LOGICAL_UNIT_IS_ACTIVE;
  1847. } else {
  1848. //
  1849. // If this is an abort request make sure that it still looks valid.
  1850. //
  1851. if (srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
  1852. srbData = IdeGetSrbData(deviceExtension, srb);
  1853. //
  1854. // Make sure the srb request is still active.
  1855. //
  1856. if (srbData == NULL || srbData->CurrentSrb == NULL
  1857. || !(srbData->CurrentSrb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) {
  1858. //
  1859. // Mark the Srb as active.
  1860. //
  1861. srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
  1862. if (timerStarted) {
  1863. logicalUnit->RequestTimeoutCounter = PD_TIMER_STOPPED;
  1864. }
  1865. //
  1866. // The request is gone.
  1867. //
  1868. DebugPrint((1, "IdePortStartIO: Request completed be for it was aborted.\n"));
  1869. srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
  1870. IdePortNotification(IdeRequestComplete,
  1871. deviceExtension + 1,
  1872. srb);
  1873. IdePortNotification(IdeNextRequest,
  1874. deviceExtension + 1);
  1875. //
  1876. // Queue a DPC to process the work that was just indicated.
  1877. //
  1878. IoRequestDpc(deviceExtension->DeviceObject, NULL, NULL);
  1879. return(TRUE);
  1880. }
  1881. }
  1882. //
  1883. // Any untagged request that bypasses the queue
  1884. // clears the need request sense flag.
  1885. //
  1886. CLRMASK (logicalUnit->LuFlags, PD_NEED_REQUEST_SENSE);
  1887. if (srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) {
  1888. //
  1889. // This request does not allow disconnects. Remember that so
  1890. // no more requests are started until this one completes.
  1891. //
  1892. CLRMASK (deviceExtension->Flags, PD_DISCONNECT_RUNNING);
  1893. }
  1894. //
  1895. // Set the timeout value in the logical unit.
  1896. //
  1897. logicalUnit->RequestTimeoutCounter = srb->TimeOutValue;
  1898. }
  1899. //
  1900. // Mark the Srb as active.
  1901. //
  1902. srb->SrbFlags |= SRB_FLAGS_IS_ACTIVE;
  1903. #if 0
  1904. //joedai
  1905. {
  1906. ULONG c;
  1907. PUCHAR s;
  1908. PUCHAR d;
  1909. s = (PUCHAR) deviceObject->CurrentIrp;
  1910. d = (PUCHAR) &deviceExtension->debugData[deviceExtension->nextEntry].irp;
  1911. deviceExtension->debugDataPtr[deviceExtension->nextEntry].irp = (PIRP) d;
  1912. for (c=0; c<sizeof(IRP); c++) {
  1913. d[c] = s[c];
  1914. }
  1915. if (deviceObject->CurrentIrp->MdlAddress) {
  1916. s = (PUCHAR) deviceObject->CurrentIrp->MdlAddress;
  1917. d = (PUCHAR) &deviceExtension->debugData[deviceExtension->nextEntry].mdl;
  1918. deviceExtension->debugDataPtr[deviceExtension->nextEntry].mdl = (PMDL) d;
  1919. for (c=0; c<sizeof(MDL); c++) {
  1920. d[c] = s[c];
  1921. }
  1922. } else {
  1923. d = (PUCHAR) &deviceExtension->debugData[deviceExtension->nextEntry].mdl;
  1924. deviceExtension->debugDataPtr[deviceExtension->nextEntry].mdl = (PMDL) d;
  1925. for (c=0; c<sizeof(MDL); c++) {
  1926. d[c] = 0;
  1927. }
  1928. }
  1929. s = (PUCHAR) srb;
  1930. d = (PUCHAR) &deviceExtension->debugData[deviceExtension->nextEntry].srb;
  1931. deviceExtension->debugDataPtr[deviceExtension->nextEntry].srb = (PSCSI_REQUEST_BLOCK) d;
  1932. for (c=0; c<sizeof(SCSI_REQUEST_BLOCK); c++) {
  1933. d[c] = s[c];
  1934. }
  1935. ASSERT((((ULONG)srb->DataBuffer) & 0x80000000));
  1936. deviceExtension->nextEntry = (deviceExtension->nextEntry + 1) % NUM_DEBUG_ENTRY;
  1937. }
  1938. #endif
  1939. //
  1940. // maybe the device is gone
  1941. //
  1942. if (logicalUnit->PdoState & PDOS_DEADMEAT) {
  1943. srb->SrbStatus = SRB_STATUS_NO_DEVICE;
  1944. IdePortNotification(IdeRequestComplete,
  1945. deviceExtension + 1,
  1946. srb);
  1947. IdePortNotification(IdeNextRequest,
  1948. deviceExtension + 1);
  1949. IoRequestDpc(deviceExtension->DeviceObject, NULL, NULL);
  1950. return TRUE;
  1951. }
  1952. if (resetRequest) {
  1953. RESET_CONTEXT resetContext;
  1954. resetContext.DeviceExtension = deviceExtension;
  1955. resetContext.PathId = 0;
  1956. resetContext.NewResetSequence = TRUE;
  1957. resetContext.ResetSrb = srb;
  1958. srb->SrbStatus = SRB_STATUS_PENDING;
  1959. returnValue = IdeResetBusSynchronized (&resetContext);
  1960. } else {
  1961. returnValue = AtapiStartIo (deviceExtension->HwDeviceExtension,
  1962. srb);
  1963. }
  1964. //
  1965. // Check for miniport work requests.
  1966. //
  1967. if (deviceExtension->InterruptData.InterruptFlags & PD_NOTIFICATION_REQUIRED) {
  1968. IoRequestDpc(deviceExtension->DeviceObject, NULL, NULL);
  1969. }
  1970. return returnValue;
  1971. } // end IdeStartIoSynchronized()
  1972. BOOLEAN
  1973. IdeTimeoutSynchronized (
  1974. PVOID ServiceContext
  1975. )
  1976. /*++
  1977. Routine Description:
  1978. This routine handles a port timeout. There are two reason these can occur
  1979. either because of a reset hold or a time out waiting for a read for next
  1980. request notification. If a reset hold completes, then any held request
  1981. must be started. If a timeout occurs, then the bus must be reset.
  1982. Arguments:
  1983. ServiceContext - Supplies the pointer to the device object.
  1984. Return Value:
  1985. TRUE - If a timeout error should be logged.
  1986. Notes:
  1987. The port driver spinlock must be held when this routine is called.
  1988. --*/
  1989. {
  1990. PDEVICE_OBJECT deviceObject = ServiceContext;
  1991. PFDO_EXTENSION deviceExtension = deviceObject->DeviceExtension;
  1992. ULONG i;
  1993. BOOLEAN enumProbing = FALSE;
  1994. BOOLEAN noErrorLog = FALSE;
  1995. DebugPrint((3, "IdeTimeoutSynchronized: Enter routine\n"));
  1996. //
  1997. // Make sure the timer is stopped.
  1998. //
  1999. deviceExtension->PortTimeoutCounter = PD_TIMER_STOPPED;
  2000. //
  2001. // Check for a reset hold. If one is in progress then clear it and check
  2002. // for a pending held request
  2003. //
  2004. if (deviceExtension->InterruptData.InterruptFlags & PD_RESET_HOLD) {
  2005. CLRMASK (deviceExtension->InterruptData.InterruptFlags, PD_RESET_HOLD);
  2006. if (deviceExtension->InterruptData.InterruptFlags & PD_HELD_REQUEST) {
  2007. //
  2008. // Clear the held request flag and restart the request.
  2009. //
  2010. CLRMASK (deviceExtension->InterruptData.InterruptFlags, PD_HELD_REQUEST);
  2011. IdeStartIoSynchronized(ServiceContext);
  2012. }
  2013. return(FALSE);
  2014. } else {
  2015. //
  2016. // Miniport is hung and not accepting new requests. So reset the
  2017. // bus to clear things up.
  2018. //
  2019. if (deviceExtension->HwDeviceExtension->CurrentSrb) {
  2020. deviceExtension->HwDeviceExtension->TimeoutCount[
  2021. deviceExtension->HwDeviceExtension->CurrentSrb->TargetId
  2022. ]++;
  2023. //
  2024. // Many harddrives fail to respond to the first DMA operation
  2025. // We then reset the device and subsequently everything works fine
  2026. // The hack is to mask this error from being logged in the system logs
  2027. //
  2028. if (deviceExtension->HwDeviceExtension->TimeoutCount[
  2029. deviceExtension->HwDeviceExtension->CurrentSrb->TargetId
  2030. ] == 1) {
  2031. noErrorLog=TRUE;
  2032. }
  2033. enumProbing = TestForEnumProbing (deviceExtension->HwDeviceExtension->CurrentSrb);
  2034. }
  2035. if (!enumProbing) {
  2036. DebugPrint((0,
  2037. "IdeTimeoutSynchronized: DevObj 0x%x Next request timed out. Resetting bus..currentSrb=0x%x\n",
  2038. deviceObject,
  2039. deviceExtension->HwDeviceExtension->CurrentSrb));
  2040. }
  2041. ASSERT (deviceExtension->ResetSrb == 0);
  2042. deviceExtension->ResetSrb = NULL;
  2043. deviceExtension->ResetCallAgain = 0;
  2044. AtapiResetController (deviceExtension->HwDeviceExtension,
  2045. 0,
  2046. &deviceExtension->ResetCallAgain);
  2047. //
  2048. // Set the reset hold flag and start the counter.
  2049. // if we are doing enumertion, don't set the flag
  2050. // we shouldn't set the flag if ResetCallAgain is not set
  2051. //
  2052. if (!enumProbing &&
  2053. (deviceExtension->ResetCallAgain)) {
  2054. ASSERT(deviceExtension->ResetCallAgain);
  2055. deviceExtension->InterruptData.InterruptFlags |= PD_RESET_HOLD;
  2056. deviceExtension->PortTimeoutCounter = PD_TIMER_RESET_HOLD_TIME;
  2057. } else {
  2058. ASSERT(deviceExtension->ResetCallAgain == 0);
  2059. }
  2060. //
  2061. // Check for miniport work requests.
  2062. //
  2063. if (deviceExtension->InterruptData.InterruptFlags & PD_NOTIFICATION_REQUIRED) {
  2064. IoRequestDpc(deviceExtension->DeviceObject, NULL, NULL);
  2065. }
  2066. }
  2067. if (enumProbing || noErrorLog) {
  2068. return(FALSE);
  2069. } else {
  2070. return(TRUE);
  2071. }
  2072. } // end IdeTimeoutSynchronized()
  2073. NTSTATUS
  2074. FASTCALL
  2075. IdeBuildAndSendIrp (
  2076. IN PPDO_EXTENSION PdoExtension,
  2077. IN PSCSI_REQUEST_BLOCK Srb,
  2078. IN PIO_COMPLETION_ROUTINE CompletionRoutine,
  2079. IN PVOID CompletionContext
  2080. )
  2081. {
  2082. LARGE_INTEGER largeInt;
  2083. NTSTATUS status = STATUS_PENDING;
  2084. PIRP irp;
  2085. PIO_STACK_LOCATION irpStack;
  2086. //
  2087. // why?
  2088. //
  2089. largeInt.QuadPart = (LONGLONG) 1;
  2090. //
  2091. // Build IRP for this request.
  2092. //
  2093. irp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
  2094. PdoExtension->DeviceObject,
  2095. Srb->DataBuffer,
  2096. Srb->DataTransferLength,
  2097. &largeInt,
  2098. NULL);
  2099. if (irp == NULL) {
  2100. IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
  2101. PdoExtension->TargetId,
  2102. NonPagedPool,
  2103. IoSizeOfIrp(PdoExtension->DeviceObject->StackSize),
  2104. IDEPORT_TAG_SEND_IRP
  2105. );
  2106. status = STATUS_INSUFFICIENT_RESOURCES;
  2107. goto GetOut;
  2108. }
  2109. IoSetCompletionRoutine(irp,
  2110. (PIO_COMPLETION_ROUTINE)CompletionRoutine,
  2111. CompletionContext,
  2112. TRUE,
  2113. TRUE,
  2114. TRUE);
  2115. irpStack = IoGetNextIrpStackLocation(irp);
  2116. irpStack->MajorFunction = IRP_MJ_SCSI;
  2117. //
  2118. // Save SRB address in next stack for port driver.
  2119. //
  2120. irpStack->Parameters.Scsi.Srb = Srb;
  2121. //
  2122. // put the irp in the original request field
  2123. //
  2124. Srb->OriginalRequest = irp;
  2125. (VOID)IoCallDriver(PdoExtension->DeviceObject, irp);
  2126. status = STATUS_PENDING;
  2127. GetOut:
  2128. return status;
  2129. }
  2130. VOID
  2131. FASTCALL
  2132. IdeFreeIrpAndMdl(
  2133. IN PIRP Irp
  2134. )
  2135. {
  2136. ASSERT(Irp);
  2137. if (Irp->MdlAddress != NULL) {
  2138. MmUnlockPages(Irp->MdlAddress);
  2139. IoFreeMdl(Irp->MdlAddress);
  2140. Irp->MdlAddress = NULL;
  2141. }
  2142. IoFreeIrp(Irp);
  2143. return;
  2144. }
  2145. VOID
  2146. IssueRequestSense(
  2147. IN PPDO_EXTENSION PdoExtension,
  2148. IN PSCSI_REQUEST_BLOCK FailingSrb
  2149. )
  2150. /*++
  2151. Routine Description:
  2152. This routine creates a REQUEST SENSE request and uses IoCallDriver to
  2153. renter the driver. The completion routine cleans up the data structures
  2154. and processes the logical unit queue according to the flags.
  2155. A pointer to failing SRB is stored at the end of the request sense
  2156. Srb, so that the completion routine can find it.
  2157. Arguments:
  2158. DeviceExension - Supplies a pointer to the pdo device extension
  2159. FailingSrb - Supplies a pointer to the request that the request sense
  2160. is being done for.
  2161. Return Value:
  2162. None.
  2163. --*/
  2164. {
  2165. PIO_STACK_LOCATION irpStack;
  2166. PIRP irp;
  2167. PSCSI_REQUEST_BLOCK srb;
  2168. PCDB cdb;
  2169. PVOID *pointer;
  2170. PLOGICAL_UNIT_EXTENSION logicalUnit;
  2171. KIRQL currentIrql;
  2172. NTSTATUS status;
  2173. #if DBG
  2174. PIO_STACK_LOCATION failingIrpStack;
  2175. PIRP failingIrp;
  2176. PLOGICAL_UNIT_EXTENSION failingLogicalUnit;
  2177. #endif
  2178. DebugPrint((3,"IssueRequestSense: Enter routine\n"));
  2179. //
  2180. // Build the asynchronous request
  2181. // to be sent to the port driver.
  2182. //
  2183. // Allocate Srb from non-paged pool
  2184. // plus room for a pointer to the failing IRP.
  2185. // Note this routine is in an error-handling
  2186. // path and is a shortterm allocation.
  2187. //
  2188. srb = ExAllocatePool(NonPagedPool,
  2189. sizeof(SCSI_REQUEST_BLOCK) + sizeof(PVOID));
  2190. if (srb == NULL) {
  2191. DebugPrint((1, "IssueRequest sense - pool allocation failed\n"));
  2192. goto Getout;
  2193. }
  2194. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  2195. //
  2196. // Save the Failing SRB after the request sense Srb.
  2197. //
  2198. pointer = (PVOID *) (srb+1);
  2199. *pointer = FailingSrb;
  2200. //
  2201. // Build the REQUEST SENSE CDB.
  2202. //
  2203. srb->CdbLength = 6;
  2204. cdb = (PCDB)srb->Cdb;
  2205. cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
  2206. cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
  2207. cdb->CDB6INQUIRY.Reserved1 = 0;
  2208. cdb->CDB6INQUIRY.PageCode = 0;
  2209. cdb->CDB6INQUIRY.IReserved = 0;
  2210. cdb->CDB6INQUIRY.AllocationLength =
  2211. (UCHAR)FailingSrb->SenseInfoBufferLength;
  2212. cdb->CDB6INQUIRY.Control = 0;
  2213. //
  2214. // Set up SCSI bus address.
  2215. //
  2216. srb->TargetId = FailingSrb->TargetId;
  2217. srb->Lun = FailingSrb->Lun;
  2218. srb->PathId = FailingSrb->PathId;
  2219. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  2220. srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  2221. //
  2222. // Set timeout value to 16 seconds.
  2223. //
  2224. srb->TimeOutValue = 0x10;
  2225. //
  2226. // Disable auto request sense.
  2227. //
  2228. srb->SenseInfoBufferLength = 0;
  2229. //
  2230. // Sense buffer is in stack.
  2231. //
  2232. srb->SenseInfoBuffer = NULL;
  2233. //
  2234. // Set read and bypass frozen queue bits in flags.
  2235. //
  2236. //
  2237. // Set SRB flags to indicate the logical unit queue should be by
  2238. // passed and that no queue processing should be done when the request
  2239. // completes. Also disable disconnect and synchronous data
  2240. // transfer if necessary.
  2241. //
  2242. srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE |
  2243. SRB_FLAGS_DISABLE_DISCONNECT;
  2244. if (FailingSrb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) {
  2245. srb->SrbFlags |= SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  2246. }
  2247. srb->DataBuffer = FailingSrb->SenseInfoBuffer;
  2248. //
  2249. // Set the transfer length.
  2250. //
  2251. srb->DataTransferLength = FailingSrb->SenseInfoBufferLength;
  2252. //
  2253. // Zero out status.
  2254. //
  2255. srb->ScsiStatus = srb->SrbStatus = 0;
  2256. srb->NextSrb = 0;
  2257. #if DBG
  2258. //
  2259. // This was added to catch a bug where the original request
  2260. // was pointing to a pnp irp
  2261. //
  2262. ASSERT(FailingSrb->OriginalRequest);
  2263. failingIrp = FailingSrb->OriginalRequest;
  2264. failingIrpStack = IoGetCurrentIrpStackLocation(failingIrp);
  2265. failingLogicalUnit = IDEPORT_GET_LUNEXT_IN_IRP (failingIrpStack);
  2266. ASSERT(failingLogicalUnit);
  2267. #endif
  2268. status = IdeBuildAndSendIrp(PdoExtension,
  2269. srb,
  2270. IdePortInternalCompletion,
  2271. srb
  2272. );
  2273. if (NT_SUCCESS(status)) {
  2274. return;
  2275. }
  2276. ASSERT(status == STATUS_INSUFFICIENT_RESOURCES);
  2277. Getout:
  2278. if (srb) {
  2279. ExFreePool(srb);
  2280. }
  2281. irp = FailingSrb->OriginalRequest;
  2282. irpStack = IoGetCurrentIrpStackLocation(irp);
  2283. logicalUnit = IDEPORT_GET_LUNEXT_IN_IRP (irpStack);
  2284. //
  2285. // Clear the request sense flag. Since IdeStartIoSync will never get called, this
  2286. // flag won't be cleared.
  2287. //
  2288. KeAcquireSpinLock(&logicalUnit->ParentDeviceExtension->SpinLock, &currentIrql);
  2289. CLRMASK (logicalUnit->LuFlags, PD_NEED_REQUEST_SENSE);
  2290. KeReleaseSpinLock(&logicalUnit->ParentDeviceExtension->SpinLock, currentIrql);
  2291. //
  2292. // unfreeze the queue if necessary
  2293. //
  2294. ASSERT(FailingSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN);
  2295. if ((FailingSrb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE) &&
  2296. (FailingSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN)) {
  2297. CLRMASK (logicalUnit->LuFlags, PD_QUEUE_FROZEN);
  2298. KeAcquireSpinLock(&logicalUnit->ParentDeviceExtension->SpinLock, &currentIrql);
  2299. GetNextLuRequest(logicalUnit->ParentDeviceExtension, logicalUnit);
  2300. KeLowerIrql(currentIrql);
  2301. CLRMASK (FailingSrb->SrbStatus, SRB_STATUS_QUEUE_FROZEN);
  2302. }
  2303. //
  2304. // Decrement the logUnitExtension reference count
  2305. //
  2306. UnrefLogicalUnitExtensionWithTag(
  2307. IDEPORT_GET_LUNEXT_IN_IRP(irpStack)->ParentDeviceExtension,
  2308. IDEPORT_GET_LUNEXT_IN_IRP(irpStack),
  2309. irp
  2310. );
  2311. //
  2312. // Complete the original request
  2313. //
  2314. IoCompleteRequest(irp, IO_DISK_INCREMENT);
  2315. return;
  2316. } // end IssueRequestSense()
  2317. NTSTATUS
  2318. IdePortInternalCompletion(
  2319. PDEVICE_OBJECT DeviceObject,
  2320. PIRP Irp,
  2321. PVOID Context
  2322. )
  2323. /*++
  2324. Routine Description:
  2325. Arguments:
  2326. Device object
  2327. IRP
  2328. Context - pointer to SRB
  2329. Return Value:
  2330. NTSTATUS
  2331. --*/
  2332. {
  2333. PIO_STACK_LOCATION irpStack;
  2334. PSCSI_REQUEST_BLOCK srb = Context;
  2335. PSCSI_REQUEST_BLOCK failingSrb;
  2336. PIRP failingIrp;
  2337. PLOGICAL_UNIT_EXTENSION logicalUnit;
  2338. PSENSE_DATA senseBuffer;
  2339. PHW_DEVICE_EXTENSION hwDeviceExtension;
  2340. KIRQL currentIrql;
  2341. UNREFERENCED_PARAMETER(DeviceObject);
  2342. DebugPrint((3,"IdePortInternalCompletion: Enter routine\n"));
  2343. //
  2344. // If RESET_BUS or ABORT_COMMAND request
  2345. // then free pool and return.
  2346. //
  2347. if ((srb->Function == SRB_FUNCTION_ABORT_COMMAND) ||
  2348. (srb->Function == SRB_FUNCTION_RESET_BUS)) {
  2349. //
  2350. // Deallocate internal SRB and IRP.
  2351. //
  2352. ExFreePool(srb);
  2353. IoFreeIrp(Irp);
  2354. return STATUS_MORE_PROCESSING_REQUIRED;
  2355. }
  2356. irpStack = IoGetCurrentIrpStackLocation(Irp);
  2357. //
  2358. // Request sense completed. If successful or data over/underrun
  2359. // get the failing SRB and indicate that the sense information
  2360. // is valid. The class driver will check for underrun and determine
  2361. // if there is enough sense information to be useful.
  2362. //
  2363. //
  2364. // Get a pointer to failing Irp and Srb.
  2365. //
  2366. failingSrb = *((PVOID *) (srb+1));
  2367. failingIrp = failingSrb->OriginalRequest;
  2368. irpStack = IoGetCurrentIrpStackLocation(failingIrp);
  2369. logicalUnit = IDEPORT_GET_LUNEXT_IN_IRP (irpStack);
  2370. if ((SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
  2371. (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)) {
  2372. //
  2373. // Report sense buffer is valid.
  2374. //
  2375. failingSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
  2376. //
  2377. // Copy bytes transferred to failing SRB
  2378. // request sense length field to communicate
  2379. // to the class drivers the number of valid
  2380. // sense bytes.
  2381. //
  2382. failingSrb->SenseInfoBufferLength = (UCHAR) srb->DataTransferLength;
  2383. #if 0
  2384. //
  2385. // enable for debugging only
  2386. // if sense buffer is smaller than 13 bytes, then the debugprint
  2387. // below could bugchecl the system
  2388. //
  2389. //
  2390. // Print the sense buffer for debugging purposes.
  2391. //
  2392. senseBuffer = failingSrb->SenseInfoBuffer;
  2393. DebugPrint((DBG_ATAPI_DEVICES, "CDB=%x, SenseKey=%x, ASC=%x, ASQ=%x\n",
  2394. failingSrb->Cdb[0],
  2395. senseBuffer->SenseKey, senseBuffer->AdditionalSenseCode,
  2396. senseBuffer->AdditionalSenseCodeQualifier));
  2397. #endif
  2398. }
  2399. //
  2400. // Clear the request sense flag. If we fail due to fault injection
  2401. // IdeStartIo won't get called and this flag never gets cleared.
  2402. //
  2403. KeAcquireSpinLock(&logicalUnit->ParentDeviceExtension->SpinLock, &currentIrql);
  2404. CLRMASK (logicalUnit->LuFlags, PD_NEED_REQUEST_SENSE);
  2405. KeReleaseSpinLock(&logicalUnit->ParentDeviceExtension->SpinLock, currentIrql);
  2406. //
  2407. // unfreeze the queue if necessary
  2408. //
  2409. ASSERT(failingSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN);
  2410. if ((failingSrb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE) &&
  2411. (failingSrb->SrbStatus & SRB_STATUS_QUEUE_FROZEN)) {
  2412. CLRMASK (logicalUnit->LuFlags, PD_QUEUE_FROZEN);
  2413. KeAcquireSpinLock(&logicalUnit->ParentDeviceExtension->SpinLock, &currentIrql);
  2414. GetNextLuRequest(logicalUnit->ParentDeviceExtension, logicalUnit);
  2415. KeLowerIrql(currentIrql);
  2416. CLRMASK (failingSrb->SrbStatus, SRB_STATUS_QUEUE_FROZEN);
  2417. }
  2418. //
  2419. // Decrement the logUnitExtension reference count
  2420. //
  2421. UnrefLogicalUnitExtensionWithTag(
  2422. IDEPORT_GET_LUNEXT_IN_IRP(irpStack)->ParentDeviceExtension,
  2423. IDEPORT_GET_LUNEXT_IN_IRP(irpStack),
  2424. failingIrp
  2425. );
  2426. //
  2427. // Complete the failing request.
  2428. //
  2429. IoCompleteRequest(failingIrp, IO_DISK_INCREMENT);
  2430. //
  2431. // Deallocate internal SRB, MDL and IRP.
  2432. //
  2433. ExFreePool(srb);
  2434. IdeFreeIrpAndMdl(Irp);
  2435. return STATUS_MORE_PROCESSING_REQUIRED;
  2436. } // IdePortInternalCompletion()
  2437. BOOLEAN
  2438. IdeGetInterruptState(
  2439. IN PVOID ServiceContext
  2440. )
  2441. /*++
  2442. Routine Description:
  2443. This routine saves the InterruptFlags, MapTransferParameters and
  2444. CompletedRequests fields and clears the InterruptFlags.
  2445. This routine also removes the request from the logical unit queue if it is
  2446. tag. Finally the request time is updated.
  2447. Arguments:
  2448. ServiceContext - Supplies a pointer to the interrupt context which contains
  2449. pointers to the interrupt data and where to save it.
  2450. Return Value:
  2451. Returns TURE if there is new work and FALSE otherwise.
  2452. Notes:
  2453. Called via KeSynchronizeExecution with the port device extension spinlock
  2454. held.
  2455. --*/
  2456. {
  2457. PINTERRUPT_CONTEXT interruptContext = ServiceContext;
  2458. ULONG limit = 0;
  2459. PFDO_EXTENSION deviceExtension;
  2460. PLOGICAL_UNIT_EXTENSION logicalUnit;
  2461. PSCSI_REQUEST_BLOCK srb;
  2462. PSRB_DATA srbData;
  2463. PSRB_DATA nextSrbData;
  2464. BOOLEAN isTimed;
  2465. deviceExtension = interruptContext->DeviceExtension;
  2466. //
  2467. // Check for pending work.
  2468. //
  2469. if (!(deviceExtension->InterruptData.InterruptFlags & PD_NOTIFICATION_REQUIRED)) {
  2470. return(FALSE);
  2471. }
  2472. //
  2473. // Move the interrupt state to save area.
  2474. //
  2475. *interruptContext->SavedInterruptData = deviceExtension->InterruptData;
  2476. //
  2477. // Clear the interrupt state.
  2478. //
  2479. deviceExtension->InterruptData.InterruptFlags &= PD_INTERRUPT_FLAG_MASK;
  2480. deviceExtension->InterruptData.CompletedRequests = NULL;
  2481. deviceExtension->InterruptData.ReadyLogicalUnit = NULL;
  2482. deviceExtension->InterruptData.CompletedAbort = NULL;
  2483. deviceExtension->InterruptData.PdoExtensionResetBus = NULL;
  2484. srbData = interruptContext->SavedInterruptData->CompletedRequests;
  2485. while (srbData != NULL) {
  2486. PIRP irp;
  2487. PIO_STACK_LOCATION irpStack;
  2488. ASSERT(limit++ < 100);
  2489. //
  2490. // Get a pointer to the SRB and the logical unit extension.
  2491. //
  2492. ASSERT(srbData->CurrentSrb != NULL);
  2493. srb = srbData->CurrentSrb;
  2494. irp = srb->OriginalRequest;
  2495. irpStack = IoGetCurrentIrpStackLocation(irp);
  2496. logicalUnit = IDEPORT_GET_LUNEXT_IN_IRP (irpStack);
  2497. //
  2498. // If the request did not succeed, then check for the special cases.
  2499. //
  2500. if (srb->SrbStatus != SRB_STATUS_SUCCESS) {
  2501. //
  2502. // If this request failed and a REQUEST SENSE command needs to
  2503. // be done, then set a flag to indicate this and prevent other
  2504. // commands from being started.
  2505. //
  2506. if (NEED_REQUEST_SENSE(srb)) {
  2507. if (logicalUnit->LuFlags & PD_NEED_REQUEST_SENSE) {
  2508. //
  2509. // This implies that requests have completed with a
  2510. // status of check condition before a REQUEST SENSE
  2511. // command could be preformed. This should never occur.
  2512. // Convert the request to another code so that only one
  2513. // auto request sense is issued.
  2514. //
  2515. srb->ScsiStatus = 0;
  2516. srb->SrbStatus = SRB_STATUS_REQUEST_SENSE_FAILED;
  2517. } else {
  2518. //
  2519. // Indicate that an auto request sense needs to be done.
  2520. //
  2521. logicalUnit->LuFlags |= PD_NEED_REQUEST_SENSE;
  2522. }
  2523. }
  2524. }
  2525. logicalUnit->RequestTimeoutCounter = PD_TIMER_STOPPED;
  2526. srbData = srbData->CompletedRequests;
  2527. }
  2528. return(TRUE);
  2529. }
  2530. VOID
  2531. IdePortAllocateAccessToken (
  2532. IN PDEVICE_OBJECT DeviceObject
  2533. )
  2534. {
  2535. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  2536. if (!fdoExtension->SyncAccessInterface.AllocateAccessToken) {
  2537. CallIdeStartIoSynchronized (
  2538. NULL,
  2539. NULL,
  2540. NULL,
  2541. DeviceObject
  2542. );
  2543. } else {
  2544. (*fdoExtension->SyncAccessInterface.AllocateAccessToken) (
  2545. fdoExtension->SyncAccessInterface.Token,
  2546. CallIdeStartIoSynchronized,
  2547. DeviceObject
  2548. );
  2549. }
  2550. }
  2551. IO_ALLOCATION_ACTION
  2552. CallIdeStartIoSynchronized (
  2553. IN PVOID Reserved1,
  2554. IN PVOID Reserved2,
  2555. IN PVOID Reserved3,
  2556. IN PVOID DeviceObject
  2557. )
  2558. {
  2559. PFDO_EXTENSION deviceExtension = ((PDEVICE_OBJECT) DeviceObject)->DeviceExtension;
  2560. KIRQL currentIrql;
  2561. KeAcquireSpinLock(&deviceExtension->SpinLock, &currentIrql);
  2562. KeSynchronizeExecution (
  2563. deviceExtension->InterruptObject,
  2564. IdeStartIoSynchronized,
  2565. DeviceObject
  2566. );
  2567. KeReleaseSpinLock(&deviceExtension->SpinLock, currentIrql);
  2568. return KeepObject;
  2569. }
  2570. VOID
  2571. LogErrorEntry(
  2572. IN PFDO_EXTENSION DeviceExtension,
  2573. IN PERROR_LOG_ENTRY LogEntry
  2574. )
  2575. /*++
  2576. Routine Description:
  2577. This function allocates an I/O error log record, fills it in and writes it
  2578. to the I/O error log.
  2579. Arguments:
  2580. DeviceExtension - Supplies a pointer to the port device extension.
  2581. LogEntry - Supplies a pointer to the scsi port log entry.
  2582. Return Value:
  2583. None.
  2584. --*/
  2585. {
  2586. PIO_ERROR_LOG_PACKET errorLogEntry;
  2587. errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
  2588. DeviceExtension->DeviceObject,
  2589. sizeof(IO_ERROR_LOG_PACKET) + 4 * sizeof(ULONG)
  2590. );
  2591. if (errorLogEntry != NULL) {
  2592. //
  2593. // Translate the miniport error code into the NT I\O driver.
  2594. //
  2595. switch (LogEntry->ErrorCode) {
  2596. case SP_BUS_PARITY_ERROR:
  2597. errorLogEntry->ErrorCode = IO_ERR_PARITY;
  2598. break;
  2599. case SP_UNEXPECTED_DISCONNECT:
  2600. errorLogEntry->ErrorCode = IO_ERR_CONTROLLER_ERROR;
  2601. break;
  2602. case SP_INVALID_RESELECTION:
  2603. errorLogEntry->ErrorCode = IO_ERR_CONTROLLER_ERROR;
  2604. break;
  2605. case SP_BUS_TIME_OUT:
  2606. errorLogEntry->ErrorCode = IO_ERR_TIMEOUT;
  2607. break;
  2608. case SP_PROTOCOL_ERROR:
  2609. errorLogEntry->ErrorCode = IO_ERR_CONTROLLER_ERROR;
  2610. break;
  2611. case SP_INTERNAL_ADAPTER_ERROR:
  2612. errorLogEntry->ErrorCode = IO_ERR_CONTROLLER_ERROR;
  2613. break;
  2614. case SP_IRQ_NOT_RESPONDING:
  2615. errorLogEntry->ErrorCode = IO_ERR_INCORRECT_IRQL;
  2616. break;
  2617. case SP_BAD_FW_ERROR:
  2618. errorLogEntry->ErrorCode = IO_ERR_BAD_FIRMWARE;
  2619. break;
  2620. case SP_BAD_FW_WARNING:
  2621. errorLogEntry->ErrorCode = IO_WRN_BAD_FIRMWARE;
  2622. break;
  2623. default:
  2624. errorLogEntry->ErrorCode = IO_ERR_CONTROLLER_ERROR;
  2625. break;
  2626. }
  2627. errorLogEntry->SequenceNumber = LogEntry->SequenceNumber;
  2628. errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
  2629. errorLogEntry->RetryCount = (UCHAR) LogEntry->ErrorLogRetryCount;
  2630. errorLogEntry->UniqueErrorValue = LogEntry->UniqueId;
  2631. errorLogEntry->FinalStatus = STATUS_SUCCESS;
  2632. errorLogEntry->DumpDataSize = 4 * sizeof(ULONG);
  2633. errorLogEntry->DumpData[0] = LogEntry->PathId;
  2634. errorLogEntry->DumpData[1] = LogEntry->TargetId;
  2635. errorLogEntry->DumpData[2] = LogEntry->Lun;
  2636. errorLogEntry->DumpData[3] = LogEntry->ErrorCode;
  2637. IoWriteErrorLogEntry(errorLogEntry);
  2638. }
  2639. #if DBG
  2640. {
  2641. PCHAR errorCodeString;
  2642. switch (LogEntry->ErrorCode) {
  2643. case SP_BUS_PARITY_ERROR:
  2644. errorCodeString = "SCSI bus partity error";
  2645. break;
  2646. case SP_UNEXPECTED_DISCONNECT:
  2647. errorCodeString = "Unexpected disconnect";
  2648. break;
  2649. case SP_INVALID_RESELECTION:
  2650. errorCodeString = "Invalid reselection";
  2651. break;
  2652. case SP_BUS_TIME_OUT:
  2653. errorCodeString = "SCSI bus time out";
  2654. break;
  2655. case SP_PROTOCOL_ERROR:
  2656. errorCodeString = "SCSI protocol error";
  2657. break;
  2658. case SP_INTERNAL_ADAPTER_ERROR:
  2659. errorCodeString = "Internal adapter error";
  2660. break;
  2661. default:
  2662. errorCodeString = "Unknown error code";
  2663. break;
  2664. }
  2665. DebugPrint((DBG_ALWAYS,"LogErrorEntry: Logging SCSI error packet. ErrorCode = %s.\n",
  2666. errorCodeString
  2667. ));
  2668. DebugPrint((DBG_ALWAYS,
  2669. "PathId = %2x, TargetId = %2x, Lun = %2x, UniqueId = %x.\n",
  2670. LogEntry->PathId,
  2671. LogEntry->TargetId,
  2672. LogEntry->Lun,
  2673. LogEntry->UniqueId
  2674. ));
  2675. }
  2676. #endif
  2677. }
  2678. VOID
  2679. GetNextLuPendingRequest(
  2680. IN PFDO_EXTENSION DeviceExtension,
  2681. IN PLOGICAL_UNIT_EXTENSION LogicalUnit
  2682. )
  2683. {
  2684. if (LogicalUnit->PendingRequest) {
  2685. GetNextLuRequest(
  2686. DeviceExtension,
  2687. LogicalUnit
  2688. );
  2689. } else {
  2690. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  2691. }
  2692. return;
  2693. }
  2694. #if DBG
  2695. #define LOG_LENGTH 5
  2696. ULONG IdeDebugGetNextLuRequestLastCallerIndex = LOG_LENGTH - 1;
  2697. UCHAR IdeDebugGetNextLuRequestLastCallerFileName[LOG_LENGTH][256] = {0};
  2698. ULONG IdeDebugGetNextLuRequestLastCallerLineNumber[LOG_LENGTH] = {0};
  2699. VOID
  2700. GetNextLuRequest2(
  2701. IN PFDO_EXTENSION DeviceExtension,
  2702. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  2703. IN PUCHAR FileName,
  2704. IN ULONG LineNumber
  2705. )
  2706. #else
  2707. VOID
  2708. GetNextLuRequest(
  2709. IN PFDO_EXTENSION DeviceExtension,
  2710. IN PLOGICAL_UNIT_EXTENSION LogicalUnit
  2711. )
  2712. #endif
  2713. /*++
  2714. Routine Description:
  2715. This routine get the next request for the specified logical unit. It does
  2716. the necessary initialization to the logical unit structure and submitts the
  2717. request to the device queue. The DeviceExtension SpinLock must be held
  2718. when this function called. It is released by this function.
  2719. Arguments:
  2720. DeviceExtension - Supplies a pointer to the port device extension.
  2721. LogicalUnit - Supplies a pointer to the logical unit extension to get the
  2722. next request from.
  2723. Return Value:
  2724. None.
  2725. --*/
  2726. {
  2727. PKDEVICE_QUEUE_ENTRY packet;
  2728. PIO_STACK_LOCATION irpStack;
  2729. PSCSI_REQUEST_BLOCK srb;
  2730. POWER_STATE powerState;
  2731. PIRP nextIrp;
  2732. BOOLEAN powerUpDevice = FALSE;
  2733. #if DBG
  2734. IdeDebugGetNextLuRequestLastCallerIndex++;
  2735. if (IdeDebugGetNextLuRequestLastCallerIndex >= LOG_LENGTH) {
  2736. IdeDebugGetNextLuRequestLastCallerIndex = 0;
  2737. }
  2738. strcpy (IdeDebugGetNextLuRequestLastCallerFileName[IdeDebugGetNextLuRequestLastCallerIndex], FileName);
  2739. IdeDebugGetNextLuRequestLastCallerLineNumber[IdeDebugGetNextLuRequestLastCallerIndex] = LineNumber;
  2740. #endif // DBG
  2741. //
  2742. // If the active flag is not set, then the queue is not busy or there is
  2743. // a request being processed and the next request should not be started..
  2744. //
  2745. if ((!(LogicalUnit->LuFlags & PD_LOGICAL_UNIT_IS_ACTIVE) &&
  2746. (LogicalUnit->PendingRequest == NULL))
  2747. || (LogicalUnit->SrbData.CurrentSrb)) {
  2748. DebugPrint ((2, "IdePort GetNextLuRequest: 0x%x 0x%x NOT PD_LOGICAL_UNIT_IS_ACTIVE\n",
  2749. DeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  2750. LogicalUnit->TargetId
  2751. ));
  2752. //
  2753. // Release the spinlock.
  2754. //
  2755. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  2756. return;
  2757. }
  2758. //
  2759. // Check for pending requests, queue full or busy requests. Pending
  2760. // requests occur when untagged request is started and there are active
  2761. // queued requests. Busy requests occur when the target returns a BUSY
  2762. // or QUEUE FULL status. Busy requests are started by the timer code.
  2763. // Also if the need request sense flag is set, it indicates that
  2764. // an error status was detected on the logical unit. No new requests
  2765. // should be started until this flag is cleared. This flag is cleared
  2766. // by an untagged command that by-passes the LU queue i.e.
  2767. //
  2768. // The busy flag and the need request sense flag have the effect of
  2769. // forcing the queue of outstanding requests to drain after an error or
  2770. // until a busy request gets started.
  2771. //
  2772. if (LogicalUnit->LuFlags & (PD_LOGICAL_UNIT_IS_BUSY
  2773. | PD_QUEUE_IS_FULL | PD_NEED_REQUEST_SENSE | PD_QUEUE_FROZEN) ||
  2774. (LogicalUnit->PdoState & (PDOS_REMOVED | PDOS_SURPRISE_REMOVED))) {
  2775. //
  2776. // If the request queue is now empty, then the pending request can
  2777. // be started.
  2778. //
  2779. DebugPrint((2, "IdePort: GetNextLuRequest: 0x%x 0x%x Ignoring a get next lu call.\n",
  2780. DeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  2781. LogicalUnit->TargetId
  2782. ));
  2783. //
  2784. // Note the active flag is not cleared. So the next request
  2785. // will be processed when the other requests have completed.
  2786. // Release the spinlock.
  2787. //
  2788. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  2789. return;
  2790. }
  2791. //
  2792. // Clear the active flag. If there is another request, the flag will be
  2793. // set again when the request is passed to the miniport.
  2794. //
  2795. CLRMASK (LogicalUnit->LuFlags, PD_LOGICAL_UNIT_IS_ACTIVE);
  2796. LogicalUnit->RetryCount = 0;
  2797. nextIrp = NULL;
  2798. if (LogicalUnit->PendingRequest) {
  2799. nextIrp = LogicalUnit->PendingRequest;
  2800. LogicalUnit->PendingRequest = NULL;
  2801. } else {
  2802. //
  2803. // Remove the packet from the logical unit device queue.
  2804. //
  2805. packet = KeRemoveByKeyDeviceQueue(&LogicalUnit->DeviceObject->DeviceQueue,
  2806. LogicalUnit->CurrentKey);
  2807. if (packet != NULL) {
  2808. nextIrp = CONTAINING_RECORD(packet, IRP, Tail.Overlay.DeviceQueueEntry);
  2809. #if DBG
  2810. InterlockedDecrement (
  2811. &LogicalUnit->NumberOfIrpQueued
  2812. );
  2813. #endif // DBG
  2814. }
  2815. }
  2816. if (!nextIrp) {
  2817. DebugPrint ((2, "IdePort GetNextLuRequest: 0x%x 0x%x no irp to processing\n",
  2818. DeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  2819. LogicalUnit->TargetId
  2820. ));
  2821. }
  2822. if (nextIrp) {
  2823. BOOLEAN pendingRequest;
  2824. irpStack = IoGetCurrentIrpStackLocation(nextIrp);
  2825. srb = (PSCSI_REQUEST_BLOCK)irpStack->Parameters.Others.Argument1;
  2826. if (LogicalUnit->PdoState & PDOS_QUEUE_BLOCKED) {
  2827. DebugPrint ((2, "IdePort GetNextLuRequest: 0x%x 0x%x Lu must queue\n",
  2828. DeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  2829. LogicalUnit->TargetId
  2830. ));
  2831. pendingRequest = TRUE;
  2832. if (!(LogicalUnit->PdoState & PDOS_MUST_QUEUE)) {
  2833. //
  2834. // device is powered down
  2835. // use a large time in case it spins up slowly
  2836. //
  2837. if (srb->TimeOutValue < DEFAULT_SPINUP_TIME) {
  2838. srb->TimeOutValue = DEFAULT_SPINUP_TIME;
  2839. }
  2840. //
  2841. // We are not powered up.
  2842. // issue an power up
  2843. //
  2844. powerUpDevice = TRUE;
  2845. DebugPrint ((2, "IdePort GetNextLuRequest: 0x%x 0x%x need to spin up device, requeue irp 0x%x\n",
  2846. DeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  2847. LogicalUnit->TargetId,
  2848. nextIrp));
  2849. }
  2850. } else {
  2851. pendingRequest = FALSE;
  2852. }
  2853. if (pendingRequest) {
  2854. ASSERT (LogicalUnit->PendingRequest == NULL);
  2855. LogicalUnit->PendingRequest = nextIrp;
  2856. nextIrp = NULL;
  2857. }
  2858. }
  2859. if (nextIrp) {
  2860. //
  2861. // Set the new current key.
  2862. //
  2863. LogicalUnit->CurrentKey = srb->QueueSortKey;
  2864. //
  2865. // Hack to work-around the starvation led to by numerous requests touching the same sector.
  2866. //
  2867. LogicalUnit->CurrentKey++;
  2868. //
  2869. // Release the spinlock.
  2870. //
  2871. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  2872. DebugPrint ((2, "GetNextLuRequest: IoStartPacket 0x%x\n", nextIrp));
  2873. IoStartPacket(DeviceExtension->DeviceObject, nextIrp, (PULONG)NULL, NULL);
  2874. } else {
  2875. NTSTATUS status;
  2876. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  2877. if (powerUpDevice) {
  2878. powerState.DeviceState = PowerDeviceD0;
  2879. status = PoRequestPowerIrp (
  2880. LogicalUnit->DeviceObject,
  2881. IRP_MN_SET_POWER,
  2882. powerState,
  2883. NULL,
  2884. NULL,
  2885. NULL
  2886. );
  2887. ASSERT (NT_SUCCESS(status));
  2888. }
  2889. }
  2890. } // end GetNextLuRequest()
  2891. VOID
  2892. IdeLogTimeoutError(
  2893. IN PFDO_EXTENSION DeviceExtension,
  2894. IN PIRP Irp,
  2895. IN ULONG UniqueId
  2896. )
  2897. /*++
  2898. Routine Description:
  2899. This function logs an error when a request times out.
  2900. Arguments:
  2901. DeviceExtension - Supplies a pointer to the port device extension.
  2902. Irp - Supplies a pointer to the request which timedout.
  2903. UniqueId - Supplies the UniqueId for this error.
  2904. Return Value:
  2905. None.
  2906. Notes:
  2907. The port device extension spinlock should be held when this routine is
  2908. called.
  2909. --*/
  2910. {
  2911. PIO_ERROR_LOG_PACKET errorLogEntry;
  2912. PIO_STACK_LOCATION irpStack;
  2913. PSRB_DATA srbData;
  2914. PSCSI_REQUEST_BLOCK srb;
  2915. irpStack = IoGetCurrentIrpStackLocation(Irp);
  2916. srb = (PSCSI_REQUEST_BLOCK)irpStack->Parameters.Others.Argument1;
  2917. srbData = IdeGetSrbData(DeviceExtension, srb);
  2918. if (!srbData) {
  2919. return;
  2920. }
  2921. errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(DeviceExtension->DeviceObject,
  2922. sizeof(IO_ERROR_LOG_PACKET) + 4 * sizeof(ULONG));
  2923. if (errorLogEntry != NULL) {
  2924. errorLogEntry->ErrorCode = IO_ERR_TIMEOUT;
  2925. errorLogEntry->SequenceNumber = srbData->SequenceNumber;
  2926. errorLogEntry->MajorFunctionCode = irpStack->MajorFunction;
  2927. errorLogEntry->RetryCount = (UCHAR) srbData->ErrorLogRetryCount;
  2928. errorLogEntry->UniqueErrorValue = UniqueId;
  2929. errorLogEntry->FinalStatus = STATUS_SUCCESS;
  2930. errorLogEntry->DumpDataSize = 4 * sizeof(ULONG);
  2931. errorLogEntry->DumpData[0] = srb->PathId;
  2932. errorLogEntry->DumpData[1] = srb->TargetId;
  2933. errorLogEntry->DumpData[2] = srb->Lun;
  2934. errorLogEntry->DumpData[3] = SP_REQUEST_TIMEOUT;
  2935. IoWriteErrorLogEntry(errorLogEntry);
  2936. }
  2937. }
  2938. VOID
  2939. IdeLogResetError(
  2940. IN PFDO_EXTENSION DeviceExtension,
  2941. IN PSCSI_REQUEST_BLOCK Srb,
  2942. IN ULONG UniqueId
  2943. )
  2944. /*++
  2945. Routine Description:
  2946. This function logs an error when the bus is reset.
  2947. Arguments:
  2948. DeviceExtension - Supplies a pointer to the port device extension.
  2949. Srb - Supplies a pointer to the request which timed-out.
  2950. UniqueId - Supplies the UniqueId for this error.
  2951. Return Value:
  2952. None.
  2953. Notes:
  2954. The port device extension spinlock should be held when this routine is
  2955. called.
  2956. --*/
  2957. {
  2958. PIO_ERROR_LOG_PACKET errorLogEntry;
  2959. PIO_STACK_LOCATION irpStack;
  2960. PIRP irp;
  2961. PSRB_DATA srbData;
  2962. ULONG sequenceNumber = 0;
  2963. UCHAR function = 0,
  2964. pathId = 0,
  2965. targetId = 0,
  2966. lun = 0,
  2967. retryCount = 0;
  2968. if (Srb) {
  2969. irp = Srb->OriginalRequest;
  2970. if (irp) {
  2971. irpStack = IoGetCurrentIrpStackLocation(irp);
  2972. function = irpStack->MajorFunction;
  2973. }
  2974. srbData = IdeGetSrbData(DeviceExtension, Srb);
  2975. if (!srbData) {
  2976. return;
  2977. }
  2978. pathId = Srb->PathId;
  2979. targetId = Srb->TargetId;
  2980. lun = Srb->Lun;
  2981. retryCount = (UCHAR) srbData->ErrorLogRetryCount;
  2982. sequenceNumber = srbData->SequenceNumber;
  2983. }
  2984. errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry( DeviceExtension->DeviceObject,
  2985. sizeof(IO_ERROR_LOG_PACKET)
  2986. + 4 * sizeof(ULONG) );
  2987. if (errorLogEntry != NULL) {
  2988. errorLogEntry->ErrorCode = IO_ERR_TIMEOUT;
  2989. errorLogEntry->SequenceNumber = sequenceNumber;
  2990. errorLogEntry->MajorFunctionCode = function;
  2991. errorLogEntry->RetryCount = retryCount;
  2992. errorLogEntry->UniqueErrorValue = UniqueId;
  2993. errorLogEntry->FinalStatus = STATUS_SUCCESS;
  2994. errorLogEntry->DumpDataSize = 4 * sizeof(ULONG);
  2995. errorLogEntry->DumpData[0] = pathId;
  2996. errorLogEntry->DumpData[1] = targetId;
  2997. errorLogEntry->DumpData[2] = lun;
  2998. errorLogEntry->DumpData[3] = SP_REQUEST_TIMEOUT;
  2999. IoWriteErrorLogEntry(errorLogEntry);
  3000. }
  3001. }
  3002. NTSTATUS
  3003. IdeTranslateSrbStatus(
  3004. IN PSCSI_REQUEST_BLOCK Srb
  3005. )
  3006. /*++
  3007. Routine Description:
  3008. This routine translates an srb status into an ntstatus.
  3009. Arguments:
  3010. Srb - Supplies a pointer to the failing Srb.
  3011. Return Value:
  3012. An nt status approprate for the error.
  3013. --*/
  3014. {
  3015. switch (SRB_STATUS(Srb->SrbStatus)) {
  3016. case SRB_STATUS_INVALID_LUN:
  3017. case SRB_STATUS_INVALID_TARGET_ID:
  3018. case SRB_STATUS_NO_DEVICE:
  3019. case SRB_STATUS_NO_HBA:
  3020. return(STATUS_DEVICE_DOES_NOT_EXIST);
  3021. case SRB_STATUS_COMMAND_TIMEOUT:
  3022. case SRB_STATUS_BUS_RESET:
  3023. case SRB_STATUS_TIMEOUT:
  3024. return(STATUS_IO_TIMEOUT);
  3025. case SRB_STATUS_SELECTION_TIMEOUT:
  3026. return(STATUS_DEVICE_NOT_CONNECTED);
  3027. case SRB_STATUS_BAD_FUNCTION:
  3028. case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
  3029. return(STATUS_INVALID_DEVICE_REQUEST);
  3030. case SRB_STATUS_DATA_OVERRUN:
  3031. return(STATUS_BUFFER_OVERFLOW);
  3032. default:
  3033. return(STATUS_IO_DEVICE_ERROR);
  3034. }
  3035. return(STATUS_IO_DEVICE_ERROR);
  3036. }
  3037. BOOLEAN
  3038. IdeResetBusSynchronized (
  3039. PVOID ServiceContext
  3040. )
  3041. /*++
  3042. Routine Description:
  3043. This function resets the bus and sets up the port timer so the reset hold
  3044. flag is clean when necessary.
  3045. Arguments:
  3046. ServiceContext - Supplies a pointer to the reset context which includes a
  3047. pointer to the device extension and the pathid to be reset.
  3048. Return Value:
  3049. TRUE - if the reset succeeds.
  3050. --*/
  3051. {
  3052. PRESET_CONTEXT resetContext = ServiceContext;
  3053. PFDO_EXTENSION deviceExtension;
  3054. PSCSI_REQUEST_BLOCK resetSrbToComplete;
  3055. BOOLEAN goodReset;
  3056. resetSrbToComplete = NULL;
  3057. deviceExtension = resetContext->DeviceExtension;
  3058. //
  3059. // Should never get a reset srb while one is in progress
  3060. //
  3061. if (resetContext->ResetSrb && deviceExtension->ResetSrb) {
  3062. ASSERT (resetContext->ResetSrb == deviceExtension->ResetSrb);
  3063. }
  3064. if (resetContext->NewResetSequence) {
  3065. //
  3066. // a new reset sequence to kill the reset in progress if any
  3067. //
  3068. if (deviceExtension->ResetCallAgain) {
  3069. DebugPrint ((0, "ATAPI: WARNING: Resetting a reset\n"));
  3070. deviceExtension->ResetCallAgain = 0;
  3071. if (deviceExtension->ResetSrb) {
  3072. resetSrbToComplete = deviceExtension->ResetSrb;
  3073. resetSrbToComplete->SrbStatus = SRB_STATUS_ERROR;
  3074. deviceExtension->ResetSrb = NULL;
  3075. }
  3076. }
  3077. deviceExtension->ResetSrb = resetContext->ResetSrb;
  3078. }
  3079. goodReset = AtapiResetController (
  3080. deviceExtension->HwDeviceExtension,
  3081. resetContext->PathId,
  3082. &deviceExtension->ResetCallAgain);
  3083. //
  3084. // Set the reset hold flag and start the counter if the reset is not done
  3085. //
  3086. if ((goodReset) && (deviceExtension->ResetCallAgain)) {
  3087. deviceExtension->InterruptData.InterruptFlags |= PD_RESET_HOLD;
  3088. deviceExtension->PortTimeoutCounter = PD_TIMER_RESET_HOLD_TIME;
  3089. } else {
  3090. CLRMASK (deviceExtension->InterruptData.InterruptFlags, PD_RESET_HOLD);
  3091. deviceExtension->PortTimeoutCounter = PD_TIMER_STOPPED;
  3092. if (deviceExtension->ResetSrb) {
  3093. resetSrbToComplete = deviceExtension->ResetSrb;
  3094. deviceExtension->ResetSrb = NULL;
  3095. }
  3096. if (resetSrbToComplete) {
  3097. if (goodReset) {
  3098. resetSrbToComplete->SrbStatus = SRB_STATUS_SUCCESS;
  3099. } else {
  3100. resetSrbToComplete->SrbStatus = SRB_STATUS_ERROR;
  3101. }
  3102. }
  3103. if (goodReset) {
  3104. IdePortNotification(IdeResetDetected,
  3105. deviceExtension->HwDeviceExtension,
  3106. resetSrbToComplete);
  3107. }
  3108. if (deviceExtension->InterruptData.InterruptFlags & PD_HELD_REQUEST) {
  3109. //
  3110. // Clear the held request flag and restart the request.
  3111. //
  3112. CLRMASK (deviceExtension->InterruptData.InterruptFlags, PD_HELD_REQUEST);
  3113. IdeStartIoSynchronized(deviceExtension->DeviceObject);
  3114. }
  3115. }
  3116. if (resetSrbToComplete) {
  3117. IdePortNotification(IdeRequestComplete,
  3118. deviceExtension->HwDeviceExtension,
  3119. resetSrbToComplete);
  3120. IdePortNotification(IdeNextRequest,
  3121. deviceExtension->HwDeviceExtension,
  3122. NULL);
  3123. }
  3124. //
  3125. // Check for miniport work requests.
  3126. //
  3127. if (deviceExtension->InterruptData.InterruptFlags & PD_NOTIFICATION_REQUIRED) {
  3128. //
  3129. // Queue a DPC.
  3130. //
  3131. IoRequestDpc(deviceExtension->DeviceObject, NULL, NULL);
  3132. }
  3133. return(TRUE);
  3134. }
  3135. VOID
  3136. IdeProcessCompletedRequest(
  3137. IN PFDO_EXTENSION DeviceExtension,
  3138. IN PSRB_DATA SrbData,
  3139. OUT PBOOLEAN CallStartIo
  3140. )
  3141. /*++
  3142. Routine Description:
  3143. This routine processes a request which has completed. It completes any
  3144. pending transfers, releases the adapter objects and map registers when
  3145. necessary. It deallocates any resources allocated for the request.
  3146. It processes the return status, by requeueing busy request, requesting
  3147. sense information or logging an error.
  3148. Arguments:
  3149. DeviceExtension - Supplies a pointer to the device extension for the
  3150. adapter data.
  3151. SrbData - Supplies a pointer to the SRB data block to be completed.
  3152. CallStartIo - This value is set if the start I/O routine needs to be
  3153. called.
  3154. Return Value:
  3155. None.
  3156. --*/
  3157. {
  3158. PLOGICAL_UNIT_EXTENSION logicalUnit;
  3159. PSCSI_REQUEST_BLOCK srb;
  3160. PIO_ERROR_LOG_PACKET errorLogEntry;
  3161. ULONG sequenceNumber;
  3162. LONG interlockResult;
  3163. PIRP irp;
  3164. PIO_STACK_LOCATION irpStack;
  3165. PHW_DEVICE_EXTENSION hwDeviceExtension = DeviceExtension->HwDeviceExtension;
  3166. ASSERT(SrbData->CurrentSrb);
  3167. srb = SrbData->CurrentSrb;
  3168. irp = srb->OriginalRequest;
  3169. DebugPrint((2,"CompletedRequest: Irp 0x%8x Srb 0x%8x DataBuf 0x%8x Len 0x%8x\n", irp, srb, srb->DataBuffer, srb->DataTransferLength));
  3170. #ifdef IDE_MULTIPLE_IRP_COMPLETE_REQUESTS_CHECK
  3171. if (irp->CurrentLocation > (CCHAR) (irp->StackCount + 1)) {
  3172. KeBugCheckEx( MULTIPLE_IRP_COMPLETE_REQUESTS, (ULONG_PTR) irp, (ULONG_PTR) srb, 0, 0 );
  3173. }
  3174. #endif // IDE_MULTIPLE_IRP_COMPLETE_REQUESTS_CHECK
  3175. irpStack = IoGetCurrentIrpStackLocation(irp);
  3176. //
  3177. // Get logical unit extension for this request.
  3178. //
  3179. logicalUnit = IDEPORT_GET_LUNEXT_IN_IRP (irpStack);
  3180. //
  3181. // If miniport needs mapped system addresses, the the
  3182. // data buffer address in the SRB must be restored to
  3183. // original unmapped virtual address. Ensure that this request requires
  3184. // a data transfer.
  3185. //
  3186. if (srb->SrbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) {
  3187. if (!SRB_USES_DMA(srb)) {
  3188. if (irp->MdlAddress) {
  3189. //
  3190. // If an IRP is for a transfer larger than a miniport driver
  3191. // can handle, the request is broken up into multiple smaller
  3192. // requests. Each request uses the same MDL and the data
  3193. // buffer address field in the SRB may not be at the
  3194. // beginning of the memory described by the MDL.
  3195. //
  3196. srb->DataBuffer = (PCCHAR)MmGetMdlVirtualAddress(irp->MdlAddress) +
  3197. ((PCCHAR)srb->DataBuffer - SrbData->SrbDataOffset);
  3198. //
  3199. // Since this driver driver did programmaged I/O then the buffer
  3200. // needs to flushed if this an data-in transfer.
  3201. //
  3202. if (srb->SrbFlags & SRB_FLAGS_DATA_IN) {
  3203. KeFlushIoBuffers(irp->MdlAddress,
  3204. TRUE,
  3205. FALSE);
  3206. }
  3207. if (SrbData->Flags & SRB_DATA_RESERVED_PAGES) {
  3208. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  3209. IdeUnmapReservedMapping(DeviceExtension, SrbData, irp->MdlAddress);
  3210. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3211. }
  3212. }
  3213. }
  3214. }
  3215. //
  3216. // Clear the current request.
  3217. //
  3218. SrbData->CurrentSrb = NULL;
  3219. //
  3220. // If the no diconnect flag was set for this SRB, then check to see
  3221. // if IoStartNextPacket must be called.
  3222. //
  3223. if (srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) {
  3224. //
  3225. // Acquire the spinlock to protect the flags strcuture.
  3226. //
  3227. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  3228. //
  3229. // Set the disconnect running flag and check the busy flag.
  3230. //
  3231. DeviceExtension->Flags |= PD_DISCONNECT_RUNNING;
  3232. //
  3233. // The interrupt flags are checked unsynchonized. This works because
  3234. // the RESET_HOLD flag is cleared with the spinlock held and the
  3235. // counter is only set with the spinlock held. So the only case where
  3236. // there is a problem is is a reset occurs before this code get run,
  3237. // but this code runs before the timer is set for a reset hold;
  3238. // the timer will soon set for the new value.
  3239. //
  3240. if (!(DeviceExtension->InterruptData.InterruptFlags & PD_RESET_HOLD)) {
  3241. //
  3242. // The miniport is ready for the next request and there is not a
  3243. // pending reset hold, so clear the port timer.
  3244. //
  3245. DeviceExtension->PortTimeoutCounter = PD_TIMER_STOPPED;
  3246. }
  3247. //
  3248. // Release the spinlock.
  3249. //
  3250. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3251. if (!(DeviceExtension->Flags & PD_DEVICE_IS_BUSY) &&
  3252. !*CallStartIo &&
  3253. !(DeviceExtension->Flags & PD_PENDING_DEVICE_REQUEST)) {
  3254. //
  3255. // The busy flag is clear so the miniport has requested the
  3256. // next request. Call IoStartNextPacket.
  3257. //
  3258. IoStartNextPacket(DeviceExtension->DeviceObject, FALSE);
  3259. }
  3260. }
  3261. //
  3262. // Check if scatter/gather list came from pool.
  3263. //
  3264. if (srb->SrbFlags & SRB_FLAGS_SGLIST_FROM_POOL) {
  3265. CLRMASK (srb->SrbFlags, SRB_FLAGS_SGLIST_FROM_POOL);
  3266. }
  3267. //
  3268. // Acquire the spinlock to protect the flags structure,
  3269. // and the free of the srb extension.
  3270. //
  3271. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  3272. //
  3273. // Move bytes transfered to IRP.
  3274. //
  3275. irp->IoStatus.Information = srb->DataTransferLength;
  3276. //
  3277. // Save the sequence number in case an error needs to be logged later.
  3278. //
  3279. sequenceNumber = SrbData->SequenceNumber;
  3280. SrbData->SequenceNumber = 0;
  3281. SrbData->ErrorLogRetryCount = 0;
  3282. #if DBG
  3283. SrbData = NULL;
  3284. #endif
  3285. if (DeviceExtension->Flags & PD_PENDING_DEVICE_REQUEST) {
  3286. //
  3287. // The start I/O routine needs to be called because it could not
  3288. // allocate an srb extension. Clear the pending flag and note
  3289. // that it needs to be called later.
  3290. //
  3291. CLRMASK (DeviceExtension->Flags, PD_PENDING_DEVICE_REQUEST);
  3292. *CallStartIo = TRUE;
  3293. }
  3294. //
  3295. // If success then start next packet.
  3296. // Not starting packet effectively
  3297. // freezes the queue.
  3298. //
  3299. if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS) {
  3300. ULONG srbFlags;
  3301. #if DBG
  3302. PVOID tag = irp;
  3303. #endif
  3304. irp->IoStatus.Status = STATUS_SUCCESS;
  3305. //
  3306. // save the srbFlags for later user
  3307. //
  3308. srbFlags = srb->SrbFlags;
  3309. if (srb->Function == SRB_FUNCTION_ATA_POWER_PASS_THROUGH) {
  3310. //
  3311. // must complete power irp before starting a new request
  3312. //
  3313. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3314. //
  3315. // Decrement the logUnitExtension reference count
  3316. //
  3317. UnrefLogicalUnitExtensionWithTag(
  3318. DeviceExtension,
  3319. logicalUnit,
  3320. tag
  3321. );
  3322. IoCompleteRequest(irp, IO_DISK_INCREMENT);
  3323. irp = NULL;
  3324. //
  3325. // we had a device state transition...restart the lu queue
  3326. //
  3327. KeAcquireSpinLockAtDpcLevel(&DeviceExtension->SpinLock);
  3328. GetNextLuRequest(DeviceExtension, logicalUnit);
  3329. } else {
  3330. //
  3331. // If the queue is being bypassed then keep the queue frozen.
  3332. // If there are outstanding requests as indicated by the timer
  3333. // being active then don't start the then next request.
  3334. //
  3335. if (!(srbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) &&
  3336. logicalUnit->RequestTimeoutCounter == PD_TIMER_STOPPED) {
  3337. //
  3338. // This is a normal request start the next packet.
  3339. //
  3340. GetNextLuRequest(DeviceExtension, logicalUnit);
  3341. } else {
  3342. //
  3343. // Release the spinlock.
  3344. //
  3345. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3346. }
  3347. }
  3348. DebugPrint((2,
  3349. "IdeProcessCompletedRequests: Iocompletion IRP %lx\n",
  3350. irp));
  3351. //
  3352. // Note that the retry count and sequence number are not cleared
  3353. // for completed packets which were generated by the port driver.
  3354. //
  3355. if (irp) {
  3356. //
  3357. // Decrement the logUnitExtension reference count
  3358. //
  3359. UnrefLogicalUnitExtensionWithTag(
  3360. DeviceExtension,
  3361. logicalUnit,
  3362. tag
  3363. );
  3364. IoCompleteRequest(irp, IO_DISK_INCREMENT);
  3365. }
  3366. return;
  3367. }
  3368. //
  3369. // Set IRP status. Class drivers will reset IRP status based
  3370. // on request sense if error.
  3371. //
  3372. irp->IoStatus.Status = IdeTranslateSrbStatus(srb);
  3373. DebugPrint((2, "IdeProcessCompletedRequests: Queue frozen TID %d\n",
  3374. srb->TargetId));
  3375. if ((srb->SrbStatus == SRB_STATUS_TIMEOUT) ||
  3376. (srb->SrbStatus == SRB_STATUS_BUS_RESET)) {
  3377. if (SRB_USES_DMA(srb)) {
  3378. ULONG errorCount;
  3379. //
  3380. // retry with PIO
  3381. //
  3382. DebugPrint ((DBG_ALWAYS, "ATAPI: retrying dma srb 0x%x with pio\n", srb));
  3383. MARK_SRB_AS_PIO_CANDIDATE(srb);
  3384. srb->SrbStatus = SRB_STATUS_PENDING;
  3385. srb->ScsiStatus = 0;
  3386. if (srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) {
  3387. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3388. //
  3389. // iostart the fdo
  3390. //
  3391. IoStartPacket(DeviceExtension->DeviceObject, irp, (PULONG)NULL, NULL);
  3392. } else {
  3393. KeInsertByKeyDeviceQueue(&logicalUnit->DeviceObject->DeviceQueue,
  3394. &irp->Tail.Overlay.DeviceQueueEntry,
  3395. srb->QueueSortKey);
  3396. GetNextLuRequest(DeviceExtension, logicalUnit);
  3397. }
  3398. //
  3399. // spinlock is released.
  3400. //
  3401. //
  3402. // we got an error using DMA
  3403. //
  3404. errorCount = InterlockedIncrement(&logicalUnit->DmaTransferTimeoutCount);
  3405. if (errorCount == PDO_DMA_TIMEOUT_LIMIT) {
  3406. ERROR_LOG_ENTRY errorLogEntry;
  3407. ULONG i;
  3408. //
  3409. // Timeout errors need not be device specific. So no need to
  3410. // update the hall of shame
  3411. //
  3412. errorLogEntry.ErrorCode = SP_PROTOCOL_ERROR;
  3413. errorLogEntry.MajorFunctionCode = IRP_MJ_SCSI;
  3414. errorLogEntry.PathId = srb->PathId;
  3415. errorLogEntry.TargetId = srb->TargetId;
  3416. errorLogEntry.Lun = srb->Lun;
  3417. errorLogEntry.UniqueId = ERRLOGID_TOO_MANY_DMA_TIMEOUT;
  3418. errorLogEntry.ErrorLogRetryCount = errorCount;
  3419. errorLogEntry.SequenceNumber = 0;
  3420. LogErrorEntry(
  3421. DeviceExtension,
  3422. &errorLogEntry
  3423. );
  3424. //
  3425. // disable DMA
  3426. //
  3427. hwDeviceExtension->DeviceParameters[srb->TargetId].TransferModeMask |= DMA_SUPPORT;
  3428. DebugPrint ((DBG_ALWAYS,
  3429. "ATAPI ERROR: 0x%x target %d has too many DMA timeout, falling back to PIO\n",
  3430. DeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  3431. srb->TargetId
  3432. ));
  3433. //
  3434. // rescan the bus to update transfer mode
  3435. //
  3436. #if defined (BUS_CHECK_ON_DMA_ERROR)
  3437. IoInvalidateDeviceRelations (
  3438. DeviceExtension->AttacheePdo,
  3439. BusRelations
  3440. );
  3441. #endif // BUS_CHECK_ON_DMA_ERROR
  3442. }
  3443. return;
  3444. } else {
  3445. if ((!TestForEnumProbing(srb)) &&
  3446. (srb->Function != SRB_FUNCTION_ATA_POWER_PASS_THROUGH) &&
  3447. (srb->Function != SRB_FUNCTION_ATA_PASS_THROUGH)) {
  3448. ULONG errorCount;
  3449. ULONG errorCountLimit;
  3450. //
  3451. // Check if were trying the flush the device cache
  3452. //
  3453. if ((srb->Function == SRB_FUNCTION_FLUSH) ||
  3454. (srb->Function == SRB_FUNCTION_SHUTDOWN) ||
  3455. (srb->Cdb[0] == SCSIOP_SYNCHRONIZE_CACHE)) {
  3456. errorCount = InterlockedIncrement(&logicalUnit->FlushCacheTimeoutCount);
  3457. DebugPrint((1,
  3458. "FlushCacheTimeout incremented to 0x%x\n",
  3459. errorCount
  3460. ));
  3461. //
  3462. // Disable flush on IDE devices
  3463. //
  3464. if (errorCount >= PDO_FLUSH_TIMEOUT_LIMIT ) {
  3465. hwDeviceExtension->
  3466. DeviceParameters[srb->TargetId].IdeFlushCommand = IDE_COMMAND_NO_FLUSH;
  3467. #ifdef ENABLE_48BIT_LBA
  3468. hwDeviceExtension->
  3469. DeviceParameters[srb->TargetId].IdeFlushCommandExt = IDE_COMMAND_NO_FLUSH;
  3470. #endif
  3471. }
  3472. ASSERT (errorCount <= PDO_FLUSH_TIMEOUT_LIMIT);
  3473. //
  3474. // looks like the device doesn't support flush cache
  3475. //
  3476. srb->SrbStatus = SRB_STATUS_SUCCESS;
  3477. irp->IoStatus.Status = STATUS_SUCCESS;
  3478. } else {
  3479. errorCount = InterlockedIncrement(&logicalUnit->ConsecutiveTimeoutCount);
  3480. DebugPrint ((DBG_ALWAYS, "0x%x target %d has 0x%x timeout errors so far\n",
  3481. logicalUnit->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  3482. logicalUnit->TargetId,
  3483. errorCount));
  3484. if (errorCount == PDO_CONSECUTIVE_TIMEOUT_WARNING_LIMIT) {
  3485. //
  3486. // the device not looking good
  3487. // make sure it is still there
  3488. //
  3489. IoInvalidateDeviceRelations (
  3490. DeviceExtension->AttacheePdo,
  3491. BusRelations
  3492. );
  3493. }
  3494. if (logicalUnit->PagingPathCount) {
  3495. errorCountLimit = PDO_CONSECUTIVE_PAGING_TIMEOUT_LIMIT;
  3496. } else {
  3497. errorCountLimit = PDO_CONSECUTIVE_TIMEOUT_LIMIT;
  3498. }
  3499. if (errorCount >= errorCountLimit) {
  3500. DebugPrint ((DBG_ALWAYS, "0x%x target %d has too many timeout. it is a goner...\n",
  3501. logicalUnit->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  3502. logicalUnit->TargetId));
  3503. //
  3504. // looks like the device is dead.
  3505. //
  3506. KeAcquireSpinLockAtDpcLevel(&logicalUnit->PdoSpinLock);
  3507. SETMASK (logicalUnit->PdoState, PDOS_DEADMEAT);
  3508. IdeLogDeadMeatReason( logicalUnit->DeadmeatRecord.Reason,
  3509. tooManyTimeout
  3510. );
  3511. KeReleaseSpinLockFromDpcLevel(&logicalUnit->PdoSpinLock);
  3512. IoInvalidateDeviceRelations (
  3513. DeviceExtension->AttacheePdo,
  3514. BusRelations
  3515. );
  3516. }
  3517. }
  3518. }
  3519. }
  3520. } else {
  3521. //
  3522. // reset error count
  3523. //
  3524. InterlockedExchange(&logicalUnit->ConsecutiveTimeoutCount, 0);
  3525. }
  3526. if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_PARITY_ERROR) {
  3527. ULONG errorCount;
  3528. errorCount = InterlockedIncrement(&logicalUnit->CrcErrorCount);
  3529. if (errorCount == PDO_UDMA_CRC_ERROR_LIMIT) {
  3530. ERROR_LOG_ENTRY errorLogEntry;
  3531. ULONG xferMode;
  3532. errorLogEntry.ErrorCode = SP_BUS_PARITY_ERROR;
  3533. errorLogEntry.MajorFunctionCode = IRP_MJ_SCSI;
  3534. errorLogEntry.PathId = srb->PathId;
  3535. errorLogEntry.TargetId = srb->TargetId;
  3536. errorLogEntry.Lun = srb->Lun;
  3537. errorLogEntry.UniqueId = ERRLOGID_TOO_MANY_CRC_ERROR;
  3538. errorLogEntry.ErrorLogRetryCount = errorCount;
  3539. errorLogEntry.SequenceNumber = 0;
  3540. LogErrorEntry(
  3541. DeviceExtension,
  3542. &errorLogEntry
  3543. );
  3544. //
  3545. //Procure the selected transfer mode again.
  3546. //
  3547. GetHighestDMATransferMode(hwDeviceExtension->DeviceParameters[srb->TargetId].TransferModeSelected,
  3548. xferMode);
  3549. //
  3550. //Gradual degradation.
  3551. //
  3552. if (xferMode > UDMA0) {
  3553. hwDeviceExtension->DeviceParameters[srb->TargetId].TransferModeMask |= (1 << xferMode);
  3554. } else if (xferMode == UDMA0) {
  3555. // Don't use MWDMA and SWDMA
  3556. hwDeviceExtension->DeviceParameters[srb->TargetId].TransferModeMask |= DMA_SUPPORT;
  3557. }
  3558. DebugPrint ((DBG_ALWAYS,
  3559. "ATAPI ERROR: 0x%x target %d has too many crc error, degrading to a lower DMA mode\n",
  3560. DeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  3561. srb->TargetId
  3562. ));
  3563. //
  3564. // rescan the bus to update transfer mode
  3565. //
  3566. IoInvalidateDeviceRelations (
  3567. DeviceExtension->AttacheePdo,
  3568. BusRelations
  3569. );
  3570. }
  3571. }
  3572. if ((srb->ScsiStatus == SCSISTAT_BUSY ||
  3573. srb->SrbStatus == SRB_STATUS_BUSY ||
  3574. srb->ScsiStatus == SCSISTAT_QUEUE_FULL) &&
  3575. !(srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE)) {
  3576. //
  3577. // Perform busy processing if a busy type status was returned and this
  3578. // is not a by-pass request.
  3579. //
  3580. DebugPrint((1,
  3581. "SCSIPORT: Busy SRB status %x, SCSI status %x)\n",
  3582. srb->SrbStatus,
  3583. srb->ScsiStatus));
  3584. //
  3585. // If there is already a pending busy request or the queue is frozen
  3586. // then just requeue this request.
  3587. //
  3588. if (logicalUnit->LuFlags & (PD_LOGICAL_UNIT_IS_BUSY | PD_QUEUE_FROZEN)) {
  3589. DebugPrint((1,
  3590. "IdeProcessCompletedRequest: Requeuing busy request\n"));
  3591. srb->SrbStatus = SRB_STATUS_PENDING;
  3592. srb->ScsiStatus = 0;
  3593. if (!KeInsertByKeyDeviceQueue(&logicalUnit->DeviceObject->DeviceQueue,
  3594. &irp->Tail.Overlay.DeviceQueueEntry,
  3595. srb->QueueSortKey)) {
  3596. //
  3597. // This should never occur since there is a busy request.
  3598. //
  3599. srb->SrbStatus = SRB_STATUS_ERROR;
  3600. srb->ScsiStatus = SCSISTAT_BUSY;
  3601. ASSERT(FALSE);
  3602. goto BusyError;
  3603. }
  3604. //
  3605. // Release the spinlock.
  3606. //
  3607. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3608. } else if (logicalUnit->RetryCount++ < BUSY_RETRY_COUNT) {
  3609. //
  3610. // If busy status is returned, then indicate that the logical
  3611. // unit is busy. The timeout code will restart the request
  3612. // when it fires. Reset the status to pending.
  3613. //
  3614. srb->SrbStatus = SRB_STATUS_PENDING;
  3615. srb->ScsiStatus = 0;
  3616. logicalUnit->LuFlags |= PD_LOGICAL_UNIT_IS_BUSY;
  3617. logicalUnit->BusyRequest = irp;
  3618. if (logicalUnit->RetryCount == (BUSY_RETRY_COUNT/2) ) {
  3619. RESET_CONTEXT resetContext;
  3620. DebugPrint ((0,
  3621. "ATAPI: PDO 0x%x 0x%x seems to be DEAD. try a reset to bring it back.\n",
  3622. logicalUnit, logicalUnit->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress
  3623. ));
  3624. resetContext.DeviceExtension = DeviceExtension;
  3625. resetContext.PathId = srb->PathId;
  3626. resetContext.NewResetSequence = TRUE;
  3627. resetContext.ResetSrb = NULL;
  3628. KeSynchronizeExecution(DeviceExtension->InterruptObject,
  3629. IdeResetBusSynchronized,
  3630. &resetContext);
  3631. #if DBG
  3632. IdeDebugHungControllerCounter = 0;
  3633. #endif // DBG
  3634. }
  3635. //
  3636. // Release the spinlock.
  3637. //
  3638. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3639. } else {
  3640. BusyError:
  3641. //
  3642. // Indicate the queue is frozen.
  3643. //
  3644. if (!(srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE)) {
  3645. srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
  3646. logicalUnit->LuFlags |= PD_QUEUE_FROZEN;
  3647. }
  3648. //#if DBG
  3649. // if (logicalUnit->PdoState & PDOS_DEADMEAT) {
  3650. // DbgBreakPoint();
  3651. // }
  3652. //#endif
  3653. //
  3654. // Release the spinlock. Start the next request.
  3655. //
  3656. if (!(srb->SrbFlags & SRB_FLAGS_BYPASS_FROZEN_QUEUE) &&
  3657. logicalUnit->RequestTimeoutCounter == PD_TIMER_STOPPED) {
  3658. //
  3659. // This is a normal request start the next packet.
  3660. //
  3661. GetNextLuRequest(DeviceExtension, logicalUnit);
  3662. } else {
  3663. //
  3664. // Release the spinlock.
  3665. //
  3666. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3667. }
  3668. if (!TestForEnumProbing(srb)) {
  3669. //
  3670. // Log an a timeout erorr if we are not probing during bus-renum.
  3671. //
  3672. errorLogEntry = (PIO_ERROR_LOG_PACKET)
  3673. IoAllocateErrorLogEntry(DeviceExtension->DeviceObject,
  3674. sizeof(IO_ERROR_LOG_PACKET) + 4 * sizeof(ULONG));
  3675. if (errorLogEntry != NULL) {
  3676. errorLogEntry->ErrorCode = IO_ERR_NOT_READY;
  3677. errorLogEntry->SequenceNumber = sequenceNumber;
  3678. errorLogEntry->MajorFunctionCode =
  3679. IoGetCurrentIrpStackLocation(irp)->MajorFunction;
  3680. errorLogEntry->RetryCount = logicalUnit->RetryCount;
  3681. errorLogEntry->UniqueErrorValue = 259;
  3682. errorLogEntry->FinalStatus = STATUS_DEVICE_NOT_READY;
  3683. errorLogEntry->DumpDataSize = 5 * sizeof(ULONG);
  3684. errorLogEntry->DumpData[0] = srb->PathId;
  3685. errorLogEntry->DumpData[1] = srb->TargetId;
  3686. errorLogEntry->DumpData[2] = srb->Lun;
  3687. errorLogEntry->DumpData[3] = srb->ScsiStatus;
  3688. errorLogEntry->DumpData[4] = SP_REQUEST_TIMEOUT;
  3689. IoWriteErrorLogEntry(errorLogEntry);
  3690. }
  3691. }
  3692. irp->IoStatus.Status = STATUS_DEVICE_NOT_READY;
  3693. //
  3694. // Decrement the logUnitExtension reference count
  3695. //
  3696. UnrefLogicalUnitExtensionWithTag(
  3697. DeviceExtension,
  3698. logicalUnit,
  3699. irp
  3700. );
  3701. IoCompleteRequest(irp, IO_DISK_INCREMENT);
  3702. }
  3703. return;
  3704. }
  3705. //
  3706. // If the request sense data is valid, or none is needed and this request
  3707. // is not going to freeze the queue, then start the next request for this
  3708. // logical unit if it is idle.
  3709. //
  3710. if (!NEED_REQUEST_SENSE(srb) && srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE) {
  3711. if (logicalUnit->RequestTimeoutCounter == PD_TIMER_STOPPED) {
  3712. GetNextLuRequest(DeviceExtension, logicalUnit);
  3713. //
  3714. // The spinlock is released by GetNextLuRequest.
  3715. //
  3716. } else {
  3717. //
  3718. // Release the spinlock.
  3719. //
  3720. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3721. }
  3722. } else {
  3723. //
  3724. // NOTE: This will also freeze the queue. For a case where there
  3725. // is no request sense.
  3726. //
  3727. // if (srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE) {
  3728. // DebugPrint ((DBG_ALWAYS, "BAD BAD BAD: Freezing queue even with a no_queue_freeze request srb = 0x%x\n", srb));
  3729. // }
  3730. if (!(srb->SrbFlags & SRB_FLAGS_NO_QUEUE_FREEZE)) {
  3731. srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
  3732. logicalUnit->LuFlags |= PD_QUEUE_FROZEN;
  3733. }
  3734. //#if DBG
  3735. // if (logicalUnit->PdoState & PDOS_DEADMEAT) {
  3736. // DbgBreakPoint();
  3737. // }
  3738. //#endif
  3739. //
  3740. // Determine if a REQUEST SENSE command needs to be done.
  3741. // Check that a CHECK_CONDITION was received, an autosense has not
  3742. // been done already, and that autosense has been requested.
  3743. //
  3744. if (NEED_REQUEST_SENSE(srb)) {
  3745. srb->SrbStatus |= SRB_STATUS_QUEUE_FROZEN;
  3746. logicalUnit->LuFlags |= PD_QUEUE_FROZEN;
  3747. //
  3748. // If a request sense is going to be issued then any busy
  3749. // requests must be requeue so that the time out routine does
  3750. // not restart them while the request sense is being executed.
  3751. //
  3752. if (logicalUnit->LuFlags & PD_LOGICAL_UNIT_IS_BUSY) {
  3753. DebugPrint((1, "IdeProcessCompletedRequest: Requeueing busy request to allow request sense.\n"));
  3754. if (!KeInsertByKeyDeviceQueue(
  3755. &logicalUnit->DeviceObject->DeviceQueue,
  3756. &logicalUnit->BusyRequest->Tail.Overlay.DeviceQueueEntry,
  3757. srb->QueueSortKey)) {
  3758. //
  3759. // This should never occur since there is a busy request.
  3760. // Complete the current request without request sense
  3761. // informaiton.
  3762. //
  3763. ASSERT(FALSE);
  3764. DebugPrint((3, "IdeProcessCompletedRequests: Iocompletion IRP %lx\n", irp ));
  3765. //
  3766. // Release the spinlock.
  3767. //
  3768. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3769. //
  3770. // Decrement the logUnitExtension reference count
  3771. //
  3772. UnrefLogicalUnitExtensionWithTag(
  3773. DeviceExtension,
  3774. logicalUnit,
  3775. irp
  3776. );
  3777. IoCompleteRequest(irp, IO_DISK_INCREMENT);
  3778. return;
  3779. }
  3780. //
  3781. // Clear the busy flag.
  3782. //
  3783. CLRMASK (logicalUnit->LuFlags, PD_LOGICAL_UNIT_IS_BUSY | PD_QUEUE_IS_FULL);
  3784. }
  3785. //
  3786. // Release the spinlock.
  3787. //
  3788. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3789. //
  3790. // Call IssueRequestSense and it will complete the request
  3791. // after the REQUEST SENSE completes.
  3792. //
  3793. IssueRequestSense(logicalUnit, srb);
  3794. return;
  3795. }
  3796. //
  3797. // Release the spinlock.
  3798. //
  3799. KeReleaseSpinLockFromDpcLevel(&DeviceExtension->SpinLock);
  3800. }
  3801. //
  3802. // Decrement the logUnitExtension reference count
  3803. //
  3804. UnrefLogicalUnitExtensionWithTag(
  3805. DeviceExtension,
  3806. logicalUnit,
  3807. irp
  3808. );
  3809. IoCompleteRequest(irp, IO_DISK_INCREMENT);
  3810. }
  3811. PSRB_DATA
  3812. IdeGetSrbData(
  3813. IN PFDO_EXTENSION DeviceExtension,
  3814. IN PSCSI_REQUEST_BLOCK Srb
  3815. )
  3816. /*++
  3817. Routine Description:
  3818. This function returns the SRB data for the addressed unit.
  3819. Arguments:
  3820. DeviceExtension - Supplies a pointer to the device extension.
  3821. Srb - Supplies the scsi request block
  3822. Return Value:
  3823. Returns a pointer to the SRB data. NULL is returned if the address is not
  3824. valid.
  3825. --*/
  3826. {
  3827. PIRP irp;
  3828. PIO_STACK_LOCATION irpStack;
  3829. PLOGICAL_UNIT_EXTENSION logicalUnit;
  3830. irp = Srb->OriginalRequest;
  3831. if (irp == NULL) {
  3832. return NULL;
  3833. }
  3834. irpStack = IoGetCurrentIrpStackLocation(irp);
  3835. logicalUnit = IDEPORT_GET_LUNEXT_IN_IRP (irpStack);
  3836. if (logicalUnit == NULL) {
  3837. return NULL;
  3838. }
  3839. return &logicalUnit->SrbData;
  3840. }
  3841. VOID
  3842. IdeCompleteRequest(
  3843. IN PFDO_EXTENSION DeviceExtension,
  3844. IN PSRB_DATA SrbData,
  3845. IN UCHAR SrbStatus
  3846. )
  3847. /*++
  3848. Routine Description:
  3849. The routine completes the specified request.
  3850. Arguments:
  3851. DeviceExtension - Supplies a pointer to the device extension.
  3852. SrbData - Supplies a pointer to the SrbData for the request to be
  3853. completed.
  3854. Return Value:
  3855. None.
  3856. --*/
  3857. {
  3858. PSCSI_REQUEST_BLOCK srb;
  3859. //
  3860. // Make sure there is a current request.
  3861. //
  3862. ASSERT(SrbData->CurrentSrb);
  3863. srb = SrbData->CurrentSrb;
  3864. if (srb == NULL || !(srb->SrbFlags & SRB_FLAGS_IS_ACTIVE)) {
  3865. return;
  3866. }
  3867. //
  3868. // Update SRB status.
  3869. //
  3870. srb->SrbStatus = SrbStatus;
  3871. //
  3872. // Indicate no bytes transferred.
  3873. //
  3874. if (!SRB_USES_DMA(srb)) {
  3875. srb->DataTransferLength = 0;
  3876. } else {
  3877. // if we are doing DMA, preserve DataTransferLength.
  3878. // so retry will know how many bytes to transfer
  3879. }
  3880. //
  3881. // Call notification routine.
  3882. //
  3883. IdePortNotification(IdeRequestComplete,
  3884. (PVOID)(DeviceExtension + 1),
  3885. srb);
  3886. }
  3887. NTSTATUS
  3888. IdeSendMiniPortIoctl(
  3889. IN PFDO_EXTENSION DeviceExtension,
  3890. IN PIRP RequestIrp
  3891. )
  3892. /*++
  3893. Routine Description:
  3894. This function sends a miniport ioctl to the miniport driver.
  3895. It creates an srb which is processed normally by the port driver.
  3896. This call is synchronous.
  3897. Arguments:
  3898. DeviceExtension - Supplies a pointer the SCSI adapter device extension.
  3899. RequestIrp - Supplies a pointe to the Irp which made the original request.
  3900. Return Value:
  3901. Returns a status indicating the success or failure of the operation.
  3902. --*/
  3903. {
  3904. PIRP irp;
  3905. PIO_STACK_LOCATION irpStack;
  3906. PSRB_IO_CONTROL srbControl;
  3907. SCSI_REQUEST_BLOCK srb;
  3908. KEVENT event;
  3909. LARGE_INTEGER startingOffset;
  3910. IO_STATUS_BLOCK ioStatusBlock;
  3911. PLOGICAL_UNIT_EXTENSION logicalUnit;
  3912. ULONG outputLength;
  3913. ULONG length;
  3914. ULONG target;
  3915. IDE_PATH_ID pathId;
  3916. PAGED_CODE();
  3917. startingOffset.QuadPart = (LONGLONG) 1;
  3918. DebugPrint((3,"IdeSendMiniPortIoctl: Enter routine\n"));
  3919. //
  3920. // Get a pointer to the control block.
  3921. //
  3922. irpStack = IoGetCurrentIrpStackLocation(RequestIrp);
  3923. srbControl = RequestIrp->AssociatedIrp.SystemBuffer;
  3924. RequestIrp->IoStatus.Information = 0;
  3925. //
  3926. // Validiate the user buffer.
  3927. //
  3928. if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SRB_IO_CONTROL)){
  3929. RequestIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  3930. return(STATUS_INVALID_PARAMETER);
  3931. }
  3932. if (srbControl->HeaderLength != sizeof(SRB_IO_CONTROL)) {
  3933. RequestIrp->IoStatus.Status = STATUS_REVISION_MISMATCH;
  3934. return(STATUS_REVISION_MISMATCH);
  3935. }
  3936. length = srbControl->HeaderLength + srbControl->Length;
  3937. if ((length < srbControl->HeaderLength) ||
  3938. (length < srbControl->Length)) {
  3939. //
  3940. // total length overflows a ULONG
  3941. //
  3942. return(STATUS_INVALID_PARAMETER);
  3943. }
  3944. outputLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  3945. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < length &&
  3946. irpStack->Parameters.DeviceIoControl.InputBufferLength < length ) {
  3947. RequestIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  3948. return(STATUS_BUFFER_TOO_SMALL);
  3949. }
  3950. //
  3951. // Set the logical unit addressing to the first logical unit. This is
  3952. // merely used for addressing purposes.
  3953. //
  3954. pathId.l = 0;
  3955. while (logicalUnit = NextLogUnitExtensionWithTag(
  3956. DeviceExtension,
  3957. &pathId,
  3958. FALSE,
  3959. RequestIrp
  3960. )) {
  3961. //
  3962. // Walk the logical unit list to the end, looking for a safe one.
  3963. // If it was created for a rescan, it might be freed before this request is
  3964. // complete.
  3965. //
  3966. if (!(logicalUnit->LuFlags & PD_RESCAN_ACTIVE)) {
  3967. //
  3968. // Found a good one!
  3969. //
  3970. break;
  3971. }
  3972. UnrefLogicalUnitExtensionWithTag (
  3973. DeviceExtension,
  3974. logicalUnit,
  3975. RequestIrp
  3976. );
  3977. }
  3978. if (logicalUnit == NULL) {
  3979. RequestIrp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
  3980. return(STATUS_DEVICE_DOES_NOT_EXIST);
  3981. }
  3982. //
  3983. // Initialize the notification event.
  3984. //
  3985. KeInitializeEvent(&event,
  3986. NotificationEvent,
  3987. FALSE);
  3988. //
  3989. // Build IRP for this request.
  3990. // Note we do this synchronously for two reasons. If it was done
  3991. // asynchonously then the completion code would have to make a special
  3992. // check to deallocate the buffer. Second if a completion routine were
  3993. // used then an additional IRP stack location would be needed.
  3994. //
  3995. irp = IoBuildSynchronousFsdRequest(
  3996. IRP_MJ_SCSI,
  3997. logicalUnit->DeviceObject,
  3998. srbControl,
  3999. length,
  4000. &startingOffset,
  4001. &event,
  4002. &ioStatusBlock);
  4003. if (irp==NULL) {
  4004. IdeLogNoMemoryError(DeviceExtension,
  4005. logicalUnit->TargetId,
  4006. NonPagedPool,
  4007. IoSizeOfIrp(logicalUnit->DeviceObject->StackSize),
  4008. IDEPORT_TAG_MPIOCTL_IRP
  4009. );
  4010. UnrefLogicalUnitExtensionWithTag (
  4011. DeviceExtension,
  4012. logicalUnit,
  4013. RequestIrp
  4014. );
  4015. RequestIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  4016. return RequestIrp->IoStatus.Status;
  4017. }
  4018. irpStack = IoGetNextIrpStackLocation(irp);
  4019. //
  4020. // Set major and minor codes.
  4021. //
  4022. irpStack->MajorFunction = IRP_MJ_SCSI;
  4023. //
  4024. // Fill in SRB fields.
  4025. //
  4026. irpStack->Parameters.Others.Argument1 = &srb;
  4027. //
  4028. // Zero out the srb.
  4029. //
  4030. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  4031. srb.PathId = logicalUnit->PathId;
  4032. srb.TargetId = logicalUnit->TargetId;
  4033. srb.Lun = logicalUnit->Lun;
  4034. srb.Function = SRB_FUNCTION_IO_CONTROL;
  4035. srb.Length = sizeof(SCSI_REQUEST_BLOCK);
  4036. srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_NO_QUEUE_FREEZE;
  4037. srb.OriginalRequest = irp;
  4038. //
  4039. // Set timeout to requested value.
  4040. //
  4041. srb.TimeOutValue = srbControl->Timeout;
  4042. //
  4043. // Set the data buffer.
  4044. //
  4045. srb.DataBuffer = srbControl;
  4046. srb.DataTransferLength = length;
  4047. //
  4048. // Flush the data buffer for output. This will insure that the data is
  4049. // written back to memory. Since the data-in flag is the the port driver
  4050. // will flush the data again for input which will ensure the data is not
  4051. // in the cache.
  4052. //
  4053. KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
  4054. //
  4055. // Call port driver to handle this request.
  4056. //
  4057. IoCallDriver(logicalUnit->DeviceObject, irp);
  4058. //
  4059. // Wait for request to complete.
  4060. //
  4061. KeWaitForSingleObject(&event,
  4062. Executive,
  4063. KernelMode,
  4064. FALSE,
  4065. NULL);
  4066. //
  4067. // Set the information length to the smaller of the output buffer length
  4068. // and the length returned in the srb.
  4069. //
  4070. RequestIrp->IoStatus.Information = srb.DataTransferLength > outputLength ?
  4071. outputLength : srb.DataTransferLength;
  4072. RequestIrp->IoStatus.Status = ioStatusBlock.Status;
  4073. UnrefLogicalUnitExtensionWithTag (
  4074. DeviceExtension,
  4075. logicalUnit,
  4076. RequestIrp
  4077. );
  4078. return RequestIrp->IoStatus.Status;
  4079. }
  4080. NTSTATUS
  4081. IdeGetInquiryData(
  4082. IN PFDO_EXTENSION DeviceExtension,
  4083. IN PIRP Irp
  4084. )
  4085. /*++
  4086. Routine Description:
  4087. This functions copies the inquiry data to the system buffer. The data
  4088. is translate from the port driver's internal format to the user mode
  4089. format.
  4090. Arguments:
  4091. DeviceExtension - Supplies a pointer the SCSI adapter device extension.
  4092. Irp - Supplies a pointer to the Irp which made the original request.
  4093. Return Value:
  4094. Returns a status indicating the success or failure of the operation.
  4095. --*/
  4096. {
  4097. PUCHAR bufferStart;
  4098. PIO_STACK_LOCATION irpStack;
  4099. PSCSI_ADAPTER_BUS_INFO adapterInfo;
  4100. PSCSI_BUS_DATA busData;
  4101. PSCSI_INQUIRY_DATA inquiryData;
  4102. ULONG inquiryDataSize;
  4103. ULONG length;
  4104. ULONG numberOfBuses;
  4105. ULONG numberOfLus;
  4106. ULONG j;
  4107. PLOGICAL_UNIT_EXTENSION logUnitExtension;
  4108. IDE_PATH_ID pathId;
  4109. PAGED_CODE();
  4110. DebugPrint((3,"IdeGetInquiryData: Enter routine\n"));
  4111. //
  4112. // Get a pointer to the control block.
  4113. //
  4114. irpStack = IoGetCurrentIrpStackLocation(Irp);
  4115. bufferStart = Irp->AssociatedIrp.SystemBuffer;
  4116. numberOfBuses = MAX_IDE_BUS;
  4117. // this number could be changing...
  4118. // but we would always fill in the right info for the numLus.
  4119. numberOfLus = DeviceExtension->NumberOfLogicalUnits;
  4120. //
  4121. // Caculate the size of the logical unit structure and round it to a word
  4122. // alignment.
  4123. //
  4124. inquiryDataSize = ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
  4125. sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
  4126. // Based on the number of buses and logical unit, determine the minimum
  4127. // buffer length to hold all of the data.
  4128. //
  4129. length = sizeof(SCSI_ADAPTER_BUS_INFO) +
  4130. (numberOfBuses - 1) * sizeof(SCSI_BUS_DATA);
  4131. length += inquiryDataSize * numberOfLus;
  4132. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < length) {
  4133. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  4134. return(STATUS_BUFFER_TOO_SMALL);
  4135. }
  4136. //
  4137. // Set the information field.
  4138. //
  4139. Irp->IoStatus.Information = length;
  4140. //
  4141. // Fill in the bus information.
  4142. //
  4143. adapterInfo = (PSCSI_ADAPTER_BUS_INFO) bufferStart;
  4144. adapterInfo->NumberOfBuses = (UCHAR) numberOfBuses;
  4145. inquiryData = (PSCSI_INQUIRY_DATA)(bufferStart + sizeof(SCSI_ADAPTER_BUS_INFO) +
  4146. (numberOfBuses - 1) * sizeof(SCSI_BUS_DATA));
  4147. for (j = 0; j < numberOfBuses; j++) {
  4148. busData = &adapterInfo->BusData[j];
  4149. busData->NumberOfLogicalUnits = 0;
  4150. busData->InitiatorBusId = IDE_PSUEDO_INITIATOR_ID;
  4151. //
  4152. // Copy the data for the logical units.
  4153. //
  4154. busData->InquiryDataOffset = (ULONG)((PUCHAR) inquiryData - bufferStart);
  4155. pathId.l = 0;
  4156. pathId.b.Path = j;
  4157. while (logUnitExtension = NextLogUnitExtensionWithTag (
  4158. DeviceExtension,
  4159. &pathId,
  4160. TRUE,
  4161. IdeGetInquiryData
  4162. )) {
  4163. INQUIRYDATA InquiryData;
  4164. NTSTATUS status;
  4165. if (pathId.b.Path != j) {
  4166. UnrefLogicalUnitExtensionWithTag (
  4167. DeviceExtension,
  4168. logUnitExtension,
  4169. IdeGetInquiryData
  4170. );
  4171. break;
  4172. }
  4173. inquiryData->PathId = logUnitExtension->PathId;
  4174. inquiryData->TargetId = logUnitExtension->TargetId;
  4175. inquiryData->Lun = logUnitExtension->Lun;
  4176. inquiryData->DeviceClaimed = (BOOLEAN) (logUnitExtension->PdoState & PDOS_DEVICE_CLIAMED);
  4177. inquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
  4178. inquiryData->NextInquiryDataOffset = (ULONG)((PUCHAR) inquiryData +
  4179. inquiryDataSize - bufferStart);
  4180. status = IssueInquirySafe(logUnitExtension->ParentDeviceExtension, logUnitExtension, &InquiryData, FALSE);
  4181. if (NT_SUCCESS(status) || (status == STATUS_DATA_OVERRUN)) {
  4182. RtlCopyMemory(
  4183. inquiryData->InquiryData,
  4184. &InquiryData,
  4185. INQUIRYDATABUFFERSIZE
  4186. );
  4187. }
  4188. inquiryData = (PSCSI_INQUIRY_DATA) ((PCHAR) inquiryData + inquiryDataSize);
  4189. UnrefLogicalUnitExtensionWithTag (
  4190. DeviceExtension,
  4191. logUnitExtension,
  4192. IdeGetInquiryData
  4193. );
  4194. busData->NumberOfLogicalUnits++;
  4195. if (busData->NumberOfLogicalUnits >= (UCHAR) numberOfLus) {
  4196. break;
  4197. }
  4198. }
  4199. //
  4200. // Fix up the last entry of the list.
  4201. //
  4202. if (busData->NumberOfLogicalUnits == 0) {
  4203. busData->InquiryDataOffset = 0;
  4204. } else {
  4205. ((PSCSI_INQUIRY_DATA) ((PCHAR) inquiryData - inquiryDataSize))->
  4206. NextInquiryDataOffset = 0;
  4207. }
  4208. }
  4209. Irp->IoStatus.Status = STATUS_SUCCESS;
  4210. return(STATUS_SUCCESS);
  4211. }
  4212. NTSTATUS
  4213. IdeSendPassThrough (
  4214. IN PFDO_EXTENSION DeviceExtension,
  4215. IN PIRP RequestIrp
  4216. )
  4217. /*++
  4218. Routine Description:
  4219. This function sends a user specified SCSI request block.
  4220. It creates an srb which is processed normally by the port driver.
  4221. This call is synchornous.
  4222. Arguments:
  4223. DeviceExtension - Supplies a pointer the SCSI adapter device extension.
  4224. RequestIrp - Supplies a pointe to the Irp which made the original request.
  4225. Return Value:
  4226. Returns a status indicating the success or failure of the operation.
  4227. --*/
  4228. {
  4229. PIRP irp;
  4230. PIO_STACK_LOCATION irpStack;
  4231. PSCSI_PASS_THROUGH srbControl;
  4232. SCSI_REQUEST_BLOCK srb;
  4233. KEVENT event;
  4234. LARGE_INTEGER startingOffset;
  4235. IO_STATUS_BLOCK ioStatusBlock;
  4236. KIRQL currentIrql;
  4237. ULONG outputLength;
  4238. ULONG length;
  4239. ULONG bufferOffset;
  4240. PVOID buffer;
  4241. PVOID endByte;
  4242. PVOID senseBuffer;
  4243. UCHAR majorCode;
  4244. NTSTATUS status;
  4245. PLOGICAL_UNIT_EXTENSION logicalUnit;
  4246. #if defined (_WIN64)
  4247. PSCSI_PASS_THROUGH32 srbControl32;
  4248. #endif
  4249. PAGED_CODE();
  4250. startingOffset.QuadPart = (LONGLONG) 1;
  4251. DebugPrint((3,"IdeSendPassThrough: Enter routine\n"));
  4252. //
  4253. // Get a pointer to the control block.
  4254. //
  4255. irpStack = IoGetCurrentIrpStackLocation(RequestIrp);
  4256. srbControl = RequestIrp->AssociatedIrp.SystemBuffer;
  4257. //
  4258. // Validiate the user buffer.
  4259. //
  4260. #if defined (_WIN64)
  4261. if (IoIs32bitProcess(RequestIrp)) {
  4262. ULONG32 dataBufferOffset;
  4263. ULONG senseInfoOffset;
  4264. srbControl32 = (PSCSI_PASS_THROUGH32) (RequestIrp->AssociatedIrp.SystemBuffer);
  4265. //
  4266. // copy the fields that follow the ULONG_PTR
  4267. //
  4268. dataBufferOffset = (ULONG32) (srbControl32->DataBufferOffset);
  4269. senseInfoOffset = srbControl32->SenseInfoOffset;
  4270. srbControl->DataBufferOffset = (ULONG_PTR) dataBufferOffset;
  4271. srbControl->SenseInfoOffset = senseInfoOffset;
  4272. RtlCopyMemory(srbControl->Cdb,
  4273. srbControl32->Cdb,
  4274. 16*sizeof(UCHAR)
  4275. );
  4276. if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32)){
  4277. return(STATUS_INVALID_PARAMETER);
  4278. }
  4279. if (srbControl->Length != sizeof(SCSI_PASS_THROUGH32) &&
  4280. srbControl->Length != sizeof(SCSI_PASS_THROUGH_DIRECT32)) {
  4281. return(STATUS_REVISION_MISMATCH);
  4282. }
  4283. } else {
  4284. #endif
  4285. if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)){
  4286. return(STATUS_INVALID_PARAMETER);
  4287. }
  4288. if (srbControl->Length != sizeof(SCSI_PASS_THROUGH) &&
  4289. srbControl->Length != sizeof(SCSI_PASS_THROUGH_DIRECT)) {
  4290. return(STATUS_REVISION_MISMATCH);
  4291. }
  4292. #if defined (_WIN64)
  4293. }
  4294. #endif
  4295. outputLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  4296. //
  4297. // Validate the rest of the buffer parameters.
  4298. //
  4299. if (srbControl->CdbLength > 16) {
  4300. return(STATUS_INVALID_PARAMETER);
  4301. }
  4302. if (srbControl->SenseInfoLength != 0 &&
  4303. (srbControl->Length > srbControl->SenseInfoOffset ||
  4304. (srbControl->SenseInfoOffset + srbControl->SenseInfoLength >
  4305. srbControl->DataBufferOffset && srbControl->DataTransferLength != 0))) {
  4306. return(STATUS_INVALID_PARAMETER);
  4307. }
  4308. majorCode = !srbControl->DataIn ? IRP_MJ_WRITE : IRP_MJ_READ;
  4309. if (srbControl->DataTransferLength == 0) {
  4310. length = 0;
  4311. buffer = NULL;
  4312. bufferOffset = 0;
  4313. majorCode = IRP_MJ_FLUSH_BUFFERS;
  4314. } else if (srbControl->DataBufferOffset > outputLength &&
  4315. srbControl->DataBufferOffset > irpStack->Parameters.DeviceIoControl.InputBufferLength) {
  4316. //
  4317. // The data buffer offset is greater than system buffer. Assume this
  4318. // is a user mode address.
  4319. //
  4320. if (srbControl->SenseInfoOffset + srbControl->SenseInfoLength > outputLength
  4321. && srbControl->SenseInfoLength) {
  4322. return(STATUS_INVALID_PARAMETER);
  4323. }
  4324. //
  4325. // Make sure the buffer is properly aligned.
  4326. //
  4327. if (srbControl->DataBufferOffset &
  4328. DeviceExtension->DeviceObject->AlignmentRequirement) {
  4329. return(STATUS_INVALID_PARAMETER);
  4330. }
  4331. length = srbControl->DataTransferLength;
  4332. buffer = (PCHAR) srbControl->DataBufferOffset;
  4333. bufferOffset = 0;
  4334. //
  4335. // make sure the user buffer is valid
  4336. //
  4337. if (RequestIrp->RequestorMode != KernelMode) {
  4338. if (length) {
  4339. endByte = (PVOID)((PCHAR)buffer + length - 1);
  4340. if ((endByte > (PVOID)MM_HIGHEST_USER_ADDRESS) || (buffer >= endByte)) {
  4341. return STATUS_INVALID_USER_BUFFER;
  4342. }
  4343. }
  4344. }
  4345. } else {
  4346. if (srbControl->DataIn != SCSI_IOCTL_DATA_IN) {
  4347. if ((srbControl->SenseInfoOffset + srbControl->SenseInfoLength > outputLength
  4348. && srbControl->SenseInfoLength != 0) ||
  4349. srbControl->DataBufferOffset + srbControl->DataTransferLength >
  4350. irpStack->Parameters.DeviceIoControl.InputBufferLength ||
  4351. srbControl->Length > srbControl->DataBufferOffset) {
  4352. return STATUS_INVALID_PARAMETER;
  4353. }
  4354. }
  4355. if (srbControl->DataIn) {
  4356. if (srbControl->DataBufferOffset + srbControl->DataTransferLength > outputLength ||
  4357. srbControl->Length > srbControl->DataBufferOffset) {
  4358. return STATUS_INVALID_PARAMETER;
  4359. }
  4360. }
  4361. length = (ULONG)srbControl->DataBufferOffset +
  4362. srbControl->DataTransferLength;
  4363. buffer = (PUCHAR) srbControl;
  4364. bufferOffset = (ULONG)srbControl->DataBufferOffset;
  4365. }
  4366. //
  4367. // Validate that the request isn't too large for the miniport.
  4368. //
  4369. if (srbControl->DataTransferLength &&
  4370. ((ADDRESS_AND_SIZE_TO_SPAN_PAGES(
  4371. (PUCHAR)buffer+bufferOffset,
  4372. srbControl->DataTransferLength
  4373. ) > DeviceExtension->Capabilities.MaximumPhysicalPages) ||
  4374. (DeviceExtension->Capabilities.MaximumTransferLength <
  4375. srbControl->DataTransferLength))) {
  4376. return(STATUS_INVALID_PARAMETER);
  4377. }
  4378. if (srbControl->TimeOutValue == 0 ||
  4379. srbControl->TimeOutValue > 30 * 60 * 60) {
  4380. return STATUS_INVALID_PARAMETER;
  4381. }
  4382. //
  4383. // Check for illegal command codes.
  4384. //
  4385. if (srbControl->Cdb[0] == SCSIOP_COPY ||
  4386. srbControl->Cdb[0] == SCSIOP_COMPARE ||
  4387. srbControl->Cdb[0] == SCSIOP_COPY_COMPARE) {
  4388. return STATUS_INVALID_DEVICE_REQUEST;
  4389. }
  4390. //
  4391. // If this request came through a normal device control rather than from
  4392. // class driver then the device must exist and be unclaimed. Class drivers
  4393. // will set the minor function code for the device control. It is always
  4394. // zero for a user request.
  4395. //
  4396. logicalUnit = RefLogicalUnitExtensionWithTag(DeviceExtension,
  4397. srbControl->PathId,
  4398. srbControl->TargetId,
  4399. srbControl->Lun,
  4400. FALSE,
  4401. RequestIrp
  4402. );
  4403. if (logicalUnit) {
  4404. if (irpStack->MinorFunction == 0) {
  4405. if (logicalUnit->PdoState & PDOS_DEVICE_CLIAMED) {
  4406. UnrefLogicalUnitExtensionWithTag(
  4407. DeviceExtension,
  4408. logicalUnit,
  4409. RequestIrp
  4410. );
  4411. logicalUnit = NULL;
  4412. }
  4413. }
  4414. }
  4415. if (logicalUnit == NULL) {
  4416. return STATUS_INVALID_PARAMETER;
  4417. }
  4418. //
  4419. // Allocate an aligned request sense buffer.
  4420. //
  4421. if (srbControl->SenseInfoLength != 0) {
  4422. senseBuffer = ExAllocatePool( NonPagedPoolCacheAligned,
  4423. srbControl->SenseInfoLength);
  4424. if (senseBuffer == NULL) {
  4425. IdeLogNoMemoryError(DeviceExtension,
  4426. logicalUnit->TargetId,
  4427. NonPagedPoolCacheAligned,
  4428. srbControl->SenseInfoLength,
  4429. IDEPORT_TAG_PASSTHRU_SENSE
  4430. );
  4431. UnrefLogicalUnitExtensionWithTag(
  4432. DeviceExtension,
  4433. logicalUnit,
  4434. RequestIrp
  4435. );
  4436. return(STATUS_INSUFFICIENT_RESOURCES);
  4437. }
  4438. } else {
  4439. senseBuffer = NULL;
  4440. }
  4441. //
  4442. // Initialize the notification event.
  4443. //
  4444. KeInitializeEvent(&event,
  4445. NotificationEvent,
  4446. FALSE);
  4447. //
  4448. // Build IRP for this request.
  4449. // Note we do this synchronously for two reasons. If it was done
  4450. // asynchonously then the completion code would have to make a special
  4451. // check to deallocate the buffer. Second if a completion routine were
  4452. // used then an addation stack locate would be needed.
  4453. //
  4454. try {
  4455. irp = IoBuildSynchronousFsdRequest(
  4456. majorCode,
  4457. logicalUnit->DeviceObject,
  4458. buffer,
  4459. length,
  4460. &startingOffset,
  4461. &event,
  4462. &ioStatusBlock);
  4463. } except(EXCEPTION_EXECUTE_HANDLER) {
  4464. //
  4465. // An exception was incurred while attempting to probe the
  4466. // caller's parameters. Dereference the file object and return
  4467. // an appropriate error status code.
  4468. //
  4469. if (senseBuffer != NULL) {
  4470. ExFreePool(senseBuffer);
  4471. }
  4472. UnrefLogicalUnitExtensionWithTag(
  4473. DeviceExtension,
  4474. logicalUnit,
  4475. RequestIrp
  4476. );
  4477. return GetExceptionCode();
  4478. }
  4479. if (irp == NULL) {
  4480. if (senseBuffer != NULL) {
  4481. ExFreePool(senseBuffer);
  4482. }
  4483. IdeLogNoMemoryError(DeviceExtension,
  4484. logicalUnit->TargetId,
  4485. NonPagedPool,
  4486. IoSizeOfIrp(logicalUnit->DeviceObject->StackSize),
  4487. IDEPORT_TAG_PASSTHRU_IRP
  4488. );
  4489. UnrefLogicalUnitExtensionWithTag(
  4490. DeviceExtension,
  4491. logicalUnit,
  4492. RequestIrp
  4493. );
  4494. return(STATUS_INSUFFICIENT_RESOURCES);
  4495. }
  4496. irpStack = IoGetNextIrpStackLocation(irp);
  4497. //
  4498. // Set major code.
  4499. //
  4500. irpStack->MajorFunction = IRP_MJ_SCSI;
  4501. //
  4502. // Fill in SRB fields.
  4503. //
  4504. irpStack->Parameters.Others.Argument1 = &srb;
  4505. //
  4506. // Zero out the srb.
  4507. //
  4508. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  4509. //
  4510. // Fill in the srb.
  4511. //
  4512. srb.Length = SCSI_REQUEST_BLOCK_SIZE;
  4513. srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
  4514. srb.SrbStatus = SRB_STATUS_PENDING;
  4515. srb.PathId = srbControl->PathId;
  4516. srb.TargetId = srbControl->TargetId;
  4517. srb.Lun = srbControl->Lun;
  4518. srb.CdbLength = srbControl->CdbLength;
  4519. srb.SenseInfoBufferLength = srbControl->SenseInfoLength;
  4520. switch (srbControl->DataIn) {
  4521. case SCSI_IOCTL_DATA_OUT:
  4522. if (srbControl->DataTransferLength) {
  4523. srb.SrbFlags = SRB_FLAGS_DATA_OUT;
  4524. }
  4525. break;
  4526. case SCSI_IOCTL_DATA_IN:
  4527. if (srbControl->DataTransferLength) {
  4528. srb.SrbFlags = SRB_FLAGS_DATA_IN;
  4529. }
  4530. break;
  4531. default:
  4532. srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT;
  4533. break;
  4534. }
  4535. if (srbControl->DataTransferLength == 0) {
  4536. srb.SrbFlags = 0;
  4537. } else {
  4538. //
  4539. // Flush the data buffer for output. This will insure that the data is
  4540. // written back to memory.
  4541. //
  4542. KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
  4543. }
  4544. srb.SrbFlags |= (SRB_FLAGS_DISABLE_SYNCH_TRANSFER & DeviceExtension->SrbFlags);
  4545. srb.SrbFlags |= SRB_FLAGS_NO_QUEUE_FREEZE;
  4546. srb.DataTransferLength = srbControl->DataTransferLength;
  4547. srb.TimeOutValue = srbControl->TimeOutValue;
  4548. srb.DataBuffer = (PCHAR) buffer + bufferOffset;
  4549. srb.SenseInfoBuffer = senseBuffer;
  4550. srb.OriginalRequest = irp;
  4551. RtlCopyMemory(srb.Cdb, srbControl->Cdb, srbControl->CdbLength);
  4552. //
  4553. // Call port driver to handle this request.
  4554. //
  4555. status = IoCallDriver(logicalUnit->DeviceObject, irp);
  4556. //
  4557. // Wait for request to complete.
  4558. //
  4559. if(status == STATUS_PENDING) {
  4560. KeWaitForSingleObject(&event,
  4561. Executive,
  4562. KernelMode,
  4563. FALSE,
  4564. NULL);
  4565. } else {
  4566. ioStatusBlock.Status = status;
  4567. }
  4568. //
  4569. // Copy the returned values from the srb to the control structure.
  4570. //
  4571. srbControl->ScsiStatus = srb.ScsiStatus;
  4572. if (srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
  4573. //
  4574. // Set the status to success so that the data is returned.
  4575. //
  4576. ioStatusBlock.Status = STATUS_SUCCESS;
  4577. srbControl->SenseInfoLength = srb.SenseInfoBufferLength;
  4578. //
  4579. // Copy the sense data to the system buffer.
  4580. //
  4581. RtlCopyMemory((PUCHAR) srbControl + srbControl->SenseInfoOffset,
  4582. senseBuffer,
  4583. srb.SenseInfoBufferLength);
  4584. } else {
  4585. srbControl->SenseInfoLength = 0;
  4586. }
  4587. //
  4588. // Free the sense buffer.
  4589. //
  4590. if (senseBuffer != NULL) {
  4591. ExFreePool(senseBuffer);
  4592. }
  4593. //
  4594. // If the srb status is buffer underrun then set the status to success.
  4595. // This insures that the data will be returned to the caller.
  4596. //
  4597. if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  4598. ioStatusBlock.Status = STATUS_SUCCESS;
  4599. }
  4600. srbControl->DataTransferLength = srb.DataTransferLength;
  4601. //
  4602. // Set the information length
  4603. //
  4604. if (!srbControl->DataIn || bufferOffset == 0) {
  4605. RequestIrp->IoStatus.Information = srbControl->SenseInfoOffset +
  4606. srbControl->SenseInfoLength;
  4607. } else {
  4608. RequestIrp->IoStatus.Information = srbControl->DataBufferOffset +
  4609. srbControl->DataTransferLength;
  4610. }
  4611. RequestIrp->IoStatus.Status = ioStatusBlock.Status;
  4612. //
  4613. // Queue should not be frozen
  4614. //
  4615. ASSERT(!(srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN));
  4616. /**
  4617. //
  4618. // If the queue is frozen then unfreeze it.
  4619. //
  4620. if (srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  4621. //
  4622. // Acquire the spinlock to protect the flags structure and the saved
  4623. // interrupt context.
  4624. //
  4625. KeAcquireSpinLock(&DeviceExtension->SpinLock, &currentIrql);
  4626. //
  4627. // Make sure the queue is frozen and that an ABORT is not
  4628. // in progress.
  4629. //
  4630. if (!(logicalUnit->LuFlags & PD_QUEUE_FROZEN)) {
  4631. KeReleaseSpinLock(&DeviceExtension->SpinLock, currentIrql);
  4632. } else {
  4633. CLRMASK (logicalUnit->LuFlags, PD_QUEUE_FROZEN);
  4634. GetNextLuRequest(DeviceExtension, logicalUnit);
  4635. KeLowerIrql(currentIrql);
  4636. //
  4637. // Get next request will release the spinlock.
  4638. //
  4639. }
  4640. }
  4641. **/
  4642. UnrefLogicalUnitExtensionWithTag(
  4643. DeviceExtension,
  4644. logicalUnit,
  4645. RequestIrp
  4646. );
  4647. return ioStatusBlock.Status;
  4648. }
  4649. VOID
  4650. SyncAtaPassThroughCompletionRoutine (
  4651. IN PDEVICE_OBJECT DeviceObject,
  4652. IN PVOID Context,
  4653. IN NTSTATUS Status
  4654. )
  4655. {
  4656. PSYNC_ATA_PASSTHROUGH_CONTEXT context = Context;
  4657. context->Status = Status;
  4658. KeSetEvent (&context->Event, 0, FALSE);
  4659. }
  4660. //
  4661. // <= DISPATCH_LEVEL
  4662. //
  4663. NTSTATUS
  4664. IssueAsyncAtaPassThroughSafe (
  4665. IN PFDO_EXTENSION DeviceExtension,
  4666. IN PLOGICAL_UNIT_EXTENSION LogUnitExtension,
  4667. IN OUT PATA_PASS_THROUGH AtaPassThroughData,
  4668. IN BOOLEAN DataIn,
  4669. IN ASYNC_PASS_THROUGH_COMPLETION Completion,
  4670. IN PVOID CallerContext,
  4671. IN BOOLEAN PowerRelated,
  4672. IN ULONG TimeOut,
  4673. IN BOOLEAN MustSucceed
  4674. )
  4675. {
  4676. PIRP irp;
  4677. PIO_STACK_LOCATION irpStack;
  4678. IO_STATUS_BLOCK ioStatusBlock;
  4679. KIRQL currentIrql;
  4680. NTSTATUS status;
  4681. PSCSI_REQUEST_BLOCK srb;
  4682. PSENSE_DATA senseInfoBuffer;
  4683. ULONG totalBufferSize;
  4684. PATA_PASSTHROUGH_CONTEXT context;
  4685. PENUMERATION_STRUCT enumStruct;
  4686. status = STATUS_UNSUCCESSFUL;
  4687. senseInfoBuffer = NULL;
  4688. srb = NULL;
  4689. irp = NULL;
  4690. if (MustSucceed) {
  4691. enumStruct = DeviceExtension->PreAllocEnumStruct;
  4692. if (enumStruct == NULL) {
  4693. ASSERT (DeviceExtension->PreAllocEnumStruct);
  4694. //
  4695. // Fall back to the usual course of action
  4696. //
  4697. MustSucceed=FALSE;
  4698. } else {
  4699. context = enumStruct->Context;
  4700. ASSERT (context);
  4701. senseInfoBuffer = enumStruct->SenseInfoBuffer;
  4702. ASSERT (senseInfoBuffer);
  4703. srb = enumStruct->Srb;
  4704. ASSERT (srb);
  4705. totalBufferSize = FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer) + AtaPassThroughData->DataBufferSize;
  4706. irp = enumStruct->Irp1;
  4707. ASSERT (irp);
  4708. IoInitializeIrp(irp,
  4709. IoSizeOfIrp(LogUnitExtension->DeviceObject->StackSize),
  4710. LogUnitExtension->DeviceObject->StackSize);
  4711. irp->MdlAddress = enumStruct->MdlAddress;
  4712. ASSERT (enumStruct->DataBufferSize >= totalBufferSize);
  4713. RtlCopyMemory(enumStruct->DataBuffer, AtaPassThroughData, totalBufferSize);
  4714. }
  4715. }
  4716. if (!MustSucceed) {
  4717. context = ExAllocatePool(NonPagedPool, sizeof (ATA_PASSTHROUGH_CONTEXT));
  4718. if (context == NULL) {
  4719. DebugPrint((1,"IssueAsyncAtaPassThrough: Can't allocate context buffer\n"));
  4720. IdeLogNoMemoryError(DeviceExtension,
  4721. LogUnitExtension->TargetId,
  4722. NonPagedPool,
  4723. sizeof(ATA_PASSTHROUGH_CONTEXT),
  4724. (IDEPORT_TAG_ATAPASS_CONTEXT+AtaPassThroughData->IdeReg.bCommandReg)
  4725. );
  4726. status = STATUS_INSUFFICIENT_RESOURCES;
  4727. goto GetOut;
  4728. }
  4729. senseInfoBuffer = ExAllocatePool( NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE);
  4730. if (senseInfoBuffer == NULL) {
  4731. DebugPrint((1,"IssueAsyncAtaPassThrough: Can't allocate request sense buffer\n"));
  4732. IdeLogNoMemoryError(DeviceExtension,
  4733. LogUnitExtension->TargetId,
  4734. NonPagedPoolCacheAligned,
  4735. SENSE_BUFFER_SIZE,
  4736. (IDEPORT_TAG_ATAPASS_SENSE+AtaPassThroughData->IdeReg.bCommandReg)
  4737. );
  4738. status = STATUS_INSUFFICIENT_RESOURCES;
  4739. goto GetOut;
  4740. }
  4741. srb = ExAllocatePool (NonPagedPool, sizeof (SCSI_REQUEST_BLOCK));
  4742. if (srb == NULL) {
  4743. DebugPrint((1,"IssueAsyncAtaPassThrough: Can't SRB\n"));
  4744. IdeLogNoMemoryError(DeviceExtension,
  4745. LogUnitExtension->TargetId,
  4746. NonPagedPool,
  4747. sizeof(SCSI_REQUEST_BLOCK),
  4748. (IDEPORT_TAG_ATAPASS_SRB+AtaPassThroughData->IdeReg.bCommandReg)
  4749. );
  4750. status = STATUS_INSUFFICIENT_RESOURCES;
  4751. goto GetOut;
  4752. }
  4753. totalBufferSize = FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer) + AtaPassThroughData->DataBufferSize;
  4754. //
  4755. // Build IRP for this request.
  4756. //
  4757. irp = IoAllocateIrp (
  4758. (CCHAR) (LogUnitExtension->DeviceObject->StackSize),
  4759. FALSE
  4760. );
  4761. if (irp == NULL) {
  4762. IdeLogNoMemoryError(DeviceExtension,
  4763. LogUnitExtension->TargetId,
  4764. NonPagedPool,
  4765. IoSizeOfIrp(LogUnitExtension->DeviceObject->StackSize),
  4766. (IDEPORT_TAG_ATAPASS_IRP+AtaPassThroughData->IdeReg.bCommandReg)
  4767. );
  4768. status = STATUS_INSUFFICIENT_RESOURCES;
  4769. goto GetOut;
  4770. }
  4771. irp->MdlAddress = IoAllocateMdl( AtaPassThroughData,
  4772. totalBufferSize,
  4773. FALSE,
  4774. FALSE,
  4775. (PIRP) NULL );
  4776. if (irp->MdlAddress == NULL) {
  4777. IdeLogNoMemoryError(DeviceExtension,
  4778. LogUnitExtension->TargetId,
  4779. NonPagedPool,
  4780. totalBufferSize,
  4781. (IDEPORT_TAG_ATAPASS_MDL+AtaPassThroughData->IdeReg.bCommandReg)
  4782. );
  4783. status = STATUS_INSUFFICIENT_RESOURCES;
  4784. goto GetOut;
  4785. }
  4786. MmBuildMdlForNonPagedPool(irp->MdlAddress);
  4787. }
  4788. irpStack = IoGetNextIrpStackLocation(irp);
  4789. irpStack->MajorFunction = IRP_MJ_SCSI;
  4790. //
  4791. // Fill in SRB fields.
  4792. //
  4793. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  4794. irpStack->Parameters.Scsi.Srb = srb;
  4795. srb->PathId = LogUnitExtension->PathId;
  4796. srb->TargetId = LogUnitExtension->TargetId;
  4797. srb->Lun = LogUnitExtension->Lun;
  4798. if (PowerRelated) {
  4799. srb->Function = SRB_FUNCTION_ATA_POWER_PASS_THROUGH;
  4800. srb->QueueSortKey = MAXULONG;
  4801. } else {
  4802. srb->Function = SRB_FUNCTION_ATA_PASS_THROUGH;
  4803. srb->QueueSortKey = 0;
  4804. }
  4805. srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  4806. //
  4807. // Set flags to disable synchronous negociation.
  4808. //
  4809. srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  4810. srb->SrbFlags |= DataIn ? 0 : SRB_FLAGS_DATA_OUT;
  4811. if (AtaPassThroughData->IdeReg.bReserved & ATA_PTFLAGS_URGENT) {
  4812. srb->SrbFlags |= SRB_FLAGS_BYPASS_FROZEN_QUEUE;
  4813. }
  4814. srb->SrbStatus = srb->ScsiStatus = 0;
  4815. srb->NextSrb = 0;
  4816. srb->OriginalRequest = irp;
  4817. //
  4818. // Set timeout to 15 seconds.
  4819. //
  4820. srb->TimeOutValue = TimeOut;
  4821. srb->CdbLength = 6;
  4822. //
  4823. // Enable auto request sense.
  4824. //
  4825. srb->SenseInfoBuffer = senseInfoBuffer;
  4826. srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  4827. srb->DataBuffer = MmGetMdlVirtualAddress(irp->MdlAddress);
  4828. srb->DataTransferLength = totalBufferSize;
  4829. IoSetCompletionRoutine(
  4830. irp,
  4831. AtaPassThroughCompletionRoutine,
  4832. context,
  4833. TRUE,
  4834. TRUE,
  4835. TRUE
  4836. );
  4837. context->DeviceObject = LogUnitExtension->DeviceObject;
  4838. context->CallerCompletion = Completion;
  4839. context->CallerContext = CallerContext;
  4840. context->SenseInfoBuffer = senseInfoBuffer;
  4841. context->Srb = srb;
  4842. context->MustSucceed = MustSucceed? 1 : 0;
  4843. context->DataBuffer = AtaPassThroughData;
  4844. //
  4845. // send the pass through irp
  4846. //
  4847. status = IoCallDriver(LogUnitExtension->DeviceObject, irp);
  4848. //
  4849. // always return STATUS_PENDING when we actually send out the irp
  4850. //
  4851. return STATUS_PENDING;
  4852. GetOut:
  4853. ASSERT (!MustSucceed);
  4854. if (context) {
  4855. ExFreePool (context);
  4856. }
  4857. if (senseInfoBuffer) {
  4858. ExFreePool (senseInfoBuffer);
  4859. }
  4860. if (srb) {
  4861. ExFreePool (srb);
  4862. }
  4863. if (irp && irp->MdlAddress) {
  4864. IoFreeMdl (irp->MdlAddress);
  4865. }
  4866. if (irp) {
  4867. IoFreeIrp( irp );
  4868. }
  4869. return status;
  4870. } // IssueAtaPassThrough
  4871. NTSTATUS
  4872. IssueSyncAtaPassThroughSafe (
  4873. IN PFDO_EXTENSION DeviceExtension,
  4874. IN PLOGICAL_UNIT_EXTENSION LogUnitExtension,
  4875. IN OUT PATA_PASS_THROUGH AtaPassThroughData,
  4876. IN BOOLEAN DataIn,
  4877. IN BOOLEAN PowerRelated,
  4878. IN ULONG TimeOut,
  4879. IN BOOLEAN MustSucceed
  4880. )
  4881. {
  4882. NTSTATUS status;
  4883. SYNC_ATA_PASSTHROUGH_CONTEXT context;
  4884. ULONG retryCount=10;
  4885. ULONG locked;
  4886. status=STATUS_INSUFFICIENT_RESOURCES;
  4887. if (MustSucceed) {
  4888. //Lock
  4889. ASSERT(InterlockedCompareExchange(&(DeviceExtension->EnumStructLock), 1, 0) == 0);
  4890. }
  4891. while ((status == STATUS_UNSUCCESSFUL || status == STATUS_INSUFFICIENT_RESOURCES) && retryCount--) {
  4892. //
  4893. // Initialize the notification event.
  4894. //
  4895. KeInitializeEvent(&context.Event,
  4896. NotificationEvent,
  4897. FALSE);
  4898. status = IssueAsyncAtaPassThroughSafe (
  4899. DeviceExtension,
  4900. LogUnitExtension,
  4901. AtaPassThroughData,
  4902. DataIn,
  4903. SyncAtaPassThroughCompletionRoutine,
  4904. &context,
  4905. PowerRelated,
  4906. TimeOut,
  4907. MustSucceed
  4908. );
  4909. if (status == STATUS_PENDING) {
  4910. KeWaitForSingleObject(&context.Event,
  4911. Executive,
  4912. KernelMode,
  4913. FALSE,
  4914. NULL);
  4915. status=context.Status;
  4916. }
  4917. if (status == STATUS_UNSUCCESSFUL) {
  4918. DebugPrint((1, "Retrying flushed request\n"));
  4919. }
  4920. }
  4921. if (MustSucceed) {
  4922. //Unlock
  4923. ASSERT(InterlockedCompareExchange(&(DeviceExtension->EnumStructLock), 0, 1) == 1);
  4924. }
  4925. if (NT_SUCCESS(status)) {
  4926. return context.Status;
  4927. } else {
  4928. return status;
  4929. }
  4930. }
  4931. NTSTATUS
  4932. AtaPassThroughCompletionRoutine(
  4933. PDEVICE_OBJECT DeviceObject,
  4934. PIRP Irp,
  4935. PVOID Context
  4936. )
  4937. {
  4938. PATA_PASSTHROUGH_CONTEXT context = Context;
  4939. PATA_PASS_THROUGH ataPassThroughData;
  4940. DebugPrint((1, "AtaPassThroughCompletionRoutine: Irp = 0x%x status=%x\n",
  4941. Irp, Irp->IoStatus.Status));
  4942. if (context->Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  4943. PLOGICAL_UNIT_EXTENSION logicalUnit;
  4944. KIRQL currentIrql;
  4945. DebugPrint((1, "AtaPassThroughCompletionRoutine: Unfreeze Queue TID %d\n",
  4946. context->Srb->TargetId));
  4947. logicalUnit = context->DeviceObject->DeviceExtension;
  4948. ASSERT (logicalUnit);
  4949. CLRMASK (logicalUnit->LuFlags, PD_QUEUE_FROZEN);
  4950. KeAcquireSpinLock(&logicalUnit->ParentDeviceExtension->SpinLock, &currentIrql);
  4951. GetNextLuRequest(logicalUnit->ParentDeviceExtension, logicalUnit);
  4952. KeLowerIrql(currentIrql);
  4953. }
  4954. ataPassThroughData = (PATA_PASS_THROUGH) context->Srb->DataBuffer;
  4955. if (ataPassThroughData->IdeReg.bReserved & ATA_PTFLAGS_OK_TO_FAIL) {
  4956. Irp->IoStatus.Status = STATUS_SUCCESS;
  4957. }
  4958. if (context->MustSucceed) {
  4959. RtlCopyMemory(context->DataBuffer,
  4960. context->Srb->DataBuffer, context->Srb->DataTransferLength);
  4961. DebugPrint((1, "AtaCompletionSafe: Device =%x, Status= %x, SrbStatus=%x\n",
  4962. context->Srb->TargetId, Irp->IoStatus.Status, context->Srb->SrbStatus));
  4963. }
  4964. if (context->CallerCompletion) {
  4965. context->CallerCompletion (context->DeviceObject, context->CallerContext, Irp->IoStatus.Status);
  4966. }
  4967. if (context->MustSucceed) {
  4968. return STATUS_MORE_PROCESSING_REQUIRED;
  4969. }
  4970. ExFreePool (context->SenseInfoBuffer);
  4971. ExFreePool (context->Srb);
  4972. ExFreePool (context);
  4973. if (Irp->MdlAddress) {
  4974. IoFreeMdl (Irp->MdlAddress);
  4975. }
  4976. IoFreeIrp (Irp);
  4977. return STATUS_MORE_PROCESSING_REQUIRED;
  4978. }
  4979. NTSTATUS
  4980. IdeClaimLogicalUnit(
  4981. IN PFDO_EXTENSION DeviceExtension,
  4982. IN PIRP Irp
  4983. )
  4984. /*++
  4985. Routine Description:
  4986. This function finds the specified device in the logical unit information
  4987. and either updates the device object point or claims the device. If the
  4988. device is already claimed, then the request fails. If the request succeeds,
  4989. then the current device object is returned in the data buffer pointer
  4990. of the SRB.
  4991. Arguments:
  4992. DeviceExtension - Supplies a pointer the SCSI adapter device extension.
  4993. Irp - Supplies a pointer to the Irp which made the original request.
  4994. Return Value:
  4995. Returns the status of the operation. Either success, no device or busy.
  4996. --*/
  4997. {
  4998. KIRQL currentIrql;
  4999. PIO_STACK_LOCATION irpStack;
  5000. PSCSI_REQUEST_BLOCK srb;
  5001. PDEVICE_OBJECT saveDevice;
  5002. PPDO_EXTENSION pdoExtension;
  5003. PVOID sectionHandle;
  5004. PAGED_CODE();
  5005. //
  5006. // Get SRB address from current IRP stack.
  5007. //
  5008. irpStack = IoGetCurrentIrpStackLocation(Irp);
  5009. srb = (PSCSI_REQUEST_BLOCK) irpStack->Parameters.Others.Argument1;
  5010. pdoExtension = IDEPORT_GET_LUNEXT_IN_IRP (irpStack);
  5011. ASSERT (pdoExtension);
  5012. #ifdef ALLOC_PRAGMA
  5013. sectionHandle = MmLockPagableCodeSection(IdeClaimLogicalUnit);
  5014. #endif
  5015. //
  5016. // Lock the data.
  5017. //
  5018. KeAcquireSpinLock(&pdoExtension->PdoSpinLock, &currentIrql);
  5019. if (srb->Function == SRB_FUNCTION_RELEASE_DEVICE) {
  5020. CLRMASK (pdoExtension->PdoState, PDOS_DEVICE_CLIAMED | PDOS_LEGACY_ATTACHER);
  5021. KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
  5022. srb->SrbStatus = SRB_STATUS_SUCCESS;
  5023. #ifdef ALLOC_PRAGMA
  5024. MmUnlockPagableImageSection(sectionHandle);
  5025. #endif
  5026. return(STATUS_SUCCESS);
  5027. }
  5028. //
  5029. // Check for a claimed device.
  5030. //
  5031. if (pdoExtension->PdoState & PDOS_DEVICE_CLIAMED) {
  5032. KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
  5033. srb->SrbStatus = SRB_STATUS_BUSY;
  5034. #ifdef ALLOC_PRAGMA
  5035. MmUnlockPagableImageSection(sectionHandle);
  5036. #endif
  5037. return(STATUS_DEVICE_BUSY);
  5038. }
  5039. //
  5040. // Save the current device object.
  5041. //
  5042. saveDevice = pdoExtension->AttacherDeviceObject;
  5043. //
  5044. // Update the lun information based on the operation type.
  5045. //
  5046. if (srb->Function == SRB_FUNCTION_CLAIM_DEVICE) {
  5047. pdoExtension->PdoState |= PDOS_DEVICE_CLIAMED;
  5048. }
  5049. if (srb->Function == SRB_FUNCTION_ATTACH_DEVICE) {
  5050. pdoExtension->AttacherDeviceObject = srb->DataBuffer;
  5051. }
  5052. srb->DataBuffer = saveDevice;
  5053. if (irpStack->DeviceObject == pdoExtension->ParentDeviceExtension->DeviceObject) {
  5054. //
  5055. // The original irp is sent to the parent. The attacher must
  5056. // be legacy class driver. We can never do pnp remove safely.
  5057. //
  5058. pdoExtension->PdoState |= PDOS_LEGACY_ATTACHER;
  5059. }
  5060. KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
  5061. srb->SrbStatus = SRB_STATUS_SUCCESS;
  5062. #ifdef ALLOC_PRAGMA
  5063. MmUnlockPagableImageSection(sectionHandle);
  5064. #endif
  5065. return(STATUS_SUCCESS);
  5066. }
  5067. NTSTATUS
  5068. IdeRemoveDevice(
  5069. IN PFDO_EXTENSION DeviceExtension,
  5070. IN PIRP Irp
  5071. )
  5072. /*++
  5073. Routine Description:
  5074. This function finds the specified device in the logical unit information
  5075. and deletes it. This is done in preparation for a failing device to be
  5076. physically removed from a SCSI bus. An assumption is that the system
  5077. utility controlling the device removal has locked the volumes so there
  5078. is no outstanding IO to this device.
  5079. Arguments:
  5080. DeviceExtension - Supplies a pointer the SCSI adapter device extension.
  5081. Irp - Supplies a pointer to the Irp which made the original request.
  5082. Return Value:
  5083. Returns the status of the operation. Either success or no device.
  5084. --*/
  5085. {
  5086. KIRQL currentIrql;
  5087. PPDO_EXTENSION pdoExtension;
  5088. PIO_STACK_LOCATION irpStack;
  5089. PSCSI_REQUEST_BLOCK srb;
  5090. NTSTATUS status;
  5091. PAGED_CODE();
  5092. // ISSUE:2000/02/11 : need to test this
  5093. //
  5094. // Get SRB address from current IRP stack.
  5095. //
  5096. irpStack = IoGetCurrentIrpStackLocation(Irp);
  5097. srb = (PSCSI_REQUEST_BLOCK) irpStack->Parameters.Others.Argument1;
  5098. srb->SrbStatus = SRB_STATUS_NO_DEVICE;
  5099. status = STATUS_DEVICE_DOES_NOT_EXIST;
  5100. pdoExtension = RefLogicalUnitExtensionWithTag(
  5101. DeviceExtension,
  5102. srb->PathId,
  5103. srb->TargetId,
  5104. srb->Lun,
  5105. FALSE,
  5106. IdeRemoveDevice
  5107. );
  5108. if (pdoExtension) {
  5109. DebugPrint((1, "IdeRemove device removing Pdo %x\n", pdoExtension));
  5110. status = FreePdoWithTag (pdoExtension, TRUE, TRUE, IdeRemoveDevice);
  5111. if (NT_SUCCESS(status)) {
  5112. srb->SrbStatus = SRB_STATUS_SUCCESS;
  5113. }
  5114. }
  5115. return status;
  5116. }
  5117. VOID
  5118. IdeMiniPortTimerDpc(
  5119. IN struct _KDPC *Dpc,
  5120. IN PVOID DeviceObject,
  5121. IN PVOID SystemArgument1,
  5122. IN PVOID SystemArgument2
  5123. )
  5124. /*++
  5125. Routine Description:
  5126. This routine calls the miniport when its requested timer fires.
  5127. It interlocks either with the port spinlock and the interrupt object.
  5128. Arguments:
  5129. Dpc - Unsed.
  5130. DeviceObject - Supplies a pointer to the device object for this adapter.
  5131. SystemArgument1 - Unused.
  5132. SystemArgument2 - Unused.
  5133. Return Value:
  5134. None.
  5135. --*/
  5136. {
  5137. PFDO_EXTENSION deviceExtension = ((PDEVICE_OBJECT) DeviceObject)->DeviceExtension;
  5138. //
  5139. // Acquire the port spinlock.
  5140. //
  5141. KeAcquireSpinLockAtDpcLevel(&deviceExtension->SpinLock);
  5142. //
  5143. // Make sure the timer routine is still desired.
  5144. //
  5145. if (deviceExtension->HwTimerRequest != NULL) {
  5146. KeSynchronizeExecution (
  5147. deviceExtension->InterruptObject,
  5148. (PKSYNCHRONIZE_ROUTINE) deviceExtension->HwTimerRequest,
  5149. deviceExtension->HwDeviceExtension
  5150. );
  5151. }
  5152. //
  5153. // Release the spinlock.
  5154. //
  5155. KeReleaseSpinLockFromDpcLevel(&deviceExtension->SpinLock);
  5156. //
  5157. // Check for miniport work requests. Note this is an unsynchonized
  5158. // test on a bit that can be set by the interrupt routine; however,
  5159. // the worst that can happen is that the completion DPC checks for work
  5160. // twice.
  5161. //
  5162. if (deviceExtension->InterruptData.InterruptFlags & PD_NOTIFICATION_REQUIRED) {
  5163. //
  5164. // Call the completion DPC directly.
  5165. //
  5166. IdePortCompletionDpc( NULL,
  5167. deviceExtension->DeviceObject,
  5168. NULL,
  5169. NULL);
  5170. }
  5171. }
  5172. NTSTATUS
  5173. IdePortFlushLogicalUnit (
  5174. PFDO_EXTENSION FdoExtension,
  5175. PLOGICAL_UNIT_EXTENSION LogUnitExtension,
  5176. BOOLEAN Forced
  5177. )
  5178. {
  5179. NTSTATUS status;
  5180. PIO_STACK_LOCATION irpStack;
  5181. PSCSI_REQUEST_BLOCK srb;
  5182. PKDEVICE_QUEUE_ENTRY packet;
  5183. KIRQL currentIrql;
  5184. PIRP nextIrp;
  5185. PIRP listIrp;
  5186. PIRP powerRelatedIrp;
  5187. //
  5188. // Acquire the spinlock to protect the flags structure and the saved
  5189. // interrupt context.
  5190. //
  5191. KeAcquireSpinLock(&FdoExtension->SpinLock, &currentIrql);
  5192. //
  5193. // Make sure the queue is frozen.
  5194. //
  5195. if ((!(LogUnitExtension->LuFlags & PD_QUEUE_FROZEN)) && (!Forced)) {
  5196. DebugPrint((1,"IdePortFlushLogicalUnit: Request to flush an unfrozen queue!\n"));
  5197. KeReleaseSpinLock(&FdoExtension->SpinLock, currentIrql);
  5198. status = STATUS_INVALID_DEVICE_REQUEST;
  5199. } else {
  5200. listIrp = NULL;
  5201. powerRelatedIrp = NULL;
  5202. if (LogUnitExtension->DeviceObject->DeviceQueue.Busy) {
  5203. while ((packet =
  5204. KeRemoveDeviceQueue(&LogUnitExtension->DeviceObject->DeviceQueue))
  5205. != NULL) {
  5206. nextIrp = CONTAINING_RECORD(packet, IRP, Tail.Overlay.DeviceQueueEntry);
  5207. //
  5208. // Get the srb.
  5209. //
  5210. irpStack = IoGetCurrentIrpStackLocation(nextIrp);
  5211. srb = irpStack->Parameters.Scsi.Srb;
  5212. if (srb->Function == SRB_FUNCTION_ATA_POWER_PASS_THROUGH) {
  5213. ASSERT (!powerRelatedIrp);
  5214. powerRelatedIrp = nextIrp;
  5215. continue;
  5216. }
  5217. //
  5218. // Set the status code.
  5219. //
  5220. srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
  5221. nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  5222. //
  5223. // Link the requests. They will be completed after the
  5224. // spinlock is released.
  5225. //
  5226. nextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)
  5227. listIrp;
  5228. listIrp = nextIrp;
  5229. }
  5230. }
  5231. //
  5232. // clear the pending reuqest blocked by busy device
  5233. //
  5234. if ((LogUnitExtension->LuFlags & PD_LOGICAL_UNIT_IS_BUSY) &&
  5235. (LogUnitExtension->BusyRequest)) {
  5236. nextIrp = LogUnitExtension->BusyRequest;
  5237. irpStack = IoGetCurrentIrpStackLocation(nextIrp);
  5238. srb = irpStack->Parameters.Scsi.Srb;
  5239. LogUnitExtension->BusyRequest = NULL;
  5240. CLRMASK (LogUnitExtension->LuFlags, PD_LOGICAL_UNIT_IS_BUSY);
  5241. if (srb->Function == SRB_FUNCTION_ATA_POWER_PASS_THROUGH) {
  5242. ASSERT (!powerRelatedIrp);
  5243. powerRelatedIrp = nextIrp;
  5244. } else {
  5245. srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
  5246. nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  5247. nextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)
  5248. listIrp;
  5249. listIrp = nextIrp;
  5250. }
  5251. }
  5252. if (LogUnitExtension->PendingRequest) {
  5253. nextIrp = LogUnitExtension->PendingRequest;
  5254. LogUnitExtension->PendingRequest = NULL;
  5255. irpStack = IoGetCurrentIrpStackLocation(nextIrp);
  5256. srb = irpStack->Parameters.Scsi.Srb;
  5257. if (srb->Function == SRB_FUNCTION_ATA_POWER_PASS_THROUGH) {
  5258. ASSERT (!powerRelatedIrp);
  5259. powerRelatedIrp = nextIrp;
  5260. } else {
  5261. srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
  5262. nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  5263. nextIrp->Tail.Overlay.ListEntry.Flink = (PLIST_ENTRY)
  5264. listIrp;
  5265. listIrp = nextIrp;
  5266. }
  5267. }
  5268. //
  5269. // Mark the queue as unfrozen. Since all the requests have
  5270. // been removed and the device queue is no longer busy, it
  5271. // is effectively unfrozen.
  5272. //
  5273. CLRMASK (LogUnitExtension->LuFlags, PD_QUEUE_FROZEN);
  5274. //
  5275. // Release the spinlock.
  5276. //
  5277. KeReleaseSpinLock(&FdoExtension->SpinLock, currentIrql);
  5278. if (powerRelatedIrp) {
  5279. PDEVICE_OBJECT deviceObject = LogUnitExtension->DeviceObject;
  5280. DebugPrint ((DBG_POWER, "Resending power related pass through reuqest 0x%x\n", powerRelatedIrp));
  5281. UnrefPdoWithTag(
  5282. LogUnitExtension,
  5283. powerRelatedIrp
  5284. );
  5285. IdePortDispatch(
  5286. deviceObject,
  5287. powerRelatedIrp
  5288. );
  5289. }
  5290. //
  5291. // Complete the flushed requests.
  5292. //
  5293. while (listIrp != NULL) {
  5294. nextIrp = listIrp;
  5295. listIrp = (PIRP) nextIrp->Tail.Overlay.ListEntry.Flink;
  5296. UnrefLogicalUnitExtensionWithTag(
  5297. FdoExtension,
  5298. LogUnitExtension,
  5299. nextIrp
  5300. );
  5301. IoCompleteRequest(nextIrp, 0);
  5302. }
  5303. status = STATUS_SUCCESS;
  5304. }
  5305. return status;
  5306. }
  5307. PVOID
  5308. IdeMapLockedPagesWithReservedMapping (
  5309. IN PFDO_EXTENSION DeviceExtension,
  5310. IN PSRB_DATA SrbData,
  5311. IN PMDL Mdl
  5312. )
  5313. /*++
  5314. Routine Description:
  5315. This routine attempts to map the physical pages represented by the supplied
  5316. MDL using the adapter's reserved page range.
  5317. Arguments:
  5318. DeviceExtension - Points to the FDO extension
  5319. SrbData - Points to SrbData structure for this request
  5320. Mdl - Points to an MDL that describes the physical range we
  5321. are tring to map.
  5322. Return Value:
  5323. Kernel VA of the mapped pages if mapped successfully.
  5324. NULL if the reserved page range is too small or if the pages are
  5325. not successfully mapped.
  5326. -1 if the reserved pages are already in use.
  5327. Notes:
  5328. This routine is called with the spinlock held.
  5329. --*/
  5330. {
  5331. ULONG_PTR numberOfPages;
  5332. PVOID startingVa;
  5333. PVOID systemAddress;
  5334. //
  5335. // Check if the reserve pages are already in use
  5336. //
  5337. if (DeviceExtension->Flags & PD_RESERVED_PAGES_IN_USE) {
  5338. DebugPrint((1,
  5339. "Reserve pages in use...\n"
  5340. ));
  5341. return (PVOID)-1;
  5342. }
  5343. startingVa = (PVOID)((PCHAR)Mdl->StartVa + Mdl->ByteOffset);
  5344. numberOfPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(startingVa, Mdl->ByteCount);
  5345. if (numberOfPages > IDE_NUM_RESERVED_PAGES) {
  5346. systemAddress = NULL;
  5347. } else {
  5348. //
  5349. // The reserved range is large enough to map all the pages. Go ahead
  5350. // and try to map them. Since we are specifying MmCached as cache
  5351. // type and we've ensured that we have enough reserved pages to
  5352. // cover the request, this should never fail.
  5353. //
  5354. systemAddress = MmMapLockedPagesWithReservedMapping (DeviceExtension->ReservedPages,
  5355. 'PedI',
  5356. Mdl,
  5357. MmCached );
  5358. if (systemAddress == NULL) {
  5359. DebugPrint((1,
  5360. "mapping failed....\n"
  5361. ));
  5362. ASSERT(systemAddress);
  5363. } else {
  5364. DebugPrint((1,
  5365. "mapping....\n"
  5366. ));
  5367. //
  5368. // We need this flag to verify if the reserved pages are already
  5369. // in use. The per request srbData flag is not available to make
  5370. // this check
  5371. //
  5372. ASSERT(!(DeviceExtension->Flags & PD_RESERVED_PAGES_IN_USE));
  5373. SETMASK(DeviceExtension->Flags, PD_RESERVED_PAGES_IN_USE);
  5374. //
  5375. // we need this flag to unmap the pages. The flag in the
  5376. // device extension cannot be relied upon as it might indicate
  5377. // the flags for the next request
  5378. //
  5379. ASSERT(!(SrbData->Flags & SRB_DATA_RESERVED_PAGES));
  5380. SETMASK(SrbData->Flags, SRB_DATA_RESERVED_PAGES);
  5381. }
  5382. }
  5383. return systemAddress;
  5384. }
  5385. VOID
  5386. IdeUnmapReservedMapping (
  5387. IN PFDO_EXTENSION DeviceExtension,
  5388. IN PSRB_DATA SrbData,
  5389. IN PMDL Mdl
  5390. )
  5391. /*++
  5392. Routine Description :
  5393. Unmap the physical pages represented by the Mdl
  5394. Arguments:
  5395. DeviceExtension: The Fdo extension
  5396. Mdl: Mdl for the request
  5397. Return Value:
  5398. No return value
  5399. Notes:
  5400. This routine is called with the spinlock held
  5401. --*/
  5402. {
  5403. DebugPrint((1,
  5404. "Unmapping....\n"
  5405. ));
  5406. ASSERT(DeviceExtension->Flags & PD_RESERVED_PAGES_IN_USE);
  5407. CLRMASK(DeviceExtension->Flags, PD_RESERVED_PAGES_IN_USE);
  5408. ASSERT(SrbData->Flags & SRB_DATA_RESERVED_PAGES);
  5409. CLRMASK(SrbData->Flags, SRB_DATA_RESERVED_PAGES);
  5410. MmUnmapReservedMapping (
  5411. DeviceExtension->ReservedPages,
  5412. 'PedI',
  5413. Mdl
  5414. );
  5415. }