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.

4705 lines
133 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. enum.c
  5. Abstract:
  6. This module contains device enumeration code for the scsi port driver
  7. Authors:
  8. Peter Wieland
  9. Environment:
  10. Kernel mode only
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include "port.h"
  15. #define __FILE_ID__ 'enum'
  16. ULONG EnumDebug = 2;
  17. #if DBG
  18. static const char *__file__ = __FILE__;
  19. #endif
  20. #define MINIMUM_BUS_SCAN_INTERVAL ((ULONGLONG) (30 * SECONDS))
  21. ULONG BreakOnTarget = (ULONG) -1;
  22. ULONG BreakOnScan = TRUE;
  23. ULONG BreakOnMissingLun = FALSE;
  24. typedef struct {
  25. UCHAR LunListLength[4]; // sizeof LunSize * 8
  26. UCHAR Reserved[4];
  27. UCHAR Luns[16][8];
  28. } SP_DEFAULT_LUN_LIST;
  29. SP_DEFAULT_LUN_LIST ScsiPortDefaultLunList = {
  30. {0, 0, 0, sizeof(ScsiPortDefaultLunList.Luns)}, // LunListLength
  31. {0, 0, 0, 0}, // Reserved
  32. {{ 0, 0, 0, 0, 0, 0, 0, 0}, // Luns
  33. { 0, 1, 0, 0, 0, 0, 0, 0},
  34. { 0, 2, 0, 0, 0, 0, 0, 0},
  35. { 0, 3, 0, 0, 0, 0, 0, 0},
  36. { 0, 4, 0, 0, 0, 0, 0, 0},
  37. { 0, 5, 0, 0, 0, 0, 0, 0},
  38. { 0, 6, 0, 0, 0, 0, 0, 0},
  39. { 0, 7, 0, 0, 0, 0, 0, 0}}};
  40. NTSTATUS
  41. SpInquireLogicalUnit(
  42. IN PADAPTER_EXTENSION Adapter,
  43. IN UCHAR PathId,
  44. IN UCHAR TargetId,
  45. IN UCHAR Lun,
  46. IN BOOLEAN ExposeDisconnectedLuns,
  47. IN OPTIONAL PLOGICAL_UNIT_EXTENSION RescanLun,
  48. OUT PLOGICAL_UNIT_EXTENSION *LogicalUnit,
  49. OUT PBOOLEAN CheckNextLun
  50. );
  51. VOID
  52. SpSignalEnumerationCompletion (
  53. IN PADAPTER_EXTENSION Adapter,
  54. IN PSP_ENUMERATION_REQUEST Request,
  55. IN NTSTATUS Status
  56. );
  57. BOOLEAN
  58. SpRemoveLogicalUnitFromBinSynchronized(
  59. IN PVOID ServiceContext // PLOGICAL_UNIT_EXTENSION
  60. );
  61. BOOLEAN
  62. SpAddLogicalUnitToBinSynchronized(
  63. IN PLOGICAL_UNIT_EXTENSION LogicalUnitExtension
  64. );
  65. ULONG
  66. SpCountLogicalUnits(
  67. IN PADAPTER_EXTENSION Adapter
  68. );
  69. NTSTATUS
  70. IssueReportLuns(
  71. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  72. OUT PLUN_LIST *LunList
  73. );
  74. PLUN_LIST
  75. AdjustReportLuns(
  76. IN PDRIVER_OBJECT DriverObject,
  77. IN PLUN_LIST RawList
  78. );
  79. VOID
  80. SpScanAdapter(
  81. IN PADAPTER_EXTENSION Adapter
  82. );
  83. NTSTATUS
  84. SpScanBus(
  85. IN PADAPTER_EXTENSION Adapter,
  86. IN UCHAR PathId,
  87. IN BOOLEAN ExposeDisconnectedLuns,
  88. IN PLOGICAL_UNIT_EXTENSION RescanLun
  89. );
  90. NTSTATUS
  91. SpScanTarget(
  92. IN PADAPTER_EXTENSION Adapter,
  93. IN UCHAR PathId,
  94. IN UCHAR TargetId,
  95. IN BOOLEAN ExposeDisconnectedLuns,
  96. IN PLOGICAL_UNIT_EXTENSION RescanLun
  97. );
  98. NTSTATUS
  99. IssueInquiry(
  100. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  101. IN BOOLEAN EnableVitalProductData,
  102. IN UCHAR PageCode,
  103. OUT PVOID InquiryData,
  104. OUT PUCHAR BytesReturned
  105. );
  106. VOID
  107. SpSetVerificationMarks(
  108. IN PADAPTER_EXTENSION Adapter,
  109. IN UCHAR PathId,
  110. IN UCHAR TargetId
  111. );
  112. VOID
  113. SpClearVerificationMark(
  114. IN PLOGICAL_UNIT_EXTENSION LogicalUnit
  115. );
  116. VOID
  117. SpPurgeTarget(
  118. IN PADAPTER_EXTENSION Adapter,
  119. IN UCHAR PathId,
  120. IN UCHAR TargetId
  121. );
  122. NTSTATUS
  123. SpCloneAndSwapLogicalUnit(
  124. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  125. IN PINQUIRYDATA InquiryData,
  126. IN ULONG InquiryDataSize,
  127. OUT PLOGICAL_UNIT_EXTENSION *NewLun
  128. );
  129. VOID
  130. SpSetLogicalUnitAddress(
  131. IN PLOGICAL_UNIT_EXTENSION RescanLun,
  132. IN UCHAR PathId,
  133. IN UCHAR TargetId,
  134. IN UCHAR Lun
  135. );
  136. VOID
  137. SpClearLogicalUnitAddress(
  138. IN PLOGICAL_UNIT_EXTENSION RescanLun
  139. );
  140. NTSTATUS
  141. SpPrepareLogicalUnitForReuse(
  142. IN PLOGICAL_UNIT_EXTENSION LogicalUnit
  143. );
  144. NTSTATUS
  145. SpCreateLogicalUnit(
  146. IN PADAPTER_EXTENSION Adapter,
  147. IN OPTIONAL UCHAR PathId,
  148. IN OPTIONAL UCHAR TargetId,
  149. IN OPTIONAL UCHAR Lun,
  150. IN BOOLEAN Temporary,
  151. IN BOOLEAN Scsi1,
  152. OUT PLOGICAL_UNIT_EXTENSION *NewLun
  153. );
  154. NTSTATUS
  155. SpSendSrbSynchronous(
  156. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  157. IN PSCSI_REQUEST_BLOCK Srb,
  158. IN OPTIONAL PIRP Irp,
  159. IN OPTIONAL PMDL Mdl,
  160. IN PVOID DataBuffer,
  161. IN ULONG TransferLength,
  162. IN PVOID SenseInfoBuffer,
  163. IN UCHAR SenseInfoBufferLength,
  164. OUT PULONG BytesReturned
  165. );
  166. BOOLEAN
  167. SpGetDeviceIdentifiers(
  168. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  169. IN BOOLEAN NewDevice
  170. );
  171. BOOLEAN
  172. FASTCALL
  173. SpCompareInquiryData(
  174. IN PUCHAR InquiryData1,
  175. IN PUCHAR InquiryData2
  176. );
  177. PLOGICAL_UNIT_EXTENSION
  178. SpCreateInitiatorLU(
  179. IN PADAPTER_EXTENSION Adapter,
  180. IN UCHAR PathId
  181. );
  182. #ifdef ALLOC_PRAGMA
  183. #pragma alloc_text(PAGE, SpEnumerateAdapterSynchronous)
  184. #pragma alloc_text(PAGE, SpEnumerateAdapterAsynchronous)
  185. #pragma alloc_text(PAGE, SpSignalEnumerationCompletion)
  186. #pragma alloc_text(PAGE, SpEnumerationWorker)
  187. #pragma alloc_text(PAGE, SpScanAdapter)
  188. #pragma alloc_text(PAGE, SpScanBus)
  189. #pragma alloc_text(PAGE, SpScanTarget)
  190. #pragma alloc_text(PAGE, SpCreateInitiatorLU)
  191. #pragma alloc_text(PAGE, SpCompareInquiryData)
  192. #pragma alloc_text(PAGE, SpInquireLogicalUnit)
  193. #pragma alloc_text(PAGE, SpExtractDeviceRelations)
  194. #pragma alloc_text(PAGELOCK, SpCountLogicalUnits)
  195. #pragma alloc_text(PAGELOCK, GetNextLuRequestWithoutLock)
  196. #pragma alloc_text(PAGELOCK, IssueReportLuns)
  197. #pragma alloc_text(PAGELOCK, SpSetVerificationMarks)
  198. #pragma alloc_text(PAGELOCK, SpPurgeTarget)
  199. #pragma alloc_text(PAGE, SpClearVerificationMark)
  200. #pragma alloc_text(PAGE, SpGetInquiryData)
  201. #pragma alloc_text(PAGE, IssueInquiry)
  202. #pragma alloc_text(PAGE, AdjustReportLuns)
  203. #pragma alloc_text(PAGE, SpCreateLogicalUnit)
  204. #pragma alloc_text(PAGE, SpCloneAndSwapLogicalUnit)
  205. #pragma alloc_text(PAGE, SpSetLogicalUnitAddress)
  206. #pragma alloc_text(PAGE, SpClearLogicalUnitAddress)
  207. #pragma alloc_text(PAGE, SpPrepareLogicalUnitForReuse)
  208. #pragma alloc_text(PAGE, SpGetDeviceIdentifiers)
  209. LONG SpPAGELOCKLockCount = 0;
  210. #endif
  211. NTSTATUS
  212. SpExtractDeviceRelations(
  213. PADAPTER_EXTENSION Adapter,
  214. DEVICE_RELATION_TYPE RelationType,
  215. PDEVICE_RELATIONS *DeviceRelations
  216. )
  217. /*++
  218. Routine Description:
  219. This routine will allocate a device relations structure and fill in the
  220. count and object array with referenced object pointers
  221. Arguments:
  222. Adapter - the adapter to extract relations from.
  223. RelationType - what type of relationship is being retrieved
  224. DeviceRelations - a place to store the relationships
  225. --*/
  226. {
  227. PDEVICE_OBJECT fdo = Adapter->DeviceObject;
  228. ULONG count = 0;
  229. ULONG relationsSize;
  230. PDEVICE_RELATIONS deviceRelations = NULL;
  231. UCHAR bus, target, lun;
  232. PLOGICAL_UNIT_EXTENSION luExtension;
  233. ULONG i;
  234. NTSTATUS status;
  235. PAGED_CODE();
  236. status = KeWaitForMutexObject(
  237. &(Adapter->EnumerationDeviceMutex),
  238. Executive,
  239. KernelMode,
  240. FALSE,
  241. NULL);
  242. if(status == STATUS_USER_APC) {
  243. status = STATUS_REQUEST_ABORTED;
  244. }
  245. if(!NT_SUCCESS(status)) {
  246. return status;
  247. }
  248. //
  249. // Find out how many devices there are
  250. //
  251. for(bus = 0; bus < Adapter->NumberOfBuses; bus++) {
  252. for(target = 0; target < Adapter->MaximumTargetIds; target++) {
  253. for(lun = 0; lun < SCSI_MAXIMUM_LUNS_PER_TARGET; lun++) {
  254. luExtension = GetLogicalUnitExtension(
  255. Adapter,
  256. bus,
  257. target,
  258. lun,
  259. FALSE,
  260. TRUE);
  261. if(luExtension == NULL) {
  262. continue;
  263. }
  264. //
  265. // Temporary luns only exist while the bus scanning code is
  266. // holding the device lock. we've got it now so we should
  267. // never find one.
  268. //
  269. ASSERT(luExtension->IsTemporary == FALSE);
  270. if(luExtension->IsMissing) {
  271. continue;
  272. }
  273. if(luExtension->IsVisible == FALSE) {
  274. continue;
  275. }
  276. if(luExtension->CommonExtension.IsRemoved >= REMOVE_COMPLETE) {
  277. ASSERT(FALSE);
  278. continue;
  279. }
  280. count++;
  281. }
  282. }
  283. }
  284. //
  285. // Allocate the structure
  286. //
  287. relationsSize = sizeof(DEVICE_RELATIONS) + (count * sizeof(PDEVICE_OBJECT));
  288. deviceRelations = SpAllocatePool(PagedPool,
  289. relationsSize,
  290. SCSIPORT_TAG_DEVICE_RELATIONS,
  291. fdo->DriverObject);
  292. if(deviceRelations == NULL) {
  293. DebugPrint((1, "SpExtractDeviceRelations: unable to allocate "
  294. "%d bytes for device relations\n", relationsSize));
  295. KeReleaseMutex(&(Adapter->EnumerationDeviceMutex), FALSE);
  296. return STATUS_INSUFFICIENT_RESOURCES;
  297. }
  298. RtlZeroMemory(deviceRelations, relationsSize);
  299. i = 0;
  300. for(bus = 0; bus < Adapter->NumberOfBuses; bus++) {
  301. for(target = 0; target < Adapter->MaximumTargetIds; target++) {
  302. for(lun = 0; lun < SCSI_MAXIMUM_LUNS_PER_TARGET; lun++) {
  303. luExtension = GetLogicalUnitExtension(
  304. Adapter,
  305. bus,
  306. target,
  307. lun,
  308. FALSE,
  309. TRUE);
  310. if(luExtension == NULL) {
  311. continue;
  312. }
  313. //
  314. // Temporary luns only exist while the bus scanning code is
  315. // holding the device lock. we've got it now so we should
  316. // never find one.
  317. //
  318. ASSERT(luExtension->IsTemporary == FALSE);
  319. if(luExtension->IsMissing) {
  320. DebugPrint((1, "SpExtractDeviceRelations: PDO %p logical unit "
  321. "(%d,%d,%d) is missing and will not be "
  322. "returned\n",
  323. luExtension->DeviceObject, bus, target, lun));
  324. luExtension->IsEnumerated = FALSE;
  325. continue;
  326. } else if(luExtension->CommonExtension.IsRemoved >= REMOVE_COMPLETE) {
  327. ASSERT(FALSE);
  328. luExtension->IsEnumerated = FALSE;
  329. continue;
  330. } else if(luExtension->IsVisible == FALSE) {
  331. luExtension->IsEnumerated = FALSE;
  332. continue;
  333. }
  334. status = ObReferenceObjectByPointer(
  335. luExtension->CommonExtension.DeviceObject,
  336. 0,
  337. NULL,
  338. KernelMode);
  339. if(!NT_SUCCESS(status)) {
  340. DebugPrint((1, "SpFdoExtractDeviceRelations: status %#08lx "
  341. "while referenceing object %#p\n",
  342. status,
  343. deviceRelations->Objects[i]));
  344. continue;
  345. }
  346. deviceRelations->Objects[i] =
  347. luExtension->CommonExtension.DeviceObject;
  348. i++;
  349. luExtension->IsEnumerated = TRUE;
  350. }
  351. }
  352. }
  353. deviceRelations->Count = i;
  354. *DeviceRelations = deviceRelations;
  355. KeReleaseMutex(&(Adapter->EnumerationDeviceMutex), FALSE);
  356. return STATUS_SUCCESS;
  357. }
  358. NTSTATUS
  359. IssueReportLuns(
  360. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  361. OUT PLUN_LIST *LunList
  362. )
  363. /*++
  364. Routine Description:
  365. Build IRP, SRB and CDB for SCSI REPORT LUNS command.
  366. Arguments:
  367. LogicalUnit - address of target's device object extension.
  368. LunList - address of buffer for LUN_LIST information.
  369. Return Value:
  370. NTSTATUS
  371. --*/
  372. {
  373. PMDL mdl;
  374. PIRP irp;
  375. PIO_STACK_LOCATION irpStack;
  376. SCSI_REQUEST_BLOCK srb;
  377. PCDB cdb;
  378. KEVENT event;
  379. KIRQL currentIrql;
  380. PLUN_LIST lunListDataBuffer;
  381. PSENSE_DATA senseInfoBuffer = NULL;
  382. NTSTATUS status;
  383. ULONG retryCount = 0;
  384. ULONG lunListSize;
  385. ULONG i;
  386. PAGED_CODE();
  387. #if 0
  388. if ((LogicalUnit->InquiryData.Versions & 7) < 3) {
  389. //
  390. // make sure the device supports scsi3 commands
  391. // without this check, we may hang some scsi2 devices
  392. //
  393. return STATUS_INVALID_DEVICE_REQUEST;
  394. }
  395. #endif
  396. //
  397. // start with the minilun of 16 byte for the lun list
  398. //
  399. lunListSize = 16;
  400. status = STATUS_INVALID_DEVICE_REQUEST;
  401. senseInfoBuffer = LogicalUnit->AdapterExtension->InquirySenseBuffer;
  402. irp = LogicalUnit->AdapterExtension->InquiryIrp;
  403. mdl = NULL;
  404. KeInitializeEvent(&event,
  405. SynchronizationEvent,
  406. FALSE);
  407. //
  408. // This is a two pass operation - for the first pass we just try to figure
  409. // out how large the list should be. On the second pass we'll actually
  410. // reallocate the buffer and try to get the entire lun list.
  411. //
  412. // NOTE - we may want to set an arbitrary limit here so we don't soak up all
  413. // of non-paged pool when some device hands us back a buffer filled
  414. // with 0xff.
  415. //
  416. for (i=0; i<2; i++) {
  417. //
  418. // Allocate a cache aligned LUN_LIST structure.
  419. //
  420. lunListDataBuffer = SpAllocatePool(
  421. NonPagedPoolCacheAligned,
  422. lunListSize,
  423. SCSIPORT_TAG_REPORT_LUNS,
  424. LogicalUnit->DeviceObject->DriverObject);
  425. if (lunListDataBuffer == NULL) {
  426. DebugPrint((1,"IssueReportLuns: Can't allocate report luns data buffer\n"));
  427. status = STATUS_INSUFFICIENT_RESOURCES;
  428. break;
  429. }
  430. mdl = SpAllocateMdl(lunListDataBuffer,
  431. lunListSize,
  432. FALSE,
  433. FALSE,
  434. NULL,
  435. LogicalUnit->DeviceObject->DriverObject);
  436. if(mdl == NULL) {
  437. DebugPrint((1,"IssueReportLuns: Can't allocate data buffer MDL\n"));
  438. status = STATUS_INSUFFICIENT_RESOURCES;
  439. break;
  440. }
  441. MmBuildMdlForNonPagedPool(mdl);
  442. //
  443. // number of retry
  444. //
  445. retryCount = 3;
  446. while (retryCount--) {
  447. //
  448. // Build IRP for this request.
  449. //
  450. IoInitializeIrp(irp,
  451. IoSizeOfIrp(INQUIRY_STACK_LOCATIONS),
  452. INQUIRY_STACK_LOCATIONS);
  453. irp->MdlAddress = mdl;
  454. irpStack = IoGetNextIrpStackLocation(irp);
  455. //
  456. // Fill in SRB fields.
  457. //
  458. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  459. //
  460. // Mark the minor function to indicate that this is an internal scsiport
  461. // request and that the start state of the device can be ignored.
  462. //
  463. irpStack->MajorFunction = IRP_MJ_SCSI;
  464. irpStack->MinorFunction = 1;
  465. irpStack->Parameters.Scsi.Srb = &srb;
  466. IoSetCompletionRoutine(irp,
  467. SpSignalCompletion,
  468. &event,
  469. TRUE,
  470. TRUE,
  471. TRUE);
  472. srb.PathId = LogicalUnit->PathId;
  473. srb.TargetId = LogicalUnit->TargetId;
  474. srb.Lun = LogicalUnit->Lun;
  475. srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
  476. srb.Length = sizeof(SCSI_REQUEST_BLOCK);
  477. //
  478. // Set flags to disable synchronous negociation.
  479. //
  480. srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  481. srb.SrbStatus = srb.ScsiStatus = 0;
  482. srb.NextSrb = 0;
  483. srb.OriginalRequest = irp;
  484. //
  485. // Set timeout to 2 seconds.
  486. //
  487. srb.TimeOutValue = LogicalUnit->AdapterExtension->SrbTimeout;
  488. srb.CdbLength = 12;
  489. //
  490. // Enable auto request sense.
  491. //
  492. srb.SenseInfoBuffer = senseInfoBuffer;
  493. srb.SenseInfoBufferLength = SENSE_BUFFER_SIZE;
  494. srb.DataBuffer = MmGetMdlVirtualAddress(irp->MdlAddress);
  495. srb.DataTransferLength = lunListSize;
  496. cdb = (PCDB)srb.Cdb;
  497. //
  498. // Set CDB operation code.
  499. //
  500. cdb->REPORT_LUNS.OperationCode = SCSIOP_REPORT_LUNS;
  501. cdb->REPORT_LUNS.AllocationLength[0] = (UCHAR) ((lunListSize >> 24) & 0xff);
  502. cdb->REPORT_LUNS.AllocationLength[1] = (UCHAR) ((lunListSize >> 16) & 0xff);
  503. cdb->REPORT_LUNS.AllocationLength[2] = (UCHAR) ((lunListSize >> 8) & 0xff);
  504. cdb->REPORT_LUNS.AllocationLength[3] = (UCHAR) ((lunListSize >> 0) & 0xff);
  505. //
  506. // Call port driver to handle this request.
  507. //
  508. status = IoCallDriver(LogicalUnit->DeviceObject, irp);
  509. //
  510. // Wait for request to complete.
  511. //
  512. KeWaitForSingleObject(&event,
  513. Executive,
  514. KernelMode,
  515. FALSE,
  516. NULL);
  517. status = irp->IoStatus.Status;
  518. if (SRB_STATUS(srb.SrbStatus) != SRB_STATUS_SUCCESS) {
  519. DebugPrint((2,"IssueReportLuns: failed SRB status %x\n",
  520. srb.SrbStatus));
  521. //
  522. // Unfreeze queue if necessary
  523. //
  524. if (srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  525. DebugPrint((3, "IssueInquiry: Unfreeze Queue TID %d\n",
  526. srb.TargetId));
  527. LogicalUnit->LuFlags &= ~LU_QUEUE_FROZEN;
  528. KeAcquireSpinLock(
  529. &(LogicalUnit->AdapterExtension->SpinLock),
  530. &currentIrql);
  531. GetNextLuRequest(LogicalUnit);
  532. KeLowerIrql(currentIrql);
  533. }
  534. if ((srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
  535. senseInfoBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST){
  536. //
  537. // A sense key of illegal request was recieved. This indicates
  538. // that the logical unit number of not valid but there is a
  539. // target device out there.
  540. //
  541. status = STATUS_INVALID_DEVICE_REQUEST;
  542. break;
  543. } else if ((SRB_STATUS(srb.SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) ||
  544. (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_NO_DEVICE)) {
  545. //
  546. // If the selection times out then give up
  547. //
  548. status = STATUS_NO_SUCH_DEVICE;
  549. break;
  550. }
  551. //
  552. // retry...
  553. //
  554. } else {
  555. status = STATUS_SUCCESS;
  556. break;
  557. }
  558. }
  559. IoFreeMdl(mdl);
  560. if (NT_SUCCESS(status)) {
  561. ULONG listLength;
  562. listLength = lunListDataBuffer->LunListLength[3] << 0;
  563. listLength |= lunListDataBuffer->LunListLength[2] << 8;
  564. listLength |= lunListDataBuffer->LunListLength[1] << 16;
  565. listLength |= lunListDataBuffer->LunListLength[0] << 24;
  566. if (lunListSize < (listLength + sizeof (LUN_LIST))) {
  567. lunListSize = listLength + sizeof (LUN_LIST);
  568. //
  569. // try report lun with a bigger buffer
  570. //
  571. ExFreePool(lunListDataBuffer);
  572. lunListDataBuffer = NULL;
  573. status = STATUS_INVALID_DEVICE_REQUEST;
  574. } else {
  575. //
  576. // lun list is good
  577. //
  578. break;
  579. }
  580. }
  581. }
  582. //
  583. // Return the lun list
  584. //
  585. if(NT_SUCCESS(status)) {
  586. //
  587. // AdjustReportLuns returns lunListDataBuffer if it cannot allocate
  588. // a new list.
  589. //
  590. *LunList = AdjustReportLuns(LogicalUnit->DeviceObject->DriverObject,
  591. lunListDataBuffer);
  592. //
  593. // Only delete lunListDataBuffer if we didn't return it from
  594. // AdjustReportLuns.
  595. //
  596. ASSERT(*LunList != NULL);
  597. ASSERT(lunListDataBuffer != NULL);
  598. if (*LunList != lunListDataBuffer) {
  599. ExFreePool(lunListDataBuffer);
  600. }
  601. } else {
  602. *LunList = NULL;
  603. if (lunListDataBuffer) {
  604. ExFreePool(lunListDataBuffer);
  605. }
  606. }
  607. return status;
  608. } // end IssueReportLuns()
  609. VOID
  610. GetNextLuRequestWithoutLock(
  611. IN PLOGICAL_UNIT_EXTENSION LogicalUnit
  612. )
  613. {
  614. KIRQL oldIrql;
  615. PAGED_CODE();
  616. ASSERT(SpPAGELOCKLockCount != 0);
  617. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  618. KeAcquireSpinLockAtDpcLevel(&(LogicalUnit->AdapterExtension->SpinLock));
  619. GetNextLuRequest(LogicalUnit);
  620. KeLowerIrql(oldIrql);
  621. PAGED_CODE();
  622. return;
  623. }
  624. ULONG
  625. SpCountLogicalUnits(
  626. IN PADAPTER_EXTENSION Adapter
  627. )
  628. {
  629. ULONG numberOfLus = 0;
  630. PLOGICAL_UNIT_EXTENSION luExtension;
  631. KIRQL oldIrql;
  632. ULONG bin;
  633. #ifdef ALLOC_PRAGMA
  634. PVOID sectionHandle;
  635. #endif
  636. //
  637. // Code is paged until locked down.
  638. //
  639. PAGED_CODE();
  640. //
  641. // Lock this routine down before grabbing the spinlock.
  642. //
  643. #ifdef ALLOC_PRAGMA
  644. sectionHandle = MmLockPagableCodeSection(SpCountLogicalUnits);
  645. #endif
  646. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  647. for(bin = 0; bin < NUMBER_LOGICAL_UNIT_BINS; bin++) {
  648. KeAcquireSpinLockAtDpcLevel(&(Adapter->LogicalUnitList[bin].Lock));
  649. for(luExtension = Adapter->LogicalUnitList[bin].List;
  650. luExtension != NULL;
  651. luExtension = luExtension->NextLogicalUnit) {
  652. if(luExtension->IsMissing == FALSE) {
  653. numberOfLus++;
  654. }
  655. }
  656. KeReleaseSpinLockFromDpcLevel(&(Adapter->LogicalUnitList[bin].Lock));
  657. }
  658. KeLowerIrql(oldIrql);
  659. #ifdef ALLOC_PRAGMA
  660. MmUnlockPagableImageSection(sectionHandle);
  661. #endif
  662. return numberOfLus;
  663. }
  664. NTSTATUS
  665. SpGetInquiryData(
  666. IN PADAPTER_EXTENSION DeviceExtension,
  667. IN PIRP Irp
  668. )
  669. /*++
  670. Routine Description:
  671. This functions copies the inquiry data to the system buffer. The data
  672. is translate from the port driver's internal format to the user mode
  673. format.
  674. Arguments:
  675. DeviceExtension - Supplies a pointer the SCSI adapter device extension.
  676. Irp - Supplies a pointer to the Irp which made the original request.
  677. Return Value:
  678. Returns a status indicating the success or failure of the operation.
  679. --*/
  680. {
  681. PUCHAR bufferStart;
  682. PIO_STACK_LOCATION irpStack;
  683. UCHAR bin;
  684. PLOGICAL_UNIT_EXTENSION luExtension;
  685. PSCSI_ADAPTER_BUS_INFO adapterInfo;
  686. PSCSI_INQUIRY_DATA inquiryData;
  687. ULONG inquiryDataSize;
  688. ULONG length;
  689. PLOGICAL_UNIT_INFO lunInfo;
  690. ULONG numberOfBuses;
  691. ULONG numberOfLus;
  692. ULONG j;
  693. UCHAR pathId;
  694. UCHAR targetId;
  695. UCHAR lun;
  696. NTSTATUS status;
  697. PAGED_CODE();
  698. ASSERT_FDO(DeviceExtension->CommonExtension.DeviceObject);
  699. status = KeWaitForMutexObject(&(DeviceExtension->EnumerationDeviceMutex),
  700. UserRequest,
  701. KernelMode,
  702. FALSE,
  703. NULL);
  704. if(status == STATUS_USER_APC) {
  705. status = STATUS_REQUEST_ABORTED;
  706. }
  707. if(!NT_SUCCESS(status)) {
  708. Irp->IoStatus.Status = status;
  709. return status;
  710. }
  711. DebugPrint((3,"SpGetInquiryData: Enter routine\n"));
  712. //
  713. // Get a pointer to the control block.
  714. //
  715. irpStack = IoGetCurrentIrpStackLocation(Irp);
  716. bufferStart = Irp->AssociatedIrp.SystemBuffer;
  717. //
  718. // Determine the number of SCSI buses and logical units.
  719. //
  720. numberOfBuses = DeviceExtension->NumberOfBuses;
  721. numberOfLus = 0;
  722. numberOfLus = SpCountLogicalUnits(DeviceExtension);
  723. //
  724. // Caculate the size of the logical unit structure and round it to a word
  725. // alignment.
  726. //
  727. inquiryDataSize = ((sizeof(SCSI_INQUIRY_DATA) - 1 + INQUIRYDATABUFFERSIZE +
  728. sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
  729. // Based on the number of buses and logical unit, determine the minimum
  730. // buffer length to hold all of the data.
  731. //
  732. length = sizeof(SCSI_ADAPTER_BUS_INFO) +
  733. (numberOfBuses - 1) * sizeof(SCSI_BUS_DATA);
  734. length += inquiryDataSize * numberOfLus;
  735. if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < length) {
  736. Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
  737. KeReleaseMutex(&(DeviceExtension->EnumerationDeviceMutex), FALSE);
  738. return(STATUS_BUFFER_TOO_SMALL);
  739. }
  740. //
  741. // Set the information field.
  742. //
  743. Irp->IoStatus.Information = length;
  744. //
  745. // Fill in the bus information.
  746. //
  747. adapterInfo = (PSCSI_ADAPTER_BUS_INFO) bufferStart;
  748. adapterInfo->NumberOfBuses = (UCHAR) numberOfBuses;
  749. inquiryData = (PSCSI_INQUIRY_DATA)(bufferStart +
  750. sizeof(SCSI_ADAPTER_BUS_INFO) +
  751. ((numberOfBuses - 1) *
  752. sizeof(SCSI_BUS_DATA)));
  753. for (pathId = 0; pathId < numberOfBuses; pathId++) {
  754. PSCSI_BUS_DATA busData;
  755. busData = &adapterInfo->BusData[pathId];
  756. busData->InitiatorBusId = DeviceExtension->PortConfig->InitiatorBusId[pathId];
  757. busData->NumberOfLogicalUnits = 0;
  758. busData->InquiryDataOffset = (ULONG)((PUCHAR) inquiryData - bufferStart);
  759. for(targetId = 0;
  760. targetId < DeviceExtension->MaximumTargetIds;
  761. targetId++) {
  762. for(lun = 0;
  763. lun < SCSI_MAXIMUM_LUNS_PER_TARGET;
  764. lun++) {
  765. luExtension = GetLogicalUnitExtension(DeviceExtension,
  766. pathId,
  767. targetId,
  768. lun,
  769. Irp,
  770. TRUE);
  771. if(luExtension == NULL) {
  772. continue;
  773. }
  774. if((luExtension->IsMissing) ||
  775. (luExtension->CommonExtension.IsRemoved)) {
  776. SpReleaseRemoveLock(
  777. luExtension->CommonExtension.DeviceObject,
  778. Irp);
  779. continue;
  780. }
  781. busData->NumberOfLogicalUnits++;
  782. DebugPrint((1, "InquiryData for (%d, %d, %d) - ",
  783. pathId,
  784. targetId,
  785. lun));
  786. DebugPrint((1, "%d units found\n", busData->NumberOfLogicalUnits));
  787. inquiryData->PathId = pathId;
  788. inquiryData->TargetId = targetId;
  789. inquiryData->Lun = lun;
  790. inquiryData->DeviceClaimed = luExtension->IsClaimed;
  791. inquiryData->InquiryDataLength = INQUIRYDATABUFFERSIZE;
  792. inquiryData->NextInquiryDataOffset = (ULONG)((PUCHAR) inquiryData + inquiryDataSize - bufferStart);
  793. RtlCopyMemory(inquiryData->InquiryData,
  794. &(luExtension->InquiryData),
  795. INQUIRYDATABUFFERSIZE);
  796. inquiryData = (PSCSI_INQUIRY_DATA) ((PUCHAR) inquiryData + inquiryDataSize);
  797. SpReleaseRemoveLock(luExtension->CommonExtension.DeviceObject,
  798. Irp);
  799. }
  800. }
  801. if(busData->NumberOfLogicalUnits == 0) {
  802. busData->InquiryDataOffset = 0;
  803. } else {
  804. ((PSCSI_INQUIRY_DATA) ((PCHAR) inquiryData - inquiryDataSize))->NextInquiryDataOffset = 0;
  805. }
  806. }
  807. Irp->IoStatus.Status = STATUS_SUCCESS;
  808. KeReleaseMutex(&(DeviceExtension->EnumerationDeviceMutex), FALSE);
  809. return(STATUS_SUCCESS);
  810. }
  811. VOID
  812. SpAddLogicalUnitToBin (
  813. IN PADAPTER_EXTENSION AdapterExtension,
  814. IN PLOGICAL_UNIT_EXTENSION LogicalUnitExtension
  815. )
  816. /*++
  817. Routine Description:
  818. This routine will synchronize with any interrupt or miniport routines and
  819. add the specified logical unit to the appropriate logical unit list.
  820. The logical unit must not already be in the list.
  821. This routine acquires the bin spinlock and calls the SynchronizeExecution
  822. routine. It cannot be called when the bin spinlock is held or from a
  823. miniport API.
  824. Arguments:
  825. AdapterExtension - the adapter to add this logical unit to.
  826. LogicalUnitExtension - the logical unit to be added.
  827. Return Value:
  828. none
  829. --*/
  830. {
  831. UCHAR hash = ADDRESS_TO_HASH(LogicalUnitExtension->PathId,
  832. LogicalUnitExtension->TargetId,
  833. LogicalUnitExtension->Lun);
  834. PLOGICAL_UNIT_BIN bin = &AdapterExtension->LogicalUnitList[hash];
  835. PLOGICAL_UNIT_EXTENSION lun;
  836. KIRQL oldIrql;
  837. KeAcquireSpinLock(&AdapterExtension->SpinLock, &oldIrql);
  838. KeAcquireSpinLockAtDpcLevel(&bin->Lock);
  839. //
  840. // Run through the list quickly and make sure this lun isn't already there
  841. //
  842. lun = bin->List;
  843. while(lun != NULL) {
  844. if(lun == LogicalUnitExtension) {
  845. break;
  846. }
  847. lun = lun->NextLogicalUnit;
  848. }
  849. ASSERTMSG("Logical Unit already in list: ", lun == NULL);
  850. ASSERTMSG("Logical Unit not properly initialized: ",
  851. (LogicalUnitExtension->AdapterExtension == AdapterExtension));
  852. ASSERTMSG("Logical Unit is already on a list: ",
  853. LogicalUnitExtension->NextLogicalUnit == NULL);
  854. LogicalUnitExtension->NextLogicalUnit = bin->List;
  855. bin->List = LogicalUnitExtension;
  856. KeReleaseSpinLockFromDpcLevel(&bin->Lock);
  857. KeReleaseSpinLock(&AdapterExtension->SpinLock, oldIrql);
  858. return;
  859. }
  860. VOID
  861. SpRemoveLogicalUnitFromBin (
  862. IN PADAPTER_EXTENSION AdapterExtension,
  863. IN PLOGICAL_UNIT_EXTENSION LogicalUnitExtension
  864. )
  865. /*++
  866. Routine Description:
  867. This routine will synchronize with any interrupt or miniport routines and
  868. remove the specified logical unit from the appropriate logical unit list.
  869. The logical unit MUST be in the logical unit list.
  870. This routine acquires the bin spinlock and calls the SynchronizeExecution
  871. routine. It cannot be called when the bin spinlock is held or from
  872. a miniport exported routine.
  873. Arguments:
  874. AdapterExtension - The adapter from which to remove this logical unit
  875. LogicalUnitExtension - the logical unit to be removed
  876. Return Value:
  877. none
  878. --*/
  879. {
  880. KIRQL oldIrql;
  881. PLOGICAL_UNIT_BIN bin =
  882. &AdapterExtension->LogicalUnitList[ADDRESS_TO_HASH(
  883. LogicalUnitExtension->PathId,
  884. LogicalUnitExtension->TargetId,
  885. LogicalUnitExtension->Lun)];
  886. KeAcquireSpinLock(&AdapterExtension->SpinLock, &oldIrql);
  887. KeAcquireSpinLockAtDpcLevel(&bin->Lock);
  888. AdapterExtension->SynchronizeExecution(
  889. AdapterExtension->InterruptObject,
  890. SpRemoveLogicalUnitFromBinSynchronized,
  891. LogicalUnitExtension
  892. );
  893. KeReleaseSpinLockFromDpcLevel(&bin->Lock);
  894. KeReleaseSpinLock(&AdapterExtension->SpinLock, oldIrql);
  895. if(LogicalUnitExtension->IsMismatched) {
  896. DebugPrint((1, "SpRemoveLogicalUnitFromBin: Signalling for rescan "
  897. "after removal of mismatched lun %#p\n",
  898. LogicalUnitExtension));
  899. IoInvalidateDeviceRelations(AdapterExtension->LowerPdo,
  900. BusRelations);
  901. }
  902. }
  903. BOOLEAN
  904. SpRemoveLogicalUnitFromBinSynchronized(
  905. IN PVOID ServiceContext
  906. )
  907. {
  908. PLOGICAL_UNIT_EXTENSION logicalUnitExtension =
  909. (PLOGICAL_UNIT_EXTENSION) ServiceContext;
  910. PADAPTER_EXTENSION adapterExtension =
  911. logicalUnitExtension->AdapterExtension;
  912. UCHAR hash = ADDRESS_TO_HASH(
  913. logicalUnitExtension->PathId,
  914. logicalUnitExtension->TargetId,
  915. logicalUnitExtension->Lun);
  916. PLOGICAL_UNIT_BIN bin;
  917. PLOGICAL_UNIT_EXTENSION *lun;
  918. ASSERT(hash < NUMBER_LOGICAL_UNIT_BINS);
  919. adapterExtension->CachedLogicalUnit = NULL;
  920. bin = &adapterExtension->LogicalUnitList[hash];
  921. lun = &bin->List;
  922. while(*lun != NULL) {
  923. if(*lun == logicalUnitExtension) {
  924. //
  925. // Found a match - unlink it from the list.
  926. //
  927. *lun = logicalUnitExtension->NextLogicalUnit;
  928. logicalUnitExtension->NextLogicalUnit = NULL;
  929. return TRUE;
  930. }
  931. lun = &((*lun)->NextLogicalUnit);
  932. }
  933. return TRUE;
  934. }
  935. PLUN_LIST
  936. AdjustReportLuns(
  937. IN PDRIVER_OBJECT DriverObject,
  938. IN PLUN_LIST RawList
  939. )
  940. {
  941. ULONG newLength;
  942. ULONG numberOfEntries;
  943. ULONG maxLun = 8;
  944. PLUN_LIST newList;
  945. //
  946. // Derive the length of the list and the number of entries currently in
  947. // the list.
  948. //
  949. newLength = RawList->LunListLength[3] << 0;
  950. newLength |= RawList->LunListLength[2] << 8;
  951. newLength |= RawList->LunListLength[1] << 16;
  952. newLength |= RawList->LunListLength[0] << 24;
  953. numberOfEntries = newLength / sizeof (RawList->Lun[0]);
  954. newLength += sizeof(LUN_LIST);
  955. newLength += maxLun * sizeof(RawList->Lun[0]);
  956. //
  957. // Allocate a list with "maxLun" extra entries in it. This might waste
  958. // some space if we have duplicates but it's easy.
  959. //
  960. //
  961. // ALLOCATION
  962. //
  963. newList = SpAllocatePool(NonPagedPool,
  964. newLength,
  965. SCSIPORT_TAG_REPORT_LUNS,
  966. DriverObject);
  967. if(newList == NULL){
  968. newList = RawList;
  969. } else {
  970. UCHAR lunNumber;
  971. ULONG entry;
  972. ULONG newEntryCount = 0;
  973. RtlZeroMemory(newList, newLength);
  974. //
  975. // First make a fake entry for each of the luns from 0 to maxLun - 1
  976. //
  977. for(lunNumber = 0; lunNumber < maxLun; lunNumber++) {
  978. newList->Lun[lunNumber][1] = lunNumber;
  979. newEntryCount++;
  980. };
  981. //
  982. // Now iterate through the entries in the remaining list. For each
  983. // one copy it over iff it's not already a lun 0 -> (maxLun - 1)
  984. //
  985. for(entry = 0; entry < numberOfEntries; entry++) {
  986. USHORT l;
  987. l = (RawList->Lun[entry][0] << 8);
  988. l |= RawList->Lun[entry][1];
  989. l &= 0x3fff;
  990. if(l >= maxLun) {
  991. RtlCopyMemory(&(newList->Lun[lunNumber]),
  992. &(RawList->Lun[entry]),
  993. sizeof(newList->Lun[0]));
  994. lunNumber++;
  995. newEntryCount++;
  996. }
  997. }
  998. //
  999. // Copy over the reserved bytes for the cases where they aren't all
  1000. // that reserved.
  1001. //
  1002. RtlCopyMemory(newList->Reserved,
  1003. RawList->Reserved,
  1004. sizeof(RawList->Reserved));
  1005. //
  1006. // Subtract out the number of duplicate entries we found.
  1007. //
  1008. newLength = newEntryCount * sizeof(RawList->Lun[0]);
  1009. newList->LunListLength[0] = (UCHAR) ((newLength >> 24) & 0xff);
  1010. newList->LunListLength[1] = (UCHAR) ((newLength >> 16) & 0xff);
  1011. newList->LunListLength[2] = (UCHAR) ((newLength >> 8) & 0xff);
  1012. newList->LunListLength[3] = (UCHAR) ((newLength >> 0) & 0xff);
  1013. }
  1014. return newList;
  1015. }
  1016. VOID
  1017. SpCompleteEnumRequest(
  1018. IN PADAPTER_EXTENSION Adapter,
  1019. IN PIRP Irp
  1020. )
  1021. /*++
  1022. Routine Description:
  1023. This routine completes our handling of an asynchronous bus scan. If the
  1024. supplied IRP has been completed successfully, we pass it down to the
  1025. driver below. If the IRP was failed, we complete the request here.
  1026. Arguments:
  1027. Adapter - The adapter we're scanning.
  1028. Irp - The IRP that prompted this asynchronous bus scan true then a
  1029. scan will be done even if one has happend within the minimum
  1030. bus scan delta time.
  1031. Return Value:
  1032. none.
  1033. --*/
  1034. {
  1035. ULONG tempLock;
  1036. //
  1037. // Acquire a temporary remove lock so we can release the lock acquired
  1038. // on behalf of the IRP.
  1039. //
  1040. SpAcquireRemoveLock(Adapter->DeviceObject, &tempLock);
  1041. //
  1042. // Release the IRP's remove lock because holding it across completion
  1043. // could trip up our remove tracking code since it is based on the
  1044. // IRP address which can be recycled.
  1045. //
  1046. SpReleaseRemoveLock(Adapter->DeviceObject, Irp);
  1047. //
  1048. // Call down or complete the IRP, depending on the request's completion
  1049. // status.
  1050. //
  1051. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  1052. IoCopyCurrentIrpStackLocationToNext(Irp);
  1053. IoCallDriver(Adapter->CommonExtension.LowerDeviceObject, Irp);
  1054. } else {
  1055. SpCompleteRequest(Adapter->DeviceObject,
  1056. Irp,
  1057. NULL,
  1058. IO_NO_INCREMENT);
  1059. }
  1060. //
  1061. // Release the temporary lock.
  1062. //
  1063. SpReleaseRemoveLock(Adapter->DeviceObject, &tempLock);
  1064. }
  1065. NTSTATUS
  1066. SpEnumerateAdapterSynchronous(
  1067. IN PADAPTER_EXTENSION Adapter,
  1068. IN BOOLEAN Force
  1069. )
  1070. /*++
  1071. Routine Description:
  1072. This routine will call SpEnumerateAdapterAsynchronous and wait for it to
  1073. complete.
  1074. Arguments:
  1075. Adapter - the adapter we're scanning.
  1076. Force - if true then a scan will be done even if one has happend within
  1077. the minimum bus scan delta time.
  1078. Return Value:
  1079. none.
  1080. --*/
  1081. {
  1082. SP_ENUMERATION_REQUEST request;
  1083. KEVENT event;
  1084. NTSTATUS status;
  1085. RtlZeroMemory(&request, sizeof(SP_ENUMERATION_REQUEST));
  1086. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  1087. request.CompletionRoutine = SpSignalEnumerationCompletion;
  1088. request.Context = &event;
  1089. request.CompletionStatus = &status;
  1090. request.Synchronous = TRUE;
  1091. SpEnumerateAdapterAsynchronous(Adapter, &request, Force);
  1092. KeWaitForSingleObject(&(event),
  1093. Executive,
  1094. KernelMode,
  1095. FALSE,
  1096. NULL);
  1097. return status;
  1098. }
  1099. VOID
  1100. SpEnumerateAdapterAsynchronous(
  1101. IN PADAPTER_EXTENSION Adapter,
  1102. IN PSP_ENUMERATION_REQUEST Request,
  1103. IN BOOLEAN Force
  1104. )
  1105. /*++
  1106. Routine Description:
  1107. This routine will queue a bus scan and return. When the scan completes the
  1108. worker thread will run the callback in the Request passed in by the caller.
  1109. Details:
  1110. If the force flag (or the ForceNextBusScan flag in the adapter) is set or
  1111. the minimum interval between bus scans has passed then this routine will
  1112. queue this enumeration request to the work list and, if necessary, start
  1113. a new worker thread to process them.
  1114. Otherwise it will attempt to acquire the EnumerationDeviceMutex in order to
  1115. run the completion routine. If this is not available then it will also
  1116. queue the work item and start the thread if necessary.
  1117. Arguments:
  1118. Adapter - the adapter to be scanned.
  1119. Request - the request to be processed when the scan is complete. The
  1120. completion routine in this request may free the request structure.
  1121. Force - hint as to whether or not we should honor the minimum bus scan
  1122. interval.
  1123. Return Value:
  1124. none
  1125. --*/
  1126. {
  1127. ULONG forceNext;
  1128. LONGLONG rescanInterval;
  1129. PAGED_CODE();
  1130. ASSERT(Request->CompletionRoutine != NULL);
  1131. ASSERT(Request->NextRequest == NULL);
  1132. ExAcquireFastMutex(&(Adapter->EnumerationWorklistMutex));
  1133. //
  1134. // Swap out the ForceNextBusScan value for FALSE.
  1135. //
  1136. forceNext = InterlockedExchange(&(Adapter->ForceNextBusScan), FALSE);
  1137. //
  1138. // Force the bus scan to happen either way.
  1139. //
  1140. Force = (Force || forceNext || Adapter->EnumerationRunning) ? TRUE : FALSE;
  1141. //
  1142. // Calculate the time between bus enumerations.
  1143. //
  1144. if(Force == FALSE) {
  1145. LARGE_INTEGER currentSystemTime;
  1146. LONGLONG lastTime;
  1147. KeQuerySystemTime(&currentSystemTime);
  1148. lastTime = Adapter->LastBusScanTime.QuadPart;
  1149. rescanInterval = currentSystemTime.QuadPart - lastTime;
  1150. }
  1151. //
  1152. // If we're required to do the bus scan then queue this request and
  1153. // schedule a work item to run in (if necessary).
  1154. //
  1155. if((Force == TRUE) || (rescanInterval > MINIMUM_BUS_SCAN_INTERVAL)) {
  1156. //
  1157. // Grab the remove lock for this device so we know it (and the
  1158. // associated code) can't be removed.
  1159. //
  1160. SpAcquireRemoveLock(Adapter->DeviceObject, Request);
  1161. //
  1162. // Queue the entry to the work list.
  1163. //
  1164. Request->NextRequest = Adapter->EnumerationWorkList;
  1165. Adapter->EnumerationWorkList = Request;
  1166. if(Adapter->EnumerationRunning == FALSE) {
  1167. //
  1168. // Start a new worker thread to run the enumeration.
  1169. //
  1170. Adapter->EnumerationRunning = TRUE;
  1171. ExQueueWorkItem(&(Adapter->EnumerationWorkItem), DelayedWorkQueue);
  1172. }
  1173. ExReleaseFastMutex(&(Adapter->EnumerationWorklistMutex));
  1174. } else {
  1175. NTSTATUS status;
  1176. PIRP irp = NULL;
  1177. //
  1178. // We're going to try and satisfy this request immediately.
  1179. // If there is currently an enumeration running then we'll try to
  1180. // acquire the EnumerationDeviceMutex. If that fails we'll just
  1181. // queue the request for the worker to complete. If the worker is
  1182. // not running then we just acquire the mutex and process the request.
  1183. //
  1184. ASSERT(Adapter->EnumerationRunning == FALSE);
  1185. ExReleaseFastMutex(&(Adapter->EnumerationWorklistMutex));
  1186. status = KeWaitForMutexObject(&(Adapter->EnumerationDeviceMutex),
  1187. UserRequest,
  1188. KernelMode,
  1189. FALSE,
  1190. NULL);
  1191. //
  1192. // If this is an async request, save the IRP so we can complete
  1193. // it after we've filled in the completion information. We can't
  1194. // touch the request after we return from our completion callback.
  1195. //
  1196. if (Request->Synchronous == FALSE) {
  1197. irp = (PIRP) Request->Context;
  1198. }
  1199. //
  1200. // Either we got the mutex (STATUS_SUCCESS) or the thread is being
  1201. // terminated (STATUS_USER_APC - since we're not alertable a
  1202. // user-mode APC can't be run except in certain special cases).
  1203. //
  1204. // Either way the completion routine will do the correct thing.
  1205. //
  1206. Request->CompletionRoutine(Adapter, Request, status);
  1207. //
  1208. // If we acquired the mutex, release it.
  1209. //
  1210. if (status == STATUS_SUCCESS) {
  1211. KeReleaseMutex(&(Adapter->EnumerationDeviceMutex), FALSE);
  1212. }
  1213. //
  1214. // If this is an async request, complete the IRP or pass it down
  1215. // depending on the status.
  1216. //
  1217. if (irp != NULL) {
  1218. SpCompleteEnumRequest(Adapter, irp);
  1219. }
  1220. }
  1221. return;
  1222. }
  1223. VOID
  1224. SpSignalEnumerationCompletion(
  1225. IN PADAPTER_EXTENSION Adapter,
  1226. IN PSP_ENUMERATION_REQUEST Request,
  1227. IN NTSTATUS Status
  1228. )
  1229. {
  1230. if(ARGUMENT_PRESENT(Request->CompletionStatus)) {
  1231. *(Request->CompletionStatus) = Status;
  1232. }
  1233. KeSetEvent((PKEVENT) Request->Context, IO_NO_INCREMENT, FALSE);
  1234. return;
  1235. }
  1236. VOID
  1237. SpEnumerationWorker(
  1238. IN PADAPTER_EXTENSION Adapter
  1239. )
  1240. {
  1241. NTSTATUS status;
  1242. PSP_ENUMERATION_REQUEST request;
  1243. PKTHREAD thread;
  1244. PIRP currentIrp;
  1245. PLIST_ENTRY currentEntry;
  1246. LIST_ENTRY completedListHead;
  1247. PAGED_CODE();
  1248. ASSERT_FDO(Adapter->DeviceObject);
  1249. ASSERT(Adapter->EnumerationRunning == TRUE);
  1250. //
  1251. // Initialize the list of completed IRPs.
  1252. //
  1253. InitializeListHead(&completedListHead);
  1254. Adapter->EnumerationWorkThread = KeGetCurrentThread();
  1255. //
  1256. // Grab the device mutex and enumerate the bus.
  1257. //
  1258. KeWaitForMutexObject(&(Adapter->EnumerationDeviceMutex),
  1259. UserRequest,
  1260. KernelMode,
  1261. FALSE,
  1262. NULL);
  1263. SpScanAdapter(Adapter);
  1264. //
  1265. // Drop the device mutex & grab the WorkList mutex.
  1266. //
  1267. KeReleaseMutex(&(Adapter->EnumerationDeviceMutex), FALSE);
  1268. ExAcquireFastMutex(&(Adapter->EnumerationWorklistMutex));
  1269. //
  1270. // Update the time of this bus scan.
  1271. //
  1272. KeQuerySystemTime(&(Adapter->LastBusScanTime));
  1273. //
  1274. // Grab a temporary remove lock. Use the address of the work item as a
  1275. // cheap way of ensuring that we haven't requeued the work item while the
  1276. // thread is still running.
  1277. //
  1278. SpAcquireRemoveLock(Adapter->DeviceObject, &(Adapter->EnumerationWorkItem));
  1279. //
  1280. // Run through the list of enumeration requests. For each one:
  1281. // * remove it from the work list.
  1282. // * save the irp if it's an async request
  1283. // * call its completion routine
  1284. //
  1285. for(request = Adapter->EnumerationWorkList;
  1286. request != NULL;
  1287. request = Adapter->EnumerationWorkList) {
  1288. //
  1289. // Remove this entry from the list. Clear the next request pointer
  1290. // as a bugcatcher.
  1291. //
  1292. Adapter->EnumerationWorkList = request->NextRequest;
  1293. request->NextRequest = NULL;
  1294. //
  1295. // If this is an asynchronous request, add the IRP to the completed list.
  1296. //
  1297. if (request->Synchronous == FALSE) {
  1298. currentIrp = (PIRP)request->Context;
  1299. InsertTailList(&completedListHead, &currentIrp->Tail.Overlay.ListEntry);
  1300. }
  1301. //
  1302. // Release the remove lock we acquired on behalf of the request object
  1303. // before we call the completion routine. The temporary lock we
  1304. // acquired above protects us.
  1305. //
  1306. SpReleaseRemoveLock(Adapter->DeviceObject, request);
  1307. //
  1308. // Call our completion callback routine.
  1309. //
  1310. request->CompletionRoutine(Adapter, request, STATUS_SUCCESS);
  1311. request = NULL;
  1312. }
  1313. //
  1314. // Indicate that the work item is no longer running.
  1315. //
  1316. Adapter->EnumerationRunning = FALSE;
  1317. Adapter->EnumerationWorkThread = NULL;
  1318. //
  1319. // Release the lock.
  1320. //
  1321. ExReleaseFastMutex(&(Adapter->EnumerationWorklistMutex));
  1322. //
  1323. // For asynchronous bus scans, we must wait until we've released the fast
  1324. // mutex to complete the IRPs. Doing so while holding the fast mutex
  1325. // completes the IRP at APC_LEVEL and this opens the door to filter
  1326. // drivers completion routines calling one of our dispatch routines at
  1327. // elevated IRQL. This is a problem because some of these dispatch
  1328. // routines process requests synchronously by blocking the thread and
  1329. // waiting for the IO Manager to set an event upon request completion.
  1330. // The problem is that the IO Manager, for synchronous operations,
  1331. // schedules an APC for the original thread in order to set the event
  1332. // and do buffer copying in the caller's thread context. This of course
  1333. // deadlocks because the waiting thread is already at APC_LEVEL.
  1334. //
  1335. // By releasing the mutex first, we drop the thread's IRQL back to
  1336. // PASSIVE_LEVEL and the problem is solved.
  1337. //
  1338. // The completion callback set the IRP's status and information fields;
  1339. // all we have to do is either forward the IRP down the stack if the
  1340. // status indicates success or complete it if the request failed.
  1341. //
  1342. ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
  1343. while (IsListEmpty(&completedListHead) == FALSE) {
  1344. //
  1345. // Get the next entry from the list.
  1346. //
  1347. currentEntry = RemoveHeadList(&completedListHead);
  1348. //
  1349. // Extract a pointer to the IRP.
  1350. //
  1351. currentIrp = CONTAINING_RECORD(currentEntry,
  1352. IRP,
  1353. Tail.Overlay.ListEntry);
  1354. //
  1355. // Complete the IRP.
  1356. //
  1357. SpCompleteEnumRequest(Adapter, currentIrp);
  1358. }
  1359. //
  1360. // Release the temporary remove lock we acquired above.
  1361. //
  1362. SpReleaseRemoveLock(Adapter->DeviceObject, &(Adapter->EnumerationWorkItem));
  1363. return;
  1364. }
  1365. VOID
  1366. SpScanAdapter(
  1367. IN PADAPTER_EXTENSION Adapter
  1368. )
  1369. /*++
  1370. Routine Description:
  1371. This routine scans all of the busses on an adapter. It locks down the
  1372. necessary memory pages, checks the registry to see if we should be
  1373. exposing disconnected luns, powers up the controller (if needed) and
  1374. then scans each bus for devices.
  1375. This routine is very much non-reenterant and should not be called outside
  1376. of the enumeration mutex (ie. outside of an enumeration request).
  1377. Arguments:
  1378. Adapter - a pointer to the adapter being enumerated.
  1379. Return Value:
  1380. none
  1381. --*/
  1382. {
  1383. PDEVICE_OBJECT deviceObject = Adapter->DeviceObject;
  1384. UCHAR i;
  1385. BOOLEAN exposeDisconnectedLuns = FALSE;
  1386. PLOGICAL_UNIT_EXTENSION rescanLun;
  1387. #ifdef ALLOC_PRAGMA
  1388. PVOID sectionHandle;
  1389. #endif
  1390. NTSTATUS status = STATUS_SUCCESS;
  1391. PAGED_CODE();
  1392. DebugPrint((EnumDebug, "SpScanAdapter: Beginning scan of adapter %#p\n", Adapter));
  1393. //
  1394. // Try to allocate a logical unit to use for probeing new bus addresses.
  1395. // Assume that it's going to be a SCSI-2 device.
  1396. //
  1397. status = SpCreateLogicalUnit(Adapter,
  1398. 0xff,
  1399. 0xff,
  1400. 0xff,
  1401. TRUE,
  1402. FALSE,
  1403. &rescanLun);
  1404. if(!NT_SUCCESS(status)) {
  1405. return;
  1406. }
  1407. //
  1408. // Lock down the PAGELOCK section - we'll need it in order to call
  1409. // IssueInquiry.
  1410. //
  1411. #ifdef ALLOC_PRAGMA
  1412. sectionHandle = MmLockPagableCodeSection(GetNextLuRequestWithoutLock);
  1413. InterlockedIncrement(&SpPAGELOCKLockCount);
  1414. #endif
  1415. //
  1416. // Check to see if we should be exposing disconnected LUNs.
  1417. //
  1418. for(i = 0; i < 3; i++) {
  1419. PWCHAR locations[] = {
  1420. L"Scsiport",
  1421. SCSIPORT_CONTROL_KEY,
  1422. DISK_SERVICE_KEY
  1423. };
  1424. UNICODE_STRING unicodeString;
  1425. OBJECT_ATTRIBUTES objectAttributes;
  1426. HANDLE instanceHandle = NULL;
  1427. HANDLE handle;
  1428. PKEY_VALUE_FULL_INFORMATION key = NULL;
  1429. if(i == 0) {
  1430. status = IoOpenDeviceRegistryKey(Adapter->LowerPdo,
  1431. PLUGPLAY_REGKEY_DEVICE,
  1432. KEY_READ,
  1433. &instanceHandle);
  1434. if(!NT_SUCCESS(status)) {
  1435. DebugPrint((2, "SpScanAdapter: Error %#08lx opening device registry key\n", status));
  1436. continue;
  1437. }
  1438. }
  1439. RtlInitUnicodeString(&unicodeString, locations[i]);
  1440. InitializeObjectAttributes(
  1441. &objectAttributes,
  1442. &unicodeString,
  1443. OBJ_CASE_INSENSITIVE,
  1444. instanceHandle,
  1445. NULL);
  1446. status = ZwOpenKey(&handle,
  1447. KEY_READ,
  1448. &objectAttributes);
  1449. if(!NT_SUCCESS(status)) {
  1450. DebugPrint((2, "SpScanAdapter: Error %#08lx opening %wZ key\n", status, &unicodeString));
  1451. if(instanceHandle != NULL) {
  1452. ZwClose(instanceHandle);
  1453. instanceHandle = NULL;
  1454. }
  1455. continue;
  1456. }
  1457. status = SpGetRegistryValue(deviceObject->DriverObject,
  1458. handle,
  1459. L"ScanDisconnectedDevices",
  1460. &key);
  1461. ZwClose(handle);
  1462. if(instanceHandle != NULL) {
  1463. ZwClose(instanceHandle);
  1464. instanceHandle = NULL;
  1465. }
  1466. if(NT_SUCCESS(status)) {
  1467. if(key->Type == REG_DWORD) {
  1468. PULONG value;
  1469. value = (PULONG) ((PUCHAR) key + key->DataOffset);
  1470. if(*value) {
  1471. exposeDisconnectedLuns = TRUE;
  1472. }
  1473. }
  1474. ExFreePool(key);
  1475. break;
  1476. } else {
  1477. DebugPrint((2, "SpScanAdapter: Error %#08lx opening %wZ\\ScanDisconnectedDevices value\n", status, &unicodeString));
  1478. }
  1479. }
  1480. //
  1481. // We need to be powered up in order to do a bus enumeration - make
  1482. // sure that we are. This is because we create new PDO's and new
  1483. // PDO's are assumed to be at D0.
  1484. //
  1485. status = SpRequestValidAdapterPowerStateSynchronous(Adapter);
  1486. if(NT_SUCCESS(status)) {
  1487. UCHAR pathId;
  1488. //
  1489. // Check if we are supposed to create a logical unit for the initiator. If
  1490. // so, try to create one if we haven't done so yet.
  1491. //
  1492. if (Adapter->CreateInitiatorLU == TRUE) {
  1493. if (Adapter->InitiatorLU[0] == NULL) {
  1494. Adapter->InitiatorLU[0] = SpCreateInitiatorLU(Adapter, Adapter->NumberOfBuses - 1);
  1495. if (Adapter->InitiatorLU[0] == NULL) {
  1496. DebugPrint((0, "SpScanBus: failed to create initiator LUN "
  1497. "for FDO %p bus %d\n",
  1498. Adapter->DeviceObject,
  1499. Adapter->NumberOfBuses - 1));
  1500. }
  1501. }
  1502. }
  1503. for (pathId = 0; pathId < Adapter->NumberOfBuses; pathId++) {
  1504. status = SpScanBus(Adapter, pathId, exposeDisconnectedLuns, rescanLun);
  1505. if(!NT_SUCCESS(status)) {
  1506. break;
  1507. }
  1508. }
  1509. }
  1510. #ifdef ALLOC_PRAGMA
  1511. InterlockedDecrement(&SpPAGELOCKLockCount);
  1512. MmUnlockPagableImageSection(sectionHandle);
  1513. #endif
  1514. SpDeleteLogicalUnit(rescanLun);
  1515. ASSERT(Adapter->RescanLun == NULL);
  1516. return;
  1517. }
  1518. NTSTATUS
  1519. SpScanBus(
  1520. IN PADAPTER_EXTENSION Adapter,
  1521. IN UCHAR PathId,
  1522. IN BOOLEAN ExposeDisconnectedLuns,
  1523. IN PLOGICAL_UNIT_EXTENSION RescanLun
  1524. )
  1525. {
  1526. UCHAR targetIndex;
  1527. NTSTATUS status = STATUS_SUCCESS;
  1528. DebugPrint((EnumDebug, "SpScanBus: Beginning scan of bus %x\n", PathId));
  1529. for(targetIndex = 0; targetIndex < Adapter->MaximumTargetIds; targetIndex++) {
  1530. UCHAR targetId;
  1531. if(Adapter->Capabilities.AdapterScansDown) {
  1532. targetId = Adapter->MaximumTargetIds - targetIndex - 1;
  1533. } else {
  1534. targetId = targetIndex;
  1535. }
  1536. DebugPrint((EnumDebug, "SpScanBus: targetIndex = %x -> targetId = %x\n",
  1537. targetIndex, targetId));
  1538. ASSERT(targetId != 255);
  1539. ASSERT(Adapter->PortConfig);
  1540. if(targetId == Adapter->PortConfig->InitiatorBusId[PathId]) {
  1541. DebugPrint((EnumDebug, "SpScanBus: Target ID matches initiator ID - skipping\n"));
  1542. continue;
  1543. }
  1544. //
  1545. // Mark all of the logical units as needing verification. At the
  1546. // end of scanning the target and LUNs which still need to be verified
  1547. // will be purged (marked as missing).
  1548. //
  1549. SpSetVerificationMarks(Adapter, PathId, targetId);
  1550. RescanLun->NeedsVerification = TRUE;
  1551. status = SpScanTarget(Adapter,
  1552. PathId,
  1553. targetId,
  1554. ExposeDisconnectedLuns,
  1555. RescanLun);
  1556. SpPurgeTarget(Adapter, PathId, targetId);
  1557. if(!NT_SUCCESS(status)) {
  1558. break;
  1559. }
  1560. }
  1561. return status;
  1562. }
  1563. NTSTATUS
  1564. SpScanTarget(
  1565. IN PADAPTER_EXTENSION Adapter,
  1566. IN UCHAR PathId,
  1567. IN UCHAR TargetId,
  1568. IN BOOLEAN ExposeDisconnectedLuns,
  1569. IN PLOGICAL_UNIT_EXTENSION RescanLun
  1570. )
  1571. {
  1572. BOOLEAN sparseLun = FALSE;
  1573. PLOGICAL_UNIT_EXTENSION lunZero;
  1574. BOOLEAN checkNextLun;
  1575. BOOLEAN scsi1 = FALSE;
  1576. PLUN_LIST lunList = NULL;
  1577. BOOLEAN saveLunList = FALSE;
  1578. ULONG numLunsReported;
  1579. UCHAR maxLuCount;
  1580. ULONG lunIndex;
  1581. NTSTATUS resetStatus;
  1582. NTSTATUS status;
  1583. DebugPrint((EnumDebug, "SpScanTarget: Beginning scan of target %x\n", TargetId));
  1584. //
  1585. // Use the SCSI-2 dispatch table when checking LUN 0.
  1586. //
  1587. ASSERT(RescanLun->CommonExtension.MajorFunction == DeviceMajorFunctionTable);
  1588. //
  1589. // Issue an inquiry to LUN 0.
  1590. //
  1591. status = SpInquireLogicalUnit(Adapter,
  1592. PathId,
  1593. TargetId,
  1594. (UCHAR) 0,
  1595. TRUE,
  1596. RescanLun,
  1597. &lunZero,
  1598. &checkNextLun);
  1599. //
  1600. // reset the rescan lun so that we can safely use it again. If this fails
  1601. // we still continue as far as possible with this target, but we return the
  1602. // reset status to the caller so it can abort its scan.
  1603. //
  1604. resetStatus = SpPrepareLogicalUnitForReuse(RescanLun);
  1605. if(!NT_SUCCESS(resetStatus)) {
  1606. RescanLun = NULL;
  1607. }
  1608. if(!NT_SUCCESS(status) &&
  1609. !((checkNextLun == TRUE) && (lunZero != NULL))) {
  1610. //
  1611. // There is no device present at LUN 0. Skip to the next target.
  1612. // Even if sparse luns is enabled there MUST be a LUN 0 for us to
  1613. // continue scanning the target.
  1614. //
  1615. DebugPrint((EnumDebug, "SpScanTarget: Lun 0 not found - terminating scan "
  1616. "(status %#08lx)\n", status));
  1617. return resetStatus;
  1618. }
  1619. //
  1620. // Indicate that lun 0 does not require verification.
  1621. //
  1622. SpClearVerificationMark(lunZero);
  1623. //
  1624. // Check for the special case of only having one LUN on this target.
  1625. //
  1626. if(lunZero->SpecialFlags.OneLun) {
  1627. DebugPrint((EnumDebug, "SpScanTarget: Target (%x,%x,*) is listed as having "
  1628. "only one lun\n", PathId, TargetId));
  1629. return resetStatus;
  1630. }
  1631. //
  1632. // Set the rescan LUN to use whatever lun zero uses for a dispatch table.
  1633. //
  1634. RescanLun->CommonExtension.MajorFunction =
  1635. lunZero->CommonExtension.MajorFunction;
  1636. //
  1637. // Determine if we should be handling sparse LUNs on this target.
  1638. //
  1639. sparseLun = TEST(lunZero->SpecialFlags.SparseLun);
  1640. if(sparseLun) {
  1641. DebugPrint((EnumDebug, "SpScanTarget: Target (%x,%x,*) will be checked for "
  1642. "sparse luns\n", PathId, TargetId));
  1643. }
  1644. //
  1645. // Issue a report luns command to the device if it supports it.
  1646. // If it doesn't support it then use the default LUN list.
  1647. //
  1648. if((lunZero->InquiryData.HiSupport || lunZero->SpecialFlags.LargeLuns)) {
  1649. DebugPrint((EnumDebug, "SpScanTarget: Target (%x,%x,*) may support REPORT_LUNS\n", PathId, TargetId));
  1650. //
  1651. // Indicate that we should indeed save the lun list. If it turns out
  1652. // that we're unable to retrieve one to be saved then we will
  1653. // clear the flag below.
  1654. //
  1655. saveLunList = TRUE;
  1656. status = IssueReportLuns(lunZero, &lunList);
  1657. //
  1658. // If the request fails for some reason then try to use the lun list
  1659. // which was saved for this target (in the extension of logical unit
  1660. // zero). If that hasn't been set either then we'll use the default
  1661. // one down below.
  1662. //
  1663. if(!NT_SUCCESS(status)) {
  1664. DebugPrint((EnumDebug, "SpScanTarget: Target (%x,%x,*) returned %#08lx to REPORT_LUNS command - using old list\n", PathId, TargetId, status));
  1665. lunList = lunZero->TargetLunList;
  1666. }
  1667. //
  1668. // If we can now or have in the past gotten a report luns list from the
  1669. // device then enable sparse lun scanning. In this case we also assume
  1670. // that up to 255 luns can be supported on this target.
  1671. //
  1672. if(lunList != NULL) {
  1673. sparseLun = TRUE;
  1674. DebugPrint((EnumDebug, "SpScanTarget: Target (%x,%x,*) will be checked for "
  1675. "sparse luns(2)\n", PathId, TargetId));
  1676. }
  1677. }
  1678. //
  1679. // if we still don't have a lun list then use the "default" one. In that
  1680. // event don't save it.
  1681. //
  1682. if(lunList == NULL) {
  1683. DebugPrint((EnumDebug, "SpScanTarget: Target (%x,%x,*) will use default lun list\n", PathId, TargetId));
  1684. lunList = (PLUN_LIST) &(ScsiPortDefaultLunList);
  1685. saveLunList = FALSE;
  1686. }
  1687. numLunsReported = lunList->LunListLength[3] << 0;
  1688. numLunsReported |= lunList->LunListLength[2] << 8;
  1689. numLunsReported |= lunList->LunListLength[1] << 16;
  1690. numLunsReported |= lunList->LunListLength[0] << 24;
  1691. numLunsReported /= sizeof (lunList->Lun[0]);
  1692. DebugPrint((EnumDebug, "SpScanTarget: Target (%x,%x,*) has reported %d luns\n", PathId, TargetId, numLunsReported));
  1693. //
  1694. // Walk through each entry in the LUN list. Stop when we run out of entries
  1695. // or the logical unit number is > MaximumNumberOfLogicalUnits (the lun
  1696. // list is assumed to be sorted in increasing order). For each entry,
  1697. // issue an inquiry. If the inquiry succeeds then clear the verification
  1698. // mark.
  1699. //
  1700. for(lunIndex = 0; lunIndex < numLunsReported; lunIndex++) {
  1701. PULONGLONG largeLun;
  1702. USHORT lun;
  1703. PLOGICAL_UNIT_EXTENSION logicalUnit;
  1704. largeLun = (PULONGLONG) (lunList->Lun[lunIndex]);
  1705. lun = lunList->Lun[lunIndex][1] << 0;
  1706. lun |= lunList->Lun[lunIndex][0] << 8;
  1707. lun &= 0x3fff;
  1708. //
  1709. // If the target reports a lun 0 just skip it.
  1710. //
  1711. DebugPrint((EnumDebug, "SpScanTarget: Checking lun %I64lx (%x): ", *largeLun, lun));
  1712. if(lun == 0) {
  1713. DebugPrint((EnumDebug, "Skipping LUN 0\n"));
  1714. continue;
  1715. }
  1716. //
  1717. // If the target reports a lun outside the range the driver can support
  1718. // then skip it.
  1719. //
  1720. if(lun >= Adapter->PortConfig->MaximumNumberOfLogicalUnits) {
  1721. DebugPrint((EnumDebug, "Skipping LUN out of range (> %x)\n",
  1722. Adapter->PortConfig->MaximumNumberOfLogicalUnits));
  1723. continue;
  1724. }
  1725. //
  1726. // Issue an inquiry to each logical unit in the system.
  1727. //
  1728. status = SpInquireLogicalUnit(Adapter,
  1729. PathId,
  1730. TargetId,
  1731. (UCHAR) lun,
  1732. ExposeDisconnectedLuns,
  1733. RescanLun,
  1734. &logicalUnit,
  1735. &checkNextLun);
  1736. if(RescanLun != NULL) {
  1737. resetStatus = SpPrepareLogicalUnitForReuse(RescanLun);
  1738. if(!NT_SUCCESS(resetStatus)) {
  1739. RescanLun = NULL;
  1740. }
  1741. }
  1742. if(NT_SUCCESS(status)) {
  1743. DebugPrint((EnumDebug, "Inquiry succeeded\n"));
  1744. SpClearVerificationMark(logicalUnit);
  1745. } else {
  1746. DebugPrint((EnumDebug, "inquiry returned %#08lx.", status));
  1747. if((sparseLun == FALSE)&&(checkNextLun == FALSE)) {
  1748. DebugPrint((EnumDebug, "Aborting\n"));
  1749. break;
  1750. } else {
  1751. DebugPrint((EnumDebug, " - checking next (%c%c)\n",
  1752. sparseLun ? 's' : ' ',
  1753. checkNextLun ? 'c' : ' '));
  1754. }
  1755. }
  1756. }
  1757. //
  1758. // If we're supposed to save the lun list then replace the one in lun0
  1759. // with this one.
  1760. //
  1761. if(saveLunList) {
  1762. DebugPrint((EnumDebug, "SpScanTarget: Saving LUN list %#08lx\n", lunList));
  1763. ASSERT(lunZero->TargetLunList != (PLUN_LIST) &(ScsiPortDefaultLunList));
  1764. if(lunZero->TargetLunList != NULL && lunZero->TargetLunList != lunList) {
  1765. DebugPrint((EnumDebug, "SpScanTarget: Freeing old LUN list %#08lx\n", lunZero->TargetLunList));
  1766. ExFreePool(lunZero->TargetLunList);
  1767. }
  1768. lunZero->TargetLunList = lunList;
  1769. } else {
  1770. ASSERT(lunList == (PLUN_LIST) &(ScsiPortDefaultLunList));
  1771. }
  1772. //
  1773. // reset the rescan LUN to use the scsi 2 dispatch table.
  1774. //
  1775. RescanLun->CommonExtension.MajorFunction = DeviceMajorFunctionTable;
  1776. return resetStatus;
  1777. }
  1778. VOID
  1779. SpSetVerificationMarks(
  1780. IN PADAPTER_EXTENSION Adapter,
  1781. IN UCHAR PathId,
  1782. IN UCHAR TargetId
  1783. )
  1784. {
  1785. PLOGICAL_UNIT_EXTENSION logicalUnit;
  1786. KIRQL oldIrql;
  1787. ULONG bin;
  1788. //
  1789. // Code is paged until locked down.
  1790. //
  1791. PAGED_CODE();
  1792. ASSERT(SpPAGELOCKLockCount != 0);
  1793. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  1794. for(bin = 0; bin < NUMBER_LOGICAL_UNIT_BINS; bin++) {
  1795. KeAcquireSpinLockAtDpcLevel(&(Adapter->LogicalUnitList[bin].Lock));
  1796. for(logicalUnit = Adapter->LogicalUnitList[bin].List;
  1797. logicalUnit != NULL;
  1798. logicalUnit = logicalUnit->NextLogicalUnit) {
  1799. ASSERT(logicalUnit->IsTemporary == FALSE);
  1800. if((logicalUnit->PathId == PathId) &&
  1801. (logicalUnit->TargetId == TargetId)) {
  1802. logicalUnit->NeedsVerification = TRUE;
  1803. }
  1804. }
  1805. KeReleaseSpinLockFromDpcLevel(&(Adapter->LogicalUnitList[bin].Lock));
  1806. }
  1807. KeLowerIrql(oldIrql);
  1808. return;
  1809. }
  1810. VOID
  1811. SpClearVerificationMark(
  1812. IN PLOGICAL_UNIT_EXTENSION LogicalUnit
  1813. )
  1814. {
  1815. PAGED_CODE();
  1816. ASSERT(LogicalUnit->IsTemporary == FALSE);
  1817. ASSERT(LogicalUnit->NeedsVerification == TRUE);
  1818. LogicalUnit->NeedsVerification = FALSE;
  1819. return;
  1820. }
  1821. VOID
  1822. SpPurgeTarget(
  1823. IN PADAPTER_EXTENSION Adapter,
  1824. IN UCHAR PathId,
  1825. IN UCHAR TargetId
  1826. )
  1827. {
  1828. PLOGICAL_UNIT_EXTENSION logicalUnit;
  1829. KIRQL oldIrql;
  1830. ULONG bin;
  1831. //
  1832. // Code is paged until locked down.
  1833. //
  1834. PAGED_CODE();
  1835. ASSERT(SpPAGELOCKLockCount != 0);
  1836. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
  1837. for(bin = 0; bin < NUMBER_LOGICAL_UNIT_BINS; bin++) {
  1838. KeAcquireSpinLockAtDpcLevel(&(Adapter->LogicalUnitList[bin].Lock));
  1839. for(logicalUnit = Adapter->LogicalUnitList[bin].List;
  1840. logicalUnit != NULL;
  1841. logicalUnit = logicalUnit->NextLogicalUnit) {
  1842. ASSERT(logicalUnit->IsTemporary == FALSE);
  1843. if((logicalUnit->PathId == PathId) &&
  1844. (logicalUnit->TargetId == TargetId) &&
  1845. (logicalUnit->NeedsVerification == TRUE)) {
  1846. //
  1847. // This device was not found to be present during our bus scan.
  1848. //
  1849. DebugPrint((EnumDebug, "SpPurgeTarget: Lun (%x,%x,%x) is still marked and will be made missing\n", logicalUnit->PathId, logicalUnit->TargetId, logicalUnit->Lun));
  1850. logicalUnit->IsMissing = TRUE;
  1851. }
  1852. }
  1853. KeReleaseSpinLockFromDpcLevel(&(Adapter->LogicalUnitList[bin].Lock));
  1854. }
  1855. KeLowerIrql(oldIrql);
  1856. return;
  1857. }
  1858. NTSTATUS
  1859. SpCreateLogicalUnit(
  1860. IN PADAPTER_EXTENSION Adapter,
  1861. IN OPTIONAL UCHAR PathId,
  1862. IN OPTIONAL UCHAR TargetId,
  1863. IN OPTIONAL UCHAR Lun,
  1864. IN BOOLEAN Temporary,
  1865. IN BOOLEAN Scsi1,
  1866. OUT PLOGICAL_UNIT_EXTENSION *NewLun
  1867. )
  1868. /*++
  1869. Routine Description:
  1870. This routine will create a physical device object for the specified device
  1871. Arguments:
  1872. Adapter - the parent adapter for this new lun
  1873. PathId, TargetId, Lun - the address of this lun. Not used if Temporary is
  1874. TRUE (see below).
  1875. Temporary - indicates whether this device is real (FALSE) or simply for
  1876. the purposes of scanning the bus (TRUE). If TRUE then the
  1877. address info is ignored and this lun is NOT inserted into the
  1878. logical unit list.
  1879. Scsi1 - indicates that this LUN is a scsi1 lun and needs to use the
  1880. dispatch routines which stick the LUN number into the CDB itself.
  1881. NewLun - a location to store the pointer to the new lun
  1882. Return Value:
  1883. status
  1884. --*/
  1885. {
  1886. PIRP senseIrp;
  1887. PDEVICE_OBJECT pdo = NULL;
  1888. PLOGICAL_UNIT_EXTENSION logicalUnitExtension;
  1889. WCHAR wideDeviceName[64];
  1890. UNICODE_STRING unicodeDeviceName;
  1891. PVOID hwExtension = NULL;
  1892. PVOID serialNumberBuffer = NULL;
  1893. PVOID idBuffer = NULL;
  1894. NTSTATUS status;
  1895. PAGED_CODE();
  1896. //
  1897. // Attempt to allocate all the persistent resources we need before we
  1898. // try to create the device object itself.
  1899. //
  1900. //
  1901. // Allocate a request sense irp.
  1902. //
  1903. senseIrp = SpAllocateIrp(1, FALSE, Adapter->DeviceObject->DriverObject);
  1904. if(senseIrp == NULL) {
  1905. DebugPrint((0, "SpCreateLogicalUnit: Could not allocate request sense "
  1906. "irp\n"));
  1907. return STATUS_INSUFFICIENT_RESOURCES;
  1908. }
  1909. //
  1910. // Build the name for the device
  1911. //
  1912. if(Temporary == FALSE) {
  1913. swprintf(wideDeviceName,
  1914. L"%wsPort%xPath%xTarget%xLun%x",
  1915. Adapter->DeviceName,
  1916. Adapter->PortNumber,
  1917. PathId,
  1918. TargetId,
  1919. Lun);
  1920. } else {
  1921. swprintf(wideDeviceName,
  1922. L"%wsPort%xRescan",
  1923. Adapter->DeviceName,
  1924. Adapter->PortNumber);
  1925. PathId = 0xff;
  1926. TargetId = 0xff;
  1927. Lun = 0xff;
  1928. ASSERT(Adapter->RescanLun == NULL);
  1929. }
  1930. RtlInitUnicodeString(&unicodeDeviceName, wideDeviceName);
  1931. //
  1932. // Round the size of the Hardware logical extension to the size of a
  1933. // PVOID and add it to the port driver's logical extension.
  1934. //
  1935. if(Adapter->HwLogicalUnitExtensionSize != 0) {
  1936. hwExtension = SpAllocatePool(
  1937. NonPagedPoolCacheAligned,
  1938. Adapter->HwLogicalUnitExtensionSize,
  1939. SCSIPORT_TAG_LUN_EXT,
  1940. Adapter->DeviceObject->DriverObject);
  1941. if(hwExtension == NULL) {
  1942. *NewLun = NULL;
  1943. IoFreeIrp(senseIrp);
  1944. return STATUS_INSUFFICIENT_RESOURCES;
  1945. }
  1946. RtlZeroMemory(hwExtension,
  1947. Adapter->HwLogicalUnitExtensionSize);
  1948. }
  1949. //
  1950. // If this is a temporary lun then allocate a large buffer to store the
  1951. // identify data.
  1952. //
  1953. if(Temporary) {
  1954. serialNumberBuffer = SpAllocatePool(
  1955. PagedPool,
  1956. VPD_MAX_BUFFER_SIZE,
  1957. SCSIPORT_TAG_TEMP_ID_BUFFER,
  1958. Adapter->DeviceObject->DriverObject);
  1959. if(serialNumberBuffer == NULL) {
  1960. if (hwExtension != NULL) {
  1961. ExFreePool(hwExtension);
  1962. }
  1963. IoFreeIrp(senseIrp);
  1964. return STATUS_INSUFFICIENT_RESOURCES;
  1965. }
  1966. idBuffer = SpAllocatePool(PagedPool,
  1967. VPD_MAX_BUFFER_SIZE,
  1968. SCSIPORT_TAG_TEMP_ID_BUFFER,
  1969. Adapter->DeviceObject->DriverObject);
  1970. if(idBuffer == NULL) {
  1971. if (hwExtension != NULL) {
  1972. ExFreePool(hwExtension);
  1973. }
  1974. IoFreeIrp(senseIrp);
  1975. ExFreePool(serialNumberBuffer);
  1976. return STATUS_INSUFFICIENT_RESOURCES;
  1977. }
  1978. RtlZeroMemory(serialNumberBuffer, VPD_MAX_BUFFER_SIZE);
  1979. RtlZeroMemory(idBuffer, VPD_MAX_BUFFER_SIZE);
  1980. }
  1981. //
  1982. // Create a physical device object
  1983. //
  1984. status = IoCreateDevice(
  1985. Adapter->DeviceObject->DriverObject,
  1986. sizeof(LOGICAL_UNIT_EXTENSION),
  1987. &unicodeDeviceName,
  1988. FILE_DEVICE_MASS_STORAGE,
  1989. FILE_DEVICE_SECURE_OPEN,
  1990. FALSE,
  1991. &pdo
  1992. );
  1993. if(NT_SUCCESS(status)) {
  1994. PCOMMON_EXTENSION commonExtension;
  1995. UCHAR i;
  1996. ULONG bin;
  1997. UCHAR rawDeviceName[64];
  1998. ANSI_STRING ansiDeviceName;
  1999. //
  2000. // Set the device object's stack size
  2001. //
  2002. //
  2003. // We need one stack location for the PDO to do lock tracking and
  2004. // one stack location to issue scsi request to the FDO.
  2005. //
  2006. pdo->StackSize = 1;
  2007. pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
  2008. pdo->Flags |= DO_DIRECT_IO;
  2009. pdo->AlignmentRequirement = Adapter->DeviceObject->AlignmentRequirement;
  2010. //
  2011. // Initialize the device extension for the root device
  2012. //
  2013. commonExtension = pdo->DeviceExtension;
  2014. logicalUnitExtension = pdo->DeviceExtension;
  2015. RtlZeroMemory(logicalUnitExtension, sizeof(LOGICAL_UNIT_EXTENSION));
  2016. commonExtension->DeviceObject = pdo;
  2017. commonExtension->IsPdo = TRUE;
  2018. commonExtension->LowerDeviceObject = Adapter->DeviceObject;
  2019. if(Scsi1) {
  2020. commonExtension->MajorFunction = Scsi1DeviceMajorFunctionTable;
  2021. } else {
  2022. commonExtension->MajorFunction = DeviceMajorFunctionTable;
  2023. }
  2024. commonExtension->WmiInitialized = FALSE;
  2025. commonExtension->WmiMiniPortSupport =
  2026. Adapter->CommonExtension.WmiMiniPortSupport;
  2027. commonExtension->WmiScsiPortRegInfoBuf = NULL;
  2028. commonExtension->WmiScsiPortRegInfoBufSize = 0;
  2029. //
  2030. // Initialize value to zero. It will be incremented once pnp is aware
  2031. // of its existance.
  2032. //
  2033. commonExtension->RemoveLock = 0;
  2034. #if DBG
  2035. KeInitializeSpinLock(&commonExtension->RemoveTrackingSpinlock);
  2036. commonExtension->RemoveTrackingList = NULL;
  2037. ExInitializeNPagedLookasideList(
  2038. &(commonExtension->RemoveTrackingLookasideList),
  2039. NULL,
  2040. NULL,
  2041. 0,
  2042. sizeof(REMOVE_TRACKING_BLOCK),
  2043. SCSIPORT_TAG_LOCK_TRACKING,
  2044. 64);
  2045. commonExtension->RemoveTrackingLookasideListInitialized = TRUE;
  2046. #else
  2047. commonExtension->RemoveTrackingSpinlock = (ULONG) -1L;
  2048. commonExtension->RemoveTrackingList = (PVOID) -1L;
  2049. #endif
  2050. commonExtension->CurrentPnpState = 0xff;
  2051. commonExtension->PreviousPnpState = 0xff;
  2052. //
  2053. // Initialize the remove lock event.
  2054. //
  2055. KeInitializeEvent(
  2056. &(logicalUnitExtension->CommonExtension.RemoveEvent),
  2057. SynchronizationEvent,
  2058. FALSE);
  2059. logicalUnitExtension->PortNumber = Adapter->PortNumber;
  2060. logicalUnitExtension->PathId = 0xff;
  2061. logicalUnitExtension->TargetId = 0xff;
  2062. logicalUnitExtension->Lun = 0xff;
  2063. logicalUnitExtension->HwLogicalUnitExtension = hwExtension;
  2064. logicalUnitExtension->AdapterExtension = Adapter;
  2065. //
  2066. // Give the caller the benefit of the doubt.
  2067. //
  2068. logicalUnitExtension->IsMissing = FALSE;
  2069. //
  2070. // The device cannot have been enumerated yet.
  2071. //
  2072. logicalUnitExtension->IsEnumerated = FALSE;
  2073. //
  2074. // Set timer counters to -1 to inidicate that there are no outstanding
  2075. // requests.
  2076. //
  2077. logicalUnitExtension->RequestTimeoutCounter = -1;
  2078. //
  2079. // Initialize the maximum queue depth size.
  2080. //
  2081. logicalUnitExtension->MaxQueueDepth = 0xFF;
  2082. //
  2083. // Initialize the request list.
  2084. //
  2085. InitializeListHead(&logicalUnitExtension->RequestList);
  2086. //
  2087. // Initialize the blocked request list.
  2088. //
  2089. InitializeListHead(&logicalUnitExtension->SrbDataBlockedRequests);
  2090. //
  2091. // Initialize the push/pop list of SRB_DATA blocks for use with bypass
  2092. // requests.
  2093. //
  2094. KeInitializeSpinLock(&(logicalUnitExtension->BypassSrbDataSpinLock));
  2095. ExInitializeSListHead(&(logicalUnitExtension->BypassSrbDataList));
  2096. for(i = 0; i < NUMBER_BYPASS_SRB_DATA_BLOCKS; i++) {
  2097. ExInterlockedPushEntrySList(
  2098. &(logicalUnitExtension->BypassSrbDataList),
  2099. &(logicalUnitExtension->BypassSrbDataBlocks[i].Reserved),
  2100. &(logicalUnitExtension->BypassSrbDataSpinLock));
  2101. }
  2102. //
  2103. // Assume devices are powered on by default.
  2104. //
  2105. commonExtension->CurrentDeviceState = PowerDeviceD0;
  2106. commonExtension->DesiredDeviceState = PowerDeviceUnspecified;
  2107. //
  2108. // Assume that we're being initialized in a working system.
  2109. //
  2110. commonExtension->CurrentSystemState = PowerSystemWorking;
  2111. //
  2112. // Setup the request sense resources.
  2113. //
  2114. logicalUnitExtension->RequestSenseIrp = senseIrp;
  2115. //
  2116. // If this is temporary record that fact in the logical unit extension
  2117. // and save a pointer in the adapter (cleared when the LUN is
  2118. // destroyed). If it's real then stick it into the logical unit list.
  2119. //
  2120. logicalUnitExtension->IsTemporary = Temporary;
  2121. #if defined (NEWQUEUE)
  2122. //
  2123. // Initialize the LU Capacity and Zone params with default values:
  2124. // Capacity : 0xffffffff blocks
  2125. // Zones : 4
  2126. //
  2127. {
  2128. ULONG zoneLen = SP_DEFAULT_MAX_CAPACITY / SP_DEFAULT_ZONES;
  2129. logicalUnitExtension->Capacity = SP_DEFAULT_MAX_CAPACITY;
  2130. logicalUnitExtension->Zones = SP_DEFAULT_ZONES;
  2131. logicalUnitExtension->ZoneLength = zoneLen;
  2132. logicalUnitExtension->FirstSector[0] = 0;
  2133. logicalUnitExtension->FirstSector[1] = zoneLen;
  2134. logicalUnitExtension->FirstSector[2] = zoneLen * 2;
  2135. logicalUnitExtension->FirstSector[3] = zoneLen * 3;
  2136. logicalUnitExtension->LastSector[0] = zoneLen - 1;
  2137. logicalUnitExtension->LastSector[1] = (zoneLen * 2) - 1;
  2138. logicalUnitExtension->LastSector[2] = (zoneLen * 3) - 1;
  2139. logicalUnitExtension->LastSector[3] = SP_DEFAULT_MAX_CAPACITY - 1;
  2140. logicalUnitExtension->NextSequentialZone[0] = 1;
  2141. logicalUnitExtension->NextSequentialZone[1] = 2;
  2142. logicalUnitExtension->NextSequentialZone[2] = 3;
  2143. logicalUnitExtension->NextSequentialZone[3] = 0;
  2144. }
  2145. #endif // NEWQUEUE
  2146. //
  2147. // Initialize
  2148. RtlInitAnsiString(&(logicalUnitExtension->SerialNumber), serialNumberBuffer);
  2149. if(serialNumberBuffer != NULL) {
  2150. logicalUnitExtension->SerialNumber.MaximumLength = VPD_MAX_BUFFER_SIZE;
  2151. }
  2152. logicalUnitExtension->DeviceIdentifierPage = idBuffer;
  2153. //
  2154. // I guess this is as ready to be opened as it ever will be.
  2155. //
  2156. pdo->Flags &= ~DO_DEVICE_INITIALIZING;
  2157. //
  2158. // Initialize the lock & unlock request queue.
  2159. //
  2160. KeInitializeDeviceQueue(&(logicalUnitExtension->LockRequestQueue));
  2161. logicalUnitExtension->CurrentLockRequest = NULL;
  2162. } else {
  2163. DebugPrint((1, "ScsiBusCreatePdo: Error %#08lx creating device object\n",
  2164. status));
  2165. logicalUnitExtension = NULL;
  2166. if(hwExtension != NULL) {
  2167. ExFreePool(hwExtension);
  2168. }
  2169. IoFreeIrp(senseIrp);
  2170. ExFreePool(serialNumberBuffer);
  2171. ExFreePool(idBuffer);
  2172. }
  2173. *NewLun = logicalUnitExtension;
  2174. return status;
  2175. }
  2176. VOID
  2177. SpSetLogicalUnitAddress(
  2178. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  2179. IN UCHAR PathId,
  2180. IN UCHAR TargetId,
  2181. IN UCHAR Lun
  2182. )
  2183. {
  2184. UCHAR i;
  2185. ULONG bin;
  2186. ASSERT_PDO(LogicalUnit->DeviceObject);
  2187. ASSERT(LogicalUnit->PathId == 0xff);
  2188. ASSERT(LogicalUnit->TargetId == 0xff);
  2189. ASSERT(LogicalUnit->Lun == 0xff);
  2190. LogicalUnit->PathId = PathId;
  2191. LogicalUnit->TargetId = TargetId;
  2192. LogicalUnit->Lun = Lun;
  2193. SpAddLogicalUnitToBin(LogicalUnit->AdapterExtension, LogicalUnit);
  2194. return;
  2195. }
  2196. VOID
  2197. SpClearLogicalUnitAddress(
  2198. IN PLOGICAL_UNIT_EXTENSION LogicalUnit
  2199. )
  2200. {
  2201. ASSERT_PDO(LogicalUnit->DeviceObject);
  2202. ASSERT(LogicalUnit->IsTemporary == TRUE);
  2203. SpRemoveLogicalUnitFromBin(LogicalUnit->AdapterExtension, LogicalUnit);
  2204. LogicalUnit->PathId = 0xff;
  2205. LogicalUnit->TargetId = 0xff;
  2206. LogicalUnit->Lun = 0xff;
  2207. return;
  2208. }
  2209. NTSTATUS
  2210. SpCloneAndSwapLogicalUnit(
  2211. IN PLOGICAL_UNIT_EXTENSION TemplateLun,
  2212. IN PINQUIRYDATA InquiryData,
  2213. IN ULONG InquiryDataSize,
  2214. OUT PLOGICAL_UNIT_EXTENSION *NewLun
  2215. )
  2216. /*++
  2217. Routine Description:
  2218. This routine will create a new logical unit object with the properties of
  2219. TemplateLun. The supplied inquiry data will be assigned to the new
  2220. logical unit. Finally the new logical unit will be swapped for
  2221. TemplateLun in the adapter's logical unit list.
  2222. TemplateLun must be a temporary logical unit which has been assigned an
  2223. address and is present in the logical unit lists.
  2224. Regardless of whether this function succeeds, the TemplateLun will be
  2225. removed from the logical unit list (effectively swapped with nothing).
  2226. Arguments:
  2227. TemplateLun - the logical unit to be cloned
  2228. InquiryData, InquiryDataSize - the inquiry data to be used for the new
  2229. logical unit
  2230. NewLun - a location to store the pointer to the new logical unit.
  2231. Return Value:
  2232. STATUS_SUCCESS indicates that a new lun has been created and swapped in
  2233. the logical unit list.
  2234. error status indicates that the new logical unit could not be created for
  2235. some reason.
  2236. --*/
  2237. {
  2238. PADAPTER_EXTENSION adapter = TemplateLun->AdapterExtension;
  2239. PSCSIPORT_DRIVER_EXTENSION driverExtension =
  2240. IoGetDriverObjectExtension(
  2241. adapter->DeviceObject->DriverObject,
  2242. ScsiPortInitialize);
  2243. UCHAR pathId, targetId, lun;
  2244. PVOID serialNumber = NULL;
  2245. USHORT serialNumberLength = 0;
  2246. PVOID identifier = NULL;
  2247. ULONG identifierLength = 0;
  2248. PLOGICAL_UNIT_EXTENSION newLun;
  2249. BOOLEAN scsi1;
  2250. NTSTATUS status;
  2251. ASSERT_PDO(TemplateLun->DeviceObject);
  2252. ASSERT(TemplateLun->IsTemporary);
  2253. *NewLun = NULL;
  2254. #if DBG
  2255. newLun = GetLogicalUnitExtension(adapter,
  2256. TemplateLun->PathId,
  2257. TemplateLun->TargetId,
  2258. TemplateLun->Lun,
  2259. NULL,
  2260. TRUE);
  2261. ASSERT(newLun == TemplateLun);
  2262. #endif
  2263. //
  2264. // Wait for any outstanding i/o on the template lun to complete.
  2265. //
  2266. SpReleaseRemoveLock(TemplateLun->DeviceObject, SpInquireLogicalUnit);
  2267. SpWaitForRemoveLock(TemplateLun->DeviceObject, SP_BASE_REMOVE_LOCK);
  2268. //
  2269. // Save the address away and then remove the template object from the
  2270. // logical unit list.
  2271. //
  2272. pathId = TemplateLun->PathId;
  2273. targetId = TemplateLun->TargetId;
  2274. lun = TemplateLun->Lun;
  2275. SpClearLogicalUnitAddress(TemplateLun);
  2276. //
  2277. // Before creating a named object, preallocate any resources we'll need
  2278. // that SpCreateLogicalUnit doesn't provide.
  2279. //
  2280. if(TemplateLun->SerialNumber.Length != 0) {
  2281. serialNumberLength = (TemplateLun->SerialNumber.Length +
  2282. sizeof(UNICODE_NULL));
  2283. serialNumber = SpAllocatePool(PagedPool,
  2284. serialNumberLength,
  2285. SCSIPORT_TAG_ID_BUFFER,
  2286. TemplateLun->DeviceObject->DriverObject);
  2287. if(serialNumber == NULL) {
  2288. return STATUS_INSUFFICIENT_RESOURCES;
  2289. }
  2290. }
  2291. if(TemplateLun->DeviceIdentifierPageLength != 0) {
  2292. identifier = SpAllocatePool(
  2293. PagedPool,
  2294. TemplateLun->DeviceIdentifierPageLength,
  2295. SCSIPORT_TAG_ID_BUFFER,
  2296. TemplateLun->DeviceObject->DriverObject);
  2297. if(identifier == NULL) {
  2298. if(serialNumber != NULL) {
  2299. ExFreePool(serialNumber);
  2300. }
  2301. return STATUS_INSUFFICIENT_RESOURCES;
  2302. }
  2303. }
  2304. //
  2305. // If the lun is scsi-1 or if the magic registry flag was set then use the
  2306. // scsi 1 dispatch table for this device.
  2307. //
  2308. if((driverExtension->BusType == BusTypeScsi) &&
  2309. ((InquiryData->ANSIVersion == 0) ||
  2310. (InquiryData->ANSIVersion == 1) ||
  2311. (TemplateLun->SpecialFlags.SetLunInCdb))) {
  2312. scsi1 = TRUE;
  2313. } else {
  2314. scsi1 = FALSE;
  2315. }
  2316. //
  2317. // Now create a new logical unit with the same address.
  2318. //
  2319. status = SpCreateLogicalUnit(adapter,
  2320. pathId,
  2321. targetId,
  2322. lun,
  2323. FALSE,
  2324. scsi1,
  2325. &newLun);
  2326. if(!NT_SUCCESS(status)) {
  2327. if(serialNumber != NULL) {
  2328. ExFreePool(serialNumber);
  2329. }
  2330. if(identifier) {
  2331. ExFreePool(identifier);
  2332. }
  2333. return status;
  2334. }
  2335. //
  2336. // Copy the important information from the template logical unit over to
  2337. // the new one. Zero out the original so that we know to reallocate one
  2338. // later.
  2339. //
  2340. newLun->HwLogicalUnitExtension = TemplateLun->HwLogicalUnitExtension;
  2341. TemplateLun->HwLogicalUnitExtension = NULL;
  2342. newLun->LuFlags = TemplateLun->LuFlags;
  2343. newLun->IsVisible = TemplateLun->IsVisible;
  2344. newLun->TargetLunList = TemplateLun->TargetLunList;
  2345. newLun->SpecialFlags = TemplateLun->SpecialFlags;
  2346. newLun->NeedsVerification = TemplateLun->NeedsVerification;
  2347. newLun->CommonExtension.SrbFlags = TemplateLun->CommonExtension.SrbFlags;
  2348. //
  2349. // Copy over any characteristics flags which were set during enumeration.
  2350. //
  2351. newLun->DeviceObject->Characteristics |=
  2352. (TemplateLun->DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA);
  2353. //
  2354. // Copy the list of supported vital product data pages.
  2355. //
  2356. newLun->DeviceIdentifierPageSupported = TemplateLun->DeviceIdentifierPageSupported;
  2357. newLun->SerialNumberPageSupported = TemplateLun->SerialNumberPageSupported;
  2358. //
  2359. // If this device reports a serial number in it's vital product data then
  2360. // copy it in to the new lun.
  2361. //
  2362. if(serialNumber != NULL) {
  2363. newLun->SerialNumber.Length = TemplateLun->SerialNumber.Length;
  2364. newLun->SerialNumber.MaximumLength = serialNumberLength;
  2365. newLun->SerialNumber.Buffer = serialNumber;
  2366. RtlCopyMemory(newLun->SerialNumber.Buffer,
  2367. TemplateLun->SerialNumber.Buffer,
  2368. serialNumberLength);
  2369. }
  2370. //
  2371. // If this has a device identifier page then copy it over two.
  2372. //
  2373. if(identifier != NULL) {
  2374. newLun->DeviceIdentifierPage = identifier;
  2375. newLun->DeviceIdentifierPageLength =
  2376. TemplateLun->DeviceIdentifierPageLength;
  2377. RtlCopyMemory(newLun->DeviceIdentifierPage,
  2378. TemplateLun->DeviceIdentifierPage,
  2379. newLun->DeviceIdentifierPageLength);
  2380. }
  2381. //
  2382. // Copy the inquiry data over.
  2383. //
  2384. ASSERT(InquiryDataSize <= sizeof(INQUIRYDATA));
  2385. RtlCopyMemory(&(newLun->InquiryData), InquiryData, InquiryDataSize);
  2386. //
  2387. // Acquire the appropriate remove locks on the new logical unit.
  2388. //
  2389. SpAcquireRemoveLock(newLun->DeviceObject, SP_BASE_REMOVE_LOCK);
  2390. SpAcquireRemoveLock(newLun->DeviceObject, SpInquireLogicalUnit);
  2391. //
  2392. // Now insert this new lun into the logical unit list.
  2393. //
  2394. SpSetLogicalUnitAddress(newLun, pathId, targetId, lun);
  2395. *NewLun = newLun;
  2396. return status;
  2397. }
  2398. NTSTATUS
  2399. SpPrepareLogicalUnitForReuse(
  2400. PLOGICAL_UNIT_EXTENSION LogicalUnit
  2401. )
  2402. {
  2403. PADAPTER_EXTENSION adapter = LogicalUnit->AdapterExtension;
  2404. PCOMMON_EXTENSION commonExtension = &(LogicalUnit->CommonExtension);
  2405. PVOID hwExtension = NULL;
  2406. NTSTATUS status;
  2407. ASSERT_PDO(LogicalUnit->DeviceObject);
  2408. ASSERT(LogicalUnit->CommonExtension.WmiInitialized == FALSE);
  2409. ASSERT(LogicalUnit->CommonExtension.WmiScsiPortRegInfoBuf == NULL);
  2410. ASSERT(LogicalUnit->CommonExtension.WmiScsiPortRegInfoBufSize == 0);
  2411. //
  2412. // Clear the remove lock event.
  2413. //
  2414. ASSERT(LogicalUnit->CommonExtension.RemoveLock == 0);
  2415. //
  2416. // Initialize the remove lock event.
  2417. //
  2418. KeClearEvent(&(LogicalUnit->CommonExtension.RemoveEvent));
  2419. LogicalUnit->PathId = 0xff;
  2420. LogicalUnit->TargetId = 0xff;
  2421. LogicalUnit->Lun = 0xff;
  2422. //
  2423. // Round the size of the Hardware logical extension to the size of a
  2424. // PVOID and add it to the port driver's logical extension.
  2425. //
  2426. if((LogicalUnit->HwLogicalUnitExtension == NULL) &&
  2427. (adapter->HwLogicalUnitExtensionSize != 0)) {
  2428. hwExtension = SpAllocatePool(NonPagedPoolCacheAligned,
  2429. adapter->HwLogicalUnitExtensionSize,
  2430. SCSIPORT_TAG_LUN_EXT,
  2431. LogicalUnit->DeviceObject->DriverObject);
  2432. if(hwExtension == NULL) {
  2433. return STATUS_INSUFFICIENT_RESOURCES;
  2434. }
  2435. LogicalUnit->HwLogicalUnitExtension = hwExtension;
  2436. }
  2437. if(LogicalUnit->HwLogicalUnitExtension != NULL) {
  2438. RtlZeroMemory(LogicalUnit->HwLogicalUnitExtension,
  2439. adapter->HwLogicalUnitExtensionSize);
  2440. }
  2441. LogicalUnit->IsMissing = FALSE;
  2442. LogicalUnit->IsVisible = FALSE;
  2443. ASSERT(LogicalUnit->IsEnumerated == FALSE);
  2444. //
  2445. // Device has no longer been removed.
  2446. //
  2447. LogicalUnit->CommonExtension.IsRemoved = NO_REMOVE;
  2448. //
  2449. // Clear cached infomation about the device identifier(s).
  2450. //
  2451. LogicalUnit->DeviceIdentifierPageSupported = FALSE;
  2452. LogicalUnit->SerialNumberPageSupported = FALSE;
  2453. RtlZeroMemory(LogicalUnit->SerialNumber.Buffer,
  2454. LogicalUnit->SerialNumber.MaximumLength);
  2455. LogicalUnit->SerialNumber.Length = 0;
  2456. return STATUS_SUCCESS;
  2457. }
  2458. BOOLEAN
  2459. FASTCALL
  2460. SpCompareInquiryData(
  2461. IN PUCHAR InquiryData1,
  2462. IN PUCHAR InquiryData2
  2463. )
  2464. /*++
  2465. Routine Description:
  2466. This routine compares two sets of inquiry data for equality.
  2467. Arguments:
  2468. InquiryData1 - Supplies a pointer to the first inquiry data to compare.
  2469. InquiryData2 - Supplies a pointer to the second inquiry data to compare.
  2470. Return Value:
  2471. TRUE if the supplied inquiry data sets match, else FALSE.
  2472. --*/
  2473. {
  2474. BOOLEAN match;
  2475. UCHAR save1;
  2476. UCHAR save2;
  2477. PAGED_CODE();
  2478. if (((PINQUIRYDATA)InquiryData1)->ANSIVersion == 3) {
  2479. //
  2480. // SCSI3 Specific:
  2481. // Save bytes 6 and 7. These bytes contain vendor specific bits which
  2482. // we're going to exclude from the comparison by just setting them equal
  2483. // to the corresponding bits in InquiryData2. We'll restore them after
  2484. // the comparison.
  2485. //
  2486. save1 = InquiryData1[6];
  2487. save2 = InquiryData1[7];
  2488. //
  2489. // Force the vendor specific bits in InquiryData1 to match the
  2490. // corresponsing bits in InquiryData2.
  2491. //
  2492. InquiryData1[6] &= ~0x20;
  2493. InquiryData1[7] &= ~0x01;
  2494. InquiryData1[6] |= (InquiryData2[6] & 0x20);
  2495. InquiryData1[7] |= (InquiryData2[7] & 0x01);
  2496. }
  2497. //
  2498. // Compare the entire inquiry data blob.
  2499. //
  2500. match = RtlEqualMemory((((PUCHAR) InquiryData1) + 1),
  2501. (((PUCHAR) InquiryData2) + 1),
  2502. (INQUIRYDATABUFFERSIZE - 1));
  2503. if (((PINQUIRYDATA)InquiryData1)->ANSIVersion == 3) {
  2504. //
  2505. // SCSI3 Specific:
  2506. // Restore bytes 6 and 7 to their original state.
  2507. //
  2508. InquiryData1[6] = save1;
  2509. InquiryData1[7] = save2;
  2510. }
  2511. return match;
  2512. }
  2513. NTSTATUS
  2514. SpInquireLogicalUnit(
  2515. IN PADAPTER_EXTENSION Adapter,
  2516. IN UCHAR PathId,
  2517. IN UCHAR TargetId,
  2518. IN UCHAR Lun,
  2519. IN BOOLEAN ExposeDisconnectedLuns,
  2520. IN OPTIONAL PLOGICAL_UNIT_EXTENSION RescanLun,
  2521. OUT PLOGICAL_UNIT_EXTENSION *LogicalUnit,
  2522. OUT PBOOLEAN CheckNextLun
  2523. )
  2524. /*++
  2525. Routine Description:
  2526. This routine will issue an inquiry to the logical unit at the specified
  2527. address. If there is not already a device object allocated for that
  2528. logical unit, it will create one. If it turns out the device does not
  2529. exist, the logical unit can be destroyed before returning.
  2530. If the logical unit exists, this routine will clear the PD_RESCAN_ACTIVE
  2531. flag in the LuFlags to indicate that the unit is safe.
  2532. If it does not respond, the IsMissing flag will be set to indicate that the
  2533. unit should not be reported during enumeration. If the IsRemoved flag has
  2534. already been set on the logical unit extension, the device object will be
  2535. destroyed. Otherwise the device object will not be destroyed until a
  2536. remove can be issued.
  2537. Arguments:
  2538. Adapter - the adapter which this device would exist on
  2539. PathId, TargetId, Lun - the address of the lun to inquire.
  2540. ExposeDisconnectedLuns - indicates whether luns with a qualifier of
  2541. disconnected should be instantiated.
  2542. RescanLun - a pointer to the logical unit extension to be used when
  2543. checking logical unit numbers which do not currently have an
  2544. extension associated with them.
  2545. LogicalUnit - the logical unit created for this address - valid if
  2546. success is returned.
  2547. CheckNextLun - indicates whether the caller should check the next
  2548. address for a logical unit.
  2549. Return Value:
  2550. STATUS_NO_SUCH_DEVICE if the device does not exist.
  2551. STATUS_SUCCESS if the device does exist.
  2552. error description otherwise.
  2553. --*/
  2554. {
  2555. PLOGICAL_UNIT_EXTENSION logicalUnit;
  2556. INQUIRYDATA inquiryData;
  2557. BOOLEAN newDevice = FALSE;
  2558. BOOLEAN deviceMismatch = FALSE;
  2559. UCHAR bytesReturned;
  2560. NTSTATUS status;
  2561. *LogicalUnit = NULL;
  2562. *CheckNextLun = TRUE;
  2563. PAGED_CODE();
  2564. ASSERT(TargetId != BreakOnTarget);
  2565. //
  2566. // Find or create the device object for this address. if it exists we'll
  2567. // grab a temporary lock (using SpInquireLogicalUnit as a tag).
  2568. //
  2569. logicalUnit = GetLogicalUnitExtension(Adapter,
  2570. PathId,
  2571. TargetId,
  2572. Lun,
  2573. SpInquireLogicalUnit,
  2574. TRUE);
  2575. if(logicalUnit == NULL) {
  2576. if(!ARGUMENT_PRESENT(RescanLun)) {
  2577. //
  2578. // No RescanLun was provided (generally means we're low on memory).
  2579. // Don't scan this logical unit.
  2580. //
  2581. return STATUS_INSUFFICIENT_RESOURCES;
  2582. }
  2583. ASSERT(RescanLun->IsTemporary == TRUE);
  2584. //
  2585. // Acquire the temporary lock for the rescan lun. We also grab the
  2586. // base lock here.
  2587. //
  2588. SpAcquireRemoveLock(RescanLun->DeviceObject, SP_BASE_REMOVE_LOCK);
  2589. SpAcquireRemoveLock(RescanLun->DeviceObject, SpInquireLogicalUnit);
  2590. //
  2591. // Set the address of the RescanLun appropriately - this operation
  2592. // will make the logical unit available for our use.
  2593. //
  2594. SpSetLogicalUnitAddress(RescanLun, PathId, TargetId, Lun);
  2595. logicalUnit = RescanLun;
  2596. newDevice = TRUE;
  2597. } else {
  2598. ASSERT(logicalUnit->IsTemporary == FALSE);
  2599. if(logicalUnit->IsMissing) {
  2600. DebugPrint((1, "SpInquireLogicalUnit: logical unit @ (%d,%d,%d) "
  2601. "(%#p) is marked as missing and will not be "
  2602. "rescanned\n",
  2603. PathId, TargetId, Lun,
  2604. logicalUnit->DeviceObject));
  2605. SpReleaseRemoveLock(logicalUnit->DeviceObject, SpInquireLogicalUnit);
  2606. return STATUS_DEVICE_DOES_NOT_EXIST;
  2607. }
  2608. }
  2609. //
  2610. // Issue an inquiry to the potential logical unit.
  2611. //
  2612. DebugPrint((2, "SpInquireTarget: Try %s device @ Bus %d, Target %d, "
  2613. "Lun %d\n",
  2614. (newDevice ? "new" : "existing"),
  2615. PathId,
  2616. TargetId,
  2617. Lun));
  2618. status = IssueInquiry(logicalUnit, FALSE, 0, &inquiryData, &bytesReturned);
  2619. //
  2620. // If the inquiry succeeds then check the data returned to determine if
  2621. // there's a device there we should expose.
  2622. //
  2623. if(NT_SUCCESS(status)) {
  2624. UCHAR qualifier;
  2625. BOOLEAN present = FALSE;
  2626. //
  2627. // Check in the registry for special device flags for this lun.
  2628. // If this is disconnected then set the qualifier to be 0 so that we
  2629. // use the normal hardware ids instead of the "disconnected" ones.
  2630. //
  2631. qualifier = inquiryData.DeviceTypeQualifier;
  2632. SpCheckSpecialDeviceFlags(logicalUnit, &(inquiryData));
  2633. //
  2634. // The inquiry was successful. Determine whether a device is present.
  2635. //
  2636. switch(qualifier) {
  2637. case DEVICE_QUALIFIER_ACTIVE: {
  2638. //
  2639. // Active devices are always present.
  2640. //
  2641. present = TRUE;
  2642. break;
  2643. }
  2644. case DEVICE_QUALIFIER_NOT_ACTIVE: {
  2645. if (Lun == 0) {
  2646. //
  2647. // If we're using REPORT_LUNS commands for LUN 0 of a target
  2648. // then we should always indicate that LUN 0 is present.
  2649. //
  2650. if ((inquiryData.HiSupport == TRUE) ||
  2651. (logicalUnit->SpecialFlags.LargeLuns == TRUE)) {
  2652. present = TRUE;
  2653. }
  2654. } else {
  2655. //
  2656. // Expose inactive luns only if the caller has requested that
  2657. // we do so.
  2658. //
  2659. present = ExposeDisconnectedLuns;
  2660. }
  2661. break;
  2662. }
  2663. case DEVICE_QUALIFIER_NOT_SUPPORTED: {
  2664. present = FALSE;
  2665. break;
  2666. }
  2667. default: {
  2668. present = TRUE;
  2669. break;
  2670. }
  2671. };
  2672. if(present == FALSE) {
  2673. //
  2674. // setup an error value so we'll clean up the logical unit.
  2675. // No need to do any more processing in this case.
  2676. //
  2677. status = STATUS_NO_SUCH_DEVICE;
  2678. } else if(newDevice == FALSE) {
  2679. //
  2680. // Verify that the inquiry data hasn't changed since the last time
  2681. // we did a rescan. Ignore the device type qualifier in this
  2682. // check.
  2683. //
  2684. deviceMismatch = FALSE;
  2685. if(inquiryData.DeviceType != logicalUnit->InquiryData.DeviceType) {
  2686. DebugPrint((1, "SpInquireTarget: Found different type of "
  2687. "device @ (%d,%d,%d)\n",
  2688. PathId,
  2689. TargetId,
  2690. Lun));
  2691. deviceMismatch = TRUE;
  2692. status = STATUS_NO_SUCH_DEVICE;
  2693. } else if(inquiryData.DeviceTypeQualifier !=
  2694. logicalUnit->InquiryData.DeviceTypeQualifier) {
  2695. //
  2696. // The device qualifiers don't match. This isn't necessarily
  2697. // a device mismatch if the existing device just went offline.
  2698. // lower down we'll check the remaining inquiry data to
  2699. // ensure that the LUN hasn't changed.
  2700. //
  2701. DebugPrint((1, "SpInquireLogicalUnit: Device @ (%d,%d,%d) type "
  2702. "qualifier was %d is now %d\n",
  2703. PathId,
  2704. TargetId,
  2705. Lun,
  2706. logicalUnit->InquiryData.DeviceTypeQualifier,
  2707. inquiryData.DeviceTypeQualifier
  2708. ));
  2709. //
  2710. // If the device was offline but no longer is then we
  2711. // treat this as a device mismatch. If the device has gone
  2712. // offline then we pretend it's the same device.
  2713. //
  2714. // the goal is to provide PNP with a new device object when
  2715. // bringing a device online, but to reuse the same device
  2716. // object when bringing the device offline.
  2717. //
  2718. if(logicalUnit->InquiryData.DeviceTypeQualifier ==
  2719. DEVICE_QUALIFIER_NOT_ACTIVE) {
  2720. DebugPrint((1, "SpInquireLogicalUnit: device mismatch\n"));
  2721. deviceMismatch = TRUE;
  2722. status = STATUS_NO_SUCH_DEVICE;
  2723. } else {
  2724. DebugPrint((1, "SpInquireLogicalUnit: device went offline\n"));
  2725. deviceMismatch = FALSE;
  2726. status = STATUS_SUCCESS;
  2727. }
  2728. }
  2729. if (deviceMismatch == FALSE) {
  2730. //
  2731. // Ok, the device type and qualifier are compatible. Now we
  2732. // need to compare all applicable parts of the inquiry
  2733. // data with the data we already have on the device at this
  2734. // address to see if the device that answered this time is the
  2735. // same one we found last time.
  2736. //
  2737. BOOLEAN same = SpCompareInquiryData(
  2738. (PUCHAR)&(inquiryData),
  2739. (PUCHAR)&(logicalUnit->InquiryData));
  2740. if (same == FALSE) {
  2741. //
  2742. // Despite the fact that the device type & qualifier are
  2743. // compatible, a mismatch still occurred.
  2744. //
  2745. deviceMismatch = TRUE;
  2746. status = STATUS_NO_SUCH_DEVICE;
  2747. DebugPrint((1, "SpInquireLogicalUnit: Device @ (%d,%d,%d) has "
  2748. "changed\n",
  2749. PathId,
  2750. TargetId,
  2751. Lun));
  2752. } else {
  2753. //
  2754. // The device that answered is the same one we found
  2755. // earlier. Depending on the SCSI version of the device,
  2756. // we might need to update the vendor specific portions of
  2757. // the existing inquiry data for this device.
  2758. //
  2759. if (inquiryData.ANSIVersion == 3) {
  2760. //
  2761. // For SCSI 3 devices, bytes 6 and 7 contain vendor
  2762. // specific bits that may differ between bus scans.
  2763. // Update these bytes of the existing inquiry data.
  2764. //
  2765. ((PUCHAR)&(logicalUnit->InquiryData))[6] =
  2766. ((PUCHAR)&(inquiryData))[6];
  2767. ((PUCHAR)&(logicalUnit->InquiryData))[7] =
  2768. ((PUCHAR)&(inquiryData))[7];
  2769. }
  2770. }
  2771. }
  2772. } else {
  2773. DebugPrint((1, "SpInquireTarget: Found new %sDevice at address "
  2774. "(%d,%d,%d)\n",
  2775. (inquiryData.RemovableMedia ? "Removable " : ""),
  2776. PathId,
  2777. TargetId,
  2778. Lun));
  2779. }
  2780. if(NT_SUCCESS(status) && (deviceMismatch == FALSE)) {
  2781. deviceMismatch = SpGetDeviceIdentifiers(logicalUnit, newDevice);
  2782. if(deviceMismatch == FALSE) {
  2783. ASSERT(newDevice);
  2784. status = STATUS_NO_SUCH_DEVICE;
  2785. }
  2786. }
  2787. } else {
  2788. *CheckNextLun = FALSE;
  2789. }
  2790. if(!NT_SUCCESS(status)) {
  2791. //
  2792. // Nothing was found at this address. If it's a new lun which hasn't
  2793. // been enumerated yet then just destroy it here. If, however, it
  2794. // has been enumerated we have to mark it as missing and wait for
  2795. // PNP to learn that it's gone and ask us to remove it. Then we can
  2796. // destroy it.
  2797. //
  2798. // If we were just using the RescanLun to check this address then do
  2799. // nothing - the rescan lun will be reset down below.
  2800. //
  2801. logicalUnit->IsMissing = TRUE;
  2802. if(newDevice) {
  2803. //
  2804. // Release the temporary lock. the base one will be released at
  2805. // the end of this routine.
  2806. //
  2807. SpReleaseRemoveLock(logicalUnit->DeviceObject,
  2808. SpInquireLogicalUnit);
  2809. logicalUnit = NULL;
  2810. } else if (logicalUnit->IsEnumerated == FALSE) {
  2811. //
  2812. // It's safe to destroy this device object ourself since it's not
  2813. // a device PNP is aware of. However we may have outstanding i/o
  2814. // due to pass-through requests or legacy class driver so we need
  2815. // to properly wait for all i/o to complete.
  2816. //
  2817. logicalUnit->CommonExtension.CurrentPnpState =
  2818. IRP_MN_REMOVE_DEVICE;
  2819. SpReleaseRemoveLock(logicalUnit->DeviceObject, SpInquireLogicalUnit);
  2820. //
  2821. // Mark this device temporarily as visible so that
  2822. // SpRemoveLogicalUnit will do the right thing. Since the rescan
  2823. // active bit is set the enumeration code won't return this device.
  2824. //
  2825. logicalUnit->IsVisible = TRUE;
  2826. ASSERT(logicalUnit->IsEnumerated == FALSE);
  2827. ASSERT(logicalUnit->IsMissing == TRUE);
  2828. ASSERT(logicalUnit->IsVisible == TRUE);
  2829. SpRemoveLogicalUnit(logicalUnit, IRP_MN_REMOVE_DEVICE);
  2830. if(deviceMismatch) {
  2831. //
  2832. // Call this routine again. This is the only recursion and
  2833. // since we've deleted the device object there should be no
  2834. // cause for a mismatch there.
  2835. //
  2836. status = SpInquireLogicalUnit(Adapter,
  2837. PathId,
  2838. TargetId,
  2839. Lun,
  2840. ExposeDisconnectedLuns,
  2841. RescanLun,
  2842. LogicalUnit,
  2843. CheckNextLun);
  2844. }
  2845. return status;
  2846. } else {
  2847. //
  2848. // CODEWORK - freeze and flush the queue. This way we don't need
  2849. // to deal with handling get next request calls
  2850. //
  2851. //
  2852. // Mark the device as being mismatched so that it's destruction
  2853. // will cause us to rescan the bus (and pickup the new device).
  2854. //
  2855. if(deviceMismatch) {
  2856. logicalUnit->IsMismatched = TRUE;
  2857. }
  2858. }
  2859. } else {
  2860. logicalUnit->IsMissing = FALSE;
  2861. if(newDevice) {
  2862. status = SpCloneAndSwapLogicalUnit(logicalUnit,
  2863. &(inquiryData),
  2864. bytesReturned,
  2865. &logicalUnit);
  2866. if(!NT_SUCCESS(status)) {
  2867. logicalUnit = NULL;
  2868. }
  2869. ASSERT(logicalUnit != RescanLun);
  2870. //
  2871. // Clear the new device flag so we don't attempt to clear the
  2872. // address of the RescanLun down below.
  2873. //
  2874. newDevice = FALSE;
  2875. } else {
  2876. //
  2877. // Update the state of the device and the device map entry if
  2878. // necessary.
  2879. //
  2880. if(logicalUnit->InquiryData.DeviceTypeQualifier !=
  2881. inquiryData.DeviceTypeQualifier) {
  2882. logicalUnit->InquiryData.DeviceTypeQualifier =
  2883. inquiryData.DeviceTypeQualifier;
  2884. SpUpdateLogicalUnitDeviceMapEntry(logicalUnit);
  2885. }
  2886. }
  2887. if(logicalUnit != NULL) {
  2888. if(logicalUnit->InquiryData.DeviceTypeQualifier ==
  2889. DEVICE_QUALIFIER_NOT_ACTIVE) {
  2890. logicalUnit->IsVisible = FALSE;
  2891. //
  2892. // Scsiport won't create a device-map entry for this device since
  2893. // it's never been exposed to PNP (and definately won't be now).
  2894. // Create one here. If the init-device routine tries to generate
  2895. // one later on down the road it will deal with this case just fine.
  2896. //
  2897. SpBuildDeviceMapEntry(&(logicalUnit->CommonExtension));
  2898. } else {
  2899. logicalUnit->IsVisible = TRUE;
  2900. }
  2901. if(inquiryData.RemovableMedia) {
  2902. SET_FLAG(logicalUnit->DeviceObject->Characteristics,
  2903. FILE_REMOVABLE_MEDIA);
  2904. }
  2905. ASSERT(logicalUnit->IsTemporary != TRUE);
  2906. }
  2907. *LogicalUnit = logicalUnit;
  2908. }
  2909. //
  2910. // If this was a new device then clean up the RescanLun.
  2911. //
  2912. if(newDevice) {
  2913. SpWaitForRemoveLock(RescanLun->DeviceObject, SP_BASE_REMOVE_LOCK);
  2914. SpClearLogicalUnitAddress(RescanLun);
  2915. }
  2916. if(logicalUnit) {
  2917. ASSERT(logicalUnit != RescanLun);
  2918. SpReleaseRemoveLock(logicalUnit->DeviceObject, SpInquireLogicalUnit);
  2919. }
  2920. return status;
  2921. }
  2922. NTSTATUS
  2923. SpSendSrbSynchronous(
  2924. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  2925. IN PSCSI_REQUEST_BLOCK Srb,
  2926. IN OPTIONAL PIRP Irp,
  2927. IN OPTIONAL PMDL Mdl,
  2928. IN PVOID DataBuffer,
  2929. IN ULONG TransferLength,
  2930. IN OPTIONAL PVOID SenseInfoBuffer,
  2931. IN OPTIONAL UCHAR SenseInfoBufferLength,
  2932. OUT PULONG BytesReturned
  2933. )
  2934. {
  2935. KEVENT event;
  2936. BOOLEAN irpAllocated = FALSE;
  2937. BOOLEAN mdlAllocated = FALSE;
  2938. PIO_STACK_LOCATION irpStack;
  2939. PSENSE_DATA senseInfo = SenseInfoBuffer;
  2940. ULONG retryCount = 0;
  2941. NTSTATUS status;
  2942. SendSrbSynchronousRetry:
  2943. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2944. //
  2945. // If the caller provided an IRP we'll use it - if not we allocate one
  2946. // here.
  2947. //
  2948. if(!ARGUMENT_PRESENT(Irp)) {
  2949. Irp = SpAllocateIrp(LogicalUnit->DeviceObject->StackSize,
  2950. FALSE,
  2951. LogicalUnit->DeviceObject->DriverObject);
  2952. if(Irp == NULL) {
  2953. return STATUS_INSUFFICIENT_RESOURCES;
  2954. }
  2955. irpAllocated = TRUE;
  2956. }
  2957. if(ARGUMENT_PRESENT(DataBuffer)) {
  2958. ASSERT(TransferLength != 0);
  2959. if(!ARGUMENT_PRESENT(Mdl)) {
  2960. Mdl = SpAllocateMdl(DataBuffer,
  2961. TransferLength,
  2962. FALSE,
  2963. FALSE,
  2964. NULL,
  2965. LogicalUnit->DeviceObject->DriverObject);
  2966. if(Mdl == NULL) {
  2967. IoFreeIrp(Irp);
  2968. return STATUS_INSUFFICIENT_RESOURCES;
  2969. }
  2970. MmBuildMdlForNonPagedPool(Mdl);
  2971. }
  2972. Irp->MdlAddress = Mdl;
  2973. } else {
  2974. ASSERT(TransferLength == 0);
  2975. ASSERT(!ARGUMENT_PRESENT(Mdl));
  2976. }
  2977. irpStack = IoGetNextIrpStackLocation(Irp);
  2978. //
  2979. // Mark the minor function to indicate that this is an internal scsiport
  2980. // request and that the start state of the device can be ignored.
  2981. //
  2982. irpStack->MajorFunction = IRP_MJ_SCSI;
  2983. irpStack->MinorFunction = 1;
  2984. irpStack->Parameters.Scsi.Srb = Srb;
  2985. Srb->SrbStatus = Srb->ScsiStatus = 0;
  2986. Srb->OriginalRequest = Irp;
  2987. //
  2988. // Enable auto request sense.
  2989. //
  2990. if(ARGUMENT_PRESENT(SenseInfoBuffer)) {
  2991. Srb->SenseInfoBuffer = SenseInfoBuffer;
  2992. Srb->SenseInfoBufferLength = SenseInfoBufferLength;
  2993. } else {
  2994. Srb->SenseInfoBuffer = NULL;
  2995. Srb->SenseInfoBufferLength = 0;
  2996. SET_FLAG(Srb->SrbFlags, SRB_FLAGS_DISABLE_AUTOSENSE);
  2997. }
  2998. if(ARGUMENT_PRESENT(Mdl)) {
  2999. Srb->DataBuffer = MmGetMdlVirtualAddress(Mdl);
  3000. Srb->DataTransferLength = TransferLength;
  3001. } else {
  3002. Srb->DataBuffer = NULL;
  3003. Srb->DataTransferLength = 0;
  3004. }
  3005. //
  3006. // Call port driver to handle this request.
  3007. //
  3008. IoSetCompletionRoutine(Irp,
  3009. SpSignalCompletion,
  3010. &event,
  3011. TRUE,
  3012. TRUE,
  3013. TRUE);
  3014. KeEnterCriticalRegion();
  3015. status = IoCallDriver(LogicalUnit->DeviceObject, Irp);
  3016. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  3017. status = Irp->IoStatus.Status;
  3018. *BytesReturned = (ULONG) Irp->IoStatus.Information;
  3019. if(Srb->SrbStatus == SRB_STATUS_PENDING) {
  3020. //
  3021. // Request was never even issued to the controller.
  3022. //
  3023. ASSERT(!NT_SUCCESS(status));
  3024. } else if (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) {
  3025. DebugPrint((2,"SpSendSrbSynchronous: Command failed SRB status %x\n",
  3026. Srb->SrbStatus));
  3027. //
  3028. // Unfreeze queue if necessary
  3029. //
  3030. if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
  3031. DebugPrint((3, "SpSendSrbSynchronous: Unfreeze Queue TID %d\n",
  3032. Srb->TargetId));
  3033. LogicalUnit->LuFlags &= ~LU_QUEUE_FROZEN;
  3034. GetNextLuRequestWithoutLock(LogicalUnit);
  3035. }
  3036. //
  3037. // NOTE: if INQUIRY fails with a data underrun,
  3038. // indicate success and let the class drivers
  3039. // determine whether the inquiry information
  3040. // is useful.
  3041. //
  3042. if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
  3043. //
  3044. // Copy INQUIRY buffer to LUNINFO.
  3045. //
  3046. DebugPrint((1,"SpSendSrbSynchronous: Data underrun at TID %d\n",
  3047. LogicalUnit->TargetId));
  3048. status = STATUS_SUCCESS;
  3049. } else if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
  3050. (senseInfo->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)) {
  3051. //
  3052. // A sense key of illegal request was recieved. This indicates
  3053. // that the logical unit number of not valid but there is a
  3054. // target device out there.
  3055. //
  3056. status = STATUS_INVALID_DEVICE_REQUEST;
  3057. } else {
  3058. //
  3059. // If the selection did not time out then retry the request.
  3060. //
  3061. if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT) &&
  3062. (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_NO_DEVICE) &&
  3063. (retryCount++ < INQUIRY_RETRY_COUNT)) {
  3064. DebugPrint((2,"SpSendSrbSynchronous: Retry %d\n", retryCount));
  3065. KeLeaveCriticalRegion();
  3066. goto SendSrbSynchronousRetry;
  3067. }
  3068. status = SpTranslateScsiStatus(Srb);
  3069. }
  3070. } else {
  3071. status = STATUS_SUCCESS;
  3072. }
  3073. KeLeaveCriticalRegion();
  3074. return status;
  3075. }
  3076. NTSTATUS
  3077. IssueInquiry(
  3078. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  3079. IN BOOLEAN EnableVitalProductData,
  3080. IN UCHAR PageCode,
  3081. OUT PVOID InquiryData,
  3082. OUT PUCHAR BytesReturned
  3083. )
  3084. /*++
  3085. Routine Description:
  3086. Build IRP, SRB and CDB for SCSI INQUIRY command.
  3087. This routine MUST be called while holding the enumeration lock.
  3088. Arguments:
  3089. LogicalUnit - address of the logical unit extension
  3090. EnableVitalProductData - indicates whether the EVPD bit should be set in
  3091. the inquiry data causing the LUN to return product
  3092. data pages (specified by page code below) rather
  3093. than the standard inquiry data.
  3094. PageCode - which VPD page to retrieve
  3095. InquiryData - the location to store the inquiry data for the LUN.
  3096. BytesReturned - the number of bytes of inquiry data returned.
  3097. Return Value:
  3098. NTSTATUS
  3099. --*/
  3100. {
  3101. PIRP irp;
  3102. SCSI_REQUEST_BLOCK srb;
  3103. PCDB cdb;
  3104. PVOID dataBuffer;
  3105. PSENSE_DATA senseInfoBuffer;
  3106. UCHAR allocationLength;
  3107. ULONG bytesReturned;
  3108. NTSTATUS status;
  3109. PAGED_CODE();
  3110. dataBuffer = LogicalUnit->AdapterExtension->InquiryBuffer;
  3111. senseInfoBuffer = LogicalUnit->AdapterExtension->InquirySenseBuffer;
  3112. ASSERT(dataBuffer != NULL);
  3113. ASSERT(senseInfoBuffer != NULL);
  3114. irp = LogicalUnit->AdapterExtension->InquiryIrp;
  3115. IoInitializeIrp(irp,
  3116. IoSizeOfIrp(INQUIRY_STACK_LOCATIONS),
  3117. INQUIRY_STACK_LOCATIONS);
  3118. //
  3119. // Fill in SRB fields.
  3120. //
  3121. RtlZeroMemory(dataBuffer, SP_INQUIRY_BUFFER_SIZE);
  3122. RtlZeroMemory(senseInfoBuffer, SENSE_BUFFER_SIZE);
  3123. RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
  3124. srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
  3125. srb.Length = sizeof(SCSI_REQUEST_BLOCK);
  3126. //
  3127. // Set flags to disable synchronous negociation.
  3128. //
  3129. srb.SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
  3130. srb.TimeOutValue = LogicalUnit->AdapterExtension->SrbTimeout;
  3131. srb.CdbLength = 6;
  3132. cdb = (PCDB)srb.Cdb;
  3133. //
  3134. // Set CDB operation code.
  3135. //
  3136. cdb->CDB6INQUIRY3.OperationCode = SCSIOP_INQUIRY;
  3137. //
  3138. // Set allocation length to inquiry data buffer size.
  3139. //
  3140. if(EnableVitalProductData) {
  3141. allocationLength = VPD_MAX_BUFFER_SIZE;
  3142. } else {
  3143. allocationLength = INQUIRYDATABUFFERSIZE;
  3144. }
  3145. cdb->CDB6INQUIRY3.AllocationLength = allocationLength;
  3146. cdb->CDB6INQUIRY3.EnableVitalProductData = TEST(EnableVitalProductData);
  3147. if(EnableVitalProductData == FALSE) {
  3148. ASSERT(PageCode == 0);
  3149. }
  3150. cdb->CDB6INQUIRY3.PageCode = PageCode;
  3151. status = SpSendSrbSynchronous(LogicalUnit,
  3152. &srb,
  3153. irp,
  3154. LogicalUnit->AdapterExtension->InquiryMdl,
  3155. dataBuffer,
  3156. allocationLength,
  3157. senseInfoBuffer,
  3158. SENSE_BUFFER_SIZE,
  3159. &bytesReturned
  3160. );
  3161. ASSERT(bytesReturned <= allocationLength);
  3162. //
  3163. // Return the inquiry data for the device if the call was successful.
  3164. // Otherwise cleanup.
  3165. //
  3166. if(NT_SUCCESS(status)) {
  3167. //
  3168. // If the caller passed in the inquiry buffer then don't bother to copy
  3169. // the data.
  3170. //
  3171. if(InquiryData != dataBuffer) {
  3172. RtlCopyMemory(InquiryData, dataBuffer, bytesReturned);
  3173. }
  3174. *BytesReturned = (UCHAR) bytesReturned;
  3175. } else if(BreakOnMissingLun) {
  3176. ASSERT(LogicalUnit->IsTemporary == TRUE);
  3177. }
  3178. return status;
  3179. }
  3180. BOOLEAN
  3181. SpGetDeviceIdentifiers(
  3182. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  3183. IN BOOLEAN NewDevice
  3184. )
  3185. /*++
  3186. Routine Description:
  3187. This routine retreives the device identifiers supported by the logical
  3188. unit in question and compares them to the ones (if any) which are currently
  3189. saved in the LogicalUnit extension. If they do not match this routine
  3190. will return false to indicate a device mismatch.
  3191. As a side effect this routine will save the serial numbers for new devices
  3192. in the logical unit extension, as well as a list of the supported vital
  3193. product data pages.
  3194. Arguments:
  3195. LogicalUnit - the logical unit being prodded.
  3196. NewDevice - whether this device has been prodded before or not. If it has
  3197. not been then the list of supported EVPD pages will need to be
  3198. retreived.
  3199. Return Value:
  3200. TRUE if the data retrieved matches the data which was stored in the
  3201. logical unit extension (TRUE is always returned for a new device).
  3202. FALSE otherwise.
  3203. --*/
  3204. {
  3205. PVOID buffer = LogicalUnit->AdapterExtension->InquiryBuffer;
  3206. UCHAR bytesReturned;
  3207. NTSTATUS status;
  3208. PAGED_CODE();
  3209. //
  3210. // If this is a new device or if the existing device supports the
  3211. // device identifier page, then get the list of supported VPD pages
  3212. // and process it.
  3213. //
  3214. if (NewDevice || LogicalUnit->DeviceIdentifierPageSupported) {
  3215. PVPD_SUPPORTED_PAGES_PAGE supportedPages = buffer;
  3216. UCHAR i;
  3217. //
  3218. // If this device is a known non-compliant device that does not support
  3219. // VPD 0x00 but does support VPDs 0x80 and/or 0x83, bypass the INQUIRY
  3220. // and just indicate that the LU does support the other VPDs based on
  3221. // the special flags.
  3222. //
  3223. if (LogicalUnit->SpecialFlags.NonStandardVPD == 0) {
  3224. status = IssueInquiry(LogicalUnit,
  3225. TRUE,
  3226. VPD_SUPPORTED_PAGES,
  3227. buffer,
  3228. &bytesReturned);
  3229. if(!NT_SUCCESS(status)) {
  3230. return TRUE;
  3231. }
  3232. if(bytesReturned < sizeof(VPD_SUPPORTED_PAGES_PAGE)) {
  3233. //
  3234. // If the device didn't return enough data to include any pages
  3235. // then we're done.
  3236. //
  3237. return TRUE;
  3238. }
  3239. for (i = 0; i < supportedPages->PageLength; i++) {
  3240. switch (supportedPages->SupportedPageList[i]) {
  3241. case VPD_SERIAL_NUMBER:
  3242. if (NewDevice) {
  3243. LogicalUnit->SerialNumberPageSupported = TRUE;
  3244. }
  3245. break;
  3246. case VPD_DEVICE_IDENTIFIERS:
  3247. LogicalUnit->DeviceIdentifierPageSupported = TRUE;
  3248. break;
  3249. default:
  3250. break;
  3251. }
  3252. }
  3253. } else {
  3254. ULONG vpdFlags = LogicalUnit->SpecialFlags.NonStandardVPD;
  3255. //
  3256. // This is one of the devices that does not support VPD 0x00 but
  3257. // does support one or more of the other VPD pages.
  3258. //
  3259. LogicalUnit->SerialNumberPageSupported =
  3260. (vpdFlags & NON_STANDARD_VPD_SUPPORTS_PAGE80) ? TRUE : FALSE;
  3261. LogicalUnit->DeviceIdentifierPageSupported =
  3262. (vpdFlags & NON_STANDARD_VPD_SUPPORTS_PAGE83) ? TRUE : FALSE;
  3263. }
  3264. }
  3265. //
  3266. // If this device supports the serial number page then retrieve it,
  3267. // convert it into an ansi string, and compare it to the one previously
  3268. // retreived (if there was a previous attempt).
  3269. //
  3270. if(LogicalUnit->SerialNumberPageSupported) {
  3271. PVPD_SERIAL_NUMBER_PAGE serialNumberPage = buffer;
  3272. ANSI_STRING serialNumber;
  3273. status = IssueInquiry(LogicalUnit,
  3274. TRUE,
  3275. VPD_SERIAL_NUMBER,
  3276. serialNumberPage,
  3277. &bytesReturned);
  3278. if(!NT_SUCCESS(status)) {
  3279. DebugPrint((0, "SpGetDeviceIdentifiers: Error %#08lx retreiving "
  3280. "serial number page from lun %#p\n",
  3281. status, LogicalUnit));
  3282. //
  3283. // We can't get the serial number - give this device the benefit
  3284. // of the doubt.
  3285. //
  3286. return TRUE;
  3287. }
  3288. //
  3289. // Fix for bug #143313:
  3290. // On rare occasions, junk appears to get copied into the serial
  3291. // number buffer. This causes us problems because the junk is
  3292. // interpreted as part of the serial number. When we compare the
  3293. // string containing junk to a previously acquired serial number, the
  3294. // comparison fails. In an effort to fix, I'll zero out all bytes
  3295. // in the buffer following the actual serial number. This will only
  3296. // work if the PageSize reported by the device does NOT include the
  3297. // junk bytes.
  3298. //
  3299. RtlZeroMemory(
  3300. serialNumberPage->SerialNumber + serialNumberPage->PageLength,
  3301. SP_INQUIRY_BUFFER_SIZE - 4 - serialNumberPage->PageLength);
  3302. //
  3303. // If this is a device known to return binary SN data, convert the
  3304. // returned bytes to ascii.
  3305. //
  3306. // Note: It is assumed that the SN data is numeric. Any bytes that
  3307. // cannot be converted to an ASCII hex number, are left alone.
  3308. //
  3309. if (LogicalUnit->SpecialFlags.BinarySN != 0) {
  3310. int i;
  3311. PUCHAR p = serialNumberPage->SerialNumber;
  3312. for (i = 0; i < serialNumberPage->PageLength; i++) {
  3313. if (*p < 0xa) {
  3314. *p += '0';
  3315. } else if (*p < 0x10) {
  3316. *p += 'A';
  3317. } else {
  3318. ASSERT(FALSE && "Data out of range");
  3319. }
  3320. p++;
  3321. }
  3322. }
  3323. //
  3324. // Create a string using the serial number. The buffer was zeroed
  3325. // before transfer (and is one character longer than the max buffer
  3326. // which can be returned) so the string is null terminated.
  3327. //
  3328. RtlInitAnsiString(&(serialNumber), serialNumberPage->SerialNumber);
  3329. if(NewDevice) {
  3330. //
  3331. // A new device will always have a large buffer into which we can
  3332. // copy the string. The clone & swap process will take care of
  3333. // moving this into a smaller sized buffer.
  3334. //
  3335. ASSERT(LogicalUnit->SerialNumber.MaximumLength != 0);
  3336. ASSERT(LogicalUnit->SerialNumber.Buffer != NULL);
  3337. RtlCopyString(&(LogicalUnit->SerialNumber), &serialNumber);
  3338. } else if(LogicalUnit->SerialNumber.Buffer == NULL &&
  3339. serialNumber.Length != 0) {
  3340. //
  3341. // ISSUE-2000-25-02-peterwie
  3342. // We didn't previously have a serial number. Since the device
  3343. // claimed that it supported one it's likely we got an error back
  3344. // when we tried to retreive it. Since we didn't get back one
  3345. // now it was a transient error (ie. not likely to be a violation
  3346. // of the spec). Should we assign the serial number to the device
  3347. // here? Or should we have failed to instantiate a device with
  3348. // a serial number we couldn't retreive?
  3349. //
  3350. ASSERT(FALSE);
  3351. } else if(RtlEqualString(&serialNumber,
  3352. &(LogicalUnit->SerialNumber),
  3353. FALSE) == FALSE) {
  3354. DebugPrint((1, "SpInquireLogicalUnit: serial number mismatch\n"));
  3355. return FALSE;
  3356. }
  3357. }
  3358. //
  3359. // If this device supports the device identifiers page then read it out.
  3360. // We don't use this page to check for mismatches at the moment, so we
  3361. // just read it out of the device if this is a new device.
  3362. //
  3363. if (LogicalUnit->DeviceIdentifierPageSupported) {
  3364. status = IssueInquiry(LogicalUnit,
  3365. TRUE,
  3366. VPD_DEVICE_IDENTIFIERS,
  3367. buffer,
  3368. &bytesReturned);
  3369. if(NT_SUCCESS(status)) {
  3370. //
  3371. // Copy the page into the buffer allocated in the template logical
  3372. // unit. The clone & swap process will take care of moving this
  3373. // into an appropriately sized buffer in the new lun.
  3374. //
  3375. ASSERT(LogicalUnit->DeviceIdentifierPage != NULL);
  3376. RtlCopyMemory(LogicalUnit->DeviceIdentifierPage,
  3377. buffer,
  3378. bytesReturned);
  3379. LogicalUnit->DeviceIdentifierPageLength = bytesReturned;
  3380. } else {
  3381. DebugPrint((1, "SpGetDeviceIdentifiers: Error %#08lx retreiving "
  3382. "serial number page from lun %#p\n",
  3383. status, LogicalUnit));
  3384. LogicalUnit->DeviceIdentifierPageLength = 0;
  3385. }
  3386. } else {
  3387. LogicalUnit->DeviceIdentifierPageLength = 0;
  3388. }
  3389. return TRUE;
  3390. }
  3391. PLOGICAL_UNIT_EXTENSION
  3392. SpCreateInitiatorLU(
  3393. IN PADAPTER_EXTENSION Adapter,
  3394. IN UCHAR PathId
  3395. )
  3396. /*++
  3397. Routine Description:
  3398. This routine creates a logical unit to represent the initiator on the bus
  3399. identified by the supplied PathId. This device will be used to send
  3400. WMI and IOCTL requests to the adapter.
  3401. Arguments:
  3402. Adapter - Pointer to the adapter device extension.
  3403. PathId - Identifies a particular bus supported by the adapter.
  3404. Return Value:
  3405. A pointer to the logical unit extension of the initiator PDO if the
  3406. device is successfully created.
  3407. NULL otherwise.
  3408. --*/
  3409. {
  3410. NTSTATUS status;
  3411. PLOGICAL_UNIT_EXTENSION newLun;
  3412. UCHAR targetId;
  3413. UCHAR lun;
  3414. //
  3415. // Extract the ID of the initiator device from the array of per-adapter
  3416. // initiator IDs.
  3417. //
  3418. targetId = Adapter->PortConfig->InitiatorBusId[PathId];
  3419. //
  3420. // Set the logical unit number to 0.
  3421. //
  3422. lun = 0;
  3423. //
  3424. // Try to create a logical unit for the initiator.
  3425. //
  3426. status = SpCreateLogicalUnit(Adapter,
  3427. PathId,
  3428. targetId,
  3429. lun,
  3430. FALSE,
  3431. FALSE,
  3432. &newLun);
  3433. if (!NT_SUCCESS(status)) {
  3434. newLun = NULL;
  3435. } else {
  3436. //
  3437. // Initialize WMI on this initiator LUN.
  3438. //
  3439. ScsiPortInitPdoWmi(newLun);
  3440. //
  3441. // Acquire the appropriate remove locks on the new logical unit.
  3442. //
  3443. SpAcquireRemoveLock(newLun->DeviceObject, SP_BASE_REMOVE_LOCK);
  3444. //
  3445. // Now insert this new lun into the logical unit list.
  3446. //
  3447. SpSetLogicalUnitAddress(newLun, PathId, targetId, lun);
  3448. }
  3449. return newLun;
  3450. }