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.

1814 lines
48 KiB

  1. /*++
  2. Copyright (C) 1990 - 99 Microsoft Corporation
  3. Module Name:
  4. port.c
  5. Abstract:
  6. Ide bus enumeration
  7. Authors:
  8. Mike Glass
  9. Jeff Havens
  10. Joe Dai
  11. Environment:
  12. kernel mode only
  13. Revision History:
  14. --*/
  15. #include "ideport.h"
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(NONPAGE, IssueSyncAtapiCommand)
  18. #pragma alloc_text(NONPAGE, IssueSyncAtapiCommandSafe)
  19. #pragma alloc_text(NONPAGE, IdePortDmaCdromDrive)
  20. //#pragma alloc_text(PAGESCAN, IdePortDmaCdromDrive)
  21. #pragma alloc_text(PAGE, IdePortInitFdo)
  22. #pragma alloc_text(PAGE, IssueInquirySafe)
  23. #pragma alloc_text(PAGE, IdePortQueryNonCdNumLun)
  24. #pragma alloc_text(PAGE, IdeBuildDeviceMap)
  25. #pragma alloc_text(PAGE, IdeCreateNumericKey)
  26. extern LONG IdePAGESCANLockCount;
  27. #endif
  28. static PWCHAR IdePortUserRegistryDeviceTypeName[MAX_IDE_DEVICE * MAX_IDE_LINE] = {
  29. USER_MASTER_DEVICE_TYPE_REG_KEY,
  30. USER_SLAVE_DEVICE_TYPE_REG_KEY,
  31. USER_MASTER_DEVICE_TYPE2_REG_KEY,
  32. USER_SLAVE_DEVICE_TYPE2_REG_KEY
  33. };
  34. static PWCHAR IdePortRegistryUserDeviceTimingModeAllowedName[MAX_IDE_DEVICE * MAX_IDE_LINE] = {
  35. USER_MASTER_DEVICE_TIMING_MODE_ALLOWED,
  36. USER_SLAVE_DEVICE_TIMING_MODE_ALLOWED,
  37. USER_MASTER_DEVICE_TIMING_MODE_ALLOWED2,
  38. USER_SLAVE_DEVICE_TIMING_MODE_ALLOWED2
  39. };
  40. //
  41. // Idle Timeout
  42. //
  43. //ULONG PdoConservationIdleTime = -1;
  44. //ULONG PdoPerformanceIdleTime = -1;
  45. NTSTATUS
  46. IdePortInitFdo(
  47. IN OUT PFDO_EXTENSION FdoExtension
  48. )
  49. /*++
  50. Routine Description:
  51. This routine enumerates the IDE bus and initialize the fdo extension
  52. Arguments:
  53. FdoExtension - FDO extension
  54. RegistryPath - registry path passed in via DriverEntry
  55. Return Value:
  56. --*/
  57. {
  58. PFDO_EXTENSION fdoExtension = FdoExtension;
  59. NTSTATUS status;
  60. PDEVICE_OBJECT deviceObject;
  61. ULONG uniqueId;
  62. KIRQL irql;
  63. PIO_SCSI_CAPABILITIES capabilities;
  64. PIO_ERROR_LOG_PACKET errorLogEntry;
  65. ULONG i;
  66. ULONG j;
  67. BOOLEAN ideDeviceFound;
  68. status = STATUS_SUCCESS;
  69. deviceObject = fdoExtension->DeviceObject;
  70. //
  71. // Save the dependent driver routines in the device extension.
  72. //
  73. fdoExtension->HwDeviceExtension = (PVOID)(fdoExtension + 1);
  74. //
  75. // Mark this object as supporting direct I/O so that I/O system
  76. // will supply mdls in irps.
  77. //
  78. deviceObject->Flags |= DO_DIRECT_IO;
  79. //
  80. // Initialize the maximum lu count variable.
  81. //
  82. fdoExtension->MaxLuCount = SCSI_MAXIMUM_LOGICAL_UNITS;
  83. //
  84. // Allocate spin lock for critical sections.
  85. //
  86. KeInitializeSpinLock(&fdoExtension->SpinLock);
  87. //
  88. // Spinlock that protects LogicalUnitList manipulation
  89. //
  90. KeInitializeSpinLock(&fdoExtension->LogicalUnitListSpinLock);
  91. //
  92. // Initialize DPC routine.
  93. //
  94. IoInitializeDpcRequest(deviceObject, IdePortCompletionDpc);
  95. //
  96. // Initialize the port timeout counter.
  97. //
  98. fdoExtension->PortTimeoutCounter = PD_TIMER_STOPPED;
  99. //
  100. // Initialize timer.
  101. //
  102. IoInitializeTimer(deviceObject, IdePortTickHandler, NULL);
  103. //
  104. // Initialize miniport timer and timer DPC.
  105. //
  106. KeInitializeTimer(&fdoExtension->MiniPortTimer);
  107. KeInitializeDpc(&fdoExtension->MiniPortTimerDpc,
  108. IdeMiniPortTimerDpc,
  109. deviceObject );
  110. //
  111. // Start timer. Request timeout counters
  112. // in the logical units have already been
  113. // initialized.
  114. //
  115. IoStartTimer(deviceObject);
  116. fdoExtension->Flags |= PD_DISCONNECT_RUNNING;
  117. //
  118. // Check to see if an error was logged.
  119. //
  120. if (fdoExtension->InterruptData.InterruptFlags & PD_LOG_ERROR) {
  121. CLRMASK (fdoExtension->InterruptData.InterruptFlags, PD_LOG_ERROR | PD_NOTIFICATION_REQUIRED);
  122. LogErrorEntry(fdoExtension,
  123. &fdoExtension->InterruptData.LogEntry);
  124. }
  125. //
  126. // Initialize the capabilities pointer.
  127. //
  128. capabilities = &fdoExtension->Capabilities;
  129. //
  130. // Initailize the capabilities structure.
  131. //
  132. capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
  133. if (fdoExtension->BoundWithBmParent) {
  134. if (fdoExtension->HwDeviceExtension->BusMasterInterface.MaxTransferByteSize <
  135. MAX_TRANSFER_SIZE_PER_SRB) {
  136. capabilities->MaximumTransferLength =
  137. fdoExtension->HwDeviceExtension->BusMasterInterface.MaxTransferByteSize;
  138. } else {
  139. capabilities->MaximumTransferLength =
  140. MAX_TRANSFER_SIZE_PER_SRB;
  141. }
  142. } else {
  143. capabilities->MaximumTransferLength = MAX_TRANSFER_SIZE_PER_SRB;
  144. }
  145. capabilities->TaggedQueuing = FALSE;
  146. capabilities->AdapterScansDown = FALSE;
  147. capabilities->AlignmentMask = deviceObject->AlignmentRequirement;
  148. capabilities->MaximumPhysicalPages = BYTES_TO_PAGES(capabilities->MaximumTransferLength);
  149. if (fdoExtension->IdeResource.TranslatedCommandBaseAddress) {
  150. DebugPrint((1,
  151. "IdePort: Initialize: Translated IO Base address %x\n",
  152. fdoExtension->IdeResource.TranslatedCommandBaseAddress));
  153. }
  154. for (i=0; i< MAX_IDE_DEVICE * MAX_IDE_LINE; i++) {
  155. fdoExtension->UserChoiceDeviceType[i] = DeviceUnknown;
  156. IdePortGetDeviceParameter (
  157. fdoExtension,
  158. IdePortUserRegistryDeviceTypeName[i],
  159. (PULONG)(fdoExtension->UserChoiceDeviceType + i)
  160. );
  161. }
  162. //
  163. // the acpi _GTM buffer should be initialized with -1s
  164. //
  165. for (i=0; i<MAX_IDE_DEVICE; i++) {
  166. PACPI_IDE_TIMING timingSettings = &(FdoExtension->BootAcpiTimingSettings);
  167. timingSettings->Speed[i].Pio = ACPI_XFER_MODE_NOT_SUPPORT;
  168. timingSettings->Speed[i].Dma = ACPI_XFER_MODE_NOT_SUPPORT;
  169. }
  170. fdoExtension->DmaDetectionLevel = DdlFirmwareOk;
  171. IdePortGetDeviceParameter (
  172. fdoExtension,
  173. DMA_DETECTION_LEVEL_REG_KEY,
  174. (PULONG)&fdoExtension->DmaDetectionLevel
  175. );
  176. //
  177. // non-pcmcia controller, MayHaveSlaveDevice is always set
  178. // if pcmcia controller, it is not set unless
  179. // registry flag PCMCIA_IDE_CONTROLLER_HAS_SLAVE
  180. // is non-zero
  181. //
  182. if (!ChannelQueryPcmciaParent (fdoExtension)) {
  183. fdoExtension->MayHaveSlaveDevice = 1;
  184. } else {
  185. fdoExtension->MayHaveSlaveDevice = 0;
  186. IdePortGetDeviceParameter (
  187. fdoExtension,
  188. PCMCIA_IDE_CONTROLLER_HAS_SLAVE,
  189. (PULONG)&fdoExtension->MayHaveSlaveDevice
  190. );
  191. }
  192. #ifdef ENABLE_ATAPI_VERIFIER
  193. ViIdeInitVerifierSettings(fdoExtension);
  194. #endif
  195. return status;
  196. } // IdePortInitFdo
  197. NTSTATUS
  198. SyncAtapiSafeCompletion (
  199. PDEVICE_OBJECT DeviceObject,
  200. PIRP Irp,
  201. PVOID Context
  202. )
  203. {
  204. PSYNC_ATA_PASSTHROUGH_CONTEXT context = Context;
  205. context->Status = Irp->IoStatus.Status;
  206. KeSetEvent (&context->Event, 0, FALSE);
  207. return STATUS_MORE_PROCESSING_REQUIRED;
  208. }
  209. NTSTATUS
  210. IssueSyncAtapiCommandSafe (
  211. IN PFDO_EXTENSION FdoExtension,
  212. IN PPDO_EXTENSION PdoExtension,
  213. IN PCDB Cdb,
  214. IN PVOID DataBuffer,
  215. IN ULONG DataBufferSize,
  216. IN BOOLEAN DataIn,
  217. IN ULONG RetryCount,
  218. IN BOOLEAN ByPassBlockedQueue
  219. )
  220. /*++
  221. Routine Description:
  222. Build IRP, SRB and CDB for the given CDB
  223. Send and wait for the IRP to complete
  224. Arguments:
  225. FdoExtension - FDO extension
  226. PdoExtension - device extension of the PDO to which the command is sent
  227. Cdb - Command Descriptor Block
  228. DataBuffer - data buffer for the command
  229. DataBufferSize - byte size of DataBuffer
  230. DataIn - TRUE is the command causes the device to return data
  231. RetryCount - number of times to retry the command if the command fails
  232. Return Value:
  233. NTSTATUS
  234. If any of the pre-alloc related operation fails, it returns STATUS_INSUFFICIENT_RESOURCES
  235. The caller should take care of the condition
  236. --*/
  237. {
  238. PIRP irp;
  239. PIO_STACK_LOCATION irpStack;
  240. PSCSI_REQUEST_BLOCK srb;
  241. KEVENT event;
  242. IO_STATUS_BLOCK ioStatusBlock;
  243. KIRQL currentIrql;
  244. NTSTATUS status;
  245. ULONG flushCount;
  246. PSENSE_DATA senseInfoBuffer;
  247. UCHAR senseInfoBufferSize;
  248. PENUMERATION_STRUCT enumStruct;
  249. SYNC_ATA_PASSTHROUGH_CONTEXT context;
  250. ULONG locked;
  251. ASSERT(InterlockedCompareExchange(&(FdoExtension->EnumStructLock), 1, 0) == 0);
  252. enumStruct=FdoExtension->PreAllocEnumStruct;
  253. if (enumStruct == NULL) {
  254. ASSERT(FdoExtension->PreAllocEnumStruct);
  255. return STATUS_INSUFFICIENT_RESOURCES;
  256. }
  257. senseInfoBufferSize = SENSE_BUFFER_SIZE;
  258. senseInfoBuffer = enumStruct->SenseInfoBuffer;
  259. ASSERT (senseInfoBuffer);
  260. DebugPrint((1, "Using Sync Atapi safe!\n"));
  261. srb= enumStruct->Srb;
  262. ASSERT(srb);
  263. status = STATUS_UNSUCCESSFUL;
  264. RetryCount = 5;
  265. flushCount = 100;
  266. irp = enumStruct->Irp1;
  267. ASSERT (irp);
  268. ASSERT (enumStruct->DataBufferSize >= DataBufferSize);
  269. while (!NT_SUCCESS(status) && RetryCount--) {
  270. //
  271. // Initialize the notification event.
  272. //
  273. KeInitializeEvent(&context.Event,
  274. NotificationEvent,
  275. FALSE);
  276. IoInitializeIrp(irp,
  277. IoSizeOfIrp(PREALLOC_STACK_LOCATIONS),
  278. PREALLOC_STACK_LOCATIONS);
  279. irp->MdlAddress = enumStruct->MdlAddress;
  280. irpStack = IoGetNextIrpStackLocation(irp);
  281. irpStack->MajorFunction = IRP_MJ_SCSI;
  282. if (DataBuffer) {
  283. RtlCopyMemory(enumStruct->DataBuffer, DataBuffer, DataBufferSize);
  284. }
  285. RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
  286. irpStack->Parameters.Scsi.Srb = srb;
  287. srb->PathId = PdoExtension->PathId;
  288. srb->TargetId = PdoExtension->TargetId;
  289. srb->Lun = PdoExtension->Lun;
  290. srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
  291. srb->Length = sizeof(SCSI_REQUEST_BLOCK);
  292. //
  293. // Set flags to disable synchronous negociation.
  294. //
  295. srb->SrbFlags = DataIn ? SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER :
  296. SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  297. if (ByPassBlockedQueue) {
  298. srb->SrbFlags |= SRB_FLAGS_BYPASS_FROZEN_QUEUE;
  299. }
  300. srb->SrbStatus = srb->ScsiStatus = 0;
  301. srb->NextSrb = 0;
  302. srb->OriginalRequest = irp;
  303. //
  304. // Set timeout to 4 seconds.
  305. //
  306. srb->TimeOutValue = 4;
  307. srb->CdbLength = 6;
  308. //
  309. // Enable auto request sense.
  310. //
  311. srb->SenseInfoBuffer = senseInfoBuffer;
  312. srb->SenseInfoBufferLength = senseInfoBufferSize;
  313. srb->DataBuffer = MmGetMdlVirtualAddress(irp->MdlAddress);
  314. srb->DataTransferLength = DataBufferSize;
  315. //
  316. // Set CDB operation code.
  317. //
  318. RtlCopyMemory(srb->Cdb, Cdb, sizeof(CDB));
  319. IoSetCompletionRoutine(
  320. irp,
  321. SyncAtapiSafeCompletion,
  322. &context,
  323. TRUE,
  324. TRUE,
  325. TRUE
  326. );
  327. //
  328. // Wait for request to complete.
  329. //
  330. if (IoCallDriver(PdoExtension->DeviceObject, irp) == STATUS_PENDING) {
  331. KeWaitForSingleObject(&context.Event,
  332. Executive,
  333. KernelMode,
  334. FALSE,
  335. NULL);
  336. }
  337. RtlCopyMemory(DataBuffer, srb->DataBuffer, DataBufferSize);
  338. if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  339. DebugPrint((1,"IssueSyncAtapiCommand: atapi command failed SRB status %x\n",
  340. srb->SrbStatus));
  341. if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_REQUEST_FLUSHED) {
  342. //
  343. // we will give it a few more retries if our request
  344. // got flushed.
  345. //
  346. flushCount--;
  347. if (flushCount) {
  348. RetryCount++;
  349. }
  350. }
  351. if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  352. status = STATUS_DATA_OVERRUN;
  353. } else {
  354. status = STATUS_UNSUCCESSFUL;
  355. }
  356. //
  357. // Unfreeze queue if necessary
  358. //
  359. if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  360. DebugPrint((3, "IssueSyncAtapiCommand: Unfreeze Queue TID %d\n",
  361. srb->TargetId));
  362. //
  363. // unfreeze queue
  364. //
  365. CLRMASK (PdoExtension->LuFlags, PD_QUEUE_FROZEN);
  366. //
  367. // restart queue
  368. //
  369. KeAcquireSpinLock(&FdoExtension->SpinLock, &currentIrql);
  370. GetNextLuRequest(FdoExtension, PdoExtension);
  371. KeLowerIrql(currentIrql);
  372. }
  373. if ((srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
  374. (senseInfoBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)) {
  375. //
  376. // A sense key of illegal request was recieved. This indicates
  377. // that the mech status command is illegal.
  378. //
  379. status = STATUS_INVALID_DEVICE_REQUEST;
  380. //
  381. // The command is illegal, no point to keep trying
  382. //
  383. RetryCount = 0;
  384. }
  385. } else {
  386. status = STATUS_SUCCESS;
  387. }
  388. }
  389. if (flushCount != 100) {
  390. DebugPrint ((DBG_ALWAYS, "IssueSyncAtapiCommand: flushCount is %u\n", flushCount));
  391. }
  392. //
  393. // Unlock
  394. //
  395. ASSERT(InterlockedCompareExchange(&(FdoExtension->EnumStructLock), 0, 1) == 1);
  396. return status;
  397. } // IssueSyncAtapiCommandSafe
  398. BOOLEAN
  399. IdePortDmaCdromDrive(
  400. IN PFDO_EXTENSION FdoExtension,
  401. IN PPDO_EXTENSION PdoExtension,
  402. IN BOOLEAN LowMem
  403. )
  404. /*++
  405. Routine Description:
  406. Build IRP, SRB and CDB for SCSI MODE_SENSE10 command.
  407. Arguments:
  408. DeviceExtension - address of adapter's device object extension.
  409. LowMem - Low memory condition, use the safe (but not thread-safe) version
  410. - This should be one only when called during enumeration.
  411. Return Value:
  412. NTSTATUS
  413. --*/
  414. {
  415. CDB cdb;
  416. NTSTATUS status;
  417. BOOLEAN isDVD = FALSE;
  418. ULONG bufLength;
  419. ULONG capPageOffset;
  420. PMODE_PARAMETER_HEADER10 modePageHeader;
  421. PCDVD_CAPABILITIES_PAGE capPage;
  422. /*
  423. //
  424. // Code is paged until locked down.
  425. //
  426. PAGED_CODE();
  427. #ifdef ALLOC_PRAGMA
  428. ASSERT(IdePAGESCANLockCount > 0);
  429. #endif
  430. */
  431. RtlZeroMemory(&cdb, sizeof(CDB));
  432. bufLength = sizeof(CDVD_CAPABILITIES_PAGE) +
  433. sizeof(MODE_PARAMETER_HEADER10);
  434. capPageOffset = sizeof(MODE_PARAMETER_HEADER10);
  435. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  436. cdb.MODE_SENSE10.Dbd = 1;
  437. cdb.MODE_SENSE10.PageCode = MODE_PAGE_CAPABILITIES;
  438. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufLength >> 8);
  439. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufLength >> 0);
  440. modePageHeader = ExAllocatePool(NonPagedPoolCacheAligned,
  441. bufLength);
  442. if (modePageHeader) {
  443. RtlZeroMemory(modePageHeader, bufLength);
  444. if (LowMem) {
  445. status = IssueSyncAtapiCommandSafe (
  446. FdoExtension,
  447. PdoExtension,
  448. &cdb,
  449. modePageHeader,
  450. bufLength,
  451. TRUE,
  452. INQUIRY_RETRY_COUNT,
  453. TRUE
  454. );
  455. } else {
  456. status = IssueSyncAtapiCommand (
  457. FdoExtension,
  458. PdoExtension,
  459. &cdb,
  460. modePageHeader,
  461. bufLength,
  462. TRUE,
  463. INQUIRY_RETRY_COUNT,
  464. TRUE
  465. );
  466. }
  467. if (NT_SUCCESS(status) ||
  468. (status == STATUS_DATA_OVERRUN)) {
  469. capPage = (PCDVD_CAPABILITIES_PAGE) (((PUCHAR) modePageHeader) + capPageOffset);
  470. if ((capPage->PageCode == MODE_PAGE_CAPABILITIES) &&
  471. (capPage->CDRWrite || capPage->CDEWrite ||
  472. capPage->DVDROMRead || capPage->DVDRRead ||
  473. capPage->DVDRAMRead || capPage->DVDRWrite ||
  474. capPage->DVDRAMWrite)) {
  475. isDVD=TRUE;
  476. }
  477. }
  478. ExFreePool (modePageHeader);
  479. }
  480. return isDVD;
  481. }
  482. NTSTATUS
  483. IssueInquirySafe(
  484. IN PFDO_EXTENSION FdoExtension,
  485. IN PPDO_EXTENSION PdoExtension,
  486. OUT PINQUIRYDATA InquiryData,
  487. IN BOOLEAN LowMem
  488. )
  489. /*++
  490. Routine Description:
  491. Build IRP, SRB and CDB for SCSI INQUIRY command.
  492. Arguments:
  493. DeviceExtension - address of adapter's device object extension.
  494. LunInfo - address of buffer for INQUIRY information.
  495. LowMem - Low memory condition, use the safe (but not thread-safe) version
  496. - This should be one only when called during enumeration.
  497. Return Value:
  498. NTSTATUS
  499. --*/
  500. {
  501. CDB cdb;
  502. NTSTATUS status;
  503. PAGED_CODE();
  504. RtlZeroMemory(InquiryData, sizeof(*InquiryData));
  505. RtlZeroMemory(&cdb, sizeof(CDB));
  506. cdb.CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
  507. //
  508. // Set CDB LUN.
  509. //
  510. cdb.CDB6INQUIRY.LogicalUnitNumber = PdoExtension->Lun;
  511. cdb.CDB6INQUIRY.Reserved1 = 0;
  512. //
  513. // Set allocation length to inquiry data buffer size.
  514. //
  515. cdb.CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
  516. //
  517. // Zero reserve field and
  518. // Set EVPD Page Code to zero.
  519. // Set Control field to zero.
  520. // (See SCSI-II Specification.)
  521. //
  522. cdb.CDB6INQUIRY.PageCode = 0;
  523. cdb.CDB6INQUIRY.IReserved = 0;
  524. cdb.CDB6INQUIRY.Control = 0;
  525. if (LowMem ) {
  526. // Use the memory safe one
  527. status = IssueSyncAtapiCommandSafe (
  528. FdoExtension,
  529. PdoExtension,
  530. &cdb,
  531. InquiryData,
  532. INQUIRYDATABUFFERSIZE,
  533. TRUE,
  534. INQUIRY_RETRY_COUNT,
  535. FALSE
  536. );
  537. } else {
  538. // Use the thread safe one
  539. status = IssueSyncAtapiCommand (
  540. FdoExtension,
  541. PdoExtension,
  542. &cdb,
  543. InquiryData,
  544. INQUIRYDATABUFFERSIZE,
  545. TRUE,
  546. INQUIRY_RETRY_COUNT,
  547. FALSE
  548. );
  549. }
  550. return status;
  551. } // IssueInquiry
  552. NTSTATUS
  553. IssueSyncAtapiCommand (
  554. IN PFDO_EXTENSION FdoExtension,
  555. IN PPDO_EXTENSION PdoExtension,
  556. IN PCDB Cdb,
  557. IN PVOID DataBuffer,
  558. IN ULONG DataBufferSize,
  559. IN BOOLEAN DataIn,
  560. IN ULONG RetryCount,
  561. IN BOOLEAN ByPassBlockedQueue
  562. )
  563. /*++
  564. Routine Description:
  565. Build IRP, SRB and CDB for the given CDB
  566. Send and wait for the IRP to complete
  567. Arguments:
  568. FdoExtension - FDO extension
  569. PdoExtension - device extension of the PDO to which the command is sent
  570. Cdb - Command Descriptor Block
  571. DataBuffer - data buffer for the command
  572. DataBufferSize - byte size of DataBuffer
  573. DataIn - TRUE is the command causes the device to return data
  574. RetryCount - number of times to retry the command if the command fails
  575. Return Value:
  576. NTSTATUS
  577. --*/
  578. {
  579. PIRP irp;
  580. PIO_STACK_LOCATION irpStack;
  581. SCSI_REQUEST_BLOCK srb;
  582. KEVENT event;
  583. IO_STATUS_BLOCK ioStatusBlock;
  584. KIRQL currentIrql;
  585. NTSTATUS status;
  586. ULONG flushCount;
  587. PSENSE_DATA senseInfoBuffer;
  588. UCHAR senseInfoBufferSize;
  589. //
  590. // Sense buffer is in non-paged pool.
  591. //
  592. senseInfoBufferSize = SENSE_BUFFER_SIZE;
  593. senseInfoBuffer = ExAllocatePool( NonPagedPoolCacheAligned, senseInfoBufferSize);
  594. if (senseInfoBuffer == NULL) {
  595. DebugPrint((1,"IssueSyncAtapiCommand: Can't allocate request sense buffer\n"));
  596. IdeLogNoMemoryError(FdoExtension,
  597. PdoExtension->TargetId,
  598. NonPagedPoolCacheAligned,
  599. senseInfoBufferSize,
  600. IDEPORT_TAG_SYNCATAPI_SENSE
  601. );
  602. return(STATUS_INSUFFICIENT_RESOURCES);
  603. }
  604. status = STATUS_UNSUCCESSFUL;
  605. RetryCount = 5;
  606. flushCount = 100;
  607. while (!NT_SUCCESS(status) && RetryCount--) {
  608. //
  609. // Initialize the notification event.
  610. //
  611. KeInitializeEvent(&event,
  612. NotificationEvent,
  613. FALSE);
  614. //
  615. // Build IRP for this request.
  616. //
  617. irp = IoBuildDeviceIoControlRequest(
  618. DataIn ? IOCTL_SCSI_EXECUTE_IN : IOCTL_SCSI_EXECUTE_OUT,
  619. FdoExtension->DeviceObject,
  620. DataBuffer,
  621. DataBufferSize,
  622. DataBuffer,
  623. DataBufferSize,
  624. TRUE,
  625. &event,
  626. &ioStatusBlock);
  627. if (!irp) {
  628. RetryCount = 0;
  629. IdeLogNoMemoryError(FdoExtension,
  630. PdoExtension->TargetId,
  631. NonPagedPool,
  632. IoSizeOfIrp(FdoExtension->DeviceObject->StackSize),
  633. IDEPORT_TAG_SYNCATAPI_IRP
  634. );
  635. status = STATUS_INSUFFICIENT_RESOURCES;
  636. break;
  637. }
  638. irpStack = IoGetNextIrpStackLocation(irp);
  639. //
  640. // Fill in SRB fields.
  641. //
  642. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  643. irpStack->Parameters.Scsi.Srb = &srb;
  644. srb.PathId = PdoExtension->PathId;
  645. srb.TargetId = PdoExtension->TargetId;
  646. srb.Lun = PdoExtension->Lun;
  647. srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
  648. srb.Length = sizeof(SCSI_REQUEST_BLOCK);
  649. //
  650. // Set flags to disable synchronous negociation.
  651. //
  652. srb.SrbFlags = DataIn ? SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER :
  653. SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  654. if (ByPassBlockedQueue) {
  655. srb.SrbFlags |= SRB_FLAGS_BYPASS_FROZEN_QUEUE;
  656. }
  657. srb.SrbStatus = srb.ScsiStatus = 0;
  658. srb.NextSrb = 0;
  659. srb.OriginalRequest = irp;
  660. //
  661. // Set timeout to 4 seconds.
  662. //
  663. srb.TimeOutValue = 4;
  664. srb.CdbLength = 6;
  665. //
  666. // Enable auto request sense.
  667. //
  668. srb.SenseInfoBuffer = senseInfoBuffer;
  669. srb.SenseInfoBufferLength = senseInfoBufferSize;
  670. srb.DataBuffer = MmGetMdlVirtualAddress(irp->MdlAddress);
  671. srb.DataTransferLength = DataBufferSize;
  672. //
  673. // Set CDB operation code.
  674. //
  675. RtlCopyMemory(srb.Cdb, Cdb, sizeof(CDB));
  676. //
  677. // Wait for request to complete.
  678. //
  679. if (IoCallDriver(PdoExtension->DeviceObject, irp) == STATUS_PENDING) {
  680. KeWaitForSingleObject(&event,
  681. Executive,
  682. KernelMode,
  683. FALSE,
  684. NULL);
  685. }
  686. if (SRB_STATUS(srb.SrbStatus) != SRB_STATUS_SUCCESS) {
  687. DebugPrint((1,"IssueSyncAtapiCommand: atapi command failed SRB status %x\n",
  688. srb.SrbStatus));
  689. if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_REQUEST_FLUSHED) {
  690. //
  691. // we will give it a few more retries if our request
  692. // got flushed.
  693. //
  694. flushCount--;
  695. if (flushCount) {
  696. RetryCount++;
  697. }
  698. }
  699. if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  700. status = STATUS_DATA_OVERRUN;
  701. } else {
  702. status = STATUS_UNSUCCESSFUL;
  703. // if (SRB_STATUS(srb.SrbStatus) != SRB_STATUS_REQUEST_FLUSHED) {
  704. // if (srb.Lun == 0 && Cdb->CDB6INQUIRY.OperationCode == SCSIOP_INQUIRY) {
  705. // DebugPrint ((DBG_ALWAYS, "IssueSyncAtapiCommand: inquiry on lun 0 returned unexpected error: srb, status = 0x%x, 0x%x\n", &srb, srb.SrbStatus));
  706. // DbgBreakPoint();
  707. // }
  708. // }
  709. }
  710. //
  711. // Unfreeze queue if necessary
  712. //
  713. if (srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  714. DebugPrint((3, "IssueSyncAtapiCommand: Unfreeze Queue TID %d\n",
  715. srb.TargetId));
  716. //
  717. // unfreeze queue
  718. //
  719. CLRMASK (PdoExtension->LuFlags, PD_QUEUE_FROZEN);
  720. //
  721. // restart queue
  722. //
  723. KeAcquireSpinLock(&FdoExtension->SpinLock, &currentIrql);
  724. GetNextLuRequest(FdoExtension, PdoExtension);
  725. KeLowerIrql(currentIrql);
  726. }
  727. if ((srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
  728. (senseInfoBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)) {
  729. //
  730. // A sense key of illegal request was recieved. This indicates
  731. // that the mech status command is illegal.
  732. //
  733. status = STATUS_INVALID_DEVICE_REQUEST;
  734. //
  735. // The command is illegal, no point to keep trying
  736. //
  737. RetryCount = 0;
  738. }
  739. } else {
  740. status = STATUS_SUCCESS;
  741. }
  742. }
  743. //
  744. // Free buffers
  745. //
  746. ExFreePool(senseInfoBuffer);
  747. if (flushCount != 100) {
  748. DebugPrint ((DBG_ALWAYS, "IssueSyncAtapiCommand: flushCount is %u\n", flushCount));
  749. }
  750. return status;
  751. } // IssueSyncAtapiCommand
  752. ULONG
  753. IdePortQueryNonCdNumLun (
  754. IN PFDO_EXTENSION FdoExtension,
  755. IN PPDO_EXTENSION PdoExtension,
  756. IN BOOLEAN ByPassBlockedQueue
  757. )
  758. /*++
  759. Routine Description:
  760. query number of Luns a device has using the protocol
  761. defined in the ATAPI Removable Rewritable Spec (SFF-8070i)
  762. Arguments:
  763. FdoExtension - FDO extension
  764. PdoExtension - device extension of the PDO to be queried
  765. Return Value:
  766. Number of logical units
  767. --*/
  768. {
  769. PIRP irp;
  770. PIO_STACK_LOCATION irpStack;
  771. SCSI_REQUEST_BLOCK srb;
  772. CDB cdb;
  773. IO_STATUS_BLOCK ioStatusBlock;
  774. KIRQL currentIrql;
  775. NTSTATUS status;
  776. PMODE_PARAMETER_HEADER10 modeParameterHeader;
  777. PATAPI_REMOVABLE_BLOCK_ACCESS_CAPABILITIES accessCap;
  778. PATAPI_NON_CD_DRIVE_OPERATION_MODE_PAGE opMode;
  779. ULONG modePageSize;
  780. ULONG accessCapPageSize;
  781. ULONG opModePageSize;
  782. PAGED_CODE();
  783. if (IsNEC_98) {
  784. PIDENTIFY_DATA fullIdentifyData;
  785. fullIdentifyData = &FdoExtension->HwDeviceExtension->IdentifyData[PdoExtension->TargetId];
  786. if (fullIdentifyData->GeneralConfiguration & 0x80) {
  787. if (fullIdentifyData->ModelNumber[8] == 0x44 &&
  788. fullIdentifyData->ModelNumber[9] == 0x50 &&
  789. fullIdentifyData->ModelNumber[10] == 0x31 &&
  790. fullIdentifyData->ModelNumber[11] == 0x2D ) {
  791. //
  792. // Find ATAPI PD drive.
  793. //
  794. return 2;
  795. }
  796. }
  797. }
  798. //
  799. // compute the size of the mode page needed
  800. //
  801. accessCapPageSize =
  802. sizeof (MODE_PARAMETER_HEADER10) +
  803. sizeof (ATAPI_REMOVABLE_BLOCK_ACCESS_CAPABILITIES);
  804. opModePageSize =
  805. sizeof (MODE_PARAMETER_HEADER10) +
  806. sizeof (ATAPI_NON_CD_DRIVE_OPERATION_MODE_PAGE);
  807. if (sizeof(ATAPI_REMOVABLE_BLOCK_ACCESS_CAPABILITIES) >=
  808. sizeof(ATAPI_NON_CD_DRIVE_OPERATION_MODE_PAGE)) {
  809. modePageSize = accessCapPageSize;
  810. } else {
  811. modePageSize = opModePageSize;
  812. }
  813. modeParameterHeader = ExAllocatePool (
  814. NonPagedPoolCacheAligned,
  815. modePageSize
  816. );
  817. if (modeParameterHeader == NULL) {
  818. DebugPrint((DBG_ALWAYS,"QueryNonCdNumLun: Can't allocate modeParameterHeader buffer\n"));
  819. return(0);
  820. }
  821. RtlZeroMemory(modeParameterHeader, accessCapPageSize);
  822. RtlZeroMemory(&cdb, sizeof(CDB));
  823. //
  824. // Set CDB operation code.
  825. //
  826. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  827. cdb.MODE_SENSE10.PageCode = ATAPI_REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGECODE;
  828. cdb.MODE_SENSE10.Pc = MODE_SENSE_CURRENT_VALUES;
  829. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR) ((accessCapPageSize & 0xff00) >> 8);
  830. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR) ((accessCapPageSize & 0x00ff) >> 0);
  831. //
  832. // get the removable block access capabilities page
  833. //
  834. status = IssueSyncAtapiCommand (
  835. FdoExtension,
  836. PdoExtension,
  837. &cdb,
  838. modeParameterHeader,
  839. accessCapPageSize,
  840. TRUE,
  841. 3,
  842. ByPassBlockedQueue
  843. );
  844. accessCap = (PATAPI_REMOVABLE_BLOCK_ACCESS_CAPABILITIES) (modeParameterHeader + 1);
  845. if (NT_SUCCESS(status) &&
  846. (accessCap->PageCode == ATAPI_REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGECODE)) {
  847. DebugPrint ((DBG_PNP,
  848. "QueryNonCdNumLun: Removable Block Access Capabilities Page:\n"
  849. "page save bit: 0x%x\n"
  850. "format progress report support: 0x%x\n"
  851. "system floppy device: 0x%x\n"
  852. "total LUNs: 0x%x\n"
  853. "in single-Lun mode: 0x%x\n"
  854. "non-CD optical deivce: 0x%x\n",
  855. accessCap->PSBit,
  856. accessCap->SRFP,
  857. accessCap->SFLP,
  858. accessCap->TotalLun,
  859. accessCap->SML,
  860. accessCap->NCD
  861. ));
  862. if (accessCap->NCD) {
  863. //
  864. // we have a non-CD optical deivce
  865. //
  866. RtlZeroMemory(modeParameterHeader, opModePageSize);
  867. RtlZeroMemory(&cdb, sizeof(CDB));
  868. //
  869. // Set CDB operation code.
  870. //
  871. cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10;
  872. cdb.MODE_SENSE10.PageCode = ATAPI_NON_CD_DRIVE_OPERATION_MODE_PAGE_PAGECODE;
  873. cdb.MODE_SENSE10.Pc = MODE_SENSE_CURRENT_VALUES;
  874. cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR) ((opModePageSize & 0xff00) >> 8);
  875. cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR) ((opModePageSize & 0x00ff) >> 0);
  876. //
  877. // get the non-cd drive operation mode page
  878. //
  879. status = IssueSyncAtapiCommand (
  880. FdoExtension,
  881. PdoExtension,
  882. &cdb,
  883. modeParameterHeader,
  884. opModePageSize,
  885. TRUE,
  886. 3,
  887. ByPassBlockedQueue
  888. );
  889. opMode = (PATAPI_NON_CD_DRIVE_OPERATION_MODE_PAGE) (modeParameterHeader + 1);
  890. if (NT_SUCCESS(status) &&
  891. (opMode->PageCode == ATAPI_NON_CD_DRIVE_OPERATION_MODE_PAGE_PAGECODE)) {
  892. DebugPrint ((DBG_PNP,
  893. "QueryNonCdNumLun: Non-CD device Operation Mode Page:\n"
  894. "page save bit: 0x%x\n"
  895. "disable verify for write: 0x%x\n"
  896. "Lun for R/W device: 0x%x\n"
  897. "multi-Lun mode: 0x%x\n",
  898. opMode->PSBit,
  899. opMode->DVW,
  900. opMode->SLR,
  901. opMode->SLM
  902. ));
  903. RtlZeroMemory(modeParameterHeader, sizeof (MODE_PARAMETER_HEADER10));
  904. //
  905. // With mode select, this is reserved and must be 0
  906. //
  907. opMode->PSBit = 0;
  908. //
  909. // Turn on multi-lun mode
  910. //
  911. opMode->SLM = 1;
  912. //
  913. // non-CD device shall be Lun 1
  914. //
  915. opMode->SLR = 1;
  916. RtlZeroMemory(&cdb, sizeof(CDB));
  917. //
  918. // Set CDB operation code.
  919. //
  920. cdb.MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10;
  921. cdb.MODE_SELECT10.SPBit = 1; // save page
  922. cdb.MODE_SELECT10.PFBit = 1;
  923. cdb.MODE_SELECT10.ParameterListLength[0] = (UCHAR) ((opModePageSize & 0xff00) >> 8);
  924. cdb.MODE_SELECT10.ParameterListLength[1] = (UCHAR) ((opModePageSize & 0x00ff) >> 0);
  925. status = IssueSyncAtapiCommand (
  926. FdoExtension,
  927. PdoExtension,
  928. &cdb,
  929. modeParameterHeader,
  930. opModePageSize,
  931. FALSE,
  932. 3,
  933. ByPassBlockedQueue
  934. );
  935. if (!NT_SUCCESS(status)) {
  936. DebugPrint ((DBG_ALWAYS, "IdePortQueryNonCdNumLun: Unable to set non-CD device into dual Lun Mode\n"));
  937. }
  938. }
  939. }
  940. }
  941. //
  942. // Free buffers
  943. //
  944. ExFreePool(modeParameterHeader);
  945. if (!NT_SUCCESS(status)) {
  946. return 0;
  947. } else {
  948. return 2;
  949. }
  950. } // IdePortQueryNonCdNumLun
  951. VOID
  952. IdeBuildDeviceMap(
  953. IN PFDO_EXTENSION FdoExtension,
  954. IN PUNICODE_STRING ServiceKey
  955. )
  956. /*++
  957. Routine Description:
  958. The routine takes the inquiry data which has been collected and creates
  959. a device map for it.
  960. Arguments:
  961. FdoExtension - FDO extension
  962. ServiceKey - Suppiles the name of the service key.
  963. Return Value:
  964. None.
  965. --*/
  966. {
  967. UNICODE_STRING name;
  968. UNICODE_STRING unicodeString;
  969. ANSI_STRING ansiString;
  970. HANDLE key;
  971. HANDLE busKey;
  972. HANDLE targetKey;
  973. HANDLE lunKey;
  974. OBJECT_ATTRIBUTES objectAttributes;
  975. NTSTATUS status;
  976. ULONG disposition;
  977. PWSTR start;
  978. WCHAR buffer[32];
  979. UCHAR lastTarget;
  980. ULONG i;
  981. ULONG dmaEnableMask;
  982. PCSTR peripheralType;
  983. UCHAR lastBus;
  984. IDE_PATH_ID pathId;
  985. IN PPDO_EXTENSION pdoExtension;
  986. PAGED_CODE();
  987. //
  988. // Create the SCSI key in the device map.
  989. //
  990. RtlInitUnicodeString(&name,
  991. L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
  992. //
  993. // Initialize the object for the key.
  994. //
  995. InitializeObjectAttributes(&objectAttributes,
  996. &name,
  997. OBJ_CASE_INSENSITIVE,
  998. NULL,
  999. (PSECURITY_DESCRIPTOR) NULL);
  1000. //
  1001. // Create the key or open it.
  1002. //
  1003. status = ZwCreateKey(&lunKey,
  1004. KEY_READ | KEY_WRITE,
  1005. &objectAttributes,
  1006. 0,
  1007. (PUNICODE_STRING) NULL,
  1008. REG_OPTION_VOLATILE,
  1009. &disposition );
  1010. if (!NT_SUCCESS(status)) {
  1011. return;
  1012. }
  1013. status = IdeCreateNumericKey(lunKey,
  1014. FdoExtension->ScsiPortNumber,
  1015. L"Scsi Port ",
  1016. &key);
  1017. ZwClose(lunKey);
  1018. if (!NT_SUCCESS(status)) {
  1019. return;
  1020. }
  1021. #ifdef IDE_MEASURE_BUSSCAN_SPEED
  1022. RtlInitUnicodeString(&name, L"FirstBusScanTimeInMs");
  1023. status = ZwSetValueKey(key,
  1024. &name,
  1025. 0,
  1026. REG_DWORD,
  1027. &FdoExtension->BusScanTime,
  1028. sizeof(ULONG));
  1029. #endif // IDE_MEASURE_BUSSCAN_SPEED
  1030. //
  1031. // Add DMA enable mask value.
  1032. //
  1033. dmaEnableMask = 0;
  1034. for (i=0; i<FdoExtension->HwDeviceExtension->MaxIdeDevice; i++) {
  1035. if (FdoExtension->HwDeviceExtension->DeviceFlags[i] & DFLAGS_USE_DMA) {
  1036. dmaEnableMask |= (1 << i);
  1037. }
  1038. }
  1039. RtlInitUnicodeString(&name, L"DMAEnabled");
  1040. status = ZwSetValueKey(key,
  1041. &name,
  1042. 0,
  1043. REG_DWORD,
  1044. &dmaEnableMask,
  1045. 4);
  1046. //
  1047. // Add Interrupt value.
  1048. //
  1049. // if (FdoExtension->InterruptLevel) {
  1050. //
  1051. // RtlInitUnicodeString(&name, L"Interrupt");
  1052. //
  1053. // status = ZwSetValueKey(key,
  1054. // &name,
  1055. // 0,
  1056. // REG_DWORD,
  1057. // &FdoExtension->InterruptLevel,
  1058. // 4);
  1059. // }
  1060. //
  1061. // //
  1062. // // Add base IO address value.
  1063. // //
  1064. //
  1065. // if (FdoExtension->IdeResource.TranslatedCommandBaseAddress) {
  1066. //
  1067. // RtlInitUnicodeString(&name, L"IOAddress");
  1068. //
  1069. // status = ZwSetValueKey(key,
  1070. // &name,
  1071. // 0,
  1072. // REG_DWORD,
  1073. // &FdoExtension->IdeResource.TranslatedCommandBaseAddress,
  1074. // 4);
  1075. // }
  1076. if (ServiceKey != NULL) {
  1077. //
  1078. // Add identifier value. This value is equal to the name of the driver
  1079. // in the from the service key. Note the service key name is not NULL
  1080. // terminated.
  1081. //
  1082. RtlInitUnicodeString(&name, L"Driver");
  1083. //
  1084. // Get the name of the driver from the service key name.
  1085. //
  1086. start = (PWSTR) ((PCHAR) ServiceKey->Buffer + ServiceKey->Length);
  1087. start--;
  1088. while (*start != L'\\' && start > ServiceKey->Buffer) {
  1089. start--;
  1090. }
  1091. if (*start != L'\\') {
  1092. ZwClose(key);
  1093. return;
  1094. }
  1095. start++;
  1096. for (i = 0; i < 31; i++) {
  1097. buffer[i] = *start++;
  1098. if (start >= ServiceKey->Buffer + ServiceKey->Length / sizeof(wchar_t)) {
  1099. break;
  1100. }
  1101. }
  1102. i++;
  1103. buffer[i] = L'\0';
  1104. status = ZwSetValueKey(key,
  1105. &name,
  1106. 0,
  1107. REG_SZ,
  1108. buffer,
  1109. (i + 1) * sizeof(wchar_t));
  1110. if (!NT_SUCCESS(status)) {
  1111. ZwClose(key);
  1112. return;
  1113. }
  1114. }
  1115. //
  1116. // Cycle through each of the lun.
  1117. //
  1118. lastBus = 0xff;
  1119. pathId.l = 0;
  1120. busKey = 0;
  1121. targetKey = 0;
  1122. lunKey = 0;
  1123. while (pdoExtension = NextLogUnitExtensionWithTag (
  1124. FdoExtension,
  1125. &pathId,
  1126. FALSE,
  1127. IdeBuildDeviceMap
  1128. )) {
  1129. //
  1130. // Create a key entry for the bus.
  1131. //
  1132. if (lastBus != pathId.b.Path) {
  1133. if (busKey) {
  1134. ZwClose(busKey);
  1135. busKey = 0;
  1136. }
  1137. if (targetKey) {
  1138. ZwClose(targetKey);
  1139. targetKey = 0;
  1140. }
  1141. status = IdeCreateNumericKey(key, pathId.b.Path, L"Scsi Bus ", &busKey);
  1142. if (!NT_SUCCESS(status)) {
  1143. break;
  1144. }
  1145. lastBus = (UCHAR) pathId.b.Path;
  1146. //
  1147. // Create a key entry for the Scsi bus adapter.
  1148. //
  1149. status = IdeCreateNumericKey(busKey,
  1150. IDE_PSUEDO_INITIATOR_ID,
  1151. L"Initiator Id ",
  1152. &targetKey);
  1153. if (!NT_SUCCESS(status)) {
  1154. break;
  1155. }
  1156. lastTarget = IDE_PSUEDO_INITIATOR_ID;
  1157. }
  1158. //
  1159. // Process the data for the logical units.
  1160. //
  1161. //
  1162. // If this is a new target Id then create a new target entry.
  1163. //
  1164. if (lastTarget != pdoExtension->TargetId) {
  1165. ZwClose(targetKey);
  1166. targetKey = 0;
  1167. status = IdeCreateNumericKey(busKey,
  1168. pdoExtension->TargetId,
  1169. L"Target Id ",
  1170. &targetKey);
  1171. if (!NT_SUCCESS(status)) {
  1172. break;
  1173. }
  1174. lastTarget = pdoExtension->TargetId;
  1175. }
  1176. //
  1177. // Create the Lun entry.
  1178. //
  1179. status = IdeCreateNumericKey(targetKey,
  1180. pdoExtension->Lun,
  1181. L"Logical Unit Id ",
  1182. &lunKey);
  1183. if (!NT_SUCCESS(status)) {
  1184. break;
  1185. }
  1186. //
  1187. // Create identifier value.
  1188. //
  1189. RtlInitUnicodeString(&name, L"Identifier");
  1190. //
  1191. // Get the Identifier from the inquiry data.
  1192. //
  1193. RtlInitAnsiString(&ansiString, pdoExtension->FullVendorProductId);
  1194. status = RtlAnsiStringToUnicodeString(&unicodeString,
  1195. &ansiString,
  1196. TRUE);
  1197. if (!NT_SUCCESS(status)) {
  1198. break;
  1199. }
  1200. status = ZwSetValueKey(lunKey,
  1201. &name,
  1202. 0,
  1203. REG_SZ,
  1204. unicodeString.Buffer,
  1205. unicodeString.Length + sizeof(wchar_t));
  1206. RtlFreeUnicodeString(&unicodeString);
  1207. if (!NT_SUCCESS(status)) {
  1208. break;
  1209. }
  1210. //
  1211. // Determine the perpherial type.
  1212. //
  1213. peripheralType = IdePortGetPeripheralIdString (
  1214. pdoExtension->ScsiDeviceType
  1215. );
  1216. if (!peripheralType) {
  1217. peripheralType = "OtherPeripheral";
  1218. }
  1219. RtlInitAnsiString(&ansiString, peripheralType);
  1220. unicodeString.MaximumLength = (USHORT) RtlAnsiStringToUnicodeSize(&ansiString) + sizeof(WCHAR);
  1221. unicodeString.Length = 0;
  1222. unicodeString.Buffer = ExAllocatePool (PagedPool, unicodeString.MaximumLength);
  1223. if (unicodeString.Buffer) {
  1224. status = RtlAnsiStringToUnicodeString(
  1225. &unicodeString,
  1226. &ansiString,
  1227. FALSE
  1228. );
  1229. if (NT_SUCCESS(status)) {
  1230. //
  1231. // Set type value.
  1232. //
  1233. RtlInitUnicodeString(&name, L"Type");
  1234. unicodeString.Buffer[unicodeString.Length / sizeof (WCHAR)] = L'\0';
  1235. status = ZwSetValueKey(lunKey,
  1236. &name,
  1237. 0,
  1238. REG_SZ,
  1239. unicodeString.Buffer,
  1240. unicodeString.Length + sizeof (WCHAR));
  1241. ExFreePool (unicodeString.Buffer);
  1242. }
  1243. } else {
  1244. status = STATUS_NO_MEMORY;
  1245. }
  1246. ZwClose(lunKey);
  1247. lunKey = 0;
  1248. if (!NT_SUCCESS(status)) {
  1249. break;
  1250. }
  1251. UnrefLogicalUnitExtensionWithTag (
  1252. FdoExtension,
  1253. pdoExtension,
  1254. IdeBuildDeviceMap
  1255. );
  1256. pdoExtension = NULL;
  1257. }
  1258. if (lunKey) {
  1259. ZwClose(lunKey);
  1260. }
  1261. if (busKey) {
  1262. ZwClose(busKey);
  1263. }
  1264. if (targetKey) {
  1265. ZwClose(targetKey);
  1266. }
  1267. if (pdoExtension) {
  1268. UnrefLogicalUnitExtensionWithTag (
  1269. FdoExtension,
  1270. pdoExtension,
  1271. IdeBuildDeviceMap
  1272. );
  1273. }
  1274. ZwClose(key);
  1275. } // IdeBuildDeviceMap
  1276. NTSTATUS
  1277. IdeCreateNumericKey(
  1278. IN HANDLE Root,
  1279. IN ULONG Name,
  1280. IN PWSTR Prefix,
  1281. OUT PHANDLE NewKey
  1282. )
  1283. /*++
  1284. Routine Description:
  1285. This function creates a registry key. The name of the key is a string
  1286. version of numeric value passed in.
  1287. Arguments:
  1288. RootKey - Supplies a handle to the key where the new key should be inserted.
  1289. Name - Supplies the numeric value to name the key.
  1290. Prefix - Supplies a prefix name to add to name.
  1291. NewKey - Returns the handle for the new key.
  1292. Return Value:
  1293. Returns the status of the operation.
  1294. --*/
  1295. {
  1296. UNICODE_STRING string;
  1297. UNICODE_STRING stringNum;
  1298. OBJECT_ATTRIBUTES objectAttributes;
  1299. WCHAR bufferNum[16];
  1300. WCHAR buffer[64];
  1301. ULONG disposition;
  1302. NTSTATUS status;
  1303. PAGED_CODE();
  1304. //
  1305. // Copy the Prefix into a string.
  1306. //
  1307. string.Length = 0;
  1308. string.MaximumLength=64;
  1309. string.Buffer = buffer;
  1310. RtlInitUnicodeString(&stringNum, Prefix);
  1311. RtlCopyUnicodeString(&string, &stringNum);
  1312. //
  1313. // Create a port number key entry.
  1314. //
  1315. stringNum.Length = 0;
  1316. stringNum.MaximumLength = 16;
  1317. stringNum.Buffer = bufferNum;
  1318. status = RtlIntegerToUnicodeString(Name, 10, &stringNum);
  1319. if (!NT_SUCCESS(status)) {
  1320. return status;
  1321. }
  1322. //
  1323. // Append the prefix and the numeric name.
  1324. //
  1325. RtlAppendUnicodeStringToString(&string, &stringNum);
  1326. InitializeObjectAttributes( &objectAttributes,
  1327. &string,
  1328. OBJ_CASE_INSENSITIVE,
  1329. Root,
  1330. (PSECURITY_DESCRIPTOR) NULL );
  1331. status = ZwCreateKey(NewKey,
  1332. KEY_READ | KEY_WRITE,
  1333. &objectAttributes,
  1334. 0,
  1335. (PUNICODE_STRING) NULL,
  1336. REG_OPTION_VOLATILE,
  1337. &disposition );
  1338. return(status);
  1339. } // IdeCreateNumericKey