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

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