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.

698 lines
18 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: luext.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "ideport.h"
  11. static ULONG IdeDeviceUniqueId = 0;
  12. PPDO_EXTENSION
  13. RefPdo(
  14. PDEVICE_OBJECT PhysicalDeviceObject,
  15. BOOLEAN RemovedOk
  16. DECLARE_EXTRA_DEBUG_PARAMETER(PVOID, Tag)
  17. )
  18. {
  19. PPDO_EXTENSION pdoExtension;
  20. PPDO_EXTENSION pdoExtension2Return;
  21. KIRQL currentIrql;
  22. pdoExtension = PhysicalDeviceObject->DeviceExtension;
  23. KeAcquireSpinLock(&pdoExtension->PdoSpinLock, &currentIrql);
  24. pdoExtension2Return = RefPdoWithSpinLockHeldWithTag(
  25. PhysicalDeviceObject,
  26. RemovedOk,
  27. Tag
  28. );
  29. if (pdoExtension2Return) {
  30. ASSERT(pdoExtension2Return == pdoExtension);
  31. }
  32. KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
  33. return pdoExtension2Return;
  34. } // RefPdo()
  35. PPDO_EXTENSION
  36. RefPdoWithSpinLockHeld(
  37. PDEVICE_OBJECT PhysicalDeviceObject,
  38. BOOLEAN RemovedOk
  39. DECLARE_EXTRA_DEBUG_PARAMETER(PVOID, Tag)
  40. )
  41. {
  42. PPDO_EXTENSION pdoExtension;
  43. KIRQL currentIrql;
  44. pdoExtension = PhysicalDeviceObject->DeviceExtension;
  45. if (!(pdoExtension->PdoState & (PDOS_REMOVED | PDOS_DEADMEAT | PDOS_SURPRISE_REMOVED)) ||
  46. RemovedOk) {
  47. IdeInterlockedIncrement (
  48. pdoExtension,
  49. &pdoExtension->ReferenceCount,
  50. Tag
  51. );
  52. } else {
  53. pdoExtension = NULL;
  54. }
  55. return pdoExtension;
  56. } // RefPdoWithSpinLockHeld()
  57. VOID
  58. UnrefPdo(
  59. PPDO_EXTENSION PdoExtension
  60. DECLARE_EXTRA_DEBUG_PARAMETER(PVOID, Tag)
  61. )
  62. {
  63. UnrefLogicalUnitExtensionWithTag(
  64. PdoExtension->ParentDeviceExtension,
  65. PdoExtension,
  66. Tag
  67. );
  68. }
  69. PPDO_EXTENSION
  70. RefLogicalUnitExtension(
  71. PFDO_EXTENSION DeviceExtension,
  72. UCHAR PathId,
  73. UCHAR TargetId,
  74. UCHAR Lun,
  75. BOOLEAN RemovedOk
  76. DECLARE_EXTRA_DEBUG_PARAMETER(PVOID, Tag)
  77. )
  78. /*++
  79. Routine Description:
  80. Walk logical unit extension list looking for
  81. extension with matching target id.
  82. Arguments:
  83. deviceExtension
  84. TargetId
  85. Return Value:
  86. Requested logical unit extension if found,
  87. else NULL.
  88. --*/
  89. {
  90. PPDO_EXTENSION pdoExtension;
  91. PPDO_EXTENSION pdoExtension2Return = NULL;
  92. KIRQL currentIrql;
  93. if (TargetId >= DeviceExtension->HwDeviceExtension->MaxIdeTargetId) {
  94. return NULL;
  95. }
  96. KeAcquireSpinLock(&DeviceExtension->LogicalUnitListSpinLock, &currentIrql);
  97. pdoExtension = DeviceExtension->LogicalUnitList[(TargetId + Lun) % NUMBER_LOGICAL_UNIT_BINS];
  98. while (pdoExtension && !(pdoExtension->TargetId == TargetId &&
  99. pdoExtension->Lun == Lun &&
  100. pdoExtension->PathId == PathId)) {
  101. pdoExtension = pdoExtension->NextLogicalUnit;
  102. }
  103. if (pdoExtension) {
  104. pdoExtension2Return = RefPdoWithTag(
  105. pdoExtension->DeviceObject,
  106. RemovedOk,
  107. Tag
  108. );
  109. }
  110. KeReleaseSpinLock(&DeviceExtension->LogicalUnitListSpinLock, currentIrql);
  111. return pdoExtension2Return;
  112. } // end RefLogicalUnitExtension()
  113. VOID
  114. UnrefLogicalUnitExtension(
  115. PFDO_EXTENSION FdoExtension,
  116. PPDO_EXTENSION PdoExtension
  117. DECLARE_EXTRA_DEBUG_PARAMETER(PVOID, Tag)
  118. )
  119. {
  120. KIRQL currentIrql;
  121. LONG refCount;
  122. BOOLEAN deletePdo = FALSE;
  123. ULONG lockCount;
  124. ASSERT (PdoExtension);
  125. if (PdoExtension) {
  126. KeAcquireSpinLock(&PdoExtension->PdoSpinLock, &currentIrql);
  127. ASSERT(PdoExtension->ReferenceCount > 0);
  128. lockCount = IdeInterlockedDecrement (
  129. PdoExtension,
  130. &PdoExtension->ReferenceCount,
  131. Tag
  132. );
  133. // ASSERT(lockCount >= 0);
  134. if (lockCount <= 0) {
  135. if ((PdoExtension->PdoState & PDOS_DEADMEAT) &&
  136. (PdoExtension->PdoState & PDOS_REMOVED)) {
  137. deletePdo = TRUE;
  138. }
  139. }
  140. KeReleaseSpinLock(&PdoExtension->PdoSpinLock, currentIrql);
  141. if (deletePdo) {
  142. // IoDeleteDevice (PdoExtension->DeviceObject);
  143. KeSetEvent (&PdoExtension->RemoveEvent, 0, FALSE);
  144. }
  145. }
  146. } // UnrefLogicalUnitExtension();
  147. PPDO_EXTENSION
  148. AllocatePdo(
  149. IN PFDO_EXTENSION FdoExtension,
  150. IN IDE_PATH_ID PathId
  151. DECLARE_EXTRA_DEBUG_PARAMETER(PVOID, Tag)
  152. )
  153. /*++
  154. Routine Description:
  155. Create logical unit extension.
  156. Arguments:
  157. DeviceExtension
  158. PathId
  159. Return Value:
  160. Logical unit extension
  161. --*/
  162. {
  163. PDEVICE_OBJECT physicalDeviceObject;
  164. KIRQL currentIrql;
  165. PPDO_EXTENSION pdoExtension;
  166. ULONG size;
  167. ULONG bin;
  168. ULONG uniqueId;
  169. NTSTATUS status;
  170. UNICODE_STRING deviceName;
  171. WCHAR deviceNameBuffer[64];
  172. PAGED_CODE();
  173. uniqueId = InterlockedIncrement (&IdeDeviceUniqueId) - 1;
  174. swprintf(deviceNameBuffer, DEVICE_OJBECT_BASE_NAME L"\\IdeDeviceP%dT%dL%d-%x",
  175. FdoExtension->IdePortNumber,
  176. PathId.b.TargetId,
  177. PathId.b.Lun,
  178. uniqueId
  179. );
  180. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  181. physicalDeviceObject = DeviceCreatePhysicalDeviceObject (
  182. FdoExtension->DriverObject,
  183. FdoExtension,
  184. &deviceName
  185. );
  186. if (physicalDeviceObject == NULL) {
  187. DebugPrint ((DBG_ALWAYS, "ATAPI: Unable to create device object\n", deviceNameBuffer));
  188. return NULL;
  189. }
  190. pdoExtension = physicalDeviceObject->DeviceExtension;
  191. pdoExtension->AttacherDeviceObject = physicalDeviceObject;
  192. pdoExtension->PathId = (UCHAR) PathId.b.Path;
  193. pdoExtension->TargetId = (UCHAR) PathId.b.TargetId;
  194. pdoExtension->Lun = (UCHAR) PathId.b.Lun;
  195. //
  196. // Set timer counters in LogicalUnits to -1 to indicate no
  197. // outstanding requests.
  198. //
  199. pdoExtension->RequestTimeoutCounter = -1;
  200. //
  201. // This logical unit is be initialized
  202. //
  203. pdoExtension->LuFlags |= PD_RESCAN_ACTIVE;
  204. //
  205. // Allocate spin lock for critical sections.
  206. //
  207. KeInitializeSpinLock(&pdoExtension->PdoSpinLock);
  208. //
  209. // Initialize the request list.
  210. //
  211. InitializeListHead(&pdoExtension->SrbData.RequestList);
  212. //
  213. // Initialize a event
  214. //
  215. KeInitializeEvent (
  216. &pdoExtension->RemoveEvent,
  217. NotificationEvent,
  218. FALSE
  219. );
  220. //
  221. // Link logical unit extension on list.
  222. //
  223. bin = (PathId.b.TargetId + PathId.b.Lun) % NUMBER_LOGICAL_UNIT_BINS;
  224. //
  225. // get spinlock for accessing the logical unit extension bin
  226. //
  227. KeAcquireSpinLock(&FdoExtension->LogicalUnitListSpinLock, &currentIrql);
  228. pdoExtension->NextLogicalUnit =
  229. FdoExtension->LogicalUnitList[bin];
  230. //
  231. // Open the Command Log
  232. //
  233. IdeLogOpenCommandLog(&pdoExtension->SrbData);
  234. FdoExtension->LogicalUnitList[bin] = pdoExtension;
  235. FdoExtension->NumberOfLogicalUnits++;
  236. FdoExtension->NumberOfLogicalUnitsPowerUp++;
  237. IdeInterlockedIncrement (
  238. pdoExtension,
  239. &pdoExtension->ReferenceCount,
  240. Tag
  241. );
  242. KeReleaseSpinLock(&FdoExtension->LogicalUnitListSpinLock, currentIrql);
  243. return pdoExtension;
  244. } // end CreateLogicalUnitExtension()
  245. NTSTATUS
  246. FreePdo(
  247. IN PPDO_EXTENSION PdoExtension,
  248. IN BOOLEAN Sync,
  249. IN BOOLEAN CallIoDeleteDevice
  250. DECLARE_EXTRA_DEBUG_PARAMETER(PVOID, Tag)
  251. )
  252. {
  253. PFDO_EXTENSION fdoExtension;
  254. PPDO_EXTENSION pdoExtension;
  255. KIRQL currentIrql;
  256. PLOGICAL_UNIT_EXTENSION lastPdoExtension;
  257. ULONG targetId;
  258. ULONG lun;
  259. LONG refCount;
  260. NTSTATUS status;
  261. targetId = PdoExtension->TargetId;
  262. lun = PdoExtension->Lun;
  263. fdoExtension = PdoExtension->ParentDeviceExtension;
  264. lastPdoExtension = NULL;
  265. //
  266. // get spinlock for accessing the logical unit extension bin
  267. //
  268. KeAcquireSpinLock(&fdoExtension->LogicalUnitListSpinLock, &currentIrql);
  269. pdoExtension = fdoExtension->LogicalUnitList[(targetId + lun) % NUMBER_LOGICAL_UNIT_BINS];
  270. while (pdoExtension != NULL) {
  271. if (pdoExtension == PdoExtension) {
  272. if (lastPdoExtension == NULL) {
  273. //
  274. // Remove from head of list.
  275. //
  276. fdoExtension->LogicalUnitList[(targetId + lun) % NUMBER_LOGICAL_UNIT_BINS] =
  277. pdoExtension->NextLogicalUnit;
  278. } else {
  279. lastPdoExtension->NextLogicalUnit = pdoExtension->NextLogicalUnit;
  280. }
  281. ASSERT (!(pdoExtension->PdoState & PDOS_LEGACY_ATTACHER));
  282. if (pdoExtension->ReferenceCount > 1) {
  283. DebugPrint ((0,
  284. "IdePort FreePdo: pdoe 0x%x ReferenceCount is 0x%x\n",
  285. pdoExtension,
  286. pdoExtension->ReferenceCount));
  287. }
  288. fdoExtension->NumberOfLogicalUnits--;
  289. //
  290. // only if pdo is freed while it is powered up
  291. //
  292. if (pdoExtension->DevicePowerState <= PowerDeviceD0) {
  293. fdoExtension->NumberOfLogicalUnitsPowerUp--;
  294. }
  295. KeReleaseSpinLock(&fdoExtension->LogicalUnitListSpinLock, currentIrql);
  296. break;
  297. }
  298. lastPdoExtension = pdoExtension;
  299. pdoExtension = pdoExtension->NextLogicalUnit;
  300. }
  301. if (pdoExtension) {
  302. ASSERT (pdoExtension == PdoExtension);
  303. KeAcquireSpinLock(&pdoExtension->PdoSpinLock, &currentIrql);
  304. //
  305. // better not attached by a legacy device
  306. //
  307. ASSERT (!(pdoExtension->PdoState & PDOS_LEGACY_ATTACHER));
  308. //
  309. // lower the refer count for the caller
  310. // and save the new refCount
  311. //
  312. ASSERT(pdoExtension->ReferenceCount > 0);
  313. refCount = IdeInterlockedDecrement (
  314. pdoExtension,
  315. &pdoExtension->ReferenceCount,
  316. Tag
  317. );
  318. //
  319. // no more new request
  320. //
  321. pdoExtension->PdoState |= PDOS_DEADMEAT | PDOS_REMOVED;
  322. KeReleaseSpinLock(&pdoExtension->PdoSpinLock, currentIrql);
  323. //
  324. // remove idle detection timer if any
  325. //
  326. DeviceUnregisterIdleDetection (PdoExtension);
  327. //
  328. // free acpi data
  329. //
  330. if (PdoExtension->AcpiDeviceSettings) {
  331. ExFreePool(PdoExtension->AcpiDeviceSettings);
  332. PdoExtension->AcpiDeviceSettings = NULL;
  333. }
  334. //
  335. // flush the requests in the queue
  336. //
  337. IdePortFlushLogicalUnit (
  338. fdoExtension,
  339. PdoExtension,
  340. TRUE
  341. );
  342. if (refCount) {
  343. if (Sync) {
  344. status = KeWaitForSingleObject(&pdoExtension->RemoveEvent,
  345. Executive,
  346. KernelMode,
  347. FALSE,
  348. NULL);
  349. }
  350. }
  351. if (CallIoDeleteDevice) {
  352. //
  353. // Free command log if it was allocated
  354. //
  355. IdeLogFreeCommandLog(&PdoExtension->SrbData);
  356. IoDeleteDevice (pdoExtension->DeviceObject);
  357. }
  358. return STATUS_SUCCESS;
  359. } else {
  360. KeReleaseSpinLock(&fdoExtension->LogicalUnitListSpinLock, currentIrql);
  361. if (CallIoDeleteDevice) {
  362. DebugPrint ((
  363. DBG_PNP,
  364. "ideport: deleting device 0x%x that was PROBABLY surprise removed\n",
  365. PdoExtension->DeviceObject
  366. ));
  367. //ASSERT (PdoExtension->PdoState & PDOS_SURPRISE_REMOVED);
  368. //
  369. // delete the device if it wasn't removed before.
  370. // PDOS_REMOVED could be set, if the device was surprise
  371. // removed. In that case remove the device
  372. //
  373. if (!(PdoExtension->PdoState & PDOS_REMOVED) ||
  374. PdoExtension->PdoState & PDOS_SURPRISE_REMOVED) {
  375. //
  376. // Free command log if it was allocated
  377. //
  378. IdeLogFreeCommandLog(&PdoExtension->SrbData);
  379. IoDeleteDevice (PdoExtension->DeviceObject);
  380. }
  381. }
  382. return STATUS_SUCCESS;
  383. }
  384. } // end FreeLogicalUnitExtension()
  385. PLOGICAL_UNIT_EXTENSION
  386. NextLogUnitExtension(
  387. IN PFDO_EXTENSION FdoExtension,
  388. IN OUT PIDE_PATH_ID PathId,
  389. IN BOOLEAN RemovedOk
  390. DECLARE_EXTRA_DEBUG_PARAMETER(PVOID, Tag)
  391. )
  392. {
  393. PLOGICAL_UNIT_EXTENSION logUnitExtension;
  394. logUnitExtension = NULL;
  395. for (;
  396. !logUnitExtension && (PathId->b.Path < MAX_IDE_PATH);
  397. PathId->b.Path++, PathId->b.TargetId = 0) {
  398. for (;
  399. !logUnitExtension && (PathId->b.TargetId < FdoExtension->HwDeviceExtension->MaxIdeTargetId);
  400. PathId->b.TargetId++, PathId->b.Lun = 0) {
  401. logUnitExtension = RefLogicalUnitExtensionWithTag (
  402. FdoExtension,
  403. (UCHAR) PathId->b.Path,
  404. (UCHAR) PathId->b.TargetId,
  405. (UCHAR) PathId->b.Lun,
  406. RemovedOk,
  407. Tag
  408. );
  409. if (logUnitExtension) {
  410. //
  411. // increment lun for the next time around
  412. //
  413. PathId->b.Lun++;
  414. return logUnitExtension;
  415. }
  416. //
  417. // Assume Lun number never skips.
  418. // If we can't find the logical unit extension for a lun,
  419. // will go to the next target ID with lun 0
  420. //
  421. }
  422. }
  423. return NULL;
  424. } // end NextLogicalUnitExtension()
  425. VOID
  426. KillPdo(
  427. IN PPDO_EXTENSION PdoExtension
  428. )
  429. {
  430. KIRQL currentIrql;
  431. ASSERT (PdoExtension);
  432. KeAcquireSpinLock(&PdoExtension->PdoSpinLock, &currentIrql);
  433. ASSERT (!(PdoExtension->PdoState & PDOS_DEADMEAT));
  434. SETMASK (PdoExtension->PdoState, PDOS_DEADMEAT);
  435. IdeLogDeadMeatReason( PdoExtension->DeadmeatRecord.Reason,
  436. byKilledPdo
  437. );
  438. KeReleaseSpinLock(&PdoExtension->PdoSpinLock, currentIrql);
  439. }
  440. #if DBG
  441. PVOID IdePortInterestedLockTag=NULL;
  442. LONG
  443. IdeInterlockedIncrement (
  444. IN PPDO_EXTENSION PdoExtension,
  445. IN PLONG Addend,
  446. IN PVOID Tag
  447. )
  448. {
  449. ULONG i;
  450. KIRQL currentIrql;
  451. DebugPrint ((
  452. DBG_PDO_LOCKTAG,
  453. ">>>>>>>>>>>>>>>>>>>> Acquire PdoLock with tag = 0x%x\n",
  454. Tag
  455. ));
  456. if (IdePortInterestedLockTag == Tag) {
  457. DebugPrint ((DBG_ALWAYS, "Found the interested lock tag 0x%x\n", Tag));
  458. DbgBreakPoint();
  459. }
  460. KeAcquireSpinLock(&PdoExtension->RefCountSpinLock, &currentIrql);
  461. if (PdoExtension->NumTagUsed >= TAG_TABLE_SIZE) {
  462. DebugPrint ((DBG_ALWAYS, "Used up all %d tag\n", TAG_TABLE_SIZE));
  463. DbgBreakPoint();
  464. }
  465. for (i=0; i<PdoExtension->NumTagUsed; i++) {
  466. if (PdoExtension->TagTable[i] == Tag) {
  467. DebugPrint ((DBG_ALWAYS, "Tag 0x%x already in used\n", Tag));
  468. DbgBreakPoint();
  469. }
  470. }
  471. PdoExtension->TagTable[PdoExtension->NumTagUsed] = Tag;
  472. PdoExtension->NumTagUsed++;
  473. KeReleaseSpinLock(&PdoExtension->RefCountSpinLock, currentIrql);
  474. return InterlockedIncrement (Addend);
  475. }
  476. LONG
  477. IdeInterlockedDecrement (
  478. IN PPDO_EXTENSION PdoExtension,
  479. IN PLONG Addend,
  480. IN PVOID Tag
  481. )
  482. {
  483. ULONG i;
  484. KIRQL currentIrql;
  485. BOOLEAN foundTag;
  486. DebugPrint ((
  487. DBG_PDO_LOCKTAG,
  488. ">>>>>>>>>>>>>>>>>>>> Release PdoLock with tag = 0x%x\n",
  489. Tag
  490. ));
  491. KeAcquireSpinLock(&PdoExtension->RefCountSpinLock, &currentIrql);
  492. for (i=0, foundTag=FALSE; i<PdoExtension->NumTagUsed; i++) {
  493. if (PdoExtension->TagTable[i] == Tag) {
  494. if (PdoExtension->NumTagUsed > 1) {
  495. PdoExtension->TagTable[i] =
  496. PdoExtension->TagTable[PdoExtension->NumTagUsed - 1];
  497. }
  498. PdoExtension->NumTagUsed--;
  499. foundTag = TRUE;
  500. break;
  501. }
  502. }
  503. if (!foundTag) {
  504. DebugPrint ((DBG_ALWAYS, "Unable to find tag 0x%x\n", Tag));
  505. DbgBreakPoint();
  506. }
  507. KeReleaseSpinLock(&PdoExtension->RefCountSpinLock, currentIrql);
  508. return InterlockedDecrement (Addend);
  509. }
  510. #endif //DBG