Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1381 lines
37 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. pdo.c
  5. Abstract:
  6. This module contains the dispatch routines for scsiport's physical device
  7. objects
  8. Authors:
  9. Peter Wieland
  10. Environment:
  11. Kernel mode only
  12. Notes:
  13. Revision History:
  14. --*/
  15. #define KEEP_COMPLETE_REQUEST
  16. #include "port.h"
  17. #define __FILE_ID__ 'pdo '
  18. #if DBG
  19. static const char *__file__ = __FILE__;
  20. #endif
  21. LONG SpPowerIdleTimeout = -1; // use system default
  22. NTSTATUS
  23. SpPagingPathNotificationCompletion(
  24. IN PDEVICE_OBJECT DeviceObject,
  25. IN PIRP LowerIrp,
  26. IN PDEVICE_OBJECT Fdo
  27. );
  28. #ifdef ALLOC_PRAGMA
  29. #pragma alloc_text(PAGE, ScsiPortPdoPnp)
  30. #pragma alloc_text(PAGE, ScsiPortPdoCreateClose)
  31. #pragma alloc_text(PAGE, ScsiPortStartLogicalUnit)
  32. #endif
  33. NTSTATUS
  34. ScsiPortPdoDeviceControl(
  35. IN PDEVICE_OBJECT Pdo,
  36. IN PIRP Irp
  37. )
  38. /*++
  39. Routine Description:
  40. This routine handles device control requests for scsi target devices
  41. Arguments:
  42. Pdo - a pointer to the physical device object
  43. Irp - a pointer to the io request packet
  44. Return Value:
  45. status
  46. --*/
  47. {
  48. PLOGICAL_UNIT_EXTENSION physicalExtension = Pdo->DeviceExtension;
  49. PCOMMON_EXTENSION commonExtension = Pdo->DeviceExtension;
  50. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  51. ULONG ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
  52. NTSTATUS status;
  53. BOOLEAN completeRequest = TRUE;
  54. ULONG isRemoved;
  55. isRemoved = SpAcquireRemoveLock(Pdo, Irp);
  56. if(isRemoved) {
  57. SpReleaseRemoveLock(Pdo, Irp);
  58. Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
  59. SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT);
  60. return STATUS_DEVICE_DOES_NOT_EXIST;
  61. }
  62. ASSERT(commonExtension->IsPdo);
  63. Irp->IoStatus.Status = 0;
  64. switch(ioControlCode) {
  65. case IOCTL_STORAGE_QUERY_PROPERTY: {
  66. //
  67. // Validate the query
  68. //
  69. PSTORAGE_PROPERTY_QUERY query = Irp->AssociatedIrp.SystemBuffer;
  70. if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
  71. sizeof(STORAGE_PROPERTY_QUERY)) {
  72. status = STATUS_INVALID_PARAMETER;
  73. break;
  74. }
  75. status = ScsiPortQueryProperty(Pdo, Irp);
  76. return status;
  77. break;
  78. }
  79. case IOCTL_SCSI_GET_ADDRESS: {
  80. PSCSI_ADDRESS scsiAddress = Irp->AssociatedIrp.SystemBuffer;
  81. if(irpStack->Parameters.DeviceIoControl.OutputBufferLength <
  82. sizeof(SCSI_ADDRESS)) {
  83. status = STATUS_BUFFER_TOO_SMALL;
  84. break;
  85. }
  86. scsiAddress->Length = sizeof(PSCSI_ADDRESS);
  87. scsiAddress->PortNumber = (UCHAR) physicalExtension->PortNumber;
  88. scsiAddress->PathId = physicalExtension->PathId;
  89. scsiAddress->TargetId = physicalExtension->TargetId;
  90. scsiAddress->Lun = physicalExtension->Lun;
  91. Irp->IoStatus.Information = sizeof(SCSI_ADDRESS);
  92. status = STATUS_SUCCESS;
  93. break;
  94. }
  95. //
  96. // XXX - need to handle
  97. //
  98. // IOCTL_STORAGE_PASS_THROUGH
  99. // IOCTL_STORAGE_PASS_THROUGH_DIRECT
  100. //
  101. case IOCTL_SCSI_PASS_THROUGH:
  102. case IOCTL_SCSI_PASS_THROUGH_DIRECT: {
  103. PSCSI_PASS_THROUGH srbControl = Irp->AssociatedIrp.SystemBuffer;
  104. if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
  105. sizeof(SCSI_PASS_THROUGH)) {
  106. status = STATUS_BUFFER_TOO_SMALL;
  107. break;
  108. }
  109. srbControl->PathId = physicalExtension->PathId;
  110. srbControl->TargetId = physicalExtension->TargetId;
  111. srbControl->Lun = physicalExtension->Lun;
  112. //
  113. // Fall through to the default handler
  114. //
  115. }
  116. default: {
  117. IoSkipCurrentIrpStackLocation(Irp);
  118. SpReleaseRemoveLock(Pdo, Irp);
  119. status = IoCallDriver(commonExtension->LowerDeviceObject, Irp);
  120. completeRequest = FALSE;
  121. }
  122. }
  123. if(completeRequest) {
  124. Irp->IoStatus.Status = status;
  125. SpReleaseRemoveLock(Pdo, Irp);
  126. SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT);
  127. }
  128. return status;
  129. }
  130. NTSTATUS
  131. ScsiPortPdoPnp(
  132. IN PDEVICE_OBJECT LogicalUnit,
  133. IN PIRP Irp
  134. )
  135. /*++
  136. Routine Description:
  137. This routine handles pnp-power requests. Currently it will just be
  138. successful
  139. Arguments:
  140. LogicalUnit - pointer to the physical device object
  141. Irp - pointer to the io request packet
  142. Return Value:
  143. status
  144. --*/
  145. {
  146. PLOGICAL_UNIT_EXTENSION logicalUnitExtension = LogicalUnit->DeviceExtension;
  147. PCOMMON_EXTENSION commonExtension = LogicalUnit->DeviceExtension;
  148. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  149. static ULONG i = 0;
  150. NTSTATUS status = STATUS_SUCCESS;
  151. ULONG isRemoved;
  152. PAGED_CODE();
  153. isRemoved = SpAcquireRemoveLock(LogicalUnit, Irp);
  154. #if 0
  155. if(isRemoved != ) {
  156. ASSERT(isRemoved != REMOVE_PENDING);
  157. status = STATUS_DEVICE_DOES_NOT_EXIST;
  158. Irp->IoStatus.Status = status;
  159. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  160. return status;
  161. }
  162. #else
  163. ASSERT(isRemoved != REMOVE_COMPLETE);
  164. #endif
  165. switch(irpStack->MinorFunction) {
  166. case IRP_MN_QUERY_PNP_DEVICE_STATE: {
  167. //
  168. // If the device is in the paging path then mark it as
  169. // not-disableable.
  170. //
  171. PPNP_DEVICE_STATE deviceState =
  172. (PPNP_DEVICE_STATE) &(Irp->IoStatus.Information);
  173. DebugPrint((1, "ScsiPortPdoPnp: QUERY_DEVICE_STATE for PDO %#x\n", LogicalUnit));
  174. if(commonExtension->PagingPathCount != 0) {
  175. SET_FLAG((*deviceState), PNP_DEVICE_NOT_DISABLEABLE);
  176. DebugPrint((1, "ScsiPortPdoPnp: QUERY_DEVICE_STATE: %#x - not disableable\n",
  177. LogicalUnit));
  178. }
  179. Irp->IoStatus.Status = STATUS_SUCCESS;
  180. SpReleaseRemoveLock(LogicalUnit, Irp);
  181. SpCompleteRequest(LogicalUnit, Irp, NULL, IO_NO_INCREMENT);
  182. return STATUS_SUCCESS;
  183. }
  184. case IRP_MN_START_DEVICE: {
  185. if(commonExtension->CurrentPnpState == IRP_MN_START_DEVICE) {
  186. Irp->IoStatus.Status = STATUS_SUCCESS;
  187. break;
  188. }
  189. if(commonExtension->IsInitialized == FALSE) {
  190. status = ScsiPortInitLogicalUnit(logicalUnitExtension);
  191. }
  192. if(NT_SUCCESS(status)) {
  193. commonExtension->IsInitialized = TRUE;
  194. status = ScsiPortStartLogicalUnit(logicalUnitExtension);
  195. }
  196. if(NT_SUCCESS(status)) {
  197. commonExtension->CurrentPnpState = IRP_MN_START_DEVICE;
  198. commonExtension->PreviousPnpState = 0xff;
  199. }
  200. Irp->IoStatus.Status = status;
  201. break;
  202. }
  203. case IRP_MN_QUERY_ID: {
  204. UCHAR rawIdString[64] = "UNKNOWN ID TYPE";
  205. ANSI_STRING ansiIdString;
  206. UNICODE_STRING unicodeIdString;
  207. BOOLEAN multiStrings;
  208. PINQUIRYDATA inquiryData = &(logicalUnitExtension->InquiryData);
  209. //
  210. // We've been asked for the id of one of the physical device objects
  211. //
  212. DebugPrint((2, "ScsiPortPnp: got IRP_MN_QUERY_ID\n"));
  213. RtlInitUnicodeString(&unicodeIdString, NULL);
  214. RtlInitAnsiString(&ansiIdString, NULL);
  215. switch(irpStack->Parameters.QueryId.IdType) {
  216. case BusQueryDeviceID: {
  217. status = ScsiPortGetDeviceId(LogicalUnit, &unicodeIdString);
  218. multiStrings = FALSE;
  219. break;
  220. }
  221. case BusQueryInstanceID: {
  222. status = ScsiPortGetInstanceId(LogicalUnit, &unicodeIdString);
  223. multiStrings = FALSE;
  224. break;
  225. }
  226. case BusQueryHardwareIDs: {
  227. status = ScsiPortGetHardwareIds(
  228. LogicalUnit->DriverObject,
  229. &(logicalUnitExtension->InquiryData),
  230. &unicodeIdString);
  231. multiStrings = TRUE;
  232. break;
  233. }
  234. case BusQueryCompatibleIDs: {
  235. status = ScsiPortGetCompatibleIds(
  236. LogicalUnit->DriverObject,
  237. &(logicalUnitExtension->InquiryData),
  238. &unicodeIdString);
  239. multiStrings = TRUE;
  240. break;
  241. }
  242. default: {
  243. status = Irp->IoStatus.Status;
  244. Irp->IoStatus.Information = 0;
  245. multiStrings = FALSE;
  246. break;
  247. }
  248. }
  249. Irp->IoStatus.Status = status;
  250. if(NT_SUCCESS(status)) {
  251. PWCHAR idString;
  252. //
  253. // fix up all invalid characters
  254. //
  255. idString = unicodeIdString.Buffer;
  256. while (*idString) {
  257. if ((*idString <= L' ') ||
  258. (*idString > (WCHAR)0x7F) ||
  259. (*idString == L',')) {
  260. *idString = L'_';
  261. }
  262. idString++;
  263. if ((*idString == L'\0') && multiStrings) {
  264. idString++;
  265. }
  266. }
  267. Irp->IoStatus.Information = (ULONG_PTR) unicodeIdString.Buffer;
  268. } else {
  269. Irp->IoStatus.Information = (ULONG_PTR) NULL;
  270. }
  271. SpReleaseRemoveLock(LogicalUnit, Irp);
  272. SpCompleteRequest(LogicalUnit, Irp, NULL, IO_NO_INCREMENT);
  273. return status;
  274. break;
  275. }
  276. case IRP_MN_QUERY_RESOURCES:
  277. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: {
  278. Irp->IoStatus.Status = STATUS_SUCCESS;
  279. Irp->IoStatus.Information = (ULONG_PTR) NULL;
  280. SpReleaseRemoveLock(LogicalUnit, Irp);
  281. SpCompleteRequest(LogicalUnit, Irp, NULL, IO_NO_INCREMENT);
  282. return STATUS_SUCCESS;
  283. }
  284. case IRP_MN_SURPRISE_REMOVAL:
  285. case IRP_MN_REMOVE_DEVICE: {
  286. BOOLEAN destroyed;
  287. //
  288. // Release the lock for this IRP before going in.
  289. //
  290. if(commonExtension->IsRemoved == NO_REMOVE) {
  291. commonExtension->IsRemoved = REMOVE_PENDING;
  292. }
  293. SpReleaseRemoveLock(LogicalUnit, Irp);
  294. destroyed = SpRemoveLogicalUnit(logicalUnitExtension,
  295. irpStack->MinorFunction);
  296. if(destroyed) {
  297. commonExtension->PreviousPnpState =
  298. commonExtension->CurrentPnpState;
  299. commonExtension->CurrentPnpState = irpStack->MinorFunction;
  300. } else {
  301. commonExtension->CurrentPnpState = 0xff;
  302. commonExtension->PreviousPnpState = irpStack->MinorFunction;
  303. }
  304. status = STATUS_SUCCESS;
  305. Irp->IoStatus.Status = status;
  306. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  307. return status;
  308. }
  309. case IRP_MN_QUERY_DEVICE_TEXT: {
  310. Irp->IoStatus.Status =
  311. SpQueryDeviceText(
  312. LogicalUnit,
  313. irpStack->Parameters.QueryDeviceText.DeviceTextType,
  314. irpStack->Parameters.QueryDeviceText.LocaleId,
  315. (PWSTR *) &Irp->IoStatus.Information
  316. );
  317. break;
  318. }
  319. case IRP_MN_QUERY_CAPABILITIES: {
  320. PDEVICE_CAPABILITIES capabilities =
  321. irpStack->Parameters.DeviceCapabilities.Capabilities;
  322. PSCSIPORT_DEVICE_TYPE deviceType = NULL;
  323. capabilities->RawDeviceOK = 1;
  324. deviceType = SpGetDeviceTypeInfo(
  325. logicalUnitExtension->InquiryData.DeviceType
  326. );
  327. if((deviceType != NULL) && (deviceType->IsStorage)) {
  328. capabilities->SilentInstall = 1;
  329. }
  330. capabilities->Address = logicalUnitExtension->TargetId;
  331. Irp->IoStatus.Status = STATUS_SUCCESS;
  332. break;
  333. }
  334. case IRP_MN_QUERY_STOP_DEVICE:
  335. case IRP_MN_QUERY_REMOVE_DEVICE: {
  336. if ((commonExtension->PagingPathCount != 0) ||
  337. (logicalUnitExtension->IsLegacyClaim == TRUE)) {
  338. Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  339. } else {
  340. Irp->IoStatus.Status = STATUS_SUCCESS;
  341. commonExtension->PreviousPnpState =
  342. commonExtension->CurrentPnpState;
  343. commonExtension->CurrentPnpState = irpStack->MinorFunction;
  344. }
  345. break;
  346. }
  347. case IRP_MN_CANCEL_STOP_DEVICE: {
  348. if(commonExtension->CurrentPnpState == IRP_MN_QUERY_STOP_DEVICE) {
  349. commonExtension->CurrentPnpState =
  350. commonExtension->PreviousPnpState;
  351. commonExtension->PreviousPnpState = 0xff;
  352. }
  353. Irp->IoStatus.Status = STATUS_SUCCESS;
  354. break;
  355. }
  356. case IRP_MN_CANCEL_REMOVE_DEVICE: {
  357. if(commonExtension->CurrentPnpState == IRP_MN_QUERY_REMOVE_DEVICE) {
  358. commonExtension->CurrentPnpState =
  359. commonExtension->PreviousPnpState;
  360. commonExtension->PreviousPnpState = 0xff;
  361. }
  362. Irp->IoStatus.Status = STATUS_SUCCESS;
  363. break;
  364. }
  365. case IRP_MN_STOP_DEVICE: {
  366. ASSERT(commonExtension->CurrentPnpState == IRP_MN_QUERY_STOP_DEVICE);
  367. status = ScsiPortStopLogicalUnit(logicalUnitExtension);
  368. ASSERT(NT_SUCCESS(status));
  369. Irp->IoStatus.Status = status;
  370. Irp->IoStatus.Information = (ULONG_PTR) NULL;
  371. if(NT_SUCCESS(status)) {
  372. commonExtension->CurrentPnpState = IRP_MN_STOP_DEVICE;
  373. commonExtension->PreviousPnpState = 0xff;
  374. }
  375. SpReleaseRemoveLock(LogicalUnit, Irp);
  376. SpCompleteRequest(LogicalUnit, Irp, NULL, IO_NO_INCREMENT);
  377. return status;
  378. }
  379. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  380. PDEVICE_RELATIONS deviceRelations;
  381. if(irpStack->Parameters.QueryDeviceRelations.Type !=
  382. TargetDeviceRelation) {
  383. break;
  384. }
  385. //
  386. // DEVICE_RELATIONS definition contains one object pointer.
  387. //
  388. deviceRelations = SpAllocatePool(PagedPool,
  389. sizeof(DEVICE_RELATIONS),
  390. SCSIPORT_TAG_DEVICE_RELATIONS,
  391. LogicalUnit->DriverObject);
  392. if(deviceRelations == NULL) {
  393. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  394. break;
  395. }
  396. RtlZeroMemory(deviceRelations, sizeof(DEVICE_RELATIONS));
  397. deviceRelations->Count = 1;
  398. deviceRelations->Objects[0] = LogicalUnit;
  399. ObReferenceObject(deviceRelations->Objects[0]);
  400. Irp->IoStatus.Status = STATUS_SUCCESS;
  401. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  402. break;
  403. }
  404. case IRP_MN_DEVICE_USAGE_NOTIFICATION: {
  405. PIRP newIrp;
  406. PIO_STACK_LOCATION nextStack;
  407. DebugPrint((1, "Pdo - IRP_MN_DEVICE_USAGE_NOTIFICATION %#p received for "
  408. "logical unit %#p\n",
  409. Irp,
  410. LogicalUnit));
  411. newIrp = SpAllocateIrp(
  412. commonExtension->LowerDeviceObject->StackSize,
  413. FALSE,
  414. LogicalUnit->DriverObject);
  415. if(newIrp == NULL) {
  416. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  417. break;
  418. }
  419. newIrp->AssociatedIrp.MasterIrp = Irp;
  420. newIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  421. nextStack = IoGetNextIrpStackLocation(newIrp);
  422. *nextStack = *IoGetCurrentIrpStackLocation(Irp);
  423. IoSetCompletionRoutine(newIrp,
  424. SpPagingPathNotificationCompletion,
  425. commonExtension->LowerDeviceObject,
  426. TRUE,
  427. TRUE,
  428. TRUE);
  429. status = IoCallDriver(commonExtension->LowerDeviceObject,
  430. newIrp);
  431. return status;
  432. break;
  433. }
  434. }
  435. SpReleaseRemoveLock(LogicalUnit, Irp);
  436. status = Irp->IoStatus.Status;
  437. SpCompleteRequest(LogicalUnit, Irp, NULL, IO_NO_INCREMENT);
  438. return status;
  439. }
  440. NTSTATUS
  441. SpPagingPathNotificationCompletion(
  442. IN PDEVICE_OBJECT DeviceObject,
  443. IN PIRP LowerIrp,
  444. IN PDEVICE_OBJECT Fdo
  445. )
  446. {
  447. PIRP upperIrp = LowerIrp->AssociatedIrp.MasterIrp;
  448. PIO_STACK_LOCATION lowerStack = IoGetCurrentIrpStackLocation(LowerIrp);
  449. PIO_STACK_LOCATION upperStack = IoGetCurrentIrpStackLocation(upperIrp);
  450. PDEVICE_OBJECT pdo = upperStack->DeviceObject;
  451. PADAPTER_EXTENSION lowerExtension;
  452. PLOGICAL_UNIT_EXTENSION upperExtension;
  453. ASSERT(Fdo != NULL);
  454. ASSERT(pdo != NULL);
  455. DebugPrint((1, "Completion - IRP_MN_DEVICE_USAGE_NOTIFICATION: Completion of "
  456. "paging notification irp %#p sent due to irp %#p\n",
  457. LowerIrp, upperIrp));
  458. lowerExtension = (PADAPTER_EXTENSION) Fdo->DeviceExtension;
  459. upperExtension = (PLOGICAL_UNIT_EXTENSION) pdo->DeviceExtension;
  460. ASSERT_FDO(lowerExtension->DeviceObject);
  461. ASSERT_PDO(upperExtension->DeviceObject);
  462. DebugPrint((1, "Completion - IRP_MN_DEVICE_USAGE_NOTIFICATION: irp status %#08lx\n",
  463. LowerIrp->IoStatus.Status));
  464. if(NT_SUCCESS(LowerIrp->IoStatus.Status)) {
  465. PUCHAR typeName = "INSERT TYPE HERE";
  466. PULONG lowerCount;
  467. PULONG upperCount;
  468. //
  469. // The parameters have already been erased from the lower irp stack
  470. // location - use the parameters from the upper once since they're
  471. // just a copy.
  472. //
  473. switch(upperStack->Parameters.UsageNotification.Type) {
  474. case DeviceUsageTypePaging: {
  475. lowerCount = &(lowerExtension->CommonExtension.PagingPathCount);
  476. upperCount = &(upperExtension->CommonExtension.PagingPathCount);
  477. typeName = "PagingPathCount";
  478. break;
  479. }
  480. case DeviceUsageTypeHibernation: {
  481. lowerCount = &(lowerExtension->CommonExtension.HibernatePathCount);
  482. upperCount = &(upperExtension->CommonExtension.HibernatePathCount);
  483. typeName = "HibernatePathCount";
  484. break;
  485. }
  486. case DeviceUsageTypeDumpFile: {
  487. lowerCount = &(lowerExtension->CommonExtension.DumpPathCount);
  488. upperCount = &(upperExtension->CommonExtension.DumpPathCount);
  489. typeName = "DumpPathCount";
  490. break;
  491. }
  492. default: {
  493. typeName = "unknown type";
  494. lowerCount = upperCount = NULL;
  495. break;
  496. }
  497. }
  498. if(lowerCount != NULL) {
  499. IoAdjustPagingPathCount(
  500. lowerCount,
  501. upperStack->Parameters.UsageNotification.InPath
  502. );
  503. DebugPrint((1, "Completion - IRP_MN_DEVICE_USAGE_NOTIFICATION: "
  504. "Fdo %s count - %d\n",
  505. typeName, *lowerCount));
  506. IoInvalidateDeviceState(lowerExtension->LowerPdo);
  507. }
  508. if(upperCount != NULL) {
  509. IoAdjustPagingPathCount(
  510. upperCount,
  511. upperStack->Parameters.UsageNotification.InPath
  512. );
  513. DebugPrint((1, "Completion - IRP_MN_DEVICE_USAGE_NOTIFICATION: "
  514. "Pdo %s count - %d\n",
  515. typeName, *upperCount));
  516. IoInvalidateDeviceState(upperExtension->DeviceObject);
  517. }
  518. }
  519. upperIrp->IoStatus = LowerIrp->IoStatus;
  520. SpReleaseRemoveLock(upperExtension->CommonExtension.DeviceObject, upperIrp);
  521. SpCompleteRequest(upperExtension->CommonExtension.DeviceObject,
  522. upperIrp,
  523. NULL,
  524. IO_NO_INCREMENT);
  525. IoFreeIrp(LowerIrp);
  526. return STATUS_MORE_PROCESSING_REQUIRED;
  527. }
  528. NTSTATUS
  529. ScsiPortPdoCreateClose(
  530. IN PDEVICE_OBJECT Pdo,
  531. IN PIRP Irp
  532. )
  533. /*++
  534. Routine Description:
  535. This routine handles creates and closes for bus device pdo's
  536. Arguments:
  537. Pdo - a pointer to the physical device object
  538. Irp - a pointer to the io request packet
  539. Return Value:
  540. status
  541. --*/
  542. {
  543. PLOGICAL_UNIT_EXTENSION logicalUnit = Pdo->DeviceExtension;
  544. ULONG isRemoved;
  545. NTSTATUS status = STATUS_SUCCESS;
  546. PAGED_CODE();
  547. ASSERT_PDO(Pdo);
  548. isRemoved = SpAcquireRemoveLock(Pdo, Irp);
  549. if(IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_CREATE) {
  550. if(isRemoved) {
  551. status = STATUS_DEVICE_DOES_NOT_EXIST;
  552. } else if(logicalUnit->IsTemporary == TRUE) {
  553. status = STATUS_DEVICE_NOT_READY;
  554. }
  555. }
  556. Irp->IoStatus.Status = status;
  557. SpReleaseRemoveLock(Pdo, Irp);
  558. SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT);
  559. return status;
  560. }
  561. NTSTATUS
  562. ScsiPortScsi1PdoScsi(
  563. IN PDEVICE_OBJECT Pdo,
  564. IN PIRP Irp
  565. )
  566. /*++
  567. Routine Description:
  568. This routine is a wrapper around ScsiPortPdoScsi. It inserts the LUN number
  569. into the CDB before calling the generic version. this is for use with
  570. older target controllers which don't pay attention to the identify message
  571. sent before the command phase.
  572. Arguments:
  573. Pdo - a pointer to the physical device object
  574. Irp - a pointer to the io request packet
  575. Return Value:
  576. status
  577. --*/
  578. {
  579. PLOGICAL_UNIT_EXTENSION lun = Pdo->DeviceExtension;
  580. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  581. PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
  582. //
  583. // NOTICE: The SCSI-II specification indicates that this field should be
  584. // zero; however, some target controllers ignore the logical unit number
  585. // in the INDENTIFY message and only look at the logical unit number field
  586. // in the CDB.
  587. //
  588. srb->Cdb[1] |= lun->Lun << 5;
  589. return ScsiPortPdoScsi(Pdo, Irp);
  590. }
  591. NTSTATUS
  592. ScsiPortPdoScsi(
  593. IN PDEVICE_OBJECT Pdo,
  594. IN PIRP Irp
  595. )
  596. /*++
  597. Routine Description:
  598. This routine dispatches SRB's for a particular target device. It will fill
  599. in the Port, Path, Target and Lun values and then forward the request
  600. through to the FDO for the bus
  601. Arguments:
  602. Pdo - a pointer to the physical device object
  603. Irp - a pointer to the io request packet
  604. Return Value:
  605. status
  606. --*/
  607. {
  608. PLOGICAL_UNIT_EXTENSION lun = Pdo->DeviceExtension;
  609. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  610. #if DBG
  611. PDRIVER_OBJECT lowerDriverObject =
  612. lun->CommonExtension.LowerDeviceObject->DriverObject;
  613. #endif
  614. PSCSI_REQUEST_BLOCK srb = irpStack->Parameters.Scsi.Srb;
  615. ULONG isRemoved;
  616. PSRB_DATA srbData;
  617. BOOLEAN isLock = FALSE;
  618. NTSTATUS status;
  619. isRemoved = SpAcquireRemoveLock(Pdo, Irp);
  620. if(isRemoved &&
  621. !IS_CLEANUP_REQUEST(irpStack) &&
  622. (srb->Function != SRB_FUNCTION_CLAIM_DEVICE)) {
  623. Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
  624. SpReleaseRemoveLock(Pdo, Irp);
  625. SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT);
  626. return STATUS_DEVICE_DOES_NOT_EXIST;
  627. }
  628. srb->PathId = lun->PathId;
  629. srb->TargetId = lun->TargetId;
  630. srb->Lun = lun->Lun;
  631. //
  632. // Queue tags should be assigned only by the StartIo routine. Set it to
  633. // a benign value here so we can tell later on that we don't have to
  634. // clear the tag value in the bitmap.
  635. //
  636. srb->QueueTag = SP_UNTAGGED;
  637. #if DBG
  638. ASSERT(lowerDriverObject->MajorFunction[IRP_MJ_SCSI] != NULL);
  639. ASSERT(lowerDriverObject->MajorFunction[IRP_MJ_SCSI] == ScsiPortGlobalDispatch);
  640. #endif
  641. switch(srb->Function) {
  642. case SRB_FUNCTION_ABORT_COMMAND: {
  643. status = STATUS_NOT_SUPPORTED;
  644. break;
  645. }
  646. case SRB_FUNCTION_CLAIM_DEVICE:
  647. case SRB_FUNCTION_REMOVE_DEVICE: {
  648. status = SpClaimLogicalUnit(
  649. lun->CommonExtension.LowerDeviceObject->DeviceExtension,
  650. lun,
  651. Irp,
  652. FALSE);
  653. break;
  654. }
  655. case SRB_FUNCTION_UNLOCK_QUEUE:
  656. case SRB_FUNCTION_LOCK_QUEUE: {
  657. SpStartLockRequest(lun, Irp);
  658. return STATUS_PENDING;
  659. }
  660. case SRB_FUNCTION_RELEASE_QUEUE:
  661. case SRB_FUNCTION_FLUSH_QUEUE: {
  662. srbData = SpAllocateBypassSrbData(lun);
  663. ASSERT(srbData != NULL);
  664. goto RunSrb;
  665. }
  666. default: {
  667. if(TEST_FLAG(srb->SrbFlags, (SRB_FLAGS_BYPASS_LOCKED_QUEUE |
  668. SRB_FLAGS_BYPASS_FROZEN_QUEUE))) {
  669. srbData = SpAllocateBypassSrbData(lun);
  670. ASSERT(srbData != NULL);
  671. } else {
  672. srbData = SpAllocateSrbData( lun->AdapterExtension, Irp);
  673. if(srbData == NULL) {
  674. //
  675. // There wasn't an SRB_DATA block available for this
  676. // request so it's been queued waiting for resources -
  677. // leave the logical unit remove-locked and return pending.
  678. //
  679. DebugPrint((1, "ScsiPortPdoScsi: Insufficient resources "
  680. "to allocate SRB_DATA structure\n"));
  681. return STATUS_PENDING;
  682. }
  683. }
  684. RunSrb:
  685. srbData->CurrentIrp = Irp;
  686. srbData->CurrentSrb = srb;
  687. srbData->LogicalUnit = lun;
  688. srb->OriginalRequest = srbData;
  689. return SpDispatchRequest(lun, Irp);
  690. }
  691. }
  692. Irp->IoStatus.Status = status;
  693. SpReleaseRemoveLock(Pdo, Irp);
  694. SpCompleteRequest(Pdo, Irp, NULL, IO_NO_INCREMENT);
  695. return status;
  696. }
  697. NTSTATUS
  698. ScsiPortStartLogicalUnit(
  699. IN PLOGICAL_UNIT_EXTENSION LogicalUnit
  700. )
  701. /*++
  702. Routine Description:
  703. This routine will attempt to start the specified device object.
  704. Currently this involves clearing the INITIALIZING flag if it was set,
  705. and running through to the device node and marking itself as started. This
  706. last is a kludge
  707. Arguments:
  708. LogicalUnit - a pointer to the PDO being started
  709. Return Value:
  710. status
  711. --*/
  712. {
  713. PADAPTER_EXTENSION adapterExtension = LogicalUnit->AdapterExtension;
  714. HANDLE instanceHandle;
  715. NTSTATUS status;
  716. PAGED_CODE();
  717. //
  718. // Open the devnode for this PDO and see if anyone's given us some
  719. // default SRB flags.
  720. //
  721. status = IoOpenDeviceRegistryKey(LogicalUnit->DeviceObject,
  722. PLUGPLAY_REGKEY_DEVICE,
  723. KEY_READ,
  724. &instanceHandle);
  725. if(NT_SUCCESS(status)) {
  726. RTL_QUERY_REGISTRY_TABLE queryTable[2];
  727. ULONG zero = 0;
  728. RtlZeroMemory(queryTable, sizeof(queryTable));
  729. queryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
  730. queryTable[0].Name = L"DefaultRequestFlags";
  731. queryTable[0].EntryContext = &(LogicalUnit->CommonExtension.SrbFlags);
  732. queryTable[0].DefaultType = REG_DWORD;
  733. queryTable[0].DefaultData = &zero;
  734. queryTable[0].DefaultLength = sizeof(ULONG);
  735. status = RtlQueryRegistryValues(
  736. RTL_REGISTRY_HANDLE | RTL_REGISTRY_OPTIONAL,
  737. (PWSTR) instanceHandle,
  738. queryTable,
  739. NULL,
  740. NULL);
  741. //
  742. // CODEWORK: need a way to turn off tagged queuing and caching. Ie.
  743. // keep track of negative flags as well.
  744. //
  745. LogicalUnit->CommonExtension.SrbFlags &=
  746. ( SRB_FLAGS_DISABLE_DISCONNECT |
  747. SRB_FLAGS_DISABLE_SYNCH_TRANSFER |
  748. SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
  749. DebugPrint((1, "SpStartDevice: Default SRB flags for (%d,%d,%d) are "
  750. "%#08lx\n",
  751. LogicalUnit->PathId,
  752. LogicalUnit->TargetId,
  753. LogicalUnit->Lun,
  754. LogicalUnit->CommonExtension.SrbFlags));
  755. ZwClose(instanceHandle);
  756. } else {
  757. DebugPrint((1, "SpStartDevice: Error opening instance key for pdo "
  758. "[%#08lx]\n",
  759. status));
  760. }
  761. //
  762. // If the queue is locked then unlock it to start i/o processing.
  763. //
  764. if(LogicalUnit->QueueLockCount > 0) {
  765. status = SpLockUnlockQueue(LogicalUnit->DeviceObject,
  766. FALSE,
  767. TRUE);
  768. }
  769. return status;
  770. }
  771. NTSTATUS
  772. ScsiPortInitLogicalUnit(
  773. IN PLOGICAL_UNIT_EXTENSION LogicalUnit
  774. )
  775. /*++
  776. Routine Description:
  777. This routine will attempt to start the specified device object.
  778. Arguments:
  779. DeviceObject - a pointer to the PDO being started
  780. Return Value:
  781. status
  782. --*/
  783. {
  784. PCOMMON_EXTENSION commonExtension = &(LogicalUnit->CommonExtension);
  785. PADAPTER_EXTENSION adapterExtension = LogicalUnit->AdapterExtension;
  786. HANDLE instanceHandle;
  787. NTSTATUS status = STATUS_SUCCESS;
  788. PAGED_CODE();
  789. //
  790. // Initialize the idle detection timer. Tell the system to put us into a
  791. // D3 state when we're not being used.
  792. //
  793. LogicalUnit->CommonExtension.IdleTimer =
  794. PoRegisterDeviceForIdleDetection(LogicalUnit->DeviceObject,
  795. SpPowerIdleTimeout,
  796. SpPowerIdleTimeout,
  797. PowerDeviceD3);
  798. //
  799. // Now that we have a LUN, we can initialize WMI support for the adapter if
  800. // the miniport supports WMI. This may be a re-register if we've already
  801. // registered on behalf of scsiport itself. We have to wait until we have
  802. // a LUN when the miniport supports WMI because we send it an SRB to do
  803. // its own initialization. We can't send it an SRB until we have a logical
  804. // unit.
  805. //
  806. if (adapterExtension->CommonExtension.WmiMiniPortInitialized == FALSE &&
  807. adapterExtension->CommonExtension.WmiMiniPortSupport == TRUE) {
  808. ULONG action;
  809. //
  810. // Decide whether we are registering or reregistering WMI for the FDO.
  811. //
  812. action = (adapterExtension->CommonExtension.WmiInitialized == FALSE) ?
  813. WMIREG_ACTION_REGISTER : WMIREG_ACTION_REREGISTER;
  814. //
  815. // Register/reregister. We can get WMI irps as soon as we do this.
  816. //
  817. IoWMIRegistrationControl(adapterExtension->DeviceObject, action);
  818. adapterExtension->CommonExtension.WmiMiniPortInitialized = TRUE;
  819. adapterExtension->CommonExtension.WmiInitialized = TRUE;
  820. }
  821. //
  822. // Initialize WMI support.
  823. //
  824. if (commonExtension->WmiInitialized == FALSE) {
  825. //
  826. // Build the SCSIPORT WMI registration information buffer for this PDO.
  827. //
  828. SpWmiInitializeSpRegInfo(LogicalUnit->DeviceObject);
  829. //
  830. // Register this device object only if the miniport supports WMI and/or
  831. // SCSIPORT will support certain WMI GUIDs on behalf of the miniport.
  832. //
  833. if (commonExtension->WmiMiniPortSupport ||
  834. commonExtension->WmiScsiPortRegInfoBuf) {
  835. //
  836. // Register this physical device object as a WMI data provider,
  837. // instructing WMI that it is ready to receive WMI IRPs.
  838. //
  839. IoWMIRegistrationControl(LogicalUnit->DeviceObject, WMIREG_ACTION_REGISTER);
  840. commonExtension->WmiInitialized = TRUE;
  841. }
  842. //
  843. // Allocate several WMI_MINIPORT_REQUEST_ITEM blocks to satisfy a
  844. // potential onslaught of WMIEvent notifications by the miniport.
  845. //
  846. if (commonExtension->WmiMiniPortSupport) {
  847. //
  848. // Currently we only allocate two per new SCSI target (PDO).
  849. //
  850. SpWmiInitializeFreeRequestList(LogicalUnit->DeviceObject, 2);
  851. }
  852. }
  853. //
  854. // Build a device map entry for this logical unit.
  855. //
  856. SpBuildDeviceMapEntry(commonExtension);
  857. return status;
  858. }
  859. VOID
  860. SpStartLockRequest(
  861. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  862. IN PIRP Irp OPTIONAL
  863. )
  864. /*++
  865. Routine Description:
  866. This routine is responsible for queueing, starting or restarting a lock
  867. request.
  868. If Irp is provided then it will dispatched iff no existing lock or unlock
  869. request is already running. If one is already running this request will
  870. be queued.
  871. If Irp is not provided then the next request on the LockRequestQueue will
  872. be removed and dispatched.
  873. This routine relies on the device queue to provide synchronization. Since
  874. we can only have one request get past the device queue at any given time we
  875. should only have one call at any given time with Irp set to NULL.
  876. Arguments:
  877. LogicalUnit - the logical unit to which this lock request was sent.
  878. Irp - the irp for the lock request.
  879. Return Value:
  880. none
  881. --*/
  882. {
  883. KIRQL oldIrql;
  884. PIO_STACK_LOCATION irpStack;
  885. PSCSI_REQUEST_BLOCK srb;
  886. PSRB_DATA srbData;
  887. BOOLEAN lock;
  888. oldIrql = KeRaiseIrqlToDpcLevel();
  889. //
  890. // If no IRP was provided then get one out of the device queue.
  891. // Otherwise make sure the device queue is not busy.
  892. //
  893. if(Irp == NULL) {
  894. PKDEVICE_QUEUE_ENTRY entry;
  895. ASSERT(LogicalUnit->CurrentLockRequest != NULL);
  896. LogicalUnit->CurrentLockRequest = NULL;
  897. entry = KeRemoveDeviceQueue(&(LogicalUnit->LockRequestQueue));
  898. if(entry == NULL) {
  899. //
  900. // No more requests have come in while processing this one -
  901. // we can just return.
  902. //
  903. KeLowerIrql(oldIrql);
  904. return;
  905. } else {
  906. Irp = CONTAINING_RECORD(entry,
  907. IRP,
  908. Tail.Overlay.DeviceQueueEntry);
  909. irpStack = IoGetCurrentIrpStackLocation(Irp);
  910. srb = irpStack->Parameters.Scsi.Srb;
  911. lock = (srb->Function == SRB_FUNCTION_LOCK_QUEUE);
  912. }
  913. } else {
  914. irpStack = IoGetCurrentIrpStackLocation(Irp);
  915. srb = irpStack->Parameters.Scsi.Srb;
  916. lock = (srb->Function == SRB_FUNCTION_LOCK_QUEUE);
  917. DebugPrint((2, "SpStartLockRequest: called to %s queue %#p\n",
  918. lock ? "lock" : "unlock",
  919. LogicalUnit));
  920. //
  921. // See if we can let this request keep processing or if we'll
  922. // have to queue it.
  923. //
  924. IoMarkIrpPending(Irp);
  925. if(KeInsertDeviceQueue(&(LogicalUnit->LockRequestQueue),
  926. &(Irp->Tail.Overlay.DeviceQueueEntry))) {
  927. KeLowerIrql(oldIrql);
  928. return;
  929. }
  930. }
  931. ASSERT(Irp != NULL);
  932. ASSERT(LogicalUnit->CurrentLockRequest == NULL);
  933. //
  934. // This srb function is only valid as part of a power up request
  935. // and will be ignored if the power state is D0.
  936. //
  937. CLEAR_FLAG(srb->SrbFlags, SRB_FLAGS_QUEUE_ACTION_ENABLE);
  938. SET_FLAG(srb->SrbFlags, SRB_FLAGS_BYPASS_LOCKED_QUEUE);
  939. //
  940. // Throw this request down so it gets processed as a real
  941. // request. We need to get the completion dpc to start
  942. // things running again. there are too many flags to set
  943. // to do it from here.
  944. //
  945. DebugPrint((2, "SpStartLockRequest: %s %#p into "
  946. "queue %#p ... issuing request\n",
  947. lock ? "lock" : "unlock", srb, LogicalUnit));
  948. //
  949. // There are four bypass srb data blocks available - we should have at most
  950. // one lock request awaiting completion and the one we're about to start
  951. // so this call should never, ever fail.
  952. //
  953. srbData = SpAllocateBypassSrbData(LogicalUnit);
  954. ASSERT(srbData != NULL);
  955. //
  956. // Set the current lock request. As long as this is cleared
  957. // before the next item is removed from the queue everything
  958. // will be happy.
  959. //
  960. ASSERT(LogicalUnit->CurrentLockRequest == NULL);
  961. LogicalUnit->CurrentLockRequest = srbData;
  962. srbData->CurrentIrp = Irp;
  963. srbData->CurrentSrb = srb;
  964. srbData->LogicalUnit = LogicalUnit;
  965. srb->OriginalRequest = srbData;
  966. SpDispatchRequest(LogicalUnit, Irp);
  967. KeLowerIrql(oldIrql);
  968. return;
  969. }