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.

4883 lines
137 KiB

  1. /*++
  2. Copyright (C) 1993-99 Microsoft Corporation
  3. Module Name:
  4. devpdo.c
  5. Abstract:
  6. --*/
  7. #include "ideport.h"
  8. #ifdef ALLOC_PRAGMA
  9. #pragma alloc_text(PAGE, IdePortSendPassThrough)
  10. #pragma alloc_text(PAGE, DeviceInitIdStrings)
  11. #pragma alloc_text(PAGE, DeviceInitDeviceType)
  12. #pragma alloc_text(PAGE, DeviceQueryDeviceRelations)
  13. #pragma alloc_text(PAGE, DeviceUsageNotification)
  14. #pragma alloc_text(PAGE, DeviceBuildStorageDeviceDescriptor)
  15. #pragma alloc_text(PAGE, DeviceQueryPnPDeviceState)
  16. #pragma alloc_text(PAGE, DeviceQueryCapabilities)
  17. #pragma alloc_text(PAGE, DeviceBuildBusId)
  18. #pragma alloc_text(PAGE, DeviceBuildCompatibleId)
  19. #pragma alloc_text(PAGE, DeviceBuildHardwareId)
  20. #pragma alloc_text(PAGE, DeviceBuildInstanceId)
  21. #pragma alloc_text(PAGE, DeviceQueryId)
  22. #pragma alloc_text(PAGE, DeviceQueryText)
  23. #pragma alloc_text(PAGE, DeviceIdeTestUnitReady)
  24. #pragma alloc_text(PAGE, DeviceQueryInitData)
  25. #pragma alloc_text(PAGE, DeviceQueryStopRemoveDevice)
  26. #pragma alloc_text(PAGE, DeviceStopDevice)
  27. #pragma alloc_text(PAGE, CopyField)
  28. #pragma alloc_text(NONPAGE, DeviceIdeModeSelect)
  29. #pragma alloc_text(NONPAGE, DeviceInitDeviceState)
  30. #pragma alloc_text(NONPAGE, DeviceStartDeviceQueue)
  31. #endif // ALLOC_PRAGMA
  32. PDEVICE_OBJECT
  33. DeviceCreatePhysicalDeviceObject (
  34. IN PDRIVER_OBJECT DriverObject,
  35. IN PFDO_EXTENSION FdoExtension,
  36. IN PUNICODE_STRING DeviceObjectName
  37. )
  38. {
  39. PDEVICE_OBJECT physicalDeviceObject;
  40. PPDO_EXTENSION pdoExtension;
  41. NTSTATUS status;
  42. physicalDeviceObject = NULL;
  43. status = IoCreateDevice(
  44. DriverObject, // our driver object
  45. sizeof(PDO_EXTENSION), // size of our extension
  46. DeviceObjectName, // our name
  47. FILE_DEVICE_MASS_STORAGE, // device type
  48. FILE_DEVICE_SECURE_OPEN, // device characteristics
  49. FALSE, // not exclusive
  50. &physicalDeviceObject // store new device object here
  51. );
  52. if (NT_SUCCESS(status)) {
  53. //
  54. // spinning up could take a lot of current;
  55. //
  56. physicalDeviceObject->Flags |= DO_POWER_INRUSH | DO_DIRECT_IO;
  57. //
  58. // fix up alignment requirement
  59. //
  60. physicalDeviceObject->AlignmentRequirement = FdoExtension->DeviceObject->AlignmentRequirement;
  61. if (physicalDeviceObject->AlignmentRequirement < 1) {
  62. physicalDeviceObject->AlignmentRequirement = 1;
  63. }
  64. pdoExtension = physicalDeviceObject->DeviceExtension;
  65. RtlZeroMemory (pdoExtension, sizeof(PDO_EXTENSION));
  66. //
  67. // Keeping track of those device objects
  68. //
  69. pdoExtension->DriverObject = DriverObject;
  70. pdoExtension->DeviceObject = physicalDeviceObject;
  71. //
  72. // keep track of our parent
  73. //
  74. pdoExtension->ParentDeviceExtension = FdoExtension;
  75. //
  76. // Dispatch Table
  77. //
  78. pdoExtension->DefaultDispatch = IdePortNoSupportIrp;
  79. pdoExtension->PnPDispatchTable = PdoPnpDispatchTable;
  80. pdoExtension->PowerDispatchTable = PdoPowerDispatchTable;
  81. pdoExtension->WmiDispatchTable = PdoWmiDispatchTable;
  82. //
  83. // We have to be in this D0 state before we can be enumurated
  84. //
  85. pdoExtension->SystemPowerState = PowerSystemWorking;
  86. pdoExtension->DevicePowerState = PowerDeviceD0;
  87. }
  88. return physicalDeviceObject;
  89. }
  90. NTSTATUS
  91. DeviceStartDevice (
  92. IN PDEVICE_OBJECT DeviceObject,
  93. IN OUT PIRP Irp
  94. )
  95. {
  96. NTSTATUS status;
  97. PPDO_EXTENSION pdoExtension;
  98. KEVENT event;
  99. pdoExtension = RefPdoWithTag(
  100. DeviceObject,
  101. TRUE,
  102. DeviceStartDevice
  103. );
  104. if (pdoExtension) {
  105. KIRQL currentIrql;
  106. // ISSUE: if we are not lun0, we really should wait for lun0 to start first
  107. #if defined (IDEPORT_WMI_SUPPORT)
  108. //
  109. // register with WMI
  110. //
  111. if (!(pdoExtension->PdoState & PDOS_STARTED)) {
  112. IdePortWmiRegister ((PDEVICE_EXTENSION_HEADER)pdoExtension);
  113. }
  114. else {
  115. DebugPrint((1, "ATAPI: PDOe %x Didn't register for WMI\n", pdoExtension));
  116. }
  117. #endif // IDEPORT_WMI_SUPPORT
  118. KeAcquireSpinLock(&pdoExtension->PdoSpinLock, &currentIrql);
  119. SETMASK (pdoExtension->PdoState, PDOS_STARTED);
  120. CLRMASK (pdoExtension->PdoState, PDOS_STOPPED | PDOS_REMOVED | PDOS_SURPRISE_REMOVED | PDOS_DISABLED_BY_USER);
  121. KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
  122. //
  123. // need to init device with acpi GTF before processing
  124. // the first request
  125. //
  126. ASSERT(pdoExtension->InitDeviceWithAcpiGtf == 0);
  127. InterlockedIncrement (&pdoExtension->InitDeviceWithAcpiGtf);
  128. //
  129. // keep the device queue block until we can go through some
  130. // init code
  131. //
  132. DeviceStopDeviceQueueSafe (pdoExtension, PDOS_QUEUE_FROZEN_BY_START, FALSE);
  133. //
  134. // clear the stop_device block
  135. //
  136. status = DeviceStartDeviceQueue (pdoExtension, PDOS_QUEUE_FROZEN_BY_STOP_DEVICE);
  137. //
  138. // init pdo with acpi bios _GTF data
  139. //
  140. KeInitializeEvent(&event,
  141. NotificationEvent,
  142. FALSE);
  143. DeviceQueryInitData(
  144. pdoExtension
  145. );
  146. //
  147. // can't really tell if it is enabled or not
  148. // assume it is.
  149. //
  150. pdoExtension->WriteCacheEnable = TRUE;
  151. status = DeviceInitDeviceState(
  152. pdoExtension,
  153. DeviceInitCompletionRoutine,
  154. &event
  155. );
  156. if (!NT_SUCCESS(status)) {
  157. ASSERT(NT_SUCCESS(status));
  158. DeviceInitCompletionRoutine (
  159. &event,
  160. status
  161. );
  162. } else {
  163. KeWaitForSingleObject(&event,
  164. Executive,
  165. KernelMode,
  166. FALSE,
  167. NULL);
  168. }
  169. //
  170. // open the queue
  171. //
  172. DeviceStartDeviceQueue (pdoExtension, PDOS_QUEUE_FROZEN_BY_START);
  173. UnrefPdoWithTag(
  174. pdoExtension,
  175. DeviceStartDevice
  176. );
  177. status = STATUS_SUCCESS;
  178. } else {
  179. status = STATUS_DEVICE_DOES_NOT_EXIST;
  180. }
  181. Irp->IoStatus.Status = status;
  182. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  183. return status;
  184. }
  185. NTSTATUS
  186. DeviceStartDeviceQueue (
  187. IN PPDO_EXTENSION PdoExtension,
  188. IN ULONG StopFlagToClear
  189. )
  190. {
  191. NTSTATUS status;
  192. KIRQL currentIrql;
  193. BOOLEAN restartQueue;
  194. ULONG oldPdoState;
  195. restartQueue = FALSE;
  196. KeAcquireSpinLock(&PdoExtension->PdoSpinLock, &currentIrql);
  197. oldPdoState = PdoExtension->PdoState;
  198. CLRMASK (PdoExtension->PdoState, StopFlagToClear);
  199. if (PdoExtension->PdoState & PDOS_DEADMEAT) {
  200. restartQueue = FALSE;
  201. } else if ((oldPdoState & PDOS_MUST_QUEUE) !=
  202. (PdoExtension->PdoState & PDOS_MUST_QUEUE)) {
  203. //
  204. // make sure we have actually cleared some
  205. // PDOS_MUST_QUEUE bits.
  206. //
  207. if (!(PdoExtension->PdoState & PDOS_MUST_QUEUE)) {
  208. restartQueue = TRUE;
  209. }
  210. }
  211. KeReleaseSpinLock(&PdoExtension->PdoSpinLock, currentIrql);
  212. //
  213. // Restart queue
  214. //
  215. if (restartQueue) {
  216. KeAcquireSpinLock(&PdoExtension->ParentDeviceExtension->SpinLock, &currentIrql);
  217. GetNextLuPendingRequest(PdoExtension->ParentDeviceExtension, PdoExtension);
  218. KeLowerIrql(currentIrql);
  219. DebugPrint ((DBG_PNP, "IdePort: pdo 0x%x is pnp started with 0x%x items queued\n", PdoExtension->DeviceObject, PdoExtension->NumberOfIrpQueued));
  220. }
  221. return STATUS_SUCCESS;
  222. }
  223. NTSTATUS
  224. DeviceStopDevice (
  225. IN PDEVICE_OBJECT DeviceObject,
  226. IN OUT PIRP Irp
  227. )
  228. {
  229. NTSTATUS status;
  230. PPDO_EXTENSION pdoExtension;
  231. PAGED_CODE();
  232. pdoExtension = RefPdoWithTag(
  233. DeviceObject,
  234. TRUE,
  235. DeviceStopDevice
  236. );
  237. if (pdoExtension) {
  238. DebugPrint ((
  239. DBG_PNP,
  240. "pdoe 0x%x 0x%x (%d, %d, %d) got a STOP device\n",
  241. pdoExtension,
  242. pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  243. pdoExtension->PathId,
  244. pdoExtension->TargetId,
  245. pdoExtension->Lun
  246. ));
  247. status = DeviceStopDeviceQueueSafe (pdoExtension, PDOS_QUEUE_FROZEN_BY_STOP_DEVICE, FALSE);
  248. UnrefPdoWithTag (
  249. pdoExtension,
  250. DeviceStopDevice
  251. );
  252. } else {
  253. status = STATUS_DEVICE_DOES_NOT_EXIST;
  254. }
  255. Irp->IoStatus.Status = status;
  256. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  257. return status;
  258. }
  259. NTSTATUS
  260. DeviceStopDeviceQueueSafe (
  261. IN PPDO_EXTENSION PdoExtension,
  262. IN ULONG QueueStopFlag,
  263. IN BOOLEAN LowMem
  264. )
  265. {
  266. NTSTATUS status;
  267. PPDO_STOP_QUEUE_CONTEXT context;
  268. KIRQL currentIrql;
  269. BOOLEAN queueAlreadyBlocked = FALSE;
  270. PENUMERATION_STRUCT enumStruct;
  271. ULONG retryCount = 1;
  272. ULONG locked;
  273. ASSERT (PDOS_MUST_QUEUE & QueueStopFlag);
  274. //
  275. // make sure the queue is not already blocked for the same reason
  276. //
  277. ASSERT (!(PdoExtension->PdoState & QueueStopFlag));
  278. if (LowMem) {
  279. //
  280. //Lock
  281. //
  282. ASSERT(InterlockedCompareExchange(&(PdoExtension->ParentDeviceExtension->EnumStructLock),
  283. 1, 0) == 0);
  284. enumStruct=PdoExtension->ParentDeviceExtension->PreAllocEnumStruct;
  285. if (enumStruct) {
  286. context=enumStruct->StopQContext;
  287. retryCount=5;
  288. } else {
  289. ASSERT(enumStruct);
  290. LowMem=FALSE;
  291. retryCount=1;
  292. }
  293. }
  294. if (!LowMem) {
  295. context = ExAllocatePool (NonPagedPool, sizeof(*context));
  296. }
  297. if (context) {
  298. //
  299. // check to see if queue is already blocked
  300. //
  301. KeAcquireSpinLock(&PdoExtension->PdoSpinLock, &currentIrql);
  302. if (PdoExtension->PdoState & (PDOS_MUST_QUEUE | PDOS_DEADMEAT)) {
  303. SETMASK (PdoExtension->PdoState, QueueStopFlag);
  304. queueAlreadyBlocked = TRUE;
  305. }
  306. KeReleaseSpinLock(&PdoExtension->PdoSpinLock, currentIrql);
  307. RtlZeroMemory (context, sizeof (*context));
  308. KeInitializeEvent(&context->Event,
  309. NotificationEvent,
  310. FALSE);
  311. context->PdoExtension = PdoExtension;
  312. context->QueueStopFlag = QueueStopFlag;
  313. context->AtaPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_NO_OP;
  314. if (queueAlreadyBlocked) {
  315. IdeStopQueueCompletionRoutine (
  316. PdoExtension->DeviceObject,
  317. context,
  318. STATUS_SUCCESS
  319. );
  320. status = STATUS_SUCCESS;
  321. } else {
  322. //
  323. // send a no-op request to block the queue
  324. //
  325. status = STATUS_INSUFFICIENT_RESOURCES;
  326. //
  327. // if lowMem=0, this loop will execute only once
  328. //
  329. while (status == STATUS_INSUFFICIENT_RESOURCES && retryCount--) {
  330. status = IssueAsyncAtaPassThroughSafe (
  331. PdoExtension->ParentDeviceExtension,
  332. PdoExtension,
  333. &context->AtaPassThroughData,
  334. FALSE,
  335. IdeStopQueueCompletionRoutine,
  336. context,
  337. TRUE, // TRUE really means complete this irp before starting a new one
  338. DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
  339. LowMem
  340. );
  341. ASSERT (NT_SUCCESS(status));
  342. if (status == STATUS_PENDING) {
  343. KeWaitForSingleObject(&context->Event,
  344. Executive,
  345. KernelMode,
  346. FALSE,
  347. NULL);
  348. }
  349. status = context->Status;
  350. }
  351. }
  352. //
  353. // Don't free the context if it was Pre-alloced.
  354. //
  355. if (!LowMem) {
  356. ExFreePool (context);
  357. } else {
  358. // Unlock
  359. ASSERT(InterlockedCompareExchange(&(PdoExtension->ParentDeviceExtension->EnumStructLock),
  360. 0, 1) == 1);
  361. }
  362. } else {
  363. status = STATUS_NO_MEMORY;
  364. }
  365. return status;
  366. }
  367. VOID
  368. IdeStopQueueCompletionRoutine (
  369. IN PDEVICE_OBJECT DeviceObject,
  370. IN PPDO_STOP_QUEUE_CONTEXT Context,
  371. IN NTSTATUS Status
  372. )
  373. {
  374. PPDO_EXTENSION pdoExtension;
  375. KIRQL currentIrql;
  376. pdoExtension = Context->PdoExtension;
  377. Context->Status = Status;
  378. if (NT_SUCCESS(Status)) {
  379. KeAcquireSpinLock(&pdoExtension->PdoSpinLock, &currentIrql);
  380. if (Context->QueueStopFlag == PDOS_QUEUE_FROZEN_BY_STOP_DEVICE) {
  381. SETMASK (pdoExtension->PdoState, PDOS_STOPPED);
  382. }
  383. SETMASK (pdoExtension->PdoState, Context->QueueStopFlag);
  384. DebugPrint ((DBG_PNP, "IdePort: pdo 0x%x is pnp stopped with 0x%x items queued\n", DeviceObject, pdoExtension->NumberOfIrpQueued));
  385. KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
  386. } else {
  387. DebugPrint ((0, "IdePort: unable to stop pdo 0x%x\n", pdoExtension));
  388. }
  389. KeSetEvent (&Context->Event, 0, FALSE);
  390. return;
  391. }
  392. NTSTATUS
  393. DeviceRemoveDevice (
  394. IN PDEVICE_OBJECT DeviceObject,
  395. IN OUT PIRP Irp
  396. )
  397. {
  398. NTSTATUS status;
  399. PPDO_EXTENSION pdoExtension;
  400. KIRQL currentIrql;
  401. PDEVICE_OBJECT parentAttacheePdo;
  402. BOOLEAN freePdo;
  403. BOOLEAN callIoDeleteDevice;
  404. BOOLEAN deregWmi = FALSE;
  405. pdoExtension = RefPdoWithTag(
  406. DeviceObject,
  407. TRUE,
  408. DeviceRemoveDevice
  409. );
  410. if (pdoExtension) {
  411. PIO_STACK_LOCATION thisIrpSp;
  412. KIRQL currentIrql;
  413. thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
  414. KeAcquireSpinLock(&pdoExtension->PdoSpinLock, &currentIrql);
  415. if (pdoExtension->PdoState & PDOS_NEED_RESCAN) {
  416. CLRMASK (pdoExtension->PdoState, PDOS_NEED_RESCAN);
  417. //
  418. // get ready for IoInvalidateDeviceRelations
  419. //
  420. parentAttacheePdo = pdoExtension->ParentDeviceExtension->AttacheePdo;
  421. } else {
  422. parentAttacheePdo = NULL;
  423. }
  424. if (thisIrpSp->MinorFunction == IRP_MN_REMOVE_DEVICE) {
  425. DebugPrint ((
  426. DBG_PNP,
  427. "pdoe 0x%x 0x%x (%d, %d, %d) got a REMOVE device\n",
  428. pdoExtension,
  429. pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  430. pdoExtension->PathId,
  431. pdoExtension->TargetId,
  432. pdoExtension->Lun
  433. ));
  434. if (pdoExtension->PdoState & (PDOS_DEADMEAT | PDOS_SURPRISE_REMOVED)) {
  435. SETMASK (pdoExtension->PdoState, PDOS_REMOVED);
  436. if (pdoExtension->PdoState & PDOS_REPORTED_TO_PNP) {
  437. freePdo = FALSE;
  438. } else {
  439. freePdo = TRUE;
  440. }
  441. } else {
  442. SETMASK (pdoExtension->PdoState, PDOS_DISABLED_BY_USER);
  443. freePdo = FALSE;
  444. }
  445. if ((pdoExtension->PdoState & PDOS_STARTED) &&
  446. !(pdoExtension->PdoState & PDOS_SURPRISE_REMOVED)) {
  447. deregWmi = TRUE;
  448. }
  449. CLRMASK (pdoExtension->PdoState, PDOS_STARTED);
  450. //
  451. // not claimed anymore
  452. //
  453. CLRMASK (pdoExtension->PdoState, PDOS_DEVICE_CLIAMED);
  454. callIoDeleteDevice = TRUE;
  455. } else {
  456. DebugPrint ((
  457. DBG_PNP,
  458. "pdoe 0x%x 0x%x (%d, %d, %d) got a SURPRISE_REMOVE device\n",
  459. pdoExtension,
  460. pdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  461. pdoExtension->PathId,
  462. pdoExtension->TargetId,
  463. pdoExtension->Lun
  464. ));
  465. SETMASK (pdoExtension->PdoState, PDOS_SURPRISE_REMOVED | PDOS_DEADMEAT);
  466. if (pdoExtension->PdoState & PDOS_STARTED) {
  467. deregWmi = TRUE;
  468. }
  469. freePdo = TRUE;
  470. freePdo = FALSE;
  471. callIoDeleteDevice = FALSE;
  472. }
  473. KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
  474. #if defined (IDEPORT_WMI_SUPPORT)
  475. //
  476. // deregister with WMI
  477. //
  478. if (deregWmi) {
  479. IdePortWmiDeregister ((PDEVICE_EXTENSION_HEADER)pdoExtension);
  480. }
  481. #endif // IDEPORT_WMI_SUPPORT
  482. if (freePdo) {
  483. status = FreePdoWithTag(
  484. pdoExtension,
  485. TRUE,
  486. callIoDeleteDevice,
  487. DeviceRemoveDevice
  488. );
  489. } else {
  490. //
  491. // release the pdo
  492. //
  493. UnrefPdoWithTag (
  494. pdoExtension,
  495. DeviceRemoveDevice
  496. );
  497. }
  498. if (parentAttacheePdo) {
  499. IoInvalidateDeviceRelations (
  500. parentAttacheePdo,
  501. BusRelations
  502. );
  503. }
  504. }
  505. Irp->IoStatus.Status = STATUS_SUCCESS;
  506. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  507. return STATUS_SUCCESS;
  508. } // DeviceRemoveDevice
  509. NTSTATUS
  510. DeviceUsageNotification (
  511. IN PDEVICE_OBJECT DeviceObject,
  512. IN OUT PIRP Irp
  513. )
  514. {
  515. PPDO_EXTENSION pdoExtension;
  516. NTSTATUS status;
  517. PAGED_CODE();
  518. pdoExtension = RefPdoWithTag(
  519. DeviceObject,
  520. FALSE,
  521. DeviceUsageNotification
  522. );
  523. status = Irp->IoStatus.Status;
  524. if (pdoExtension) {
  525. PIO_STACK_LOCATION irpSp;
  526. PDEVICE_OBJECT targetDeviceObject;
  527. IO_STATUS_BLOCK ioStatus;
  528. PULONG deviceUsageCount;
  529. irpSp = IoGetCurrentIrpStackLocation(Irp);
  530. if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging) {
  531. //
  532. // Adjust the paging path count for this device.
  533. //
  534. deviceUsageCount = &pdoExtension->PagingPathCount;
  535. //
  536. // changing device state
  537. //
  538. IoInvalidateDeviceState(pdoExtension->DeviceObject);
  539. } else if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeHibernation) {
  540. //
  541. // Adjust the paging path count for this device.
  542. //
  543. deviceUsageCount = &pdoExtension->HiberPathCount;
  544. } else if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeDumpFile) {
  545. //
  546. // Adjust the paging path count for this device.
  547. //
  548. deviceUsageCount = &pdoExtension->CrashDumpPathCount;
  549. } else {
  550. deviceUsageCount = NULL;
  551. DebugPrint ((DBG_ALWAYS,
  552. "ATAPI: Unknown IRP_MN_DEVICE_USAGE_NOTIFICATION type: 0x%x\n",
  553. irpSp->Parameters.UsageNotification.Type));
  554. }
  555. //
  556. // get the top of parent's device stack
  557. //
  558. targetDeviceObject = IoGetAttachedDeviceReference(
  559. pdoExtension->
  560. ParentDeviceExtension->
  561. DeviceObject);
  562. ioStatus.Status = STATUS_NOT_SUPPORTED;
  563. status = IdePortSyncSendIrp (targetDeviceObject, irpSp, &ioStatus);
  564. ObDereferenceObject (targetDeviceObject);
  565. if (NT_SUCCESS(status)) {
  566. POWER_STATE powerState;
  567. if (deviceUsageCount) {
  568. IoAdjustPagingPathCount (
  569. deviceUsageCount,
  570. irpSp->Parameters.UsageNotification.InPath
  571. );
  572. }
  573. if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeDumpFile) {
  574. //
  575. // reset the idle timeout to "forever"
  576. //
  577. DeviceRegisterIdleDetection (
  578. pdoExtension,
  579. DEVICE_VERY_LONG_IDLE_TIMEOUT,
  580. DEVICE_VERY_LONG_IDLE_TIMEOUT
  581. );
  582. if (pdoExtension->IdleCounter) {
  583. PoSetDeviceBusy (pdoExtension->IdleCounter);
  584. }
  585. //
  586. // spin up the crash dump drive
  587. //
  588. powerState.DeviceState = PowerDeviceD0;
  589. PoRequestPowerIrp (
  590. pdoExtension->DeviceObject,
  591. IRP_MN_SET_POWER,
  592. powerState,
  593. NULL,
  594. NULL,
  595. NULL
  596. );
  597. }
  598. }
  599. //
  600. // release the pdo
  601. //
  602. UnrefPdoWithTag (
  603. pdoExtension,
  604. DeviceUsageNotification
  605. );
  606. } else {
  607. status = STATUS_NO_SUCH_DEVICE;
  608. }
  609. Irp->IoStatus.Status = status;
  610. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  611. return status;
  612. } // DeviceUsageNotification
  613. NTSTATUS
  614. DeviceQueryStopRemoveDevice (
  615. IN PDEVICE_OBJECT DeviceObject,
  616. IN OUT PIRP Irp
  617. )
  618. {
  619. NTSTATUS status;
  620. PPDO_EXTENSION pdoExtension;
  621. PIO_STACK_LOCATION thisIrpSp;
  622. PAGED_CODE();
  623. thisIrpSp = IoGetCurrentIrpStackLocation(Irp);
  624. pdoExtension = RefPdoWithTag(
  625. DeviceObject,
  626. TRUE,
  627. DeviceQueryStopRemoveDevice
  628. );
  629. if (pdoExtension) {
  630. if ((pdoExtension->PdoState & PDOS_LEGACY_ATTACHER) &&
  631. (thisIrpSp->MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE)) {
  632. status = STATUS_UNSUCCESSFUL;
  633. } else if (pdoExtension->PagingPathCount ||
  634. pdoExtension->CrashDumpPathCount) {
  635. //
  636. // Check the paging path count for this device.
  637. //
  638. status = STATUS_UNSUCCESSFUL;
  639. } else {
  640. status = STATUS_SUCCESS;
  641. }
  642. UnrefPdoWithTag (
  643. pdoExtension,
  644. DeviceQueryStopRemoveDevice
  645. );
  646. } else {
  647. status = STATUS_NO_SUCH_DEVICE;
  648. DebugPrint((1, "Query remove failed\n"));
  649. }
  650. Irp->IoStatus.Status = status;
  651. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  652. return status;
  653. } // DeviceQueryStopRemoveDevice
  654. NTSTATUS
  655. DeviceQueryId (
  656. IN PDEVICE_OBJECT DeviceObject,
  657. IN OUT PIRP Irp
  658. )
  659. {
  660. PIO_STACK_LOCATION thisIrpSp;
  661. PPDO_EXTENSION pdoExtension;
  662. NTSTATUS status;
  663. PWSTR idString;
  664. PAGED_CODE();
  665. thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
  666. idString = NULL;
  667. status = STATUS_DEVICE_DOES_NOT_EXIST;
  668. pdoExtension = RefPdoWithTag (
  669. DeviceObject,
  670. TRUE,
  671. DeviceQueryId
  672. );
  673. if (pdoExtension) {
  674. switch (thisIrpSp->Parameters.QueryId.IdType) {
  675. case BusQueryDeviceID:
  676. //
  677. // Caller wants the bus ID of this device.
  678. //
  679. idString = DeviceBuildBusId(pdoExtension);
  680. break;
  681. case BusQueryInstanceID:
  682. //
  683. // Caller wants the unique id of the device
  684. //
  685. idString = DeviceBuildInstanceId(pdoExtension);
  686. break;
  687. case BusQueryCompatibleIDs:
  688. //
  689. // Caller wants the compatible id of the device
  690. //
  691. idString = DeviceBuildCompatibleId(pdoExtension);
  692. break;
  693. case BusQueryHardwareIDs:
  694. //
  695. // Caller wants the hardware id of the device
  696. //
  697. idString = DeviceBuildHardwareId(pdoExtension);
  698. break;
  699. default:
  700. DebugPrint ((1, "ideport: QueryID type %d not supported\n", thisIrpSp->Parameters.QueryId.IdType));
  701. status = STATUS_NOT_SUPPORTED;
  702. break;
  703. }
  704. UnrefPdoWithTag(
  705. pdoExtension,
  706. DeviceQueryId
  707. );
  708. }
  709. if( idString != NULL ){
  710. Irp->IoStatus.Information = (ULONG_PTR) idString;
  711. status = STATUS_SUCCESS;
  712. }
  713. Irp->IoStatus.Status = status;
  714. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  715. return status;
  716. } // DeviceQueryId
  717. PWSTR
  718. DeviceBuildBusId(
  719. IN PPDO_EXTENSION pdoExtension
  720. )
  721. {
  722. #define IDE_BUS_ID_PREFIX "IDE\\"
  723. PUCHAR deviceTypeIdString;
  724. ULONG deviceTypeIdLen;
  725. UCHAR compatibleId[10];
  726. USHORT idStringBufLen;
  727. PUCHAR idString;
  728. ANSI_STRING ansiBusIdString;
  729. PWCHAR idWString;
  730. UNICODE_STRING unicodeIdString;
  731. PAGED_CODE();
  732. //
  733. // get the device type
  734. //
  735. deviceTypeIdString = (PUCHAR)IdePortGetDeviceTypeString (
  736. pdoExtension->ScsiDeviceType
  737. );
  738. if (deviceTypeIdString == NULL) {
  739. sprintf (compatibleId,
  740. "Type%d",
  741. pdoExtension->ScsiDeviceType);
  742. deviceTypeIdString = compatibleId;
  743. }
  744. deviceTypeIdLen = strlen(deviceTypeIdString);
  745. idStringBufLen = (USHORT)(strlen( IDE_BUS_ID_PREFIX ) +
  746. deviceTypeIdLen +
  747. sizeof (pdoExtension->FullVendorProductId) +
  748. sizeof (pdoExtension->FullProductRevisionId) +
  749. sizeof (pdoExtension->FullSerialNumber) +
  750. 1);
  751. //
  752. // get the string buffers
  753. //
  754. idWString = ExAllocatePool( PagedPool, idStringBufLen * sizeof(WCHAR));
  755. idString = ExAllocatePool( PagedPool, idStringBufLen);
  756. if (idString && idWString) {
  757. //
  758. // build the ansi string
  759. //
  760. sprintf(idString, IDE_BUS_ID_PREFIX);
  761. CopyField(idString + strlen(idString),
  762. deviceTypeIdString,
  763. deviceTypeIdLen,
  764. '_');
  765. CopyField(idString + strlen(idString),
  766. pdoExtension->FullVendorProductId,
  767. sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR),
  768. '_');
  769. CopyField(idString + strlen(idString),
  770. pdoExtension->FullProductRevisionId,
  771. sizeof (pdoExtension->FullProductRevisionId) - sizeof(CHAR),
  772. '_');
  773. RtlInitAnsiString (
  774. &ansiBusIdString,
  775. idString
  776. );
  777. //
  778. // build the unicode string
  779. //
  780. unicodeIdString.Length = 0;
  781. unicodeIdString.MaximumLength = idStringBufLen * sizeof(WCHAR);
  782. unicodeIdString.Buffer = (PWSTR) idWString;
  783. RtlAnsiStringToUnicodeString(
  784. &unicodeIdString,
  785. &ansiBusIdString,
  786. FALSE
  787. );
  788. unicodeIdString.Buffer[unicodeIdString.Length/sizeof(WCHAR)] = L'\0';
  789. } else {
  790. if (idWString) {
  791. ExFreePool (idWString);
  792. }
  793. }
  794. if (idString) {
  795. ExFreePool (idString);
  796. }
  797. return idWString;
  798. }
  799. PWSTR
  800. DeviceBuildInstanceId(
  801. IN PPDO_EXTENSION pdoExtension
  802. )
  803. {
  804. PWSTR idString;
  805. USHORT idStringBufLen;
  806. NTSTATUS status;
  807. WCHAR ideNonUniqueIdFormat[] = L"%x.%x.%x";
  808. PAGED_CODE();
  809. idStringBufLen = (sizeof(pdoExtension->FullSerialNumber) + 1) * sizeof(WCHAR);
  810. idString = ExAllocatePool (PagedPool, idStringBufLen);
  811. if( idString == NULL ){
  812. return NULL;
  813. }
  814. //
  815. // Form the string and return it.
  816. //
  817. if (pdoExtension->FullSerialNumber[0]) {
  818. ANSI_STRING ansiCompatibleIdString;
  819. UNICODE_STRING unicodeIdString;
  820. //
  821. // unique id
  822. //
  823. RtlInitAnsiString (
  824. &ansiCompatibleIdString,
  825. pdoExtension->FullSerialNumber
  826. );
  827. unicodeIdString.Length = 0;
  828. unicodeIdString.MaximumLength = idStringBufLen;
  829. unicodeIdString.Buffer = idString;
  830. RtlAnsiStringToUnicodeString(
  831. &unicodeIdString,
  832. &ansiCompatibleIdString,
  833. FALSE
  834. );
  835. idString[unicodeIdString.Length / 2] = L'\0';
  836. } else {
  837. //
  838. // non-unique id
  839. //
  840. swprintf( idString,
  841. ideNonUniqueIdFormat,
  842. pdoExtension->PathId,
  843. pdoExtension->TargetId,
  844. pdoExtension->Lun);
  845. }
  846. return idString;
  847. }
  848. PWSTR
  849. DeviceBuildCompatibleId(
  850. IN PPDO_EXTENSION pdoExtension
  851. )
  852. {
  853. NTSTATUS status;
  854. PCSTR compatibleIdString;
  855. ANSI_STRING ansiCompatibleIdString;
  856. UNICODE_STRING unicodeIdString;
  857. PWCHAR compIdStrings;
  858. ULONG totalBufferLen;
  859. PAGED_CODE();
  860. if (pdoExtension->ParentDeviceExtension->HwDeviceExtension->
  861. DeviceFlags[pdoExtension->TargetId] & DFLAGS_LS120_FORMAT) {
  862. //
  863. // ls-120 drive detected
  864. // return the special ls-120 compatible ID
  865. //
  866. compatibleIdString = SuperFloppyCompatibleIdString;
  867. } else {
  868. compatibleIdString = IdePortGetCompatibleIdString (pdoExtension->ScsiDeviceType);
  869. }
  870. RtlInitAnsiString (
  871. &ansiCompatibleIdString,
  872. compatibleIdString
  873. );
  874. totalBufferLen = RtlAnsiStringToUnicodeSize (
  875. &ansiCompatibleIdString
  876. );
  877. unicodeIdString.Length = 0;
  878. unicodeIdString.MaximumLength = (USHORT) totalBufferLen;
  879. //
  880. // null terminator
  881. //
  882. totalBufferLen += sizeof(WCHAR);
  883. //
  884. // multi-string null terminator
  885. //
  886. totalBufferLen += sizeof(WCHAR);
  887. compIdStrings = ExAllocatePool (PagedPool, totalBufferLen);
  888. if (compIdStrings) {
  889. unicodeIdString.Buffer = compIdStrings;
  890. } else {
  891. unicodeIdString.Buffer = NULL;
  892. }
  893. if (unicodeIdString.Buffer) {
  894. RtlAnsiStringToUnicodeString(
  895. &unicodeIdString,
  896. &ansiCompatibleIdString,
  897. FALSE
  898. );
  899. unicodeIdString.Buffer[unicodeIdString.Length/2 + 0] = L'\0';
  900. unicodeIdString.Buffer[unicodeIdString.Length/2 + 1] = L'\0';
  901. }
  902. return compIdStrings;
  903. }
  904. PWSTR
  905. DeviceBuildHardwareId(
  906. IN PPDO_EXTENSION pdoExtension
  907. )
  908. {
  909. #define NUMBER_HARDWARE_STRINGS 5
  910. ULONG i;
  911. PWSTR idMultiString;
  912. PWSTR idString;
  913. UCHAR scratch[64];
  914. ULONG idStringLen;
  915. NTSTATUS status;
  916. ANSI_STRING ansiCompatibleIdString;
  917. UNICODE_STRING unicodeIdString;
  918. PCSTR deviceTypeCompIdString;
  919. UCHAR deviceTypeCompId[20];
  920. PCSTR deviceTypeIdString;
  921. UCHAR deviceTypeId[20];
  922. UCHAR ScsiDeviceType;
  923. PAGED_CODE();
  924. ScsiDeviceType = pdoExtension->ScsiDeviceType;
  925. idStringLen = (64 * NUMBER_HARDWARE_STRINGS + sizeof (UCHAR)) * sizeof (WCHAR);
  926. idMultiString = ExAllocatePool (PagedPool, idStringLen);
  927. if (idMultiString == NULL) {
  928. return NULL;
  929. }
  930. deviceTypeIdString = IdePortGetDeviceTypeString(ScsiDeviceType);
  931. if (deviceTypeIdString == NULL) {
  932. sprintf (deviceTypeId,
  933. "Type%d",
  934. ScsiDeviceType);
  935. deviceTypeIdString = deviceTypeId;
  936. }
  937. if (pdoExtension->ParentDeviceExtension->HwDeviceExtension->
  938. DeviceFlags[pdoExtension->TargetId] & DFLAGS_LS120_FORMAT) {
  939. //
  940. // ls-120 drive detected
  941. // return the special ls-120 compatible ID
  942. //
  943. deviceTypeCompIdString = SuperFloppyCompatibleIdString;
  944. } else {
  945. deviceTypeCompIdString = IdePortGetCompatibleIdString (ScsiDeviceType);
  946. if (deviceTypeCompIdString == NULL) {
  947. sprintf (deviceTypeCompId,
  948. "GenType%d",
  949. ScsiDeviceType);
  950. deviceTypeCompIdString = deviceTypeCompId;
  951. }
  952. }
  953. //
  954. // Zero out the string buffer
  955. //
  956. RtlZeroMemory(idMultiString, idStringLen);
  957. idString = idMultiString;
  958. for(i = 0; i < NUMBER_HARDWARE_STRINGS; i++) {
  959. //
  960. // Build each of the hardware id's
  961. //
  962. switch(i) {
  963. //
  964. // Bus + Dev Type + Vendor + Product + Revision
  965. //
  966. case 0: {
  967. sprintf(scratch, "IDE\\%s", deviceTypeIdString);
  968. CopyField(scratch + strlen(scratch),
  969. pdoExtension->FullVendorProductId,
  970. sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR),
  971. '_');
  972. CopyField(scratch + strlen(scratch),
  973. pdoExtension->FullProductRevisionId,
  974. sizeof (pdoExtension->FullProductRevisionId) - sizeof(CHAR),
  975. '_');
  976. break;
  977. }
  978. //
  979. // bus + vendor + product + revision[0]
  980. case 1: {
  981. sprintf(scratch, "IDE\\");
  982. CopyField(scratch + strlen(scratch),
  983. pdoExtension->FullVendorProductId,
  984. sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR),
  985. '_');
  986. CopyField(scratch + strlen(scratch),
  987. pdoExtension->FullProductRevisionId,
  988. sizeof (pdoExtension->FullProductRevisionId) - sizeof(CHAR),
  989. '_');
  990. break;
  991. }
  992. //
  993. // bus + device + vendor + product
  994. case 2: {
  995. sprintf(scratch, "IDE\\%s", deviceTypeIdString);
  996. CopyField(scratch + strlen(scratch),
  997. pdoExtension->FullVendorProductId,
  998. sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR),
  999. '_');
  1000. break;
  1001. }
  1002. //
  1003. // vendor + product + revision[0] (win9x)
  1004. case 3: {
  1005. CopyField(scratch,
  1006. pdoExtension->FullVendorProductId,
  1007. sizeof (pdoExtension->FullVendorProductId) - sizeof(CHAR),
  1008. '_');
  1009. CopyField(scratch + strlen(scratch),
  1010. pdoExtension->FullProductRevisionId,
  1011. sizeof (pdoExtension->FullProductRevisionId) - sizeof(CHAR),
  1012. '_');
  1013. break;
  1014. }
  1015. case 4: {
  1016. sprintf(scratch, "%s", deviceTypeCompIdString);
  1017. break;
  1018. }
  1019. default: {
  1020. break;
  1021. }
  1022. }
  1023. RtlInitAnsiString (
  1024. &ansiCompatibleIdString,
  1025. scratch
  1026. );
  1027. unicodeIdString.Length = 0;
  1028. unicodeIdString.MaximumLength = (USHORT) RtlAnsiStringToUnicodeSize(
  1029. &ansiCompatibleIdString
  1030. );
  1031. unicodeIdString.Buffer = idString;
  1032. RtlAnsiStringToUnicodeString(
  1033. &unicodeIdString,
  1034. &ansiCompatibleIdString,
  1035. FALSE
  1036. );
  1037. idString[unicodeIdString.Length / 2] = L'\0';
  1038. idString += unicodeIdString.Length / 2+ 1;
  1039. }
  1040. idString[0] = L'\0';
  1041. return idMultiString;
  1042. #undef NUMBER_HARDWARE_STRINGS
  1043. }
  1044. VOID
  1045. CopyField(
  1046. IN PUCHAR Destination,
  1047. IN PUCHAR Source,
  1048. IN ULONG Count,
  1049. IN UCHAR Change
  1050. )
  1051. /*++
  1052. Routine Description:
  1053. This routine will copy Count string bytes from Source to Destination. If
  1054. it finds a nul byte in the Source it will translate that and any subsequent
  1055. bytes into Change. It will also replace non-printable characters with the
  1056. specified character.
  1057. Arguments:
  1058. Destination - the location to copy bytes
  1059. Source - the location to copy bytes from
  1060. Count - the number of bytes to be copied
  1061. Return Value:
  1062. none
  1063. --*/
  1064. {
  1065. ULONG i = 0;
  1066. BOOLEAN pastEnd = FALSE;
  1067. PAGED_CODE();
  1068. for(i = 0; i < Count; i++) {
  1069. if(!pastEnd) {
  1070. if(Source[i] == 0) {
  1071. pastEnd = TRUE;
  1072. Destination[i] = Change;
  1073. } else if ((Source[i] <= L' ') ||
  1074. (Source[i] > ((WCHAR)0x7f)) ||
  1075. (Source[i] == L',')) {
  1076. Destination[i] = Change;
  1077. } else {
  1078. Destination[i] = Source[i];
  1079. }
  1080. } else {
  1081. Destination[i] = Change;
  1082. }
  1083. }
  1084. Destination[i] = L'\0';
  1085. return;
  1086. }
  1087. NTSTATUS
  1088. DeviceDeviceIoControl(
  1089. IN PDEVICE_OBJECT DeviceObject,
  1090. IN PIRP Irp
  1091. )
  1092. {
  1093. PIO_STACK_LOCATION thisIrpSp = IoGetCurrentIrpStackLocation(Irp);
  1094. PPDO_EXTENSION pdoExtension;
  1095. PSTORAGE_PROPERTY_QUERY storageQuery;
  1096. BOOLEAN passItToFdo;
  1097. PDEVICE_OBJECT ParentDeviceObject;
  1098. NTSTATUS status;
  1099. ULONG controlCode;
  1100. #ifdef GET_DISK_GEOMETRY_DEFINED
  1101. PIDE_READ_CAPACITY_CONTEXT context;
  1102. PATA_PASS_THROUGH ataPassThroughData;
  1103. PFDO_EXTENSION fdoExtension;
  1104. #endif
  1105. controlCode = thisIrpSp->Parameters.DeviceIoControl.IoControlCode;
  1106. #ifdef GET_DISK_GEOMETRY_DEFINED
  1107. if ((DEVICE_TYPE_FROM_CTL_CODE(controlCode) != IOCTL_STORAGE_BASE) &&
  1108. (DEVICE_TYPE_FROM_CTL_CODE(controlCode) != IOCTL_SCSI_BASE &&
  1109. controlCode != IOCTL_DISK_GET_DRIVE_GEOMETRY)) {
  1110. #else
  1111. if ((DEVICE_TYPE_FROM_CTL_CODE(controlCode) != IOCTL_STORAGE_BASE) &&
  1112. (DEVICE_TYPE_FROM_CTL_CODE(controlCode) != IOCTL_SCSI_BASE)) {
  1113. #endif
  1114. status = Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
  1115. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1116. return status;
  1117. }
  1118. pdoExtension = RefPdoWithTag(
  1119. DeviceObject,
  1120. FALSE,
  1121. Irp
  1122. );
  1123. if (pdoExtension) {
  1124. passItToFdo = TRUE;
  1125. ParentDeviceObject = pdoExtension->ParentDeviceExtension->DeviceObject;
  1126. #ifdef GET_DISK_GEOMETRY_DEFINED
  1127. fdoExtension=pdoExtension->ParentDeviceExtension;
  1128. //DebugPrint((DBG_ALWAYS, "DeviceIoCtl: ContlCode=%x, type=%x\n", controlCode,
  1129. // DEVICE_TYPE_FROM_CTL_CODE(controlCode)));
  1130. #endif
  1131. //
  1132. // RefPdo makes sure that the pdo is not removed.
  1133. //
  1134. switch (controlCode) {
  1135. case IOCTL_SCSI_PASS_THROUGH:
  1136. case IOCTL_SCSI_PASS_THROUGH_DIRECT:
  1137. if (thisIrpSp->Parameters.DeviceIoControl.InputBufferLength <
  1138. sizeof(SCSI_PASS_THROUGH)) {
  1139. passItToFdo = FALSE;
  1140. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1141. } else {
  1142. PSCSI_PASS_THROUGH srbControl;
  1143. srbControl = Irp->AssociatedIrp.SystemBuffer;
  1144. srbControl->PathId = pdoExtension->PathId;
  1145. srbControl->TargetId = pdoExtension->TargetId;
  1146. srbControl->Lun = pdoExtension->Lun;
  1147. }
  1148. break;
  1149. case IOCTL_IDE_PASS_THROUGH:
  1150. passItToFdo = FALSE;
  1151. Irp->IoStatus.Status = IdePortSendPassThrough(pdoExtension, Irp);
  1152. break;
  1153. #ifdef GET_DISK_GEOMETRY_DEFINED
  1154. case IOCTL_DISK_GET_DRIVE_GEOMETRY:
  1155. passItToFdo = FALSE;
  1156. if ( thisIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1157. sizeof( DISK_GEOMETRY ) ) {
  1158. Irp->IoStatus.Status = STATUS_INFO_LENGTH_MISMATCH;
  1159. break;
  1160. }
  1161. if ((fdoExtension->HwDeviceExtension->DeviceFlags[pdoExtension->TargetId] & DFLAGS_ATAPI_DEVICE)) {
  1162. Irp->IoStatus.Status=STATUS_INVALID_PARAMETER;
  1163. break;
  1164. }
  1165. //
  1166. // do DeviceIdeReadCapacity
  1167. // code duplication.
  1168. //
  1169. context = ExAllocatePool (
  1170. NonPagedPool,
  1171. sizeof(IDE_READ_CAPACITY_CONTEXT)
  1172. );
  1173. if (context == NULL) {
  1174. //UnrefLogicalUnitExtensionWithTag(
  1175. // fdoExtension,
  1176. // pdoExtension,
  1177. // Irp
  1178. //);
  1179. DebugPrint((1, "Could not allocate context\n"));
  1180. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  1181. break;
  1182. }
  1183. //
  1184. // Not a read capacity srb
  1185. //
  1186. context->GeometryIoctl=TRUE;
  1187. context->PdoExtension = pdoExtension;
  1188. context->OriginalIrp = Irp;
  1189. IoMarkIrpPending(Irp);
  1190. ataPassThroughData = &context->AtaPassThroughData;
  1191. RtlZeroMemory (
  1192. ataPassThroughData,
  1193. sizeof (*ataPassThroughData)
  1194. );
  1195. ataPassThroughData->DataBufferSize = sizeof(IDENTIFY_DATA);
  1196. ataPassThroughData->IdeReg.bCommandReg = IDE_COMMAND_IDENTIFY;
  1197. ataPassThroughData->IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
  1198. status = IssueAsyncAtaPassThroughSafe (
  1199. pdoExtension->ParentDeviceExtension,
  1200. pdoExtension,
  1201. ataPassThroughData,
  1202. TRUE,
  1203. DeviceIdeReadCapacityCompletionRoutine,
  1204. context,
  1205. FALSE,
  1206. DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
  1207. FALSE
  1208. );
  1209. if (status != STATUS_PENDING) {
  1210. DeviceIdeReadCapacityCompletionRoutine (
  1211. pdoExtension->DeviceObject,
  1212. context,
  1213. status
  1214. );
  1215. }
  1216. return status;
  1217. #endif
  1218. case IOCTL_SCSI_GET_ADDRESS: {
  1219. PSCSI_ADDRESS scsiAddress = Irp->AssociatedIrp.SystemBuffer;
  1220. passItToFdo = FALSE;
  1221. if(thisIrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  1222. sizeof(SCSI_ADDRESS)) {
  1223. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  1224. break;
  1225. }
  1226. scsiAddress->Length = sizeof(SCSI_ADDRESS);
  1227. scsiAddress->PortNumber = (UCHAR) pdoExtension->ParentDeviceExtension->ScsiPortNumber;
  1228. scsiAddress->PathId = pdoExtension->PathId;
  1229. scsiAddress->TargetId = pdoExtension->TargetId;
  1230. scsiAddress->Lun = pdoExtension->Lun;
  1231. Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
  1232. Irp->IoStatus.Status = STATUS_SUCCESS;
  1233. break;
  1234. }
  1235. case IOCTL_SCSI_GET_DUMP_POINTERS:
  1236. passItToFdo = FALSE;
  1237. //
  1238. // Get parameters for crash dump driver.
  1239. //
  1240. if (Irp->RequestorMode != KernelMode) {
  1241. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  1242. } else if (thisIrpSp->Parameters.DeviceIoControl.OutputBufferLength
  1243. < sizeof(DUMP_POINTERS)) {
  1244. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  1245. } else {
  1246. PCRASHDUMP_INIT_DATA dumpInitData;
  1247. //
  1248. // caller needs to free this
  1249. //
  1250. // ISSUE: make sure we tell the parent to power up
  1251. //
  1252. dumpInitData = ExAllocatePool (NonPagedPool, sizeof (CRASHDUMP_INIT_DATA));
  1253. if (dumpInitData) {
  1254. PDUMP_POINTERS dumpPointers;
  1255. dumpPointers = (PDUMP_POINTERS)Irp->AssociatedIrp.SystemBuffer;
  1256. RtlZeroMemory (dumpInitData, sizeof (CRASHDUMP_INIT_DATA));
  1257. dumpInitData->PathId = pdoExtension->PathId;
  1258. dumpInitData->TargetId = pdoExtension->TargetId;
  1259. dumpInitData->Lun = pdoExtension->Lun;
  1260. dumpInitData->LiveHwDeviceExtension = pdoExtension->ParentDeviceExtension->HwDeviceExtension;
  1261. dumpPointers->AdapterObject = NULL;
  1262. dumpPointers->MappedRegisterBase = NULL;
  1263. dumpPointers->DumpData = dumpInitData;
  1264. dumpPointers->CommonBufferVa = NULL;
  1265. dumpPointers->CommonBufferPa.QuadPart = 0;
  1266. dumpPointers->CommonBufferSize = 0;
  1267. dumpPointers->DeviceObject = pdoExtension->DeviceObject;
  1268. dumpPointers->AllocateCommonBuffers = FALSE;
  1269. Irp->IoStatus.Status = STATUS_SUCCESS;
  1270. Irp->IoStatus.Information = sizeof(DUMP_POINTERS);
  1271. } else {
  1272. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  1273. IdeLogNoMemoryError(pdoExtension->ParentDeviceExtension,
  1274. pdoExtension->TargetId,
  1275. NonPagedPool,
  1276. sizeof(CRASHDUMP_INIT_DATA),
  1277. IDEPORT_TAG_DUMP_POINTER
  1278. );
  1279. }
  1280. }
  1281. break;
  1282. case IOCTL_STORAGE_QUERY_PROPERTY:
  1283. storageQuery = Irp->AssociatedIrp.SystemBuffer;
  1284. if (thisIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(STORAGE_PROPERTY_QUERY)) {
  1285. Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
  1286. passItToFdo = FALSE;
  1287. } else {
  1288. if (storageQuery->PropertyId == StorageDeviceProperty) { // device property
  1289. ULONG bufferSize;
  1290. passItToFdo = FALSE;
  1291. switch (storageQuery->QueryType) {
  1292. case PropertyStandardQuery:
  1293. DebugPrint ((2, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY PropertyStandardQuery\n"));
  1294. bufferSize = thisIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  1295. Irp->IoStatus.Status = DeviceBuildStorageDeviceDescriptor(
  1296. pdoExtension,
  1297. (PSTORAGE_DEVICE_DESCRIPTOR) Irp->AssociatedIrp.SystemBuffer,
  1298. &bufferSize
  1299. );
  1300. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  1301. Irp->IoStatus.Information = bufferSize;
  1302. }
  1303. break;
  1304. case PropertyExistsQuery:
  1305. DebugPrint ((2, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY PropertyExistsQuery\n"));
  1306. // ISSUE: Will be implemented when required
  1307. Irp->IoStatus.Status = STATUS_SUCCESS;
  1308. break;
  1309. case PropertyMaskQuery:
  1310. DebugPrint ((2, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY PropertyMaskQuery\n"));
  1311. //ISSUE: Will implement when required
  1312. Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
  1313. break;
  1314. default:
  1315. DebugPrint ((2, "IdePortPdoDispatch: IOCTL_STORAGE_QUERY_PROPERTY unknown type\n"));
  1316. // ISSUE: Will implement when required
  1317. Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
  1318. break;
  1319. }
  1320. }
  1321. }
  1322. break;
  1323. }
  1324. UnrefPdoWithTag(
  1325. pdoExtension,
  1326. Irp
  1327. );
  1328. } else {
  1329. passItToFdo = FALSE;
  1330. Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
  1331. }
  1332. if (passItToFdo) {
  1333. return IdePortDeviceControl (
  1334. ParentDeviceObject, Irp
  1335. );
  1336. } else {
  1337. status = Irp->IoStatus.Status;
  1338. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1339. return status;
  1340. }
  1341. }
  1342. NTSTATUS
  1343. DeviceBuildStorageDeviceDescriptor(
  1344. PPDO_EXTENSION pdoExtension,
  1345. IN OUT PSTORAGE_DEVICE_DESCRIPTOR StorageDeviceDescriptor,
  1346. IN OUT PULONG BufferSize
  1347. )
  1348. {
  1349. STORAGE_DEVICE_DESCRIPTOR localStorageDeviceDescriptor;
  1350. ULONG productIdLength;
  1351. ULONG revisionIdLength;
  1352. ULONG serialNumberLength;
  1353. PUCHAR bytebuffer;
  1354. ULONG byteLeft;
  1355. ULONG byteToCopy;
  1356. INQUIRYDATA InquiryData;
  1357. NTSTATUS status;
  1358. ASSERT (pdoExtension);
  1359. ASSERT (StorageDeviceDescriptor);
  1360. productIdLength = strlen(pdoExtension->FullVendorProductId) + sizeof(UCHAR);
  1361. revisionIdLength = strlen(pdoExtension->FullProductRevisionId) + sizeof(UCHAR);
  1362. serialNumberLength = strlen(pdoExtension->FullSerialNumber) + sizeof(UCHAR);
  1363. RtlZeroMemory (&localStorageDeviceDescriptor, sizeof (STORAGE_DEVICE_DESCRIPTOR));
  1364. localStorageDeviceDescriptor.Version = sizeof (STORAGE_DEVICE_DESCRIPTOR);
  1365. localStorageDeviceDescriptor.Size = sizeof (STORAGE_DEVICE_DESCRIPTOR) +
  1366. INQUIRYDATABUFFERSIZE +
  1367. productIdLength +
  1368. revisionIdLength +
  1369. serialNumberLength;
  1370. localStorageDeviceDescriptor.DeviceType = pdoExtension->ScsiDeviceType;
  1371. if (pdoExtension->
  1372. ParentDeviceExtension->
  1373. HwDeviceExtension->
  1374. DeviceFlags[pdoExtension->TargetId] &
  1375. DFLAGS_REMOVABLE_DRIVE) {
  1376. localStorageDeviceDescriptor.RemovableMedia = TRUE;
  1377. }
  1378. if (pdoExtension->
  1379. ParentDeviceExtension->
  1380. HwDeviceExtension->
  1381. DeviceFlags[pdoExtension->TargetId] &
  1382. DFLAGS_ATAPI_DEVICE) {
  1383. localStorageDeviceDescriptor.BusType = BusTypeAtapi;
  1384. } else {
  1385. localStorageDeviceDescriptor.BusType = BusTypeAta;
  1386. }
  1387. bytebuffer = (PUCHAR) StorageDeviceDescriptor;
  1388. byteLeft = *BufferSize;
  1389. //
  1390. // copy the basic STORAGE_DEVICE_DESCRIPTOR
  1391. //
  1392. if (byteLeft) {
  1393. byteToCopy = min(sizeof (STORAGE_DEVICE_DESCRIPTOR), byteLeft);
  1394. RtlCopyMemory (StorageDeviceDescriptor,
  1395. &localStorageDeviceDescriptor,
  1396. byteToCopy);
  1397. bytebuffer += byteToCopy;
  1398. byteLeft -= byteToCopy;
  1399. }
  1400. //
  1401. // copy raw device properties (Inquiry Data)
  1402. //
  1403. if (byteLeft) {
  1404. status = IssueInquirySafe(
  1405. pdoExtension->ParentDeviceExtension,
  1406. pdoExtension,
  1407. &InquiryData,
  1408. FALSE
  1409. );
  1410. if (NT_SUCCESS(status) || (status == STATUS_DATA_OVERRUN)) {
  1411. byteToCopy = min(INQUIRYDATABUFFERSIZE, byteLeft);
  1412. RtlCopyMemory (bytebuffer,
  1413. &InquiryData,
  1414. byteToCopy);
  1415. StorageDeviceDescriptor->RawPropertiesLength = byteToCopy;
  1416. bytebuffer += byteToCopy;
  1417. byteLeft -= byteToCopy;
  1418. }
  1419. }
  1420. //
  1421. // copy product ID
  1422. //
  1423. if (byteLeft) {
  1424. byteToCopy = min(productIdLength, byteLeft);
  1425. RtlCopyMemory (bytebuffer,
  1426. pdoExtension->FullVendorProductId,
  1427. byteToCopy);
  1428. bytebuffer[byteToCopy - 1] = '\0';
  1429. StorageDeviceDescriptor->ProductIdOffset = *BufferSize - byteLeft;
  1430. bytebuffer += byteToCopy;
  1431. byteLeft -= byteToCopy;
  1432. }
  1433. //
  1434. // copy revision ID
  1435. //
  1436. if (byteLeft) {
  1437. byteToCopy = min(productIdLength, byteLeft);
  1438. RtlCopyMemory (bytebuffer,
  1439. pdoExtension->FullProductRevisionId,
  1440. byteToCopy);
  1441. bytebuffer[byteToCopy - 1] = '\0';
  1442. StorageDeviceDescriptor->ProductRevisionOffset = *BufferSize - byteLeft;
  1443. bytebuffer += byteToCopy;
  1444. byteLeft -= byteToCopy;
  1445. }
  1446. //
  1447. // copy serial #
  1448. //
  1449. if (byteLeft) {
  1450. byteToCopy = min(serialNumberLength, byteLeft);
  1451. RtlCopyMemory (bytebuffer,
  1452. pdoExtension->FullSerialNumber,
  1453. byteToCopy);
  1454. bytebuffer[byteToCopy - 1] = '\0';
  1455. StorageDeviceDescriptor->SerialNumberOffset = *BufferSize - byteLeft;
  1456. bytebuffer += byteToCopy;
  1457. byteLeft -= byteToCopy;
  1458. }
  1459. *BufferSize -= byteLeft;
  1460. return STATUS_SUCCESS;
  1461. } // DeviceBuildStorageDeviceDescriptor
  1462. NTSTATUS
  1463. DeviceQueryCapabilities (
  1464. IN PDEVICE_OBJECT DeviceObject,
  1465. IN OUT PIRP Irp
  1466. )
  1467. {
  1468. PIO_STACK_LOCATION thisIrpSp;
  1469. PPDO_EXTENSION pdoExtension;
  1470. PDEVICE_CAPABILITIES capabilities;
  1471. NTSTATUS status;
  1472. PAGED_CODE();
  1473. thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
  1474. capabilities = thisIrpSp->Parameters.DeviceCapabilities.Capabilities;
  1475. pdoExtension = RefPdoWithTag (
  1476. DeviceObject,
  1477. TRUE,
  1478. DeviceQueryCapabilities
  1479. );
  1480. if (pdoExtension == NULL) {
  1481. status = STATUS_DEVICE_DOES_NOT_EXIST;
  1482. } else {
  1483. DEVICE_CAPABILITIES parentDeviceCapabilities;
  1484. status = IdeGetDeviceCapabilities(
  1485. pdoExtension->ParentDeviceExtension->AttacheePdo,
  1486. &parentDeviceCapabilities);
  1487. if (NT_SUCCESS(status)) {
  1488. RtlMoveMemory (
  1489. capabilities,
  1490. &parentDeviceCapabilities,
  1491. sizeof(DEVICE_CAPABILITIES));
  1492. if (pdoExtension->FullSerialNumber[0]) {
  1493. capabilities->UniqueID = TRUE;
  1494. } else {
  1495. capabilities->UniqueID = FALSE;
  1496. }
  1497. //
  1498. // never!
  1499. //
  1500. capabilities->Removable = FALSE;
  1501. capabilities->SurpriseRemovalOK = FALSE;
  1502. capabilities->Address = PNP_ADDRESS(pdoExtension->TargetId, pdoExtension->Lun);
  1503. capabilities->UINumber = pdoExtension->TargetId;
  1504. capabilities->D1Latency = 31 * (1000 * 10); // 31s
  1505. capabilities->D2Latency = 31 * (1000 * 10); // 31s
  1506. capabilities->D3Latency = 31 * (1000 * 10); // 31s
  1507. }
  1508. UnrefPdoWithTag (
  1509. pdoExtension,
  1510. DeviceQueryCapabilities
  1511. );
  1512. }
  1513. Irp->IoStatus.Status = status;
  1514. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  1515. return status;
  1516. } // DeviceQueryCapabitilies
  1517. NTSTATUS
  1518. IdePortInsertByKeyDeviceQueue (
  1519. IN PPDO_EXTENSION PdoExtension,
  1520. IN PIRP Irp,
  1521. IN ULONG SortKey,
  1522. OUT PBOOLEAN Inserted
  1523. )
  1524. {
  1525. KIRQL currentIrql;
  1526. NTSTATUS status;
  1527. POWER_STATE powerState;
  1528. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1529. PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
  1530. BOOLEAN urgentSrb;
  1531. status = STATUS_SUCCESS;
  1532. *Inserted = FALSE;
  1533. KeRaiseIrql(DISPATCH_LEVEL, &currentIrql);
  1534. if (PdoExtension->LuFlags & PD_QUEUE_FROZEN) {
  1535. DebugPrint((1,"IdePortDispatch: Request put in frozen queue!\n"));
  1536. }
  1537. *Inserted = KeInsertByKeyDeviceQueue(
  1538. &PdoExtension->DeviceObject->DeviceQueue,
  1539. &Irp->Tail.Overlay.DeviceQueueEntry,
  1540. SortKey);
  1541. if (*Inserted == FALSE) {
  1542. if (PdoExtension->PdoState & PDOS_QUEUE_BLOCKED) {
  1543. ASSERT (PdoExtension->PendingRequest == NULL);
  1544. PdoExtension->PendingRequest = Irp;
  1545. *Inserted = TRUE;
  1546. if (!(PdoExtension->PdoState & PDOS_MUST_QUEUE)) {
  1547. POWER_STATE powerState;
  1548. //
  1549. // device is powered down
  1550. // use a large time in case it spins up slowly
  1551. //
  1552. if (srb->TimeOutValue < DEFAULT_SPINUP_TIME) {
  1553. srb->TimeOutValue = DEFAULT_SPINUP_TIME;
  1554. }
  1555. //
  1556. // We are not powered up.
  1557. // issue an power up
  1558. //
  1559. powerState.DeviceState = PowerDeviceD0;
  1560. status = PoRequestPowerIrp (
  1561. PdoExtension->DeviceObject,
  1562. IRP_MN_SET_POWER,
  1563. powerState,
  1564. NULL,
  1565. NULL,
  1566. NULL
  1567. );
  1568. ASSERT (NT_SUCCESS(status));
  1569. DebugPrint ((2, "IdePort GetNextLuRequest: 0x%x 0x%x need to spin up device, requeue irp 0x%x\n",
  1570. PdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  1571. PdoExtension->TargetId,
  1572. Irp));
  1573. }
  1574. } else if (srb->Function != SRB_FUNCTION_ATA_POWER_PASS_THROUGH) {
  1575. //
  1576. // If this irp is not for changing power state, we may have
  1577. // to queue it
  1578. //
  1579. if (PdoExtension->DevicePowerState != PowerDeviceD0) {
  1580. if (PdoExtension->DevicePowerState != PowerDeviceD3) {
  1581. //
  1582. // we are in D1 or D2.
  1583. // We can never be sure that we are in D0 when
  1584. // we tell the device to go from D1/D2 to D0.
  1585. // Some device lies and won't spin up until it sees
  1586. // a media access command. This causes longer time
  1587. // to execute the command
  1588. //
  1589. // to prevent the next command from timing out, we
  1590. // will increment its timeout
  1591. //
  1592. if (srb->TimeOutValue < 30) {
  1593. srb->TimeOutValue = 30;
  1594. }
  1595. }
  1596. //
  1597. // We are not powered up.
  1598. // issue an power up
  1599. //
  1600. powerState.DeviceState = PowerDeviceD0;
  1601. status = PoRequestPowerIrp (
  1602. PdoExtension->DeviceObject,
  1603. IRP_MN_SET_POWER,
  1604. powerState,
  1605. NULL,
  1606. NULL,
  1607. NULL
  1608. );
  1609. ASSERT (NT_SUCCESS(status));
  1610. status = STATUS_SUCCESS;
  1611. ASSERT (PdoExtension->PendingRequest == NULL);
  1612. PdoExtension->PendingRequest = Irp;
  1613. DebugPrint ((1, "IdePort IdePortInsertByKeyDeviceQueue: 0x%x 0x%x need to spin up device, requeue irp 0x%x\n",
  1614. PdoExtension->ParentDeviceExtension->IdeResource.TranslatedCommandBaseAddress,
  1615. PdoExtension->TargetId,
  1616. Irp));
  1617. *Inserted = TRUE;
  1618. }
  1619. }
  1620. } else {
  1621. #if DBG
  1622. InterlockedIncrement (
  1623. &PdoExtension->NumberOfIrpQueued
  1624. );
  1625. #endif // DBG
  1626. }
  1627. KeLowerIrql(currentIrql);
  1628. return status;
  1629. }
  1630. VOID
  1631. DeviceInitCompletionRoutine (
  1632. PVOID Context,
  1633. NTSTATUS Status
  1634. )
  1635. {
  1636. PKEVENT event = Context;
  1637. if (!NT_SUCCESS(Status)) {
  1638. //ASSERT (!"DeviceInitDeviceState Failed\n");
  1639. DebugPrint((DBG_ALWAYS, "ATAPI: ERROR: DeviceInitDeviceStateFailed with Status %x\n",
  1640. Status));
  1641. }
  1642. KeSetEvent (event, 0, FALSE);
  1643. }
  1644. NTSTATUS
  1645. DeviceQueryText (
  1646. IN PDEVICE_OBJECT DeviceObject,
  1647. IN OUT PIRP Irp
  1648. )
  1649. {
  1650. PIO_STACK_LOCATION thisIrpSp;
  1651. PPDO_EXTENSION pdoExtension;
  1652. PWCHAR returnString;
  1653. LONG i;
  1654. UNICODE_STRING unicodeString;
  1655. ANSI_STRING ansiString;
  1656. ULONG stringLen;
  1657. NTSTATUS status;
  1658. PAGED_CODE();
  1659. thisIrpSp = IoGetCurrentIrpStackLocation (Irp);
  1660. returnString = NULL;
  1661. Irp->IoStatus.Information = 0;
  1662. pdoExtension = RefPdoWithTag (
  1663. DeviceObject,
  1664. TRUE,
  1665. DeviceQueryText
  1666. );
  1667. if (pdoExtension == NULL) {
  1668. status = STATUS_DEVICE_DOES_NOT_EXIST;
  1669. } else {
  1670. status = STATUS_NO_MEMORY;
  1671. if (thisIrpSp->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription) {
  1672. stringLen = sizeof (pdoExtension->FullVendorProductId) * sizeof (WCHAR);
  1673. returnString = ExAllocatePool (
  1674. PagedPool,
  1675. stringLen
  1676. );
  1677. if (returnString) {
  1678. unicodeString.Length = 0;
  1679. unicodeString.MaximumLength = (USHORT) stringLen;
  1680. unicodeString.Buffer = returnString;
  1681. //
  1682. // vendor ID
  1683. //
  1684. RtlInitAnsiString (
  1685. &ansiString,
  1686. pdoExtension->FullVendorProductId
  1687. );
  1688. RtlAnsiStringToUnicodeString(
  1689. &unicodeString,
  1690. &ansiString,
  1691. FALSE
  1692. );
  1693. ASSERT(unicodeString.Length < unicodeString.MaximumLength);
  1694. //
  1695. // get rid of trailing spaces and nulls
  1696. //
  1697. for (i=(unicodeString.Length/2)-1; i >= 0; i--) {
  1698. if ((returnString[i] == ' ') || (returnString[i] == 0)) {
  1699. continue;
  1700. } else {
  1701. break;
  1702. }
  1703. }
  1704. //
  1705. // null terminate it
  1706. //
  1707. returnString[i + 1] = 0;
  1708. status = STATUS_SUCCESS;
  1709. }
  1710. } else if (thisIrpSp->Parameters.QueryDeviceText.DeviceTextType == DeviceTextLocationInformation) {
  1711. stringLen = 100;
  1712. returnString = ExAllocatePool (
  1713. PagedPool,
  1714. stringLen
  1715. );
  1716. if (returnString) {
  1717. swprintf(returnString, L"%ws",
  1718. (((pdoExtension->TargetId & 0x1) == 0) ? L"0" :
  1719. L"1"));
  1720. RtlInitUnicodeString(&unicodeString, returnString);
  1721. //
  1722. // null terminate it
  1723. //
  1724. unicodeString.Buffer[unicodeString.Length/sizeof(WCHAR) + 0] = L'\0';
  1725. status = STATUS_SUCCESS;
  1726. }
  1727. } else {
  1728. status = STATUS_NOT_SUPPORTED;
  1729. }
  1730. UnrefPdoWithTag (
  1731. pdoExtension,
  1732. DeviceQueryText
  1733. );
  1734. }
  1735. Irp->IoStatus.Information = (ULONG_PTR) returnString;
  1736. Irp->IoStatus.Status = status;
  1737. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  1738. return status;
  1739. } // DeviceQueryText
  1740. NTSTATUS
  1741. IdePortSendPassThrough (
  1742. IN PPDO_EXTENSION PdoExtension,
  1743. IN PIRP Irp
  1744. )
  1745. /*++
  1746. Routine Description:
  1747. This function sends a user specified IDE task registers
  1748. It creates an srb which is processed normally by the port driver.
  1749. This call is synchornous.
  1750. Arguments:
  1751. DeviceExtension - Supplies a pointer the SCSI adapter device extension.
  1752. RequestIrp - Supplies a pointe to the Irp which made the original request.
  1753. Return Value:
  1754. Returns a status indicating the success or failure of the operation.
  1755. --*/
  1756. {
  1757. PIO_STACK_LOCATION irpStack;
  1758. PATA_PASS_THROUGH ataPassThroughData;
  1759. ULONG dataBufferSize;
  1760. BOOLEAN dataIn;
  1761. NTSTATUS status;
  1762. ULONG outputBufferSize;
  1763. PAGED_CODE();
  1764. DebugPrint((3,"IdePortSendPassThrough: Enter routine\n"));
  1765. //
  1766. // validate target device
  1767. //
  1768. if (PdoExtension->Lun != 0) {
  1769. return STATUS_INVALID_DEVICE_REQUEST;
  1770. }
  1771. //
  1772. // Get a pointer to the control block.
  1773. //
  1774. irpStack = IoGetCurrentIrpStackLocation(Irp);
  1775. ataPassThroughData = Irp->AssociatedIrp.SystemBuffer;
  1776. //
  1777. // Validiate the user buffer.
  1778. //
  1779. if (irpStack->Parameters.DeviceIoControl.InputBufferLength < FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer)) {
  1780. return STATUS_INVALID_PARAMETER;
  1781. }
  1782. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer)) {
  1783. return STATUS_INVALID_PARAMETER;
  1784. }
  1785. ASSERT(ataPassThroughData != NULL);
  1786. dataBufferSize = ataPassThroughData->DataBufferSize;
  1787. outputBufferSize = FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer) + dataBufferSize;
  1788. if (outputBufferSize < dataBufferSize) {
  1789. //
  1790. // outputBufferSize overflows a ULONG
  1791. //
  1792. outputBufferSize = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  1793. }
  1794. if ((irpStack->Parameters.DeviceIoControl.OutputBufferLength) >=
  1795. outputBufferSize) {
  1796. dataIn = TRUE;
  1797. } else {
  1798. dataIn = FALSE;
  1799. }
  1800. status = IssueSyncAtaPassThroughSafe (
  1801. PdoExtension->ParentDeviceExtension,
  1802. PdoExtension,
  1803. ataPassThroughData,
  1804. dataIn,
  1805. FALSE,
  1806. DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
  1807. FALSE
  1808. );
  1809. if (NT_SUCCESS(status)) {
  1810. Irp->IoStatus.Information = outputBufferSize;
  1811. } else {
  1812. //
  1813. // ignore all errors
  1814. // let the caller figure out the error
  1815. // from the task file registers
  1816. //
  1817. status = STATUS_SUCCESS;
  1818. Irp->IoStatus.Information = FIELD_OFFSET(ATA_PASS_THROUGH, DataBuffer);
  1819. }
  1820. Irp->IoStatus.Status = status;
  1821. return status;
  1822. } // IdePortSendPassThrough
  1823. VOID
  1824. DeviceRegisterIdleDetection (
  1825. IN PPDO_EXTENSION PdoExtension,
  1826. IN ULONG ConservationIdleTime,
  1827. IN ULONG PerformanceIdleTime
  1828. )
  1829. {
  1830. NTSTATUS status;
  1831. ATA_PASS_THROUGH ataPassThroughData;
  1832. //
  1833. // Many ATAPI device (Acer and Panasonice Changer) doesn't like ATA
  1834. // power down command. Since they auto-spin-down anyway, we are not
  1835. // go to power manage it
  1836. //
  1837. if (!(PdoExtension->PdoState & PDOS_NO_POWER_DOWN)) {
  1838. if (!PdoExtension->CrashDumpPathCount) {
  1839. RtlZeroMemory (&ataPassThroughData, sizeof(ataPassThroughData));
  1840. ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_IDLE_IMMEDIATE;
  1841. ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
  1842. status = IssueSyncAtaPassThroughSafe (
  1843. PdoExtension->ParentDeviceExtension,
  1844. PdoExtension,
  1845. &ataPassThroughData,
  1846. FALSE,
  1847. FALSE,
  1848. DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
  1849. FALSE
  1850. );
  1851. if (NT_SUCCESS(status)) {
  1852. DEVICE_POWER_STATE devicePowerState;
  1853. //
  1854. // ISSUE
  1855. // should check the registry/device property whether
  1856. // idle detection has been disabled for this device
  1857. //
  1858. devicePowerState = PowerDeviceD3;
  1859. PdoExtension->IdleCounter = PoRegisterDeviceForIdleDetection (
  1860. PdoExtension->DeviceObject,
  1861. ConservationIdleTime, // seconds
  1862. PerformanceIdleTime, // seconds
  1863. devicePowerState
  1864. );
  1865. DebugPrint ((1, "IdePort: pdoExtension 0x%x support power managerment command\n", PdoExtension));
  1866. } else {
  1867. KIRQL currentIrql;
  1868. KeAcquireSpinLock(&PdoExtension->PdoSpinLock, &currentIrql);
  1869. SETMASK (PdoExtension->PdoState, PDOS_NO_POWER_DOWN);
  1870. KeReleaseSpinLock(&PdoExtension->PdoSpinLock, currentIrql);
  1871. DebugPrint ((1, "IdePort: pdoExtension 0x%x DOES NOT support power managerment command\n", PdoExtension));
  1872. }
  1873. }
  1874. }
  1875. return;
  1876. }
  1877. VOID
  1878. DeviceUnregisterIdleDetection (
  1879. IN PPDO_EXTENSION PdoExtension
  1880. )
  1881. {
  1882. DEVICE_POWER_STATE devicePowerState;
  1883. devicePowerState = PowerDeviceD3;
  1884. if (PdoExtension->IdleCounter) {
  1885. PoRegisterDeviceForIdleDetection (
  1886. PdoExtension->DeviceObject,
  1887. 0,
  1888. 0,
  1889. devicePowerState
  1890. );
  1891. PdoExtension->IdleCounter = NULL;
  1892. }
  1893. return;
  1894. }
  1895. VOID
  1896. DeviceInitIdStrings (
  1897. IN PPDO_EXTENSION PdoExtension,
  1898. IN IDE_DEVICETYPE DeviceType,
  1899. IN PINQUIRYDATA InquiryData,
  1900. IN PIDENTIFY_DATA IdentifyData
  1901. )
  1902. {
  1903. LONG i;
  1904. UCHAR c;
  1905. SPECIAL_ACTION_FLAG specialFlags;
  1906. PAGED_CODE();
  1907. ASSERT (PdoExtension);
  1908. ASSERT (IdentifyData);
  1909. if (DeviceType == DeviceIsAta) {
  1910. CopyField(
  1911. PdoExtension->FullVendorProductId,
  1912. IdentifyData->ModelNumber,
  1913. sizeof(PdoExtension->FullVendorProductId)-1,
  1914. ' '
  1915. );
  1916. CopyField(
  1917. PdoExtension->FullProductRevisionId,
  1918. IdentifyData->FirmwareRevision,
  1919. sizeof(PdoExtension->FullProductRevisionId)-1,
  1920. ' '
  1921. );
  1922. //
  1923. // byte swap
  1924. //
  1925. for (i=0; i<sizeof(PdoExtension->FullVendorProductId)-1; i+=2) {
  1926. c = PdoExtension->FullVendorProductId[i];
  1927. PdoExtension->FullVendorProductId[i] = PdoExtension->FullVendorProductId[i + 1];
  1928. PdoExtension->FullVendorProductId[i + 1] = c;
  1929. }
  1930. for (i=0; i<sizeof(PdoExtension->FullProductRevisionId)-1; i+=2) {
  1931. c = PdoExtension->FullProductRevisionId[i];
  1932. PdoExtension->FullProductRevisionId[i] = PdoExtension->FullProductRevisionId[i + 1];
  1933. PdoExtension->FullProductRevisionId[i + 1] = c;
  1934. }
  1935. } else if (DeviceType == DeviceIsAtapi) {
  1936. PUCHAR fullVendorProductId;
  1937. fullVendorProductId = PdoExtension->FullVendorProductId;
  1938. CopyField(
  1939. fullVendorProductId,
  1940. InquiryData->VendorId,
  1941. 8,
  1942. ' '
  1943. );
  1944. for (i=7; i >= 0; i--) {
  1945. if (fullVendorProductId[i] != ' ') {
  1946. fullVendorProductId[i + 1] = ' ';
  1947. fullVendorProductId += i + 2;
  1948. break;
  1949. }
  1950. }
  1951. CopyField(
  1952. fullVendorProductId,
  1953. InquiryData->ProductId,
  1954. 16,
  1955. ' '
  1956. );
  1957. fullVendorProductId += 16;
  1958. for (i=0; fullVendorProductId+i < PdoExtension->FullVendorProductId+40; i++) {
  1959. fullVendorProductId[i] = ' ';
  1960. }
  1961. CopyField(
  1962. PdoExtension->FullProductRevisionId,
  1963. InquiryData->ProductRevisionLevel,
  1964. 4,
  1965. ' '
  1966. );
  1967. for (i=4; i<8; i++) {
  1968. PdoExtension->FullProductRevisionId[i] = ' ';
  1969. }
  1970. } else {
  1971. ASSERT (FALSE);
  1972. }
  1973. //
  1974. // take out trailing spaces
  1975. //
  1976. for (i=sizeof(PdoExtension->FullVendorProductId)-2; i >= 0; i--) {
  1977. if (PdoExtension->FullVendorProductId[i] != ' ') {
  1978. PdoExtension->FullVendorProductId[i+1] = '\0';
  1979. break;
  1980. }
  1981. }
  1982. for (i=sizeof(PdoExtension->FullProductRevisionId)-2; i >= 0; i--) {
  1983. if (PdoExtension->FullProductRevisionId[i] != ' ') {
  1984. PdoExtension->FullProductRevisionId[i+1] = '\0';
  1985. break;
  1986. }
  1987. }
  1988. //
  1989. // Check the vendor & product id to see if we should disable the serial
  1990. // number for this device.
  1991. //
  1992. specialFlags = IdeFindSpecialDevice(PdoExtension->FullVendorProductId,
  1993. PdoExtension->FullProductRevisionId);
  1994. //
  1995. // look for serial number
  1996. //
  1997. // some device returns non-printable characters as part of its
  1998. // serial number. to get around this, we will turn all raw numbers
  1999. // into a string.
  2000. //
  2001. if ((specialFlags != disableSerialNumber) &&
  2002. (IdentifyData->SerialNumber[0] != ' ') &&
  2003. (IdentifyData->SerialNumber[0] != '\0')) {
  2004. for (i=0; i<sizeof(IdentifyData->SerialNumber); i++) {
  2005. sprintf (PdoExtension->FullSerialNumber+i*2, "%2x", IdentifyData->SerialNumber[i]);
  2006. }
  2007. PdoExtension->FullSerialNumber[sizeof(PdoExtension->FullSerialNumber) - 1] = '\0';
  2008. } else {
  2009. PdoExtension->FullSerialNumber[0] = '\0';
  2010. }
  2011. DebugPrint ((
  2012. DBG_BUSSCAN,
  2013. "PDOE 0x%x: Full IDs \n\t%s\n\t%s\n\t%s\n",
  2014. PdoExtension,
  2015. PdoExtension->FullVendorProductId,
  2016. PdoExtension->FullProductRevisionId,
  2017. PdoExtension->FullSerialNumber
  2018. ));
  2019. return;
  2020. }
  2021. VOID
  2022. DeviceInitDeviceType (
  2023. IN PPDO_EXTENSION PdoExtension,
  2024. IN PINQUIRYDATA InquiryData
  2025. )
  2026. {
  2027. PdoExtension->ScsiDeviceType = InquiryData->DeviceType;
  2028. if(InquiryData->RemovableMedia) {
  2029. SETMASK (PdoExtension->DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA);
  2030. }
  2031. return;
  2032. }
  2033. NTSTATUS
  2034. DeviceQueryDeviceRelations (
  2035. IN PDEVICE_OBJECT DeviceObject,
  2036. IN OUT PIRP Irp
  2037. )
  2038. {
  2039. PIO_STACK_LOCATION thisIrpSp;
  2040. PDEVICE_RELATIONS deviceRelations;
  2041. NTSTATUS status;
  2042. IDE_PATH_ID pathId;
  2043. PPDO_EXTENSION pdoExtension;
  2044. PPDO_EXTENSION otherPdoExtension;
  2045. ULONG numPdos;
  2046. thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
  2047. switch (thisIrpSp->Parameters.QueryDeviceRelations.Type) {
  2048. case TargetDeviceRelation:
  2049. deviceRelations = ExAllocatePool (
  2050. NonPagedPool,
  2051. sizeof(*deviceRelations) +
  2052. sizeof(deviceRelations->Objects[0]) * 1
  2053. );
  2054. if (deviceRelations != NULL) {
  2055. deviceRelations->Count = 1;
  2056. deviceRelations->Objects[0] = DeviceObject;
  2057. ObReferenceObjectByPointer(DeviceObject,
  2058. 0,
  2059. 0,
  2060. KernelMode);
  2061. Irp->IoStatus.Status = STATUS_SUCCESS;
  2062. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  2063. } else {
  2064. Irp->IoStatus.Status = STATUS_NO_MEMORY;
  2065. Irp->IoStatus.Information = 0;
  2066. }
  2067. break;
  2068. }
  2069. status = Irp->IoStatus.Status;
  2070. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  2071. return status;
  2072. } // DeviceQueryDeviceRelations
  2073. NTSTATUS
  2074. DeviceQueryInitData (
  2075. IN PPDO_EXTENSION PdoExtension
  2076. )
  2077. {
  2078. PDEVICE_SETTINGS deviceSettings;
  2079. PDEVICE_SETTINGS tempDeviceSettings;
  2080. NTSTATUS status;
  2081. ATA_PASS_THROUGH ataPassThroughData;
  2082. ULONG i;
  2083. PPDO_EXTENSION lun0PdoExtension;
  2084. ULONG totalDeviceSettingEntries;
  2085. ULONG firstNewEntryOffset;
  2086. PAGED_CODE();
  2087. DebugPrint ((
  2088. DBG_PNP,
  2089. "DeviceQueryInitData: Init. pdoe 0x%x (%d,%d,%d)\n",
  2090. PdoExtension,
  2091. PdoExtension->PathId,
  2092. PdoExtension->TargetId,
  2093. PdoExtension->Lun
  2094. ));
  2095. deviceSettings = PdoExtension->AcpiDeviceSettings;
  2096. if (deviceSettings == NULL) {
  2097. //
  2098. // ISSUE: we can't be sure acpi is always attached on lun0
  2099. //
  2100. // get the lun0 pdo
  2101. //
  2102. lun0PdoExtension = RefLogicalUnitExtensionWithTag(
  2103. PdoExtension->ParentDeviceExtension,
  2104. PdoExtension->PathId,
  2105. PdoExtension->TargetId,
  2106. 0,
  2107. TRUE,
  2108. DeviceQueryInitData
  2109. );
  2110. if (lun0PdoExtension) {
  2111. ASSERT (lun0PdoExtension->TargetId == PdoExtension->TargetId);
  2112. status = DeviceQueryFirmwareBootSettings (
  2113. lun0PdoExtension,
  2114. &deviceSettings
  2115. );
  2116. //
  2117. // let go Lun0
  2118. //
  2119. UnrefPdoWithTag(
  2120. lun0PdoExtension,
  2121. DeviceQueryInitData
  2122. );
  2123. }
  2124. if (deviceSettings) {
  2125. ULONG i;
  2126. ULONG j;
  2127. for (i=0; i<deviceSettings->NumEntries; i++) {
  2128. //
  2129. // Ignore SET_DRIVE_PARAMETERS, SET_MULTIPLE and set transfermode commands
  2130. // in GTF
  2131. //
  2132. if (((deviceSettings->FirmwareSettings[i].bCommandReg == IDE_COMMAND_SET_FEATURE) &&
  2133. (deviceSettings->FirmwareSettings[i].bFeaturesReg == IDE_SET_FEATURE_SET_TRANSFER_MODE)) ||
  2134. (deviceSettings->FirmwareSettings[i].bCommandReg == IDE_COMMAND_SET_DRIVE_PARAMETERS) ||
  2135. (deviceSettings->FirmwareSettings[i].bCommandReg == IDE_COMMAND_SET_MULTIPLE)) {
  2136. DebugPrint((DBG_ACPI,
  2137. "Ignoring Command %xin GTF\n",
  2138. deviceSettings->FirmwareSettings[i].bCommandReg
  2139. ));
  2140. deviceSettings->NumEntries--;
  2141. //
  2142. // remove this command by shifting the rest up one entry
  2143. //
  2144. for (j=i; j<deviceSettings->NumEntries; j++) {
  2145. deviceSettings->FirmwareSettings[j] = deviceSettings->FirmwareSettings[j+1];
  2146. }
  2147. //
  2148. // we move something new into the current i entry
  2149. // better adjust i so that we will check this entry
  2150. // again
  2151. //
  2152. if (i < deviceSettings->NumEntries) {
  2153. i--;
  2154. }
  2155. }
  2156. }
  2157. }
  2158. //
  2159. // we need to add a new setting
  2160. //
  2161. if (PdoExtension->ScsiDeviceType == DIRECT_ACCESS_DEVICE) {
  2162. totalDeviceSettingEntries = 2;
  2163. } else {
  2164. totalDeviceSettingEntries = 1;
  2165. }
  2166. if (deviceSettings) {
  2167. totalDeviceSettingEntries += deviceSettings->NumEntries;
  2168. firstNewEntryOffset = deviceSettings->NumEntries;
  2169. } else {
  2170. firstNewEntryOffset = 0;
  2171. }
  2172. tempDeviceSettings = ExAllocatePool (
  2173. NonPagedPool,
  2174. sizeof(DEVICE_SETTINGS) +
  2175. (totalDeviceSettingEntries) * sizeof(IDEREGS)
  2176. );
  2177. if (tempDeviceSettings) {
  2178. tempDeviceSettings->NumEntries = totalDeviceSettingEntries;
  2179. //
  2180. // copy the settings from acpi query
  2181. //
  2182. if (deviceSettings) {
  2183. RtlCopyMemory (&tempDeviceSettings->FirmwareSettings,
  2184. &deviceSettings->FirmwareSettings,
  2185. sizeof(IDEREGS) * deviceSettings->NumEntries);
  2186. //
  2187. // don't need the old structure anymore
  2188. //
  2189. ExFreePool (deviceSettings);
  2190. deviceSettings = NULL;
  2191. }
  2192. //
  2193. // add the new settings
  2194. //
  2195. RtlZeroMemory (
  2196. &tempDeviceSettings->FirmwareSettings[firstNewEntryOffset],
  2197. sizeof (IDEREGS));
  2198. tempDeviceSettings->FirmwareSettings[firstNewEntryOffset].bFeaturesReg =
  2199. IDE_SET_FEATURE_DISABLE_REVERT_TO_POWER_ON;
  2200. tempDeviceSettings->FirmwareSettings[firstNewEntryOffset].bCommandReg =
  2201. IDE_COMMAND_SET_FEATURE;
  2202. tempDeviceSettings->FirmwareSettings[firstNewEntryOffset].bReserved =
  2203. ATA_PTFLAGS_STATUS_DRDY_REQUIRED | ATA_PTFLAGS_OK_TO_FAIL;
  2204. if (PdoExtension->ScsiDeviceType == DIRECT_ACCESS_DEVICE) {
  2205. RtlZeroMemory (
  2206. &tempDeviceSettings->FirmwareSettings[firstNewEntryOffset + 1],
  2207. sizeof (IDEREGS));
  2208. tempDeviceSettings->FirmwareSettings[firstNewEntryOffset + 1].bFeaturesReg =
  2209. IDE_SET_FEATURE_ENABLE_WRITE_CACHE;
  2210. tempDeviceSettings->FirmwareSettings[firstNewEntryOffset + 1].bCommandReg =
  2211. IDE_COMMAND_SET_FEATURE;
  2212. tempDeviceSettings->FirmwareSettings[firstNewEntryOffset + 1].bReserved =
  2213. ATA_PTFLAGS_STATUS_DRDY_REQUIRED | ATA_PTFLAGS_OK_TO_FAIL;
  2214. }
  2215. //
  2216. // throw away the old and keep the new
  2217. //
  2218. deviceSettings = tempDeviceSettings;
  2219. } else {
  2220. //
  2221. // someone took all the memory.
  2222. // we can't build a new device setting structure
  2223. // will have to use the old one
  2224. //
  2225. }
  2226. //
  2227. // keep it around
  2228. //
  2229. PdoExtension->AcpiDeviceSettings = deviceSettings;
  2230. }
  2231. return STATUS_SUCCESS;
  2232. }
  2233. NTSTATUS
  2234. DeviceInitDeviceState (
  2235. IN PPDO_EXTENSION PdoExtension,
  2236. DEVICE_INIT_COMPLETION DeviceInitCompletionRoutine,
  2237. PVOID DeviceInitCompletionContext
  2238. )
  2239. {
  2240. PDEVICE_SETTINGS deviceSettings;
  2241. NTSTATUS status;
  2242. PDEVICE_INIT_DEVICE_STATE_CONTEXT deviceStateContext;
  2243. ULONG deviceStateContextSize;
  2244. ULONG numState;
  2245. ULONG numRequestSent;
  2246. DEVICE_INIT_STATE deviceInitState[deviceInitState_done];
  2247. if (!InterlockedExchange (&PdoExtension->InitDeviceWithAcpiGtf, 0)) {
  2248. //
  2249. // make sure we only do this once per start
  2250. //
  2251. return STATUS_SUCCESS;
  2252. }
  2253. if (!(PdoExtension->PdoState & PDOS_STARTED)) {
  2254. DebugPrint ((DBG_PNP, "DeviceInitDeviceState: device not started...skipping acpi init\n"));
  2255. (DeviceInitCompletionRoutine) (
  2256. DeviceInitCompletionContext,
  2257. STATUS_SUCCESS
  2258. );
  2259. return STATUS_SUCCESS;
  2260. }
  2261. deviceStateContextSize = sizeof (DEVICE_INIT_DEVICE_STATE_CONTEXT);
  2262. deviceStateContext = ExAllocatePool (NonPagedPool, deviceStateContextSize);
  2263. if (deviceStateContext == NULL) {
  2264. return STATUS_NO_MEMORY;
  2265. }
  2266. if (!RefPdoWithTag(PdoExtension->DeviceObject, FALSE, DeviceInitDeviceState)) {
  2267. ExFreePool (deviceStateContext);
  2268. return STATUS_NO_SUCH_DEVICE;
  2269. }
  2270. RtlZeroMemory(
  2271. deviceStateContext,
  2272. deviceStateContextSize
  2273. );
  2274. deviceSettings = PdoExtension->AcpiDeviceSettings;
  2275. //
  2276. // compute the total number of inti state we are going to have
  2277. //
  2278. numState = 0;
  2279. if (deviceSettings) {
  2280. deviceStateContext->DeviceInitState[numState] = deviceInitState_acpi;
  2281. numState++;
  2282. }
  2283. deviceStateContext->DeviceInitState[numState] = deviceInitState_done;
  2284. numState++;
  2285. ASSERT(numState <= deviceInitState_max);
  2286. deviceStateContext->PdoExtension = PdoExtension;
  2287. deviceStateContext->NumInitState = numState;
  2288. deviceStateContext->DeviceInitCompletionRoutine = DeviceInitCompletionRoutine;
  2289. deviceStateContext->DeviceInitCompletionContext = DeviceInitCompletionContext;
  2290. DeviceInitDeviceStateCompletionRoutine (
  2291. PdoExtension->DeviceObject,
  2292. deviceStateContext,
  2293. STATUS_SUCCESS
  2294. );
  2295. return STATUS_PENDING;
  2296. } // DeviceInitDeviceState
  2297. VOID
  2298. DeviceInitDeviceStateCompletionRoutine (
  2299. PDEVICE_OBJECT DeviceObject,
  2300. PVOID Context,
  2301. NTSTATUS Status
  2302. )
  2303. {
  2304. ULONG numRequestCompleted;
  2305. PDEVICE_INIT_DEVICE_STATE_CONTEXT deviceStateContext = Context;
  2306. PDEVICE_SETTINGS deviceSettings;
  2307. PPDO_EXTENSION PdoExtension;
  2308. NTSTATUS status;
  2309. if (!NT_SUCCESS(Status)) {
  2310. InterlockedIncrement (&deviceStateContext->NumRequestFailed);
  2311. DebugPrint ((DBG_ALWAYS, "DeviceInitDeviceStateCompletionRoutine: Last init. command failed with status %x\n",
  2312. Status));
  2313. }
  2314. PdoExtension = deviceStateContext->PdoExtension;
  2315. switch (deviceStateContext->DeviceInitState[deviceStateContext->CurrentState]) {
  2316. case deviceInitState_acpi:
  2317. deviceSettings = PdoExtension->AcpiDeviceSettings;
  2318. ASSERT (deviceSettings);
  2319. RtlZeroMemory (
  2320. &deviceStateContext->AtaPassThroughData,
  2321. sizeof(deviceStateContext->AtaPassThroughData)
  2322. );
  2323. deviceStateContext->AtaPassThroughData.IdeReg =
  2324. deviceSettings->FirmwareSettings[deviceStateContext->NumAcpiRequestSent];
  2325. deviceStateContext->AtaPassThroughData.IdeReg.bReserved |=
  2326. ATA_PTFLAGS_STATUS_DRDY_REQUIRED | ATA_PTFLAGS_URGENT;
  2327. deviceStateContext->NumAcpiRequestSent++;
  2328. if (deviceStateContext->NumAcpiRequestSent >= deviceSettings->NumEntries) {
  2329. //
  2330. // sent all acpi init state. go to the next state
  2331. //
  2332. deviceStateContext->CurrentState++;
  2333. }
  2334. if ((deviceStateContext->AtaPassThroughData.IdeReg.bFeaturesReg ==
  2335. IDE_SET_FEATURE_ENABLE_WRITE_CACHE) &&
  2336. (deviceStateContext->AtaPassThroughData.IdeReg.bCommandReg ==
  2337. IDE_COMMAND_SET_FEATURE)) {
  2338. //
  2339. // only ata harddisk should have this entry
  2340. //
  2341. ASSERT (PdoExtension->ScsiDeviceType == DIRECT_ACCESS_DEVICE);
  2342. if (PdoExtension->WriteCacheEnable == FALSE) {
  2343. deviceStateContext->AtaPassThroughData.IdeReg.bFeaturesReg =
  2344. IDE_SET_FEATURE_DISABLE_WRITE_CACHE;
  2345. }
  2346. }
  2347. DebugPrint ((
  2348. DBG_PNP,
  2349. "IdePort: restore firmware settings from ACPI BIOS. ide command = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
  2350. deviceStateContext->AtaPassThroughData.IdeReg.bFeaturesReg,
  2351. deviceStateContext->AtaPassThroughData.IdeReg.bSectorCountReg,
  2352. deviceStateContext->AtaPassThroughData.IdeReg.bSectorNumberReg,
  2353. deviceStateContext->AtaPassThroughData.IdeReg.bCylLowReg,
  2354. deviceStateContext->AtaPassThroughData.IdeReg.bCylHighReg,
  2355. deviceStateContext->AtaPassThroughData.IdeReg.bDriveHeadReg,
  2356. deviceStateContext->AtaPassThroughData.IdeReg.bCommandReg
  2357. ));
  2358. status = IssueAsyncAtaPassThroughSafe (
  2359. PdoExtension->ParentDeviceExtension,
  2360. PdoExtension,
  2361. &deviceStateContext->AtaPassThroughData,
  2362. TRUE,
  2363. DeviceInitDeviceStateCompletionRoutine,
  2364. deviceStateContext,
  2365. FALSE,
  2366. DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
  2367. FALSE
  2368. );
  2369. if (!NT_SUCCESS(status)) {
  2370. //
  2371. // can't send the request
  2372. // notify the completion routine that we fail
  2373. //
  2374. DeviceInitDeviceStateCompletionRoutine (
  2375. PdoExtension->DeviceObject,
  2376. deviceStateContext,
  2377. status
  2378. );
  2379. }
  2380. break;
  2381. case deviceInitState_done:
  2382. //
  2383. // notify the original caller w/ error if any
  2384. //
  2385. (*deviceStateContext->DeviceInitCompletionRoutine) (
  2386. deviceStateContext->DeviceInitCompletionContext,
  2387. deviceStateContext->NumRequestFailed ?
  2388. STATUS_UNSUCCESSFUL :
  2389. STATUS_SUCCESS
  2390. );
  2391. UnrefPdoWithTag(
  2392. deviceStateContext->PdoExtension,
  2393. DeviceInitDeviceState
  2394. );
  2395. ExFreePool (deviceStateContext);
  2396. break;
  2397. default:
  2398. ASSERT(FALSE);
  2399. }
  2400. return;
  2401. }
  2402. NTSTATUS
  2403. DeviceIdeReadCapacity (
  2404. IN PPDO_EXTENSION PdoExtension,
  2405. IN OUT PIRP Irp
  2406. )
  2407. {
  2408. NTSTATUS status;
  2409. PIDE_READ_CAPACITY_CONTEXT context;
  2410. PATA_PASS_THROUGH ataPassThroughData;
  2411. ULONG dataSize;
  2412. PUCHAR dataOffset;
  2413. PHW_DEVICE_EXTENSION hwDeviceExtension=PdoExtension->ParentDeviceExtension->HwDeviceExtension;
  2414. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  2415. PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
  2416. //
  2417. // Check for device present flag
  2418. //
  2419. if (!(hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_DEVICE_PRESENT)) {
  2420. srb->SrbStatus = SRB_STATUS_NO_DEVICE;
  2421. UnrefLogicalUnitExtensionWithTag(
  2422. PdoExtension->ParentDeviceExtension,
  2423. PdoExtension,
  2424. Irp
  2425. );
  2426. Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  2427. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2428. return STATUS_NO_SUCH_DEVICE;
  2429. }
  2430. context = ExAllocatePool (
  2431. NonPagedPool,
  2432. sizeof(IDE_READ_CAPACITY_CONTEXT)
  2433. );
  2434. if ((context == NULL) || (Irp->MdlAddress == NULL)) {
  2435. if (context) {
  2436. ExFreePool(context);
  2437. }
  2438. UnrefLogicalUnitExtensionWithTag(
  2439. PdoExtension->ParentDeviceExtension,
  2440. PdoExtension,
  2441. Irp
  2442. );
  2443. srb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  2444. srb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
  2445. IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
  2446. PdoExtension->TargetId,
  2447. NonPagedPool,
  2448. sizeof(IDE_READ_CAPACITY_CONTEXT),
  2449. IDEPORT_TAG_READCAP_CONTEXT
  2450. );
  2451. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2452. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2453. return STATUS_INSUFFICIENT_RESOURCES;
  2454. }
  2455. //
  2456. // save the old data buffer for restoring later
  2457. //
  2458. context->OldDataBuffer = srb->DataBuffer;
  2459. context->GeometryIoctl=FALSE;
  2460. //
  2461. // map the buffer in
  2462. //
  2463. dataOffset = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
  2464. srb->DataBuffer = dataOffset +
  2465. (ULONG)((PUCHAR)srb->DataBuffer -
  2466. (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
  2467. context->PdoExtension = PdoExtension;
  2468. context->OriginalIrp = Irp;
  2469. // MdlSafe failed
  2470. if (dataOffset == NULL) {
  2471. IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
  2472. PdoExtension->TargetId,
  2473. NonPagedPool,
  2474. sizeof(MDL),
  2475. IDEPORT_TAG_READCAP_MDL
  2476. );
  2477. DeviceIdeReadCapacityCompletionRoutine (
  2478. PdoExtension->DeviceObject,
  2479. context,
  2480. STATUS_INSUFFICIENT_RESOURCES
  2481. );
  2482. return STATUS_INSUFFICIENT_RESOURCES;
  2483. }
  2484. IoMarkIrpPending(Irp);
  2485. ataPassThroughData = &context->AtaPassThroughData;
  2486. RtlZeroMemory (
  2487. ataPassThroughData,
  2488. sizeof (*ataPassThroughData)
  2489. );
  2490. ataPassThroughData->DataBufferSize = sizeof(IDENTIFY_DATA);
  2491. ataPassThroughData->IdeReg.bCommandReg = IDE_COMMAND_IDENTIFY;
  2492. ataPassThroughData->IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
  2493. status = IssueAsyncAtaPassThroughSafe (
  2494. PdoExtension->ParentDeviceExtension,
  2495. PdoExtension,
  2496. ataPassThroughData,
  2497. TRUE,
  2498. DeviceIdeReadCapacityCompletionRoutine,
  2499. context,
  2500. FALSE,
  2501. DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
  2502. FALSE
  2503. );
  2504. if (status != STATUS_PENDING) {
  2505. DeviceIdeReadCapacityCompletionRoutine (
  2506. PdoExtension->DeviceObject,
  2507. context,
  2508. status
  2509. );
  2510. }
  2511. //
  2512. // the irp was marked pending. return status_pending
  2513. //
  2514. return STATUS_PENDING;
  2515. }
  2516. VOID
  2517. DeviceIdeReadCapacityCompletionRoutine (
  2518. IN PDEVICE_OBJECT DeviceObject,
  2519. PVOID Context,
  2520. NTSTATUS Status
  2521. )
  2522. {
  2523. PIDE_READ_CAPACITY_CONTEXT context = Context;
  2524. PIRP irp = context->OriginalIrp;
  2525. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(irp);
  2526. PSCSI_REQUEST_BLOCK srb;
  2527. KIRQL currentIrql;
  2528. PKSPIN_LOCK spinLock;
  2529. ULONG numberOfCylinders;
  2530. ULONG numberOfHeads;
  2531. ULONG sectorsPerTrack;
  2532. PHW_DEVICE_EXTENSION hwDeviceExtension;
  2533. ULONG i;
  2534. ULONG targetId;
  2535. PIDENTIFY_DATA identifyData;
  2536. #ifdef GET_DISK_GEOMETRY_DEFINED
  2537. DISK_GEOMETRY diskGeometry;
  2538. //
  2539. // ioctl_disk_get_drive_geometry
  2540. // not interested in updating the srb
  2541. //
  2542. if (context->GeometryIoctl) {
  2543. srb=NULL;
  2544. targetId=context->PdoExtension->TargetId;
  2545. }
  2546. else {
  2547. #endif
  2548. srb = irpStack->Parameters.Scsi.Srb;
  2549. targetId=srb->TargetId;
  2550. #ifdef GET_DISK_GEOMETRY_DEFINED
  2551. }
  2552. #endif
  2553. hwDeviceExtension = context->PdoExtension->ParentDeviceExtension->HwDeviceExtension;
  2554. spinLock = &context->PdoExtension->ParentDeviceExtension->SpinLock;
  2555. if (NT_SUCCESS(Status)) {
  2556. identifyData = (PIDENTIFY_DATA) context->AtaPassThroughData.DataBuffer;
  2557. IdePortFudgeAtaIdentifyData(
  2558. identifyData
  2559. );
  2560. if ( (!Is98LegacyIde(&hwDeviceExtension->BaseIoAddress1)) &&
  2561. ((identifyData->MajorRevision == 0) ||
  2562. ((identifyData->NumberOfCurrentCylinders == 0) ||
  2563. (identifyData->NumberOfCurrentHeads == 0) ||
  2564. (identifyData->CurrentSectorsPerTrack == 0))) ) {
  2565. numberOfCylinders = identifyData->NumCylinders;
  2566. numberOfHeads = identifyData->NumHeads;
  2567. sectorsPerTrack = identifyData->NumSectorsPerTrack;
  2568. } else {
  2569. numberOfCylinders = identifyData->NumberOfCurrentCylinders;
  2570. numberOfHeads = identifyData->NumberOfCurrentHeads;
  2571. sectorsPerTrack = identifyData->CurrentSectorsPerTrack;
  2572. if (!Is98LegacyIde(&hwDeviceExtension->BaseIoAddress1)) {
  2573. if (identifyData->UserAddressableSectors >
  2574. (numberOfCylinders * numberOfHeads * sectorsPerTrack)) {
  2575. //
  2576. // some ide driver has a 2G jumer to get around bios
  2577. // problem. make sure we are not tricked the samw way.
  2578. //
  2579. if ((numberOfCylinders <= 0xfff) &&
  2580. (numberOfHeads == 0x10) &&
  2581. (sectorsPerTrack == 0x3f)) {
  2582. numberOfCylinders = identifyData->UserAddressableSectors / (0x10 * 0x3f);
  2583. }
  2584. }
  2585. }
  2586. }
  2587. //
  2588. // update the HW Device Extension Data
  2589. //
  2590. KeAcquireSpinLock(spinLock, &currentIrql);
  2591. InitDeviceGeometry(
  2592. hwDeviceExtension,
  2593. targetId,
  2594. numberOfCylinders,
  2595. numberOfHeads,
  2596. sectorsPerTrack
  2597. );
  2598. if (hwDeviceExtension->DeviceFlags[targetId] & DFLAGS_IDENTIFY_INVALID) {
  2599. RtlMoveMemory (
  2600. hwDeviceExtension->IdentifyData + targetId,
  2601. identifyData,
  2602. sizeof (IDENTIFY_DATA)
  2603. );
  2604. ASSERT(!(hwDeviceExtension->DeviceFlags[targetId] & DFLAGS_REMOVABLE_DRIVE));
  2605. SETMASK(hwDeviceExtension->DeviceFlags[targetId], DFLAGS_IDENTIFY_VALID);
  2606. CLRMASK(hwDeviceExtension->DeviceFlags[targetId], DFLAGS_IDENTIFY_INVALID);
  2607. }
  2608. if (srb) {
  2609. //
  2610. // Claim 512 byte blocks (big-endian).
  2611. //
  2612. ((PREAD_CAPACITY_DATA)srb->DataBuffer)->BytesPerBlock = 0x20000;
  2613. //
  2614. // Calculate last sector.
  2615. //
  2616. if (context->PdoExtension->ParentDeviceExtension->
  2617. HwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_LBA) {
  2618. // LBA device
  2619. i = identifyData->UserAddressableSectors - 1;
  2620. //
  2621. // LBAs can only be 28 bits wide
  2622. //
  2623. if (i >= MAX_28BIT_LBA) {
  2624. i = MAX_28BIT_LBA - 1;
  2625. }
  2626. #ifdef ENABLE_48BIT_LBA
  2627. if (context->PdoExtension->ParentDeviceExtension->
  2628. HwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_48BIT_LBA) {
  2629. i = identifyData->Max48BitLBA[0] - 1;
  2630. //
  2631. // currently we support only upto 32 bits.
  2632. //
  2633. ASSERT(identifyData->Max48BitLBA[1] == 0);
  2634. }
  2635. #endif
  2636. DebugPrint((1,
  2637. "IDE LBA disk %x - total # of sectors = 0x%x\n",
  2638. srb->TargetId,
  2639. identifyData->UserAddressableSectors));
  2640. } else {
  2641. // CHS device
  2642. i = (numberOfHeads * numberOfCylinders * sectorsPerTrack) - 1;
  2643. DebugPrint((1,
  2644. "IDE CHS disk %x - #sectors %x, #heads %x, #cylinders %x\n",
  2645. srb->TargetId,
  2646. sectorsPerTrack,
  2647. numberOfHeads,
  2648. numberOfCylinders));
  2649. DebugPrint((1,
  2650. "IDE CHS disk Identify data%x - #sectors %x, #heads %x, #cylinders %x\n",
  2651. srb->TargetId,
  2652. identifyData->NumSectorsPerTrack,
  2653. identifyData->NumHeads,
  2654. identifyData->NumCylinders));
  2655. DebugPrint((1,
  2656. "IDE CHS disk Identify currentdata%x - #sectors %x, #heads %x, #cylinders %x\n",
  2657. srb->TargetId,
  2658. identifyData->CurrentSectorsPerTrack,
  2659. identifyData->NumberOfCurrentHeads,
  2660. identifyData->NumberOfCurrentCylinders));
  2661. }
  2662. ((PREAD_CAPACITY_DATA)srb->DataBuffer)->LogicalBlockAddress =
  2663. (((PUCHAR)&i)[0] << 24) | (((PUCHAR)&i)[1] << 16) |
  2664. (((PUCHAR)&i)[2] << 8) | ((PUCHAR)&i)[3];
  2665. srb->SrbStatus = SRB_STATUS_SUCCESS;
  2666. irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA);
  2667. }
  2668. KeReleaseSpinLock(spinLock, currentIrql);
  2669. } else {
  2670. if (srb) {
  2671. if (Status==STATUS_INSUFFICIENT_RESOURCES) {
  2672. srb->SrbStatus=SRB_STATUS_INTERNAL_ERROR;
  2673. srb->InternalStatus=STATUS_INSUFFICIENT_RESOURCES;
  2674. }
  2675. else {
  2676. srb->SrbStatus = SRB_STATUS_ERROR;
  2677. }
  2678. }
  2679. }
  2680. if (srb) {
  2681. //
  2682. // restoring DataBuffer
  2683. //
  2684. srb->DataBuffer = context->OldDataBuffer;
  2685. }
  2686. #ifdef GET_DISK_GEOMETRY_DEFINED
  2687. if (context->GeometryIoctl && NT_SUCCESS(Status)) {
  2688. //
  2689. // Update Disk geometry from device extension
  2690. //
  2691. //diskGeometry.Cylinders.QuadPart=hwDeviceExtension->NumberOfCylinders[targetId];
  2692. diskGeometry.Cylinders.QuadPart=numberOfCylinders;
  2693. if (hwDeviceExtension->DeviceFlags[targetId] & DFLAGS_REMOVABLE_DRIVE) {
  2694. diskGeometry.MediaType=RemovableMedia;
  2695. } else {
  2696. diskGeometry.MediaType=FixedMedia;
  2697. }
  2698. diskGeometry.TracksPerCylinder=hwDeviceExtension->NumberOfHeads[targetId];
  2699. diskGeometry.SectorsPerTrack=hwDeviceExtension->SectorsPerTrack[targetId];
  2700. diskGeometry.BytesPerSector=512; //check
  2701. //
  2702. // >8Gb
  2703. //
  2704. if ((hwDeviceExtension->NumberOfCylinders[targetId] == 16383) &&
  2705. (hwDeviceExtension->NumberOfHeads[targetId] <= 16) &&
  2706. (hwDeviceExtension->SectorsPerTrack[targetId] == 63)) {
  2707. diskGeometry.Cylinders.QuadPart= (identifyData->UserAddressableSectors)/
  2708. (hwDeviceExtension->NumberOfHeads[targetId]*
  2709. hwDeviceExtension->SectorsPerTrack[targetId]);
  2710. }
  2711. DebugPrint((1, "Geometry: device=%d, tpc=%d, spt=%d, bps=%d, cyl=%x, ncyl=%d, uas=%d\n",
  2712. targetId,
  2713. diskGeometry.TracksPerCylinder,
  2714. diskGeometry.SectorsPerTrack,
  2715. diskGeometry.BytesPerSector,
  2716. diskGeometry.Cylinders.QuadPart,
  2717. hwDeviceExtension->NumberOfCylinders[targetId],
  2718. identifyData->UserAddressableSectors));
  2719. RtlMoveMemory(irp->AssociatedIrp.SystemBuffer,
  2720. &(diskGeometry),
  2721. sizeof(DISK_GEOMETRY));
  2722. irp->IoStatus.Information = sizeof(DISK_GEOMETRY);
  2723. Status=STATUS_SUCCESS;
  2724. }
  2725. #endif
  2726. UnrefLogicalUnitExtensionWithTag(
  2727. context->PdoExtension->ParentDeviceExtension,
  2728. context->PdoExtension,
  2729. irp
  2730. );
  2731. IDEPORT_PUT_LUNEXT_IN_IRP (irpStack, NULL);
  2732. ExFreePool (context);
  2733. irp->IoStatus.Status = Status;
  2734. IoCompleteRequest(irp, IO_NO_INCREMENT);
  2735. return;
  2736. }
  2737. NTSTATUS
  2738. DeviceIdeModeSense (
  2739. IN PPDO_EXTENSION PdoExtension,
  2740. IN OUT PIRP Irp
  2741. )
  2742. {
  2743. NTSTATUS status;
  2744. PIO_STACK_LOCATION irpStack;
  2745. PSCSI_REQUEST_BLOCK srb;
  2746. PCDB cdb;
  2747. ULONG modeDataBufferSize;
  2748. ULONG dataBufferSize;
  2749. ULONG dataBufferByteLeft;
  2750. PMODE_PARAMETER_HEADER modePageHeader;
  2751. PUCHAR pageData;
  2752. PHW_DEVICE_EXTENSION hwDeviceExtension;
  2753. PAGED_CODE();
  2754. hwDeviceExtension = PdoExtension->ParentDeviceExtension->HwDeviceExtension;
  2755. irpStack = IoGetCurrentIrpStackLocation(Irp);
  2756. srb = irpStack->Parameters.Scsi.Srb;
  2757. cdb = (PCDB) srb->Cdb;
  2758. //
  2759. // Check for device present flag
  2760. //
  2761. if (!(hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_DEVICE_PRESENT)) {
  2762. srb->SrbStatus = SRB_STATUS_NO_DEVICE;
  2763. UnrefLogicalUnitExtensionWithTag(
  2764. PdoExtension->ParentDeviceExtension,
  2765. PdoExtension,
  2766. Irp
  2767. );
  2768. Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  2769. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2770. return STATUS_NO_SUCH_DEVICE;
  2771. }
  2772. ASSERT(cdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE);
  2773. //
  2774. // make sure this is for the right lun
  2775. //
  2776. if (cdb->MODE_SENSE.LogicalUnitNumber != PdoExtension->Lun) {
  2777. srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
  2778. status = STATUS_INVALID_DEVICE_REQUEST;
  2779. goto getout;
  2780. }
  2781. //
  2782. // only support page control for current values
  2783. //
  2784. if (cdb->MODE_SENSE.Pc != 0) {
  2785. srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
  2786. status = STATUS_INVALID_DEVICE_REQUEST;
  2787. goto getout;
  2788. }
  2789. //
  2790. // save the data buffer size for later use
  2791. //
  2792. modeDataBufferSize = srb->DataTransferLength;
  2793. //
  2794. // make sure the output buffer is at least the size of the header
  2795. //
  2796. if (modeDataBufferSize < sizeof(MODE_PARAMETER_HEADER)) {
  2797. srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
  2798. status = STATUS_BUFFER_TOO_SMALL;
  2799. goto getout;
  2800. }
  2801. //
  2802. // some basic init.
  2803. //
  2804. modePageHeader = srb->DataBuffer;
  2805. pageData = (PUCHAR) (modePageHeader + 1);
  2806. RtlZeroMemory (modePageHeader, modeDataBufferSize);
  2807. ASSERT (modeDataBufferSize);
  2808. ASSERT (modePageHeader);
  2809. modePageHeader->ModeDataLength = sizeof(MODE_PARAMETER_HEADER) -
  2810. FIELD_OFFSET(MODE_PARAMETER_HEADER, MediumType);
  2811. //
  2812. // get write protect bit from smart data
  2813. //
  2814. if (hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) {
  2815. ATA_PASS_THROUGH ataPassThroughData;
  2816. NTSTATUS localStatus;
  2817. RtlZeroMemory (
  2818. &ataPassThroughData,
  2819. sizeof (ataPassThroughData)
  2820. );
  2821. ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_GET_MEDIA_STATUS;
  2822. ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
  2823. localStatus = IssueSyncAtaPassThroughSafe (
  2824. PdoExtension->ParentDeviceExtension,
  2825. PdoExtension,
  2826. &ataPassThroughData,
  2827. FALSE,
  2828. FALSE,
  2829. DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
  2830. FALSE);
  2831. //if (NT_SUCCESS(localStatus)) {
  2832. if (ataPassThroughData.IdeReg.bCommandReg & IDE_STATUS_ERROR){
  2833. if (ataPassThroughData.IdeReg.bFeaturesReg & IDE_ERROR_DATA_ERROR){
  2834. modePageHeader->DeviceSpecificParameter |= MODE_DSP_WRITE_PROTECT;
  2835. }
  2836. // }
  2837. }
  2838. }
  2839. dataBufferByteLeft = modeDataBufferSize - sizeof(MODE_PARAMETER_HEADER);
  2840. if (IsNEC_98) {
  2841. HANDLE pageHandle;
  2842. ULONG numberOfCylinders;
  2843. ULONG numberOfHeads;
  2844. ULONG sectorsPerTrack;
  2845. KIRQL currentIrql;
  2846. PKSPIN_LOCK spinLock;
  2847. //
  2848. // take a snap shot of the CHS values
  2849. //
  2850. spinLock = &PdoExtension->ParentDeviceExtension->SpinLock;
  2851. //
  2852. // lock the code before grabbing a lock
  2853. //
  2854. pageHandle = MmLockPagableCodeSection(DeviceIdeModeSense);
  2855. KeAcquireSpinLock(spinLock, &currentIrql);
  2856. numberOfCylinders = hwDeviceExtension->NumberOfCylinders[srb->TargetId];
  2857. numberOfHeads = hwDeviceExtension->NumberOfHeads[srb->TargetId];
  2858. sectorsPerTrack = hwDeviceExtension->SectorsPerTrack[srb->TargetId];
  2859. KeReleaseSpinLock(spinLock, currentIrql);
  2860. MmUnlockPagableImageSection(pageHandle);
  2861. //
  2862. // Set pages which are formated as nec-scsi.
  2863. //
  2864. if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) ||
  2865. (cdb->MODE_SENSE.PageCode == MODE_PAGE_ERROR_RECOVERY)) {
  2866. //
  2867. // error recovery page
  2868. //
  2869. if (dataBufferByteLeft >= 0x6 + 2) {
  2870. PMODE_DISCONNECT_PAGE recoveryPage;
  2871. recoveryPage = (PMODE_DISCONNECT_PAGE) pageData;
  2872. recoveryPage->PageCode = MODE_PAGE_ERROR_RECOVERY;
  2873. recoveryPage->PageLength = 0x6;
  2874. //
  2875. // update out data buffer pointer
  2876. //
  2877. pageData += recoveryPage->PageLength + 2;
  2878. dataBufferByteLeft -= (recoveryPage->PageLength + 2);
  2879. modePageHeader->ModeDataLength += recoveryPage->PageLength + 2;
  2880. } else {
  2881. status = STATUS_BUFFER_TOO_SMALL;
  2882. goto getout;
  2883. }
  2884. }
  2885. if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) ||
  2886. (cdb->MODE_SENSE.PageCode == MODE_PAGE_FORMAT_DEVICE)) {
  2887. //
  2888. // format device page
  2889. //
  2890. if (dataBufferByteLeft >= 0x16 + 2) {
  2891. PMODE_FORMAT_PAGE formatPage;
  2892. formatPage = (PMODE_FORMAT_PAGE) pageData;
  2893. formatPage->PageCode = MODE_PAGE_FORMAT_DEVICE;
  2894. formatPage->PageLength = 0x16;
  2895. //
  2896. // SectorsPerTrack
  2897. //
  2898. ((PFOUR_BYTE)&formatPage->SectorsPerTrack[0])->Byte1 =
  2899. ((PFOUR_BYTE)&sectorsPerTrack)->Byte0;
  2900. ((PFOUR_BYTE)&formatPage->SectorsPerTrack[0])->Byte0 =
  2901. ((PFOUR_BYTE)&sectorsPerTrack)->Byte1;
  2902. //
  2903. // update out data buffer pointer
  2904. //
  2905. pageData += formatPage->PageLength + 2;
  2906. dataBufferByteLeft -= (formatPage->PageLength + 2);
  2907. modePageHeader->ModeDataLength += formatPage->PageLength + 2;
  2908. } else {
  2909. status = STATUS_BUFFER_TOO_SMALL;
  2910. goto getout;
  2911. }
  2912. }
  2913. if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) ||
  2914. (cdb->MODE_SENSE.PageCode == MODE_PAGE_RIGID_GEOMETRY)) {
  2915. //
  2916. // rigid geometry page
  2917. //
  2918. if (dataBufferByteLeft >= 0x12 + 2) {
  2919. PMODE_RIGID_GEOMETRY_PAGE geometryPage;
  2920. geometryPage = (PMODE_RIGID_GEOMETRY_PAGE) pageData;
  2921. geometryPage->PageCode = MODE_PAGE_RIGID_GEOMETRY;
  2922. geometryPage->PageLength = 0x12;
  2923. //
  2924. // NumberOfHeads
  2925. //
  2926. geometryPage->NumberOfHeads = (UCHAR) numberOfHeads;
  2927. //
  2928. // NumberOfCylinders
  2929. //
  2930. ((PFOUR_BYTE)&geometryPage->NumberOfCylinders)->Byte2
  2931. = ((PFOUR_BYTE)&numberOfCylinders)->Byte0;
  2932. ((PFOUR_BYTE)&geometryPage->NumberOfCylinders)->Byte1
  2933. = ((PFOUR_BYTE)&numberOfCylinders)->Byte1;
  2934. ((PFOUR_BYTE)&geometryPage->NumberOfCylinders)->Byte0
  2935. = 0;
  2936. //
  2937. // update out data buffer pointer
  2938. //
  2939. pageData += geometryPage->PageLength + 2;
  2940. dataBufferByteLeft -= (geometryPage->PageLength + 2);
  2941. modePageHeader->ModeDataLength += geometryPage->PageLength + 2;
  2942. } else {
  2943. status = STATUS_BUFFER_TOO_SMALL;
  2944. goto getout;
  2945. }
  2946. }
  2947. }
  2948. if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) ||
  2949. (cdb->MODE_SENSE.PageCode == MODE_PAGE_CACHING)) {
  2950. if (dataBufferByteLeft >= sizeof(MODE_CACHING_PAGE)) {
  2951. //
  2952. // cache settings page
  2953. //
  2954. PMODE_CACHING_PAGE cachePage;
  2955. cachePage = (PMODE_CACHING_PAGE) pageData;
  2956. cachePage->PageCode = MODE_PAGE_CACHING;
  2957. cachePage->PageSavable = 0;
  2958. cachePage->PageLength = 0xa;
  2959. cachePage->ReadDisableCache = 0;
  2960. cachePage->WriteCacheEnable = PdoExtension->WriteCacheEnable;
  2961. //
  2962. // update out data buffer pointer
  2963. //
  2964. pageData += sizeof (MODE_CACHING_PAGE);
  2965. dataBufferByteLeft -= sizeof (MODE_CACHING_PAGE);
  2966. modePageHeader->ModeDataLength += sizeof (MODE_CACHING_PAGE);
  2967. } else {
  2968. srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
  2969. srb->DataTransferLength -= dataBufferByteLeft;
  2970. Irp->IoStatus.Information = srb->DataTransferLength;
  2971. status = STATUS_BUFFER_TOO_SMALL;
  2972. goto getout;
  2973. }
  2974. }
  2975. //
  2976. // update the number of bytes we are returning
  2977. //
  2978. srb->DataTransferLength -= dataBufferByteLeft;
  2979. Irp->IoStatus.Information = srb->DataTransferLength;
  2980. status = STATUS_SUCCESS;
  2981. srb->SrbStatus = SRB_STATUS_SUCCESS;
  2982. getout:
  2983. UnrefPdoWithTag(
  2984. PdoExtension,
  2985. Irp
  2986. );
  2987. Irp->IoStatus.Status = status;
  2988. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  2989. return status;
  2990. }
  2991. NTSTATUS
  2992. DeviceIdeModeSelect (
  2993. IN PPDO_EXTENSION PdoExtension,
  2994. IN OUT PIRP Irp
  2995. )
  2996. {
  2997. NTSTATUS status;
  2998. PIO_STACK_LOCATION irpStack;
  2999. PSCSI_REQUEST_BLOCK srb;
  3000. PCDB cdb;
  3001. ULONG modeDataBufferSize;
  3002. PMODE_PARAMETER_HEADER modePageHeader;
  3003. PUCHAR modePage;
  3004. ULONG pageOffset;
  3005. PMODE_CACHING_PAGE cachePage;
  3006. PHW_DEVICE_EXTENSION hwDeviceExtension;
  3007. PAGED_CODE();
  3008. irpStack = IoGetCurrentIrpStackLocation(Irp);
  3009. srb = irpStack->Parameters.Scsi.Srb;
  3010. cdb = (PCDB) srb->Cdb;
  3011. hwDeviceExtension = PdoExtension->ParentDeviceExtension->HwDeviceExtension;
  3012. //
  3013. // Check for device present flag
  3014. //
  3015. if (!(hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_DEVICE_PRESENT)) {
  3016. srb->SrbStatus = SRB_STATUS_NO_DEVICE;
  3017. UnrefLogicalUnitExtensionWithTag(
  3018. PdoExtension->ParentDeviceExtension,
  3019. PdoExtension,
  3020. Irp
  3021. );
  3022. Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
  3023. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3024. return STATUS_NO_SUCH_DEVICE;
  3025. }
  3026. ASSERT(cdb->MODE_SELECT.OperationCode == SCSIOP_MODE_SELECT);
  3027. //
  3028. // make sure this is for the right lun
  3029. //
  3030. if (cdb->MODE_SELECT.LogicalUnitNumber != PdoExtension->Lun) {
  3031. srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
  3032. status = STATUS_INVALID_DEVICE_REQUEST;
  3033. goto getout;
  3034. }
  3035. //
  3036. // only support scsi-2 mode select format
  3037. //
  3038. if (cdb->MODE_SELECT.PFBit != 1) {
  3039. srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
  3040. status = STATUS_INVALID_DEVICE_REQUEST;
  3041. goto getout;
  3042. }
  3043. modeDataBufferSize = cdb->MODE_SELECT.ParameterListLength;
  3044. modePageHeader = srb->DataBuffer;
  3045. if (modeDataBufferSize < sizeof(MODE_PARAMETER_HEADER)) {
  3046. srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
  3047. status = STATUS_INVALID_DEVICE_REQUEST;
  3048. goto getout;
  3049. }
  3050. pageOffset = sizeof(MODE_PARAMETER_HEADER) + modePageHeader->BlockDescriptorLength;
  3051. while (modeDataBufferSize > pageOffset) {
  3052. modePage = ((PUCHAR) modePageHeader) + pageOffset;
  3053. cachePage = (PMODE_CACHING_PAGE) modePage;
  3054. if ((cachePage->PageCode == MODE_PAGE_CACHING) &&
  3055. ((modePageHeader->ModeDataLength - pageOffset) >= sizeof(MODE_CACHING_PAGE)) &&
  3056. (cachePage->PageLength == 0xa)) {
  3057. if (cachePage->WriteCacheEnable != PdoExtension->WriteCacheEnable) {
  3058. ATA_PASS_THROUGH ataPassThroughData;
  3059. NTSTATUS localStatus;
  3060. RtlZeroMemory (
  3061. &ataPassThroughData,
  3062. sizeof (ataPassThroughData)
  3063. );
  3064. if (cachePage->WriteCacheEnable) {
  3065. ataPassThroughData.IdeReg.bFeaturesReg = IDE_SET_FEATURE_ENABLE_WRITE_CACHE;
  3066. } else {
  3067. ataPassThroughData.IdeReg.bFeaturesReg = IDE_SET_FEATURE_DISABLE_WRITE_CACHE;
  3068. }
  3069. ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_SET_FEATURE;
  3070. ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
  3071. localStatus = IssueSyncAtaPassThroughSafe (
  3072. PdoExtension->ParentDeviceExtension,
  3073. PdoExtension,
  3074. &ataPassThroughData,
  3075. FALSE,
  3076. FALSE,
  3077. DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
  3078. FALSE);
  3079. if (NT_SUCCESS(localStatus) &&
  3080. !(ataPassThroughData.IdeReg.bCommandReg & IDE_STATUS_ERROR)) {
  3081. PdoExtension->WriteCacheEnable = cachePage->WriteCacheEnable;
  3082. } else {
  3083. status = STATUS_IO_DEVICE_ERROR;
  3084. srb->SrbStatus = SRB_STATUS_ERROR;
  3085. goto getout;
  3086. }
  3087. }
  3088. pageOffset += sizeof(MODE_CACHING_PAGE);
  3089. } else {
  3090. status = STATUS_INVALID_PARAMETER;
  3091. srb->SrbStatus = SRB_STATUS_ERROR;
  3092. goto getout;
  3093. }
  3094. }
  3095. status = STATUS_SUCCESS;
  3096. srb->SrbStatus = SRB_STATUS_SUCCESS;
  3097. getout:
  3098. UnrefPdoWithTag(
  3099. PdoExtension,
  3100. Irp
  3101. );
  3102. Irp->IoStatus.Information = 0;
  3103. Irp->IoStatus.Status = status;
  3104. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3105. return status;
  3106. }
  3107. NTSTATUS
  3108. DeviceQueryPnPDeviceState (
  3109. IN PDEVICE_OBJECT DeviceObject,
  3110. IN OUT PIRP Irp
  3111. )
  3112. {
  3113. NTSTATUS status;
  3114. PPDO_EXTENSION pdoExtension;
  3115. pdoExtension = RefPdoWithTag(
  3116. DeviceObject,
  3117. TRUE,
  3118. DeviceQueryPnPDeviceState
  3119. );
  3120. if (pdoExtension) {
  3121. PPNP_DEVICE_STATE deviceState;
  3122. DebugPrint((DBG_PNP, "QUERY_DEVICE_STATE for PDOE 0x%x\n", pdoExtension));
  3123. if(pdoExtension->PagingPathCount != 0) {
  3124. deviceState = (PPNP_DEVICE_STATE) &(Irp->IoStatus.Information);
  3125. SETMASK((*deviceState), PNP_DEVICE_NOT_DISABLEABLE);
  3126. }
  3127. status = STATUS_SUCCESS;
  3128. UnrefPdoWithTag(
  3129. pdoExtension,
  3130. DeviceQueryPnPDeviceState
  3131. );
  3132. } else {
  3133. status = STATUS_DEVICE_DOES_NOT_EXIST;
  3134. }
  3135. Irp->IoStatus.Status = status;
  3136. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  3137. return status;
  3138. }
  3139. NTSTATUS
  3140. DeviceAtapiModeCommandCompletion (
  3141. IN PDEVICE_OBJECT DeviceObject,
  3142. IN PIRP Irp,
  3143. IN PVOID Context
  3144. )
  3145. /*++
  3146. Description
  3147. Completes the original irp after copying the data from the current srb
  3148. Arguments:
  3149. DeviceObject Not used
  3150. Irp The irp - Not used
  3151. Context Srb
  3152. Return value:
  3153. STATUS_MORE_PROCESSING_REQUIRED
  3154. --*/
  3155. {
  3156. PIO_STACK_LOCATION irpStack;
  3157. PIDE_MODE_COMMAND_CONTEXT context = Context;
  3158. PSCSI_REQUEST_BLOCK srb = context->Srb;
  3159. PSCSI_REQUEST_BLOCK originalSrb;
  3160. PIRP originalIrp;
  3161. UCHAR bytesAdjust = sizeof(MODE_PARAMETER_HEADER_10) -
  3162. sizeof(MODE_PARAMETER_HEADER);
  3163. ULONG transferLength;
  3164. //
  3165. // retrieve the original srb and the irp
  3166. //
  3167. originalSrb = *((PVOID *) (srb+1));
  3168. ASSERT(originalSrb);
  3169. originalIrp = originalSrb->OriginalRequest;
  3170. ASSERT(originalIrp);
  3171. transferLength = srb->DataTransferLength;
  3172. if (srb->Cdb[0] == ATAPI_MODE_SENSE) {
  3173. PMODE_PARAMETER_HEADER_10 header_10 = (PMODE_PARAMETER_HEADER_10)(srb->DataBuffer);
  3174. PMODE_PARAMETER_HEADER header = (PMODE_PARAMETER_HEADER)(originalSrb->DataBuffer);
  3175. header->ModeDataLength = header_10->ModeDataLengthLsb;
  3176. header->MediumType = header_10->MediumType;
  3177. //
  3178. // ATAPI Mode Parameter Header doesn't have these fields.
  3179. //
  3180. header->DeviceSpecificParameter = header_10->Reserved[0];
  3181. //
  3182. // ISSUE:
  3183. //
  3184. header->BlockDescriptorLength = header_10->Reserved[4];
  3185. //
  3186. // copy the rest of the data
  3187. //
  3188. if (transferLength > sizeof(MODE_PARAMETER_HEADER_10)) {
  3189. RtlMoveMemory((PUCHAR)originalSrb->DataBuffer+sizeof(MODE_PARAMETER_HEADER),
  3190. (PUCHAR)srb->DataBuffer+sizeof(MODE_PARAMETER_HEADER_10),
  3191. transferLength - sizeof(MODE_PARAMETER_HEADER_10));
  3192. }
  3193. DebugPrint((1,
  3194. "Mode Sense completed - status 0x%x, length 0x%x\n",
  3195. srb->SrbStatus,
  3196. srb->DataTransferLength
  3197. ));
  3198. } else if (srb->Cdb[0] == ATAPI_MODE_SELECT) {
  3199. DebugPrint((1,
  3200. "Mode Select completed - status 0x%x, length 0x%x\n",
  3201. srb->SrbStatus,
  3202. srb->DataTransferLength
  3203. ));
  3204. } else {
  3205. ASSERT (FALSE);
  3206. }
  3207. //
  3208. // update the original srb
  3209. //
  3210. originalSrb->DataBuffer = context->OriginalDataBuffer;
  3211. originalSrb->SrbStatus = srb->SrbStatus;
  3212. originalSrb->ScsiStatus = srb->ScsiStatus;
  3213. if (transferLength > bytesAdjust) {
  3214. originalSrb->DataTransferLength = transferLength - bytesAdjust;
  3215. } else {
  3216. //
  3217. // error. transfer length should be zero.
  3218. // if it is less than the header, we will just pass it up.
  3219. //
  3220. originalSrb->DataTransferLength = transferLength;
  3221. }
  3222. //
  3223. // Decrement the logUnitExtension reference count
  3224. //
  3225. irpStack = IoGetCurrentIrpStackLocation(originalIrp);
  3226. UnrefLogicalUnitExtensionWithTag(
  3227. IDEPORT_GET_LUNEXT_IN_IRP(irpStack)->ParentDeviceExtension,
  3228. IDEPORT_GET_LUNEXT_IN_IRP(irpStack),
  3229. originalIrp
  3230. );
  3231. //
  3232. // we will follow the same logic as we did for srb data transfer length.
  3233. //
  3234. if (Irp->IoStatus.Information > bytesAdjust) {
  3235. originalIrp->IoStatus.Information = Irp->IoStatus.Information - bytesAdjust;
  3236. } else {
  3237. originalIrp->IoStatus.Information = Irp->IoStatus.Information;
  3238. }
  3239. originalIrp->IoStatus.Status = Irp->IoStatus.Status;
  3240. DebugPrint((1,
  3241. "Original Mode command completed - status 0x%x, length 0x%x, irpstatus 0x%x\n",
  3242. originalSrb->SrbStatus,
  3243. originalSrb->DataTransferLength,
  3244. originalIrp->IoStatus.Status
  3245. ));
  3246. IoCompleteRequest(originalIrp, IO_NO_INCREMENT);
  3247. //
  3248. // Free the srb, buffer and the irp
  3249. //
  3250. ASSERT(srb->DataBuffer);
  3251. ExFreePool(srb->DataBuffer);
  3252. ExFreePool(srb);
  3253. ExFreePool(context);
  3254. IdeFreeIrpAndMdl(Irp);
  3255. return STATUS_MORE_PROCESSING_REQUIRED;
  3256. }
  3257. NTSTATUS
  3258. DeviceAtapiModeSense (
  3259. IN PPDO_EXTENSION PdoExtension,
  3260. IN PIRP Irp
  3261. )
  3262. /*++
  3263. --*/
  3264. {
  3265. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  3266. PSCSI_REQUEST_BLOCK originalSrb = irpStack->Parameters.Scsi.Srb;
  3267. PSCSI_REQUEST_BLOCK srb = NULL;
  3268. NTSTATUS status;
  3269. PVOID *pointer;
  3270. PCDB cdb;
  3271. UCHAR length;
  3272. PVOID modeSenseBuffer;
  3273. PUCHAR dataOffset;
  3274. PIDE_MODE_COMMAND_CONTEXT context;
  3275. PMODE_PARAMETER_HEADER_10 header_10;
  3276. PMODE_PARAMETER_HEADER header;
  3277. UCHAR bytesAdjust = sizeof(MODE_PARAMETER_HEADER_10) -
  3278. sizeof(MODE_PARAMETER_HEADER);
  3279. IoMarkIrpPending(Irp);
  3280. //
  3281. // allocate the context
  3282. //
  3283. context = ExAllocatePool (
  3284. NonPagedPool,
  3285. sizeof(IDE_MODE_COMMAND_CONTEXT)
  3286. );
  3287. if (context == NULL) {
  3288. IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
  3289. PdoExtension->TargetId,
  3290. NonPagedPool,
  3291. sizeof(IDE_MODE_COMMAND_CONTEXT),
  3292. IDEPORT_TAG_ATAPI_MODE_SENSE
  3293. );
  3294. status = STATUS_INSUFFICIENT_RESOURCES;
  3295. goto GetOut;
  3296. }
  3297. ASSERT(context);
  3298. context->OriginalDataBuffer = originalSrb->DataBuffer;
  3299. if (Irp->MdlAddress == NULL) {
  3300. status = STATUS_INSUFFICIENT_RESOURCES;
  3301. goto GetOut;
  3302. }
  3303. //
  3304. // map the buffer in
  3305. //
  3306. dataOffset = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
  3307. originalSrb->DataBuffer = dataOffset +
  3308. (ULONG)((PUCHAR)originalSrb->DataBuffer -
  3309. (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
  3310. //
  3311. // allocate a new srb
  3312. //
  3313. srb = ExAllocatePool (NonPagedPool,
  3314. sizeof (SCSI_REQUEST_BLOCK)+ sizeof(PVOID));
  3315. if (srb == NULL) {
  3316. IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
  3317. PdoExtension->TargetId,
  3318. NonPagedPool,
  3319. sizeof(SCSI_REQUEST_BLOCK),
  3320. IDEPORT_TAG_ATAPI_MODE_SENSE
  3321. );
  3322. status = STATUS_INSUFFICIENT_RESOURCES;
  3323. goto GetOut;
  3324. }
  3325. //
  3326. // Save the original SRB after the Srb.
  3327. //
  3328. pointer = (PVOID *) (srb+1);
  3329. *pointer = originalSrb;
  3330. //
  3331. // Fill in SRB fields.
  3332. //
  3333. RtlCopyMemory(srb, originalSrb, sizeof(SCSI_REQUEST_BLOCK));
  3334. length = ((PCDB)originalSrb->Cdb)->MODE_SENSE.AllocationLength;
  3335. //
  3336. // Allocate a new buffer
  3337. //
  3338. modeSenseBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
  3339. originalSrb->DataTransferLength + bytesAdjust
  3340. );
  3341. RtlZeroMemory(modeSenseBuffer,originalSrb->DataTransferLength+bytesAdjust);
  3342. header_10 = (PMODE_PARAMETER_HEADER_10)modeSenseBuffer;
  3343. header = (PMODE_PARAMETER_HEADER)(originalSrb->DataBuffer);
  3344. header_10->ModeDataLengthLsb = header->ModeDataLength;
  3345. header_10->MediumType = header->MediumType;
  3346. header_10->Reserved[4] = header->BlockDescriptorLength;
  3347. srb->DataBuffer = modeSenseBuffer;
  3348. srb->DataTransferLength = originalSrb->DataTransferLength + bytesAdjust;
  3349. srb->CdbLength = 12;
  3350. cdb = (PCDB) srb->Cdb;
  3351. RtlZeroMemory(cdb, sizeof(CDB));
  3352. cdb->MODE_SENSE10.OperationCode = ATAPI_MODE_SENSE;
  3353. cdb->MODE_SENSE10.LogicalUnitNumber = ((PCDB)originalSrb->Cdb)->MODE_SENSE.LogicalUnitNumber;
  3354. cdb->MODE_SENSE10.PageCode = ((PCDB)originalSrb->Cdb)->MODE_SENSE.PageCode;
  3355. cdb->MODE_SENSE10.AllocationLength[0] = 0;
  3356. cdb->MODE_SENSE10.AllocationLength[1] = length+ bytesAdjust;
  3357. context->Srb = srb;
  3358. //
  3359. // send the srb
  3360. //
  3361. status = IdeBuildAndSendIrp (PdoExtension,
  3362. srb,
  3363. DeviceAtapiModeCommandCompletion,
  3364. context
  3365. );
  3366. if (NT_SUCCESS(status)) {
  3367. ASSERT(status == STATUS_PENDING);
  3368. return STATUS_PENDING;
  3369. }
  3370. GetOut:
  3371. ASSERT(status == STATUS_INSUFFICIENT_RESOURCES);
  3372. if (srb) {
  3373. ExFreePool(srb);
  3374. }
  3375. if (context) {
  3376. originalSrb->DataBuffer = context->OriginalDataBuffer;
  3377. ExFreePool(context);
  3378. }
  3379. UnrefLogicalUnitExtensionWithTag(
  3380. PdoExtension->ParentDeviceExtension,
  3381. PdoExtension,
  3382. Irp
  3383. );
  3384. originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  3385. originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
  3386. Irp->IoStatus.Status = status;
  3387. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3388. return STATUS_PENDING;
  3389. }
  3390. NTSTATUS
  3391. DeviceAtapiModeSelect (
  3392. IN PPDO_EXTENSION PdoExtension,
  3393. IN PIRP Irp
  3394. )
  3395. /*++
  3396. --*/
  3397. {
  3398. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  3399. PSCSI_REQUEST_BLOCK originalSrb = irpStack->Parameters.Scsi.Srb;
  3400. PSCSI_REQUEST_BLOCK srb = NULL;
  3401. NTSTATUS status;
  3402. PVOID *pointer;
  3403. PCDB cdb;
  3404. UCHAR length;
  3405. PVOID modeSelectBuffer;
  3406. PUCHAR dataOffset;
  3407. PIDE_MODE_COMMAND_CONTEXT context;
  3408. PMODE_PARAMETER_HEADER_10 header_10;
  3409. PMODE_PARAMETER_HEADER header;
  3410. UCHAR bytesAdjust = sizeof(MODE_PARAMETER_HEADER_10) -
  3411. sizeof(MODE_PARAMETER_HEADER);
  3412. IoMarkIrpPending(Irp);
  3413. //
  3414. // allocate the context
  3415. //
  3416. context = ExAllocatePool (
  3417. NonPagedPool,
  3418. sizeof(IDE_MODE_COMMAND_CONTEXT)
  3419. );
  3420. if (context == NULL) {
  3421. IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
  3422. PdoExtension->TargetId,
  3423. NonPagedPool,
  3424. sizeof(IDE_MODE_COMMAND_CONTEXT),
  3425. IDEPORT_TAG_ATAPI_MODE_SENSE
  3426. );
  3427. status = STATUS_INSUFFICIENT_RESOURCES;
  3428. goto GetOut;
  3429. }
  3430. ASSERT(context);
  3431. context->OriginalDataBuffer = originalSrb->DataBuffer;
  3432. if (Irp->MdlAddress == NULL) {
  3433. status = STATUS_INSUFFICIENT_RESOURCES;
  3434. goto GetOut;
  3435. }
  3436. //
  3437. // map the buffer in
  3438. //
  3439. dataOffset = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority);
  3440. originalSrb->DataBuffer = dataOffset +
  3441. (ULONG)((PUCHAR)originalSrb->DataBuffer -
  3442. (PCCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress));
  3443. //
  3444. // allocate a new srb
  3445. //
  3446. srb = ExAllocatePool (NonPagedPool,
  3447. sizeof (SCSI_REQUEST_BLOCK)+ sizeof(PVOID));
  3448. if (srb == NULL) {
  3449. IdeLogNoMemoryError(PdoExtension->ParentDeviceExtension,
  3450. PdoExtension->TargetId,
  3451. NonPagedPool,
  3452. sizeof(SCSI_REQUEST_BLOCK),
  3453. IDEPORT_TAG_ATAPI_MODE_SENSE
  3454. );
  3455. status = STATUS_INSUFFICIENT_RESOURCES;
  3456. goto GetOut;
  3457. }
  3458. //
  3459. // Save the original SRB after the Srb.
  3460. //
  3461. pointer = (PVOID *) (srb+1);
  3462. *pointer = originalSrb;
  3463. //
  3464. // Fill in SRB fields.
  3465. //
  3466. RtlCopyMemory(srb, originalSrb, sizeof(SCSI_REQUEST_BLOCK));
  3467. length = ((PCDB)originalSrb->Cdb)->MODE_SELECT.ParameterListLength;
  3468. //
  3469. // Allocate a new buffer
  3470. //
  3471. modeSelectBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
  3472. originalSrb->DataTransferLength + bytesAdjust
  3473. );
  3474. RtlZeroMemory(modeSelectBuffer, sizeof(MODE_PARAMETER_HEADER_10));
  3475. header_10 = (PMODE_PARAMETER_HEADER_10)modeSelectBuffer;
  3476. header = (PMODE_PARAMETER_HEADER)(originalSrb->DataBuffer);
  3477. header_10->ModeDataLengthLsb = header->ModeDataLength;
  3478. header_10->MediumType = header->MediumType;
  3479. header_10->Reserved[4] = header->BlockDescriptorLength;
  3480. RtlCopyMemory(((PUCHAR)modeSelectBuffer+sizeof(MODE_PARAMETER_HEADER_10)),
  3481. ((PUCHAR)originalSrb->DataBuffer + sizeof(MODE_PARAMETER_HEADER)),
  3482. (originalSrb->DataTransferLength - sizeof(MODE_PARAMETER_HEADER))
  3483. );
  3484. srb->DataBuffer = modeSelectBuffer;
  3485. srb->DataTransferLength = originalSrb->DataTransferLength + bytesAdjust;
  3486. srb->CdbLength = 12;
  3487. //
  3488. // fill in the cdb
  3489. //
  3490. cdb = (PCDB) srb->Cdb;
  3491. RtlZeroMemory(cdb, sizeof(CDB));
  3492. cdb->MODE_SELECT10.OperationCode = ATAPI_MODE_SELECT;
  3493. cdb->MODE_SELECT10.LogicalUnitNumber = ((PCDB)originalSrb->Cdb)->MODE_SELECT.LogicalUnitNumber;
  3494. cdb->MODE_SELECT10.SPBit = ((PCDB)originalSrb->Cdb)->MODE_SELECT.SPBit;
  3495. cdb->MODE_SELECT10.PFBit = 1;
  3496. cdb->MODE_SELECT10.ParameterListLength[0] = 0;
  3497. cdb->MODE_SELECT10.ParameterListLength[1] = length+ bytesAdjust;
  3498. context->Srb = srb;
  3499. //
  3500. // send the srb
  3501. //
  3502. status = IdeBuildAndSendIrp (PdoExtension,
  3503. srb,
  3504. DeviceAtapiModeCommandCompletion,
  3505. context
  3506. );
  3507. if (NT_SUCCESS(status)) {
  3508. ASSERT(status == STATUS_PENDING);
  3509. return STATUS_PENDING;
  3510. }
  3511. GetOut:
  3512. ASSERT(status == STATUS_INSUFFICIENT_RESOURCES);
  3513. if (srb) {
  3514. ExFreePool(srb);
  3515. }
  3516. if (context) {
  3517. originalSrb->DataBuffer = context->OriginalDataBuffer;
  3518. ExFreePool(context);
  3519. }
  3520. UnrefLogicalUnitExtensionWithTag(
  3521. PdoExtension->ParentDeviceExtension,
  3522. PdoExtension,
  3523. Irp
  3524. );
  3525. originalSrb->SrbStatus = SRB_STATUS_INTERNAL_ERROR;
  3526. originalSrb->InternalStatus = STATUS_INSUFFICIENT_RESOURCES;
  3527. Irp->IoStatus.Status = status;
  3528. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3529. return STATUS_PENDING;
  3530. }
  3531. #if 0
  3532. NTSTATUS
  3533. DeviceIdeTestUnitReady (
  3534. IN PPDO_EXTENSION PdoExtension,
  3535. IN OUT PIRP Irp
  3536. )
  3537. {
  3538. NTSTATUS status;
  3539. PIO_STACK_LOCATION irpStack;
  3540. PSCSI_REQUEST_BLOCK srb;
  3541. PHW_DEVICE_EXTENSION hwDeviceExtension;
  3542. PAGED_CODE();
  3543. hwDeviceExtension = PdoExtension->ParentDeviceExtension->HwDeviceExtension;
  3544. irpStack = IoGetCurrentIrpStackLocation(Irp);
  3545. srb = irpStack->Parameters.Scsi.Srb;
  3546. //
  3547. // get write protect bit from smart data
  3548. //
  3549. if (hwDeviceExtension->DeviceFlags[srb->TargetId] & DFLAGS_MEDIA_STATUS_ENABLED) {
  3550. ATA_PASS_THROUGH ataPassThroughData;
  3551. NTSTATUS localStatus;
  3552. RtlZeroMemory (
  3553. &ataPassThroughData,
  3554. sizeof (ataPassThroughData)
  3555. );
  3556. ataPassThroughData.IdeReg.bCommandReg = IDE_COMMAND_GET_MEDIA_STATUS;
  3557. ataPassThroughData.IdeReg.bReserved = ATA_PTFLAGS_STATUS_DRDY_REQUIRED;
  3558. localStatus = IssueSyncAtaPassThroughSafe (
  3559. PdoExtension->ParentDeviceExtension,
  3560. PdoExtension,
  3561. &ataPassThroughData,
  3562. FALSE,
  3563. FALSE,
  3564. DEFAULT_ATA_PASS_THROUGH_TIMEOUT,
  3565. FALSE);
  3566. if (NT_SUCCESS(localStatus)) {
  3567. if (ataPassThroughData.IdeReg.bCommandReg & IDE_STATUS_ERROR){
  3568. if (ataPassThroughData.IdeReg.bFeaturesReg & IDE_ERROR_DATA_ERROR){
  3569. //
  3570. // Special case: If current media is write-protected,
  3571. // the 0xDA command will always fail since the write-protect bit
  3572. // is sticky,so we can ignore this error
  3573. //
  3574. status = SRB_STATUS_SUCCESS;
  3575. }
  3576. }
  3577. }
  3578. }
  3579. dataBufferByteLeft = modeDataBufferSize - sizeof(MODE_PARAMETER_HEADER);
  3580. if (IsNEC_98) {
  3581. HANDLE pageHandle;
  3582. ULONG numberOfCylinders;
  3583. ULONG numberOfHeads;
  3584. ULONG sectorsPerTrack;
  3585. KIRQL currentIrql;
  3586. PKSPIN_LOCK spinLock;
  3587. //
  3588. // take a snap shot of the CHS values
  3589. //
  3590. spinLock = &PdoExtension->ParentDeviceExtension->SpinLock;
  3591. //
  3592. // lock the code before grabbing a lock
  3593. //
  3594. pageHandle = MmLockPagableCodeSection(DeviceIdeModeSense);
  3595. KeAcquireSpinLock(spinLock, &currentIrql);
  3596. numberOfCylinders = hwDeviceExtension->NumberOfCylinders[srb->TargetId];
  3597. numberOfHeads = hwDeviceExtension->NumberOfHeads[srb->TargetId];
  3598. sectorsPerTrack = hwDeviceExtension->SectorsPerTrack[srb->TargetId];
  3599. KeReleaseSpinLock(spinLock, currentIrql);
  3600. MmUnlockPagableImageSection(pageHandle);
  3601. //
  3602. // Set pages which are formated as nec-scsi.
  3603. //
  3604. if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) ||
  3605. (cdb->MODE_SENSE.PageCode == MODE_PAGE_ERROR_RECOVERY)) {
  3606. //
  3607. // error recovery page
  3608. //
  3609. if (dataBufferByteLeft >= 0x6 + 2) {
  3610. PMODE_DISCONNECT_PAGE recoveryPage;
  3611. recoveryPage = (PMODE_DISCONNECT_PAGE) pageData;
  3612. recoveryPage->PageCode = MODE_PAGE_ERROR_RECOVERY;
  3613. recoveryPage->PageLength = 0x6;
  3614. //
  3615. // update out data buffer pointer
  3616. //
  3617. pageData += recoveryPage->PageLength + 2;
  3618. dataBufferByteLeft -= (recoveryPage->PageLength + 2);
  3619. modePageHeader->ModeDataLength += recoveryPage->PageLength + 2;
  3620. } else {
  3621. status = STATUS_BUFFER_TOO_SMALL;
  3622. goto getout;
  3623. }
  3624. }
  3625. if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) ||
  3626. (cdb->MODE_SENSE.PageCode == MODE_PAGE_FORMAT_DEVICE)) {
  3627. //
  3628. // format device page
  3629. //
  3630. if (dataBufferByteLeft >= 0x16 + 2) {
  3631. PMODE_FORMAT_PAGE formatPage;
  3632. formatPage = (PMODE_FORMAT_PAGE) pageData;
  3633. formatPage->PageCode = MODE_PAGE_FORMAT_DEVICE;
  3634. formatPage->PageLength = 0x16;
  3635. //
  3636. // SectorsPerTrack
  3637. //
  3638. ((PFOUR_BYTE)&formatPage->SectorsPerTrack[0])->Byte1 =
  3639. ((PFOUR_BYTE)&sectorsPerTrack)->Byte0;
  3640. ((PFOUR_BYTE)&formatPage->SectorsPerTrack[0])->Byte0 =
  3641. ((PFOUR_BYTE)&sectorsPerTrack)->Byte1;
  3642. //
  3643. // update out data buffer pointer
  3644. //
  3645. pageData += formatPage->PageLength + 2;
  3646. dataBufferByteLeft -= (formatPage->PageLength + 2);
  3647. modePageHeader->ModeDataLength += formatPage->PageLength + 2;
  3648. } else {
  3649. status = STATUS_BUFFER_TOO_SMALL;
  3650. goto getout;
  3651. }
  3652. }
  3653. if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) ||
  3654. (cdb->MODE_SENSE.PageCode == MODE_PAGE_RIGID_GEOMETRY)) {
  3655. //
  3656. // rigid geometry page
  3657. //
  3658. if (dataBufferByteLeft >= 0x12 + 2) {
  3659. PMODE_RIGID_GEOMETRY_PAGE geometryPage;
  3660. geometryPage = (PMODE_RIGID_GEOMETRY_PAGE) pageData;
  3661. geometryPage->PageCode = MODE_PAGE_RIGID_GEOMETRY;
  3662. geometryPage->PageLength = 0x12;
  3663. //
  3664. // NumberOfHeads
  3665. //
  3666. geometryPage->NumberOfHeads = (UCHAR) numberOfHeads;
  3667. //
  3668. // NumberOfCylinders
  3669. //
  3670. ((PFOUR_BYTE)&geometryPage->NumberOfCylinders)->Byte2
  3671. = ((PFOUR_BYTE)&numberOfCylinders)->Byte0;
  3672. ((PFOUR_BYTE)&geometryPage->NumberOfCylinders)->Byte1
  3673. = ((PFOUR_BYTE)&numberOfCylinders)->Byte1;
  3674. ((PFOUR_BYTE)&geometryPage->NumberOfCylinders)->Byte0
  3675. = 0;
  3676. //
  3677. // update out data buffer pointer
  3678. //
  3679. pageData += geometryPage->PageLength + 2;
  3680. dataBufferByteLeft -= (geometryPage->PageLength + 2);
  3681. modePageHeader->ModeDataLength += geometryPage->PageLength + 2;
  3682. } else {
  3683. status = STATUS_BUFFER_TOO_SMALL;
  3684. goto getout;
  3685. }
  3686. }
  3687. }
  3688. if ((cdb->MODE_SENSE.PageCode == MODE_SENSE_RETURN_ALL) ||
  3689. (cdb->MODE_SENSE.PageCode == MODE_PAGE_CACHING)) {
  3690. if (dataBufferByteLeft >= sizeof(MODE_CACHING_PAGE)) {
  3691. //
  3692. // cache settings page
  3693. //
  3694. PMODE_CACHING_PAGE cachePage;
  3695. cachePage = (PMODE_CACHING_PAGE) pageData;
  3696. cachePage->PageCode = MODE_PAGE_CACHING;
  3697. cachePage->PageSavable = 0;
  3698. cachePage->PageLength = 0xa;
  3699. cachePage->ReadDisableCache = 0;
  3700. cachePage->WriteCacheEnable = PdoExtension->WriteCacheEnable;
  3701. //
  3702. // update out data buffer pointer
  3703. //
  3704. pageData += sizeof (MODE_CACHING_PAGE);
  3705. dataBufferByteLeft -= sizeof (MODE_CACHING_PAGE);
  3706. modePageHeader->ModeDataLength += sizeof (MODE_CACHING_PAGE);
  3707. } else {
  3708. status = STATUS_BUFFER_TOO_SMALL;
  3709. goto getout;
  3710. }
  3711. }
  3712. //
  3713. // update the number of bytes we are returning
  3714. //
  3715. srb->DataTransferLength -= dataBufferByteLeft;
  3716. Irp->IoStatus.Information = srb->DataTransferLength;
  3717. status = STATUS_SUCCESS;
  3718. srb->SrbStatus = SRB_STATUS_SUCCESS;
  3719. getout:
  3720. UnrefPdoWithTag(
  3721. PdoExtension,
  3722. Irp
  3723. );
  3724. Irp->IoStatus.Status = status;
  3725. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3726. return status;
  3727. }
  3728. #endif