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.

1540 lines
49 KiB

  1. /*--
  2. Copyright (C) Microsoft Corporation, 2000
  3. Module Name:
  4. mmc.c
  5. Abstract:
  6. This file is used to extend cdrom.sys to detect and use mmc-compatible
  7. drives' capabilities more wisely.
  8. Environment:
  9. kernel mode only
  10. Notes:
  11. SCSI Tape, CDRom and Disk class drivers share common routines
  12. that can be found in the CLASS directory (..\ntos\dd\class).
  13. Revision History:
  14. --*/
  15. #include "ntddk.h"
  16. #include "classpnp.h"
  17. #include "cdrom.h"
  18. #include "mmc.tmh"
  19. NTSTATUS
  20. CdRomGetConfiguration(
  21. IN PDEVICE_OBJECT Fdo,
  22. OUT PGET_CONFIGURATION_HEADER *Buffer,
  23. OUT PULONG BytesReturned,
  24. IN FEATURE_NUMBER StartingFeature,
  25. IN ULONG RequestedType
  26. );
  27. VOID
  28. CdRompPrintAllFeaturePages(
  29. IN PGET_CONFIGURATION_HEADER Buffer,
  30. IN ULONG Usable
  31. );
  32. NTSTATUS
  33. CdRomUpdateMmcDriveCapabilitiesCompletion(
  34. IN PDEVICE_OBJECT Unused,
  35. IN PIRP Irp,
  36. IN PDEVICE_OBJECT Fdo
  37. );
  38. VOID
  39. CdRomPrepareUpdateCapabilitiesIrp(
  40. PDEVICE_OBJECT Fdo
  41. );
  42. /*++
  43. NOT DOCUMENTED YET - may be called at up to DISPATCH_LEVEL
  44. if memory is non-paged
  45. PRESUMES ALL DATA IS ACCESSIBLE based on FeatureBuffer
  46. --*/
  47. VOID
  48. CdRomFindProfileInProfiles(
  49. IN PFEATURE_DATA_PROFILE_LIST ProfileHeader,
  50. IN FEATURE_PROFILE_TYPE ProfileToFind,
  51. OUT PBOOLEAN Found
  52. )
  53. {
  54. PFEATURE_DATA_PROFILE_LIST_EX profile;
  55. ULONG numberOfProfiles;
  56. ULONG i;
  57. *Found = FALSE;
  58. if (ProfileHeader->Header.AdditionalLength % 4 != 0) {
  59. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  60. "Profile total length %x is not integral multiple of 4\n",
  61. ProfileHeader->Header.AdditionalLength));
  62. ASSERT(FALSE);
  63. return;
  64. }
  65. numberOfProfiles = ProfileHeader->Header.AdditionalLength / 4;
  66. profile = ProfileHeader->Profiles; // zero-sized array
  67. for (i = 0; i < numberOfProfiles; i++) {
  68. FEATURE_PROFILE_TYPE currentProfile;
  69. currentProfile =
  70. (profile->ProfileNumber[0] << 8) |
  71. (profile->ProfileNumber[1] & 0xff);
  72. if (currentProfile == ProfileToFind) {
  73. *Found = TRUE;
  74. }
  75. profile++;
  76. }
  77. return;
  78. }
  79. /*++
  80. NOT DOCUMENTED YET - may be called at up to DISPATCH_LEVEL
  81. if memory is non-paged
  82. --*/
  83. PVOID
  84. CdRomFindFeaturePage(
  85. IN PGET_CONFIGURATION_HEADER FeatureBuffer,
  86. IN ULONG Length,
  87. IN FEATURE_NUMBER Feature
  88. )
  89. {
  90. PUCHAR buffer;
  91. PUCHAR limit;
  92. if (Length < sizeof(GET_CONFIGURATION_HEADER) + sizeof(FEATURE_HEADER)) {
  93. return NULL;
  94. }
  95. //
  96. // set limit to point to first illegal address
  97. //
  98. limit = (PUCHAR)FeatureBuffer;
  99. limit += Length;
  100. //
  101. // set buffer to point to first page
  102. //
  103. buffer = FeatureBuffer->Data;
  104. //
  105. // loop through each page until we find the requested one, or
  106. // until it's not safe to access the entire feature header
  107. // (if equal, have exactly enough for the feature header)
  108. //
  109. while (buffer + sizeof(FEATURE_HEADER) <= limit) {
  110. PFEATURE_HEADER header = (PFEATURE_HEADER)buffer;
  111. FEATURE_NUMBER thisFeature;
  112. thisFeature =
  113. (header->FeatureCode[0] << 8) |
  114. (header->FeatureCode[1]);
  115. if (thisFeature == Feature) {
  116. PUCHAR temp;
  117. //
  118. // if don't have enough memory to safely access all the feature
  119. // information, return NULL
  120. //
  121. temp = buffer;
  122. temp += sizeof(FEATURE_HEADER);
  123. temp += header->AdditionalLength;
  124. if (temp > limit) {
  125. //
  126. // this means the transfer was cut-off, an insufficiently
  127. // small buffer was given, or other arbitrary error. since
  128. // it's not safe to view the amount of data (even though
  129. // the header is safe) in this feature, pretend it wasn't
  130. // transferred at all...
  131. //
  132. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  133. "Feature %x exists, but not safe to access all its "
  134. "data. returning NULL\n", Feature));
  135. return NULL;
  136. } else {
  137. return buffer;
  138. }
  139. }
  140. if (header->AdditionalLength % 4) {
  141. ASSERT(!"Feature page AdditionalLength field must be integral multiple of 4!\n");
  142. return NULL;
  143. }
  144. buffer += sizeof(FEATURE_HEADER);
  145. buffer += header->AdditionalLength;
  146. }
  147. return NULL;
  148. }
  149. /*++
  150. Private so we can later expose to someone wanting to use a preallocated buffer
  151. --*/
  152. NTSTATUS
  153. CdRompGetConfiguration(
  154. IN PDEVICE_OBJECT Fdo,
  155. IN PGET_CONFIGURATION_HEADER Buffer,
  156. IN ULONG BufferSize,
  157. OUT PULONG ValidBytes,
  158. IN FEATURE_NUMBER StartingFeature,
  159. IN ULONG RequestedType
  160. )
  161. {
  162. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  163. PCDROM_DATA cdData;
  164. SCSI_REQUEST_BLOCK srb = {0};
  165. PCDB cdb;
  166. ULONG_PTR returned;
  167. NTSTATUS status;
  168. PAGED_CODE();
  169. ASSERT(Buffer);
  170. ASSERT(ValidBytes);
  171. *ValidBytes = 0;
  172. returned = 0;
  173. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  174. RtlZeroMemory(Buffer, BufferSize);
  175. fdoExtension = Fdo->DeviceExtension;
  176. cdData = (PCDROM_DATA)(fdoExtension->CommonExtension.DriverData);
  177. if (TEST_FLAG(cdData->HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT)) {
  178. return STATUS_INVALID_DEVICE_REQUEST;
  179. }
  180. srb.TimeOutValue = CDROM_GET_CONFIGURATION_TIMEOUT;
  181. srb.CdbLength = 10;
  182. cdb = (PCDB)srb.Cdb;
  183. cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION;
  184. cdb->GET_CONFIGURATION.RequestType = (UCHAR)RequestedType;
  185. cdb->GET_CONFIGURATION.StartingFeature[0] = (UCHAR)(StartingFeature >> 8);
  186. cdb->GET_CONFIGURATION.StartingFeature[1] = (UCHAR)(StartingFeature & 0xff);
  187. cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(BufferSize >> 8);
  188. cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(BufferSize & 0xff);
  189. status = ClassSendSrbSynchronous(Fdo, &srb, Buffer,
  190. BufferSize, FALSE);
  191. returned = srb.DataTransferLength;
  192. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  193. "CdromGetConfiguration: Status was %x\n", status));
  194. if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {
  195. //
  196. // if returned more than can be stored in a ULONG, return false
  197. //
  198. if (returned > (ULONG)(-1)) {
  199. return STATUS_UNSUCCESSFUL;
  200. }
  201. ASSERT(returned <= BufferSize);
  202. *ValidBytes = (ULONG)returned;
  203. return STATUS_SUCCESS;
  204. } else {
  205. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  206. "CdromGetConfiguration: failed %x\n", status));
  207. return status;
  208. }
  209. ASSERT(FALSE);
  210. return STATUS_UNSUCCESSFUL;
  211. }
  212. /*++
  213. Allocates buffer with configuration info, returns STATUS_SUCCESS
  214. or an error if one occurred
  215. NOTE: does not handle case where more than 65000 bytes are returned,
  216. which requires multiple calls with different starting feature
  217. numbers.
  218. --*/
  219. NTSTATUS
  220. CdRomGetConfiguration(
  221. IN PDEVICE_OBJECT Fdo,
  222. OUT PGET_CONFIGURATION_HEADER *Buffer,
  223. OUT PULONG BytesReturned,
  224. IN FEATURE_NUMBER StartingFeature,
  225. IN ULONG RequestedType
  226. )
  227. {
  228. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension;
  229. GET_CONFIGURATION_HEADER header = {0}; // eight bytes, not a lot
  230. PGET_CONFIGURATION_HEADER buffer;
  231. ULONG returned;
  232. ULONG size;
  233. ULONG i;
  234. NTSTATUS status;
  235. PAGED_CODE();
  236. fdoExtension = Fdo->DeviceExtension;
  237. *Buffer = NULL;
  238. *BytesReturned = 0;
  239. buffer = NULL;
  240. returned = 0;
  241. //
  242. // send the first request down to just get the header
  243. //
  244. status = CdRompGetConfiguration(Fdo, &header, sizeof(header),
  245. &returned, StartingFeature, RequestedType);
  246. if (!NT_SUCCESS(status)) {
  247. return status;
  248. }
  249. //
  250. // now try again, using information returned to allocate
  251. // just enough memory
  252. //
  253. size = header.DataLength[0] << 24 |
  254. header.DataLength[1] << 16 |
  255. header.DataLength[2] << 8 |
  256. header.DataLength[3] << 0 ;
  257. for (i = 0; i < 4; i++) {
  258. //
  259. // the datalength field is the size *following*
  260. // itself, so adjust accordingly
  261. //
  262. size += 4*sizeof(UCHAR);
  263. //
  264. // make sure the size is reasonable
  265. //
  266. if (size <= sizeof(FEATURE_HEADER)) {
  267. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  268. "CdromGetConfiguration: drive reports only %x bytes?\n",
  269. size));
  270. return STATUS_UNSUCCESSFUL;
  271. }
  272. //
  273. // allocate the memory
  274. //
  275. buffer = (PGET_CONFIGURATION_HEADER)
  276. ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  277. size,
  278. CDROM_TAG_FEATURE);
  279. if (buffer == NULL) {
  280. return STATUS_INSUFFICIENT_RESOURCES;
  281. }
  282. //
  283. // send the first request down to just get the header
  284. //
  285. status = CdRompGetConfiguration(Fdo, buffer, size, &returned,
  286. StartingFeature, RequestedType);
  287. if (!NT_SUCCESS(status)) {
  288. ExFreePool(buffer);
  289. return status;
  290. }
  291. if (returned > size) {
  292. ExFreePool(buffer);
  293. return STATUS_INTERNAL_ERROR;
  294. }
  295. returned = buffer->DataLength[0] << 24 |
  296. buffer->DataLength[1] << 16 |
  297. buffer->DataLength[2] << 8 |
  298. buffer->DataLength[3] << 0 ;
  299. returned += 4*sizeof(UCHAR);
  300. if (returned <= size) {
  301. *Buffer = buffer;
  302. *BytesReturned = size; // amount of 'safe' memory
  303. return STATUS_SUCCESS;
  304. }
  305. //
  306. // else retry using the new size....
  307. //
  308. size = returned;
  309. ExFreePool(buffer);
  310. buffer = NULL;
  311. }
  312. //
  313. // it failed after a number of attempts, so just fail.
  314. //
  315. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  316. "CdRomGetConfiguration: Failed %d attempts to get all feature "
  317. "information\n", i));
  318. return STATUS_IO_DEVICE_ERROR;
  319. }
  320. VOID
  321. CdRomIsDeviceMmcDevice(
  322. IN PDEVICE_OBJECT Fdo,
  323. OUT PBOOLEAN IsMmc
  324. )
  325. {
  326. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  327. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  328. PCDROM_DATA cdData = commonExtension->DriverData;
  329. GET_CONFIGURATION_HEADER localHeader = {0};
  330. NTSTATUS status;
  331. ULONG usable;
  332. ULONG size;
  333. ULONG previouslyFailed;
  334. PAGED_CODE();
  335. ASSERT( commonExtension->IsFdo );
  336. *IsMmc = FALSE;
  337. //
  338. // read the registry in case the drive failed previously,
  339. // and a timeout is occurring.
  340. //
  341. previouslyFailed = FALSE;
  342. ClassGetDeviceParameter(fdoExtension,
  343. CDROM_SUBKEY_NAME,
  344. CDROM_NON_MMC_DRIVE_NAME,
  345. &previouslyFailed
  346. );
  347. if (previouslyFailed) {
  348. SET_FLAG(cdData->HackFlags, CDROM_HACK_BAD_GET_CONFIG_SUPPORT);
  349. }
  350. //
  351. // check for the following profiles:
  352. //
  353. // ProfileList
  354. //
  355. status = CdRompGetConfiguration(Fdo,
  356. &localHeader,
  357. sizeof(localHeader),
  358. &usable,
  359. FeatureProfileList,
  360. SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
  361. if (status == STATUS_INVALID_DEVICE_REQUEST ||
  362. status == STATUS_NO_MEDIA_IN_DEVICE ||
  363. status == STATUS_IO_DEVICE_ERROR ||
  364. status == STATUS_IO_TIMEOUT) {
  365. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  366. "GetConfiguration Failed (%x), device %p not mmc-compliant\n",
  367. status, Fdo
  368. ));
  369. previouslyFailed = TRUE;
  370. ClassSetDeviceParameter(fdoExtension,
  371. CDROM_SUBKEY_NAME,
  372. CDROM_NON_MMC_DRIVE_NAME,
  373. previouslyFailed
  374. );
  375. return;
  376. } else if (!NT_SUCCESS(status)) {
  377. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
  378. "GetConfiguration Failed, status %x -- defaulting to -ROM\n",
  379. status));
  380. return;
  381. } else if (usable < sizeof(GET_CONFIGURATION_HEADER)) {
  382. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  383. "GetConfiguration Failed, returned only %x bytes!\n", usable));
  384. previouslyFailed = TRUE;
  385. ClassSetDeviceParameter(fdoExtension,
  386. CDROM_SUBKEY_NAME,
  387. CDROM_NON_MMC_DRIVE_NAME,
  388. previouslyFailed
  389. );
  390. return;
  391. }
  392. size = (localHeader.DataLength[0] << 24) |
  393. (localHeader.DataLength[1] << 16) |
  394. (localHeader.DataLength[2] << 8) |
  395. (localHeader.DataLength[3] << 0);
  396. if (size <= 4) {
  397. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  398. "GetConfiguration Failed, claims MMC support but doesn't "
  399. "correctly return config length! (%x)\n",
  400. size
  401. ));
  402. previouslyFailed = TRUE;
  403. ClassSetDeviceParameter(fdoExtension,
  404. CDROM_SUBKEY_NAME,
  405. CDROM_NON_MMC_DRIVE_NAME,
  406. previouslyFailed
  407. );
  408. return;
  409. } else if ((size % 4) != 0) {
  410. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  411. "GetConfiguration Failed, returned odd number of bytes %x!\n",
  412. size
  413. ));
  414. previouslyFailed = TRUE;
  415. ClassSetDeviceParameter(fdoExtension,
  416. CDROM_SUBKEY_NAME,
  417. CDROM_NON_MMC_DRIVE_NAME,
  418. previouslyFailed
  419. );
  420. return;
  421. }
  422. size += 4; // sizeof the datalength fields
  423. #if DBG
  424. {
  425. PGET_CONFIGURATION_HEADER dbgBuffer;
  426. NTSTATUS dbgStatus;
  427. dbgBuffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
  428. (SIZE_T)size,
  429. CDROM_TAG_FEATURE);
  430. if (dbgBuffer != NULL) {
  431. RtlZeroMemory(dbgBuffer, size);
  432. dbgStatus = CdRompGetConfiguration(Fdo, dbgBuffer, size,
  433. &size, FeatureProfileList,
  434. SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
  435. if (NT_SUCCESS(dbgStatus)) {
  436. CdRompPrintAllFeaturePages(dbgBuffer, usable);
  437. }
  438. ExFreePool(dbgBuffer);
  439. }
  440. }
  441. #endif // DBG
  442. *IsMmc = TRUE;
  443. return;
  444. }
  445. VOID
  446. CdRompPrintAllFeaturePages(
  447. IN PGET_CONFIGURATION_HEADER Buffer,
  448. IN ULONG Usable
  449. )
  450. {
  451. PFEATURE_HEADER header;
  452. ////////////////////////////////////////////////////////////////////////////////
  453. // items expected to ALWAYS be current if they exist
  454. ////////////////////////////////////////////////////////////////////////////////
  455. header = CdRomFindFeaturePage(Buffer, Usable, FeatureProfileList);
  456. if (header != NULL) {
  457. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  458. "CdromGetConfiguration: CurrentProfile %x "
  459. "with %x bytes of data at %p\n",
  460. Buffer->CurrentProfile[0] << 8 |
  461. Buffer->CurrentProfile[1],
  462. Usable, Buffer));
  463. }
  464. header = CdRomFindFeaturePage(Buffer, Usable, FeatureCore);
  465. if (header) {
  466. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  467. "CdromGetConfiguration: %s %s\n",
  468. (header->Current ?
  469. "Currently supports" : "Is able to support"),
  470. "CORE Features"
  471. ));
  472. }
  473. header = CdRomFindFeaturePage(Buffer, Usable, FeatureMorphing);
  474. if (header) {
  475. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  476. "CdromGetConfiguration: %s %s\n",
  477. (header->Current ?
  478. "Currently supports" : "Is able to support"),
  479. "Morphing"
  480. ));
  481. }
  482. header = CdRomFindFeaturePage(Buffer, Usable, FeatureRemovableMedium);
  483. if (header) {
  484. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  485. "CdromGetConfiguration: %s %s\n",
  486. (header->Current ?
  487. "Currently supports" : "Is able to support"),
  488. "Removable Medium"
  489. ));
  490. }
  491. header = CdRomFindFeaturePage(Buffer, Usable, FeaturePowerManagement);
  492. if (header) {
  493. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  494. "CdromGetConfiguration: %s %s\n",
  495. (header->Current ?
  496. "Currently supports" : "Is able to support"),
  497. "Power Management"
  498. ));
  499. }
  500. header = CdRomFindFeaturePage(Buffer, Usable, FeatureEmbeddedChanger);
  501. if (header) {
  502. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  503. "CdromGetConfiguration: %s %s\n",
  504. (header->Current ?
  505. "Currently supports" : "Is able to support"),
  506. "Embedded Changer"
  507. ));
  508. }
  509. header = CdRomFindFeaturePage(Buffer, Usable, FeatureMicrocodeUpgrade);
  510. if (header) {
  511. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  512. "CdromGetConfiguration: %s %s\n",
  513. (header->Current ?
  514. "Currently supports" : "Is able to support"),
  515. "Microcode Update"
  516. ));
  517. }
  518. header = CdRomFindFeaturePage(Buffer, Usable, FeatureTimeout);
  519. if (header) {
  520. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  521. "CdromGetConfiguration: %s %s\n",
  522. (header->Current ?
  523. "Currently supports" : "Is able to support"),
  524. "Timeouts"
  525. ));
  526. }
  527. header = CdRomFindFeaturePage(Buffer, Usable, FeatureLogicalUnitSerialNumber);
  528. if (header) {
  529. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  530. "CdromGetConfiguration: %s %s\n",
  531. (header->Current ?
  532. "Currently supports" : "Is able to support"),
  533. "LUN Serial Number"
  534. ));
  535. }
  536. ////////////////////////////////////////////////////////////////////////////////
  537. // items expected not to always be current
  538. ////////////////////////////////////////////////////////////////////////////////
  539. header = CdRomFindFeaturePage(Buffer, Usable, FeatureWriteProtect);
  540. if (header) {
  541. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  542. "CdromGetConfiguration: %s %s\n",
  543. (header->Current ?
  544. "Currently supports" : "Is able to support"),
  545. "Software Write Protect"
  546. ));
  547. }
  548. header = CdRomFindFeaturePage(Buffer, Usable, FeatureRandomReadable);
  549. if (header) {
  550. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  551. "CdromGetConfiguration: %s %s\n",
  552. (header->Current ?
  553. "Currently supports" : "Is able to support"),
  554. "Random Reads"
  555. ));
  556. }
  557. header = CdRomFindFeaturePage(Buffer, Usable, FeatureMultiRead);
  558. if (header) {
  559. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  560. "CdromGetConfiguration: %s %s\n",
  561. (header->Current ?
  562. "Currently supports" : "Is able to support"),
  563. "Multi-Read"
  564. ));
  565. }
  566. header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdRead);
  567. if (header) {
  568. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  569. "CdromGetConfiguration: %s %s\n",
  570. (header->Current ?
  571. "Currently supports" : "Is able to support"),
  572. "reading from CD-ROM/R/RW"
  573. ));
  574. }
  575. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdRead);
  576. if (header) {
  577. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  578. "CdromGetConfiguration: %s %s\n",
  579. (header->Current ?
  580. "Currently supports" : "Is able to support"),
  581. "DVD Structure Reads"
  582. ));
  583. }
  584. header = CdRomFindFeaturePage(Buffer, Usable, FeatureRandomWritable);
  585. if (header) {
  586. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  587. "CdromGetConfiguration: %s %s\n",
  588. (header->Current ?
  589. "Currently supports" : "Is able to support"),
  590. "Random Writes"
  591. ));
  592. }
  593. header = CdRomFindFeaturePage(Buffer, Usable, FeatureIncrementalStreamingWritable);
  594. if (header) {
  595. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  596. "CdromGetConfiguration: %s %s\n",
  597. (header->Current ?
  598. "Currently supports" : "Is able to support"),
  599. "Incremental Streaming Writing"
  600. ));
  601. }
  602. header = CdRomFindFeaturePage(Buffer, Usable, FeatureSectorErasable);
  603. if (header) {
  604. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  605. "CdromGetConfiguration: %s %s\n",
  606. (header->Current ?
  607. "Currently supports" : "Is able to support"),
  608. "Sector Erasable Media"
  609. ));
  610. }
  611. header = CdRomFindFeaturePage(Buffer, Usable, FeatureFormattable);
  612. if (header) {
  613. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  614. "CdromGetConfiguration: %s %s\n",
  615. (header->Current ?
  616. "Currently supports" : "Is able to support"),
  617. "Formatting"
  618. ));
  619. }
  620. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDefectManagement);
  621. if (header) {
  622. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  623. "CdromGetConfiguration: %s %s\n",
  624. (header->Current ?
  625. "Currently supports" : "Is able to support"),
  626. "defect management"
  627. ));
  628. }
  629. header = CdRomFindFeaturePage(Buffer, Usable, FeatureWriteOnce);
  630. if (header) {
  631. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  632. "CdromGetConfiguration: %s %s\n",
  633. (header->Current ?
  634. "Currently supports" : "Is able to support"),
  635. "Write Once Media"
  636. ));
  637. }
  638. header = CdRomFindFeaturePage(Buffer, Usable, FeatureRestrictedOverwrite);
  639. if (header) {
  640. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  641. "CdromGetConfiguration: %s %s\n",
  642. (header->Current ?
  643. "Currently supports" : "Is able to support"),
  644. "Restricted Overwrites"
  645. ));
  646. }
  647. header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdrwCAVWrite);
  648. if (header) {
  649. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  650. "CdromGetConfiguration: %s %s\n",
  651. (header->Current ?
  652. "Currently supports" : "Is able to support"),
  653. "CD-RW CAV recording"
  654. ));
  655. }
  656. header = CdRomFindFeaturePage(Buffer, Usable, FeatureMrw);
  657. if (header) {
  658. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  659. "CdromGetConfiguration: %s %s\n",
  660. (header->Current ?
  661. "Currently supports" : "Is able to support"),
  662. "Mount Rainier media"
  663. ));
  664. }
  665. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdPlusRW);
  666. if (header) {
  667. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  668. "CdromGetConfiguration: %s %s\n",
  669. (header->Current ?
  670. "Currently supports" : "Is able to support"),
  671. "DVD+RW media"
  672. ));
  673. }
  674. header = CdRomFindFeaturePage(Buffer, Usable, FeatureRigidRestrictedOverwrite);
  675. if (header) {
  676. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  677. "CdromGetConfiguration: %s %s\n",
  678. (header->Current ?
  679. "Currently supports" : "Is able to support"),
  680. "Rigid Restricted Overwrite"
  681. ));
  682. }
  683. header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdTrackAtOnce);
  684. if (header) {
  685. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  686. "CdromGetConfiguration: %s %s\n",
  687. (header->Current ?
  688. "Currently supports" : "Is able to support"),
  689. "CD Recording (Track At Once)"
  690. ));
  691. }
  692. header = CdRomFindFeaturePage(Buffer, Usable, FeatureCdMastering);
  693. if (header) {
  694. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  695. "CdromGetConfiguration: %s %s\n",
  696. (header->Current ?
  697. "Currently supports" : "Is able to support"),
  698. "CD Recording (Mastering)"
  699. ));
  700. }
  701. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdRecordableWrite);
  702. if (header) {
  703. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  704. "CdromGetConfiguration: %s %s\n",
  705. (header->Current ?
  706. "Currently supports" : "Is able to support"),
  707. "DVD Recording (Mastering)"
  708. ));
  709. }
  710. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDDCDRead);
  711. if (header) {
  712. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  713. "CdromGetConfiguration: %s %s\n",
  714. (header->Current ?
  715. "Currently supports" : "Is able to support"),
  716. "DD CD Reading"
  717. ));
  718. }
  719. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDDCDRWrite);
  720. if (header) {
  721. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  722. "CdromGetConfiguration: %s %s\n",
  723. (header->Current ?
  724. "Currently supports" : "Is able to support"),
  725. "DD CD-R Writing"
  726. ));
  727. }
  728. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDDCDRWWrite);
  729. if (header) {
  730. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  731. "CdromGetConfiguration: %s %s\n",
  732. (header->Current ?
  733. "Currently supports" : "Is able to support"),
  734. "DD CD-RW Writing"
  735. ));
  736. }
  737. header = CdRomFindFeaturePage(Buffer, Usable, FeatureSMART);
  738. if (header) {
  739. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  740. "CdromGetConfiguration: %s %s\n",
  741. (header->Current ?
  742. "Currently supports" : "Is able to support"),
  743. "S.M.A.R.T."
  744. ));
  745. }
  746. header = CdRomFindFeaturePage(Buffer, Usable, FeatureCDAudioAnalogPlay);
  747. if (header) {
  748. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  749. "CdromGetConfiguration: %s %s\n",
  750. (header->Current ?
  751. "Currently supports" : "Is able to support"),
  752. "Analogue CD Audio Operations"
  753. ));
  754. }
  755. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdCSS);
  756. if (header) {
  757. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  758. "CdromGetConfiguration: %s %s\n",
  759. (header->Current ?
  760. "Currently supports" : "Is able to support"),
  761. "DVD CSS"
  762. ));
  763. }
  764. header = CdRomFindFeaturePage(Buffer, Usable, FeatureRealTimeStreaming);
  765. if (header) {
  766. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  767. "CdromGetConfiguration: %s %s\n",
  768. (header->Current ?
  769. "Currently supports" : "Is able to support"),
  770. "Real-time Streaming Reads"
  771. ));
  772. }
  773. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDiscControlBlocks);
  774. if (header) {
  775. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  776. "CdromGetConfiguration: %s %s\n",
  777. (header->Current ?
  778. "Currently supports" : "Is able to support"),
  779. "DVD Disc Control Blocks"
  780. ));
  781. }
  782. header = CdRomFindFeaturePage(Buffer, Usable, FeatureDvdCPRM);
  783. if (header) {
  784. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  785. "CdromGetConfiguration: %s %s\n",
  786. (header->Current ?
  787. "Currently supports" : "Is able to support"),
  788. "DVD CPRM"
  789. ));
  790. }
  791. return;
  792. }
  793. NTSTATUS
  794. CdRomUpdateMmcDriveCapabilitiesCompletion(
  795. IN PDEVICE_OBJECT Unused,
  796. IN PIRP Irp,
  797. IN PDEVICE_OBJECT Fdo
  798. )
  799. {
  800. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  801. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  802. PCDROM_DATA cdData = fdoExtension->CommonExtension.DriverData;
  803. PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc);
  804. PSCSI_REQUEST_BLOCK srb = &(mmcData->CapabilitiesSrb);
  805. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  806. NTSTATUS status = STATUS_UNSUCCESSFUL;
  807. PIRP delayedIrp;
  808. // completion routine should retry as neccessary.
  809. // when success, clear the flag to allow startio to proceed.
  810. // else fail original request when retries are exhausted.
  811. ASSERT(mmcData->CapabilitiesIrp == Irp);
  812. // for now, if succeeded, just print the new pages.
  813. if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  814. //
  815. // ISSUE-2000/4/20-henrygab - should we try to reallocate if size
  816. // available became larger than what we
  817. // originally allocated? otherwise, it
  818. // is possible (not probable) that we
  819. // would miss the feature. can check
  820. // that by looking at the header size
  821. // and comparing it to requested data
  822. // size.
  823. //
  824. BOOLEAN retry;
  825. ULONG retryInterval;
  826. //
  827. // Release the queue if it is frozen.
  828. //
  829. if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  830. ClassReleaseQueue(Fdo);
  831. }
  832. retry = ClassInterpretSenseInfo(
  833. Fdo,
  834. srb,
  835. irpStack->MajorFunction,
  836. 0,
  837. MAXIMUM_RETRIES - ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4),
  838. &status,
  839. &retryInterval);
  840. //
  841. // DATA_OVERRUN is not an error in this case....
  842. //
  843. if (status == STATUS_DATA_OVERRUN) {
  844. status = STATUS_SUCCESS;
  845. }
  846. //
  847. // override verify_volume based on original irp's settings
  848. //
  849. if (TEST_FLAG(irpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
  850. status == STATUS_VERIFY_REQUIRED) {
  851. status = STATUS_IO_DEVICE_ERROR;
  852. retry = TRUE;
  853. }
  854. if (retry && ((ULONG)(ULONG_PTR)irpStack->Parameters.Others.Argument4)--) {
  855. LARGE_INTEGER delay;
  856. delay.QuadPart = retryInterval;
  857. delay.QuadPart *= (LONGLONG)1000 * 1000 * 10;
  858. //
  859. // retry the request
  860. //
  861. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugError,
  862. "Not using ClassRetryRequest Yet\n"));
  863. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  864. "Retry update capabilities %p\n", Irp));
  865. CdRomPrepareUpdateCapabilitiesIrp(Fdo);
  866. CdRomRetryRequest(fdoExtension, Irp, retryInterval, TRUE);
  867. //
  868. // ClassRetryRequest(Fdo, Irp, delay);
  869. //
  870. return STATUS_MORE_PROCESSING_REQUIRED;
  871. }
  872. } else {
  873. status = STATUS_SUCCESS;
  874. }
  875. Irp->IoStatus.Status = status;
  876. KeSetEvent(&mmcData->CapabilitiesEvent, IO_CD_ROM_INCREMENT, FALSE);
  877. return STATUS_MORE_PROCESSING_REQUIRED;
  878. }
  879. VOID
  880. CdRomPrepareUpdateCapabilitiesIrp(
  881. PDEVICE_OBJECT Fdo
  882. )
  883. {
  884. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  885. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  886. PCDROM_DATA cdData = fdoExtension->CommonExtension.DriverData;
  887. PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc);
  888. PIO_STACK_LOCATION nextStack;
  889. PSCSI_REQUEST_BLOCK srb;
  890. PCDB cdb;
  891. ULONG bufferSize;
  892. PIRP irp;
  893. ASSERT(mmcData->UpdateState);
  894. ASSERT(mmcData->NumDelayedIrps != 0);
  895. ASSERT(mmcData->CapabilitiesIrp != NULL);
  896. ASSERT(mmcData->CapabilitiesMdl != NULL);
  897. ASSERT(mmcData->CapabilitiesBuffer);
  898. ASSERT(mmcData->CapabilitiesBufferSize != 0);
  899. ASSERT(fdoExtension->SenseData);
  900. //
  901. // do *NOT* call IoReuseIrp(), since it would zero out our
  902. // current irp stack location, which we really don't want
  903. // to happen. it would also set the current irp stack location
  904. // to one greater than currently exists (to give max irp usage),
  905. // but we don't want that either, since we use the top irp stack.
  906. //
  907. // IoReuseIrp(mmcData->CapabilitiesIrp, STATUS_UNSUCCESSFUL);
  908. //
  909. irp = mmcData->CapabilitiesIrp;
  910. srb = &(mmcData->CapabilitiesSrb);
  911. cdb = (PCDB)(srb->Cdb);
  912. bufferSize = mmcData->CapabilitiesBufferSize;
  913. //
  914. // zero stuff out
  915. //
  916. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  917. RtlZeroMemory(fdoExtension->SenseData, sizeof(SENSE_DATA));
  918. RtlZeroMemory(mmcData->CapabilitiesBuffer, bufferSize);
  919. //
  920. // setup the srb
  921. //
  922. srb->TimeOutValue = CDROM_GET_CONFIGURATION_TIMEOUT;
  923. srb->Length = SCSI_REQUEST_BLOCK_SIZE;
  924. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  925. srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  926. srb->SenseInfoBuffer = fdoExtension->SenseData;
  927. srb->DataBuffer = mmcData->CapabilitiesBuffer;
  928. srb->QueueAction = SRB_SIMPLE_TAG_REQUEST;
  929. srb->DataTransferLength = mmcData->CapabilitiesBufferSize;
  930. srb->ScsiStatus = 0;
  931. srb->SrbStatus = 0;
  932. srb->NextSrb = NULL;
  933. srb->OriginalRequest = irp;
  934. srb->SrbFlags = fdoExtension->SrbFlags;
  935. srb->CdbLength = 10;
  936. SET_FLAG(srb->SrbFlags, SRB_FLAGS_DATA_IN);
  937. SET_FLAG(srb->SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
  938. //
  939. // setup the cdb
  940. //
  941. cdb->GET_CONFIGURATION.OperationCode = SCSIOP_GET_CONFIGURATION;
  942. cdb->GET_CONFIGURATION.RequestType = SCSI_GET_CONFIGURATION_REQUEST_TYPE_CURRENT;
  943. cdb->GET_CONFIGURATION.StartingFeature[0] = 0;
  944. cdb->GET_CONFIGURATION.StartingFeature[1] = 0;
  945. cdb->GET_CONFIGURATION.AllocationLength[0] = (UCHAR)(bufferSize >> 8);
  946. cdb->GET_CONFIGURATION.AllocationLength[1] = (UCHAR)(bufferSize & 0xff);
  947. //
  948. // setup the irp
  949. //
  950. nextStack = IoGetNextIrpStackLocation(irp);
  951. nextStack->MajorFunction = IRP_MJ_SCSI;
  952. nextStack->Parameters.Scsi.Srb = srb;
  953. irp->MdlAddress = mmcData->CapabilitiesMdl;
  954. irp->AssociatedIrp.SystemBuffer = mmcData->CapabilitiesBuffer;
  955. IoSetCompletionRoutine(irp, CdRomUpdateMmcDriveCapabilitiesCompletion, Fdo,
  956. TRUE, TRUE, TRUE);
  957. return;
  958. }
  959. VOID
  960. CdRomUpdateMmcDriveCapabilities(
  961. IN PDEVICE_OBJECT Fdo,
  962. IN PVOID Context
  963. )
  964. {
  965. PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Fdo->DeviceExtension;
  966. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  967. PCDROM_DATA cdData = fdoExtension->CommonExtension.DriverData;
  968. PCDROM_MMC_EXTENSION mmcData = &(cdData->Mmc);
  969. PIO_STACK_LOCATION thisStack = IoGetCurrentIrpStackLocation(mmcData->CapabilitiesIrp);
  970. PSCSI_REQUEST_BLOCK srb = &(mmcData->CapabilitiesSrb);
  971. NTSTATUS status;
  972. ASSERT(Context == NULL);
  973. //
  974. // NOTE: a remove lock is unneccessary, since the delayed irp
  975. // will have said lock held for itself, preventing a remove.
  976. //
  977. CdRomPrepareUpdateCapabilitiesIrp(Fdo);
  978. ASSERT(thisStack->Parameters.Others.Argument1 == Fdo);
  979. ASSERT(thisStack->Parameters.Others.Argument2 == mmcData->CapabilitiesBuffer);
  980. ASSERT(thisStack->Parameters.Others.Argument3 == &(mmcData->CapabilitiesSrb));
  981. mmcData->WriteAllowed = FALSE; // default to read-only
  982. //
  983. // set max retries, and also allow volume verify override based on
  984. // original (delayed) irp
  985. //
  986. thisStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES;
  987. //
  988. // send to self... note that SL_OVERRIDE_VERIFY_VOLUME is not required,
  989. // as this is IRP_MJ_INTERNAL_DEVICE_CONTROL
  990. //
  991. IoCallDriver(commonExtension->LowerDeviceObject, mmcData->CapabilitiesIrp);
  992. KeWaitForSingleObject(&mmcData->CapabilitiesEvent,
  993. Executive, KernelMode, FALSE, NULL);
  994. status = mmcData->CapabilitiesIrp->IoStatus.Status;
  995. if (!NT_SUCCESS(status)) {
  996. goto FinishDriveUpdate;
  997. }
  998. //
  999. // we've updated the feature set, so update whether or not reads and writes
  1000. // are allowed or not.
  1001. //
  1002. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  1003. "CdRomUpdateMmc => Succeeded "
  1004. "--------------------"
  1005. "--------------------\n"));
  1006. /*++
  1007. NOTE: It is important to only use srb->DataTransferLength worth
  1008. of data at this point, since the bufferSize is what is
  1009. *available* to use, not what was *actually* used.
  1010. --*/
  1011. #if DBG
  1012. CdRompPrintAllFeaturePages(mmcData->CapabilitiesBuffer,
  1013. srb->DataTransferLength);
  1014. #endif // DBG
  1015. //
  1016. // update whether or not writes are allowed. this is currently defined
  1017. // as requiring TargetDefectManagement and RandomWritable features
  1018. //
  1019. {
  1020. PFEATURE_HEADER defectHeader;
  1021. PFEATURE_HEADER writableHeader;
  1022. defectHeader = CdRomFindFeaturePage(mmcData->CapabilitiesBuffer,
  1023. srb->DataTransferLength,
  1024. FeatureDefectManagement);
  1025. writableHeader = CdRomFindFeaturePage(mmcData->CapabilitiesBuffer,
  1026. srb->DataTransferLength,
  1027. FeatureRandomWritable);
  1028. if ((defectHeader != NULL) && (writableHeader != NULL) &&
  1029. (defectHeader->Current) && (writableHeader->Current)) {
  1030. //
  1031. // this should be the *ONLY* place writes are set to allowed
  1032. //
  1033. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  1034. "CdRomUpdateMmc => Writes *allowed*\n"));
  1035. mmcData->WriteAllowed = TRUE;
  1036. } else {
  1037. if (defectHeader == NULL) {
  1038. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  1039. "CdRomUpdateMmc => No writes - %s = %s\n",
  1040. "defect management", "DNE"));
  1041. } else {
  1042. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  1043. "CdRomUpdateMmc => No writes - %s = %s\n",
  1044. "defect management", "Not Current"));
  1045. }
  1046. if (writableHeader == NULL) {
  1047. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  1048. "CdRomUpdateMmc => No writes - %s = %s\n",
  1049. "sector writable", "DNE"));
  1050. } else {
  1051. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  1052. "CdRomUpdateMmc => No writes - %s = %s\n",
  1053. "sector writable", "Not Current"));
  1054. }
  1055. } // end of feature checking
  1056. } // end of check for writability
  1057. status = STATUS_SUCCESS;
  1058. FinishDriveUpdate:
  1059. CdRompFlushDelayedList(Fdo, mmcData, status, TRUE);
  1060. return;
  1061. }
  1062. VOID
  1063. CdRompFlushDelayedList(
  1064. IN PDEVICE_OBJECT Fdo,
  1065. IN PCDROM_MMC_EXTENSION MmcData,
  1066. IN NTSTATUS Status,
  1067. IN BOOLEAN CalledFromWorkItem
  1068. )
  1069. {
  1070. LIST_ENTRY irpList;
  1071. PLIST_ENTRY listEntry;
  1072. KIRQL oldIrql;
  1073. // NOTE - REF #0002
  1074. //
  1075. // need to set the new state first to prevent deadlocks.
  1076. // this is only done from the workitem, to prevent any
  1077. // edge cases where we'd "lose" the UpdateRequired
  1078. //
  1079. // then, must ignore the state, since it's not guaranteed to
  1080. // be the same any longer. the only thing left is to handle
  1081. // all the delayed irps by flushing the queue and sending them
  1082. // back onto the StartIo queue for the device.
  1083. //
  1084. if (CalledFromWorkItem) {
  1085. LONG oldState;
  1086. LONG newState;
  1087. if (NT_SUCCESS(Status)) {
  1088. newState = CdromMmcUpdateComplete;
  1089. } else {
  1090. newState = CdromMmcUpdateRequired;
  1091. }
  1092. oldState = InterlockedCompareExchange(&MmcData->UpdateState,
  1093. newState,
  1094. CdromMmcUpdateStarted);
  1095. ASSERT(oldState == CdromMmcUpdateStarted);
  1096. } else {
  1097. //
  1098. // just flushing the queue if not called from the workitem,
  1099. // and we don't want to ever fail the queue in those cases.
  1100. //
  1101. ASSERT(NT_SUCCESS(Status));
  1102. }
  1103. /*
  1104. * Get all the delayed IRPs into a private list first to avoid an infinite loop
  1105. * where irps are added to the DelayedIrpsList while we are siphoning them off.
  1106. */
  1107. InitializeListHead(&irpList);
  1108. KeAcquireSpinLock(&MmcData->DelayedIrpsLock, &oldIrql);
  1109. while (!IsListEmpty(&MmcData->DelayedIrpsList)){
  1110. listEntry = RemoveHeadList(&MmcData->DelayedIrpsList);
  1111. InsertTailList(&irpList, listEntry);
  1112. ASSERT(MmcData->NumDelayedIrps > 0);
  1113. MmcData->NumDelayedIrps--;
  1114. }
  1115. ASSERT(MmcData->NumDelayedIrps == 0);
  1116. KeReleaseSpinLock(&MmcData->DelayedIrpsLock, oldIrql);
  1117. // if this assert fires, it means that we have started
  1118. // a workitem when the previous workitem took the delayed
  1119. // irp. if this happens, then the logic in HACKHACK #0002
  1120. // is either flawed or the rules set within are not being
  1121. // followed. this would require investigation.
  1122. ASSERT(!IsListEmpty(&irpList));
  1123. //
  1124. // now either succeed or fail all the delayed irps, according
  1125. // to the update status.
  1126. //
  1127. while (!IsListEmpty(&irpList)){
  1128. PIRP irp;
  1129. listEntry = RemoveHeadList(&irpList);
  1130. irp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
  1131. irp->Tail.Overlay.DriverContext[0] = 0;
  1132. irp->Tail.Overlay.DriverContext[1] = 0;
  1133. irp->Tail.Overlay.DriverContext[2] = 0;
  1134. irp->Tail.Overlay.DriverContext[3] = 0;
  1135. if (NT_SUCCESS(Status)) {
  1136. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  1137. "CdRomUpdateMmc => Re-sending delayed irp %p\n",
  1138. irp));
  1139. IoStartPacket(Fdo, irp, NULL, NULL);
  1140. } else {
  1141. KdPrintEx((DPFLTR_CDROM_ID, CdromDebugFeatures,
  1142. "CdRomUpdateMmc => Failing delayed irp %p with "
  1143. " status %x\n", irp, Status));
  1144. irp->IoStatus.Information = 0;
  1145. irp->IoStatus.Status = Status;
  1146. ClassReleaseRemoveLock(Fdo, irp);
  1147. IoCompleteRequest(irp, IO_CD_ROM_INCREMENT);
  1148. }
  1149. } // while (list)
  1150. return;
  1151. }
  1152. VOID
  1153. CdRomDeAllocateMmcResources(
  1154. IN PDEVICE_OBJECT Fdo
  1155. )
  1156. {
  1157. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  1158. PCDROM_DATA cddata = commonExtension->DriverData;
  1159. PCDROM_MMC_EXTENSION mmcData = &cddata->Mmc;
  1160. NTSTATUS status;
  1161. if (mmcData->CapabilitiesWorkItem) {
  1162. IoFreeWorkItem(mmcData->CapabilitiesWorkItem);
  1163. mmcData->CapabilitiesWorkItem = NULL;
  1164. }
  1165. if (mmcData->CapabilitiesIrp) {
  1166. IoFreeIrp(mmcData->CapabilitiesIrp);
  1167. mmcData->CapabilitiesIrp = NULL;
  1168. }
  1169. if (mmcData->CapabilitiesMdl) {
  1170. IoFreeMdl(mmcData->CapabilitiesMdl);
  1171. mmcData->CapabilitiesMdl = NULL;
  1172. }
  1173. if (mmcData->CapabilitiesBuffer) {
  1174. ExFreePool(mmcData->CapabilitiesBuffer);
  1175. mmcData->CapabilitiesBuffer = NULL;
  1176. }
  1177. mmcData->CapabilitiesBuffer = 0;
  1178. mmcData->IsMmc = FALSE;
  1179. mmcData->WriteAllowed = FALSE;
  1180. return;
  1181. }
  1182. NTSTATUS
  1183. CdRomAllocateMmcResources(
  1184. IN PDEVICE_OBJECT Fdo
  1185. )
  1186. {
  1187. PCOMMON_DEVICE_EXTENSION commonExtension = Fdo->DeviceExtension;
  1188. PCDROM_DATA cddata = commonExtension->DriverData;
  1189. PCDROM_MMC_EXTENSION mmcData = &cddata->Mmc;
  1190. PIO_STACK_LOCATION irpStack;
  1191. NTSTATUS status;
  1192. ASSERT(mmcData->CapabilitiesWorkItem == NULL);
  1193. ASSERT(mmcData->CapabilitiesIrp == NULL);
  1194. ASSERT(mmcData->CapabilitiesMdl == NULL);
  1195. ASSERT(mmcData->CapabilitiesBuffer == NULL);
  1196. ASSERT(mmcData->CapabilitiesBufferSize == 0);
  1197. status = CdRomGetConfiguration(Fdo,
  1198. &mmcData->CapabilitiesBuffer,
  1199. &mmcData->CapabilitiesBufferSize,
  1200. FeatureProfileList,
  1201. SCSI_GET_CONFIGURATION_REQUEST_TYPE_ALL);
  1202. if (!NT_SUCCESS(status)) {
  1203. ASSERT(mmcData->CapabilitiesBuffer == NULL);
  1204. ASSERT(mmcData->CapabilitiesBufferSize == 0);
  1205. return status;
  1206. }
  1207. ASSERT(mmcData->CapabilitiesBuffer != NULL);
  1208. ASSERT(mmcData->CapabilitiesBufferSize != 0);
  1209. mmcData->CapabilitiesMdl = IoAllocateMdl(mmcData->CapabilitiesBuffer,
  1210. mmcData->CapabilitiesBufferSize,
  1211. FALSE, FALSE, NULL);
  1212. if (mmcData->CapabilitiesMdl == NULL) {
  1213. ExFreePool(mmcData->CapabilitiesBuffer);
  1214. mmcData->CapabilitiesBufferSize = 0;
  1215. return STATUS_INSUFFICIENT_RESOURCES;
  1216. }
  1217. mmcData->CapabilitiesIrp = IoAllocateIrp(Fdo->StackSize + 2, FALSE);
  1218. if (mmcData->CapabilitiesIrp == NULL) {
  1219. IoFreeMdl(mmcData->CapabilitiesMdl);
  1220. ExFreePool(mmcData->CapabilitiesBuffer);
  1221. mmcData->CapabilitiesBufferSize = 0;
  1222. return STATUS_INSUFFICIENT_RESOURCES;
  1223. }
  1224. mmcData->CapabilitiesWorkItem = IoAllocateWorkItem(Fdo);
  1225. if (mmcData->CapabilitiesWorkItem == NULL) {
  1226. IoFreeIrp(mmcData->CapabilitiesIrp);
  1227. IoFreeMdl(mmcData->CapabilitiesMdl);
  1228. ExFreePool(mmcData->CapabilitiesBuffer);
  1229. mmcData->CapabilitiesBufferSize = 0;
  1230. return STATUS_INSUFFICIENT_RESOURCES;
  1231. }
  1232. //
  1233. // everything has been allocated, so now prepare it all....
  1234. //
  1235. MmBuildMdlForNonPagedPool(mmcData->CapabilitiesMdl);
  1236. InitializeListHead(&mmcData->DelayedIrpsList);
  1237. KeInitializeSpinLock(&mmcData->DelayedIrpsLock);
  1238. mmcData->NumDelayedIrps = 0;
  1239. //
  1240. // use the extra stack for internal bookkeeping
  1241. //
  1242. IoSetNextIrpStackLocation(mmcData->CapabilitiesIrp);
  1243. irpStack = IoGetCurrentIrpStackLocation(mmcData->CapabilitiesIrp);
  1244. irpStack->Parameters.Others.Argument1 = Fdo;
  1245. irpStack->Parameters.Others.Argument2 = mmcData->CapabilitiesBuffer;
  1246. irpStack->Parameters.Others.Argument3 = &(mmcData->CapabilitiesSrb);
  1247. // arg 4 is the retry count
  1248. //
  1249. // set the completion event to FALSE for now
  1250. //
  1251. KeInitializeEvent(&mmcData->CapabilitiesEvent,
  1252. SynchronizationEvent, FALSE);
  1253. return STATUS_SUCCESS;
  1254. }