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

785 lines
20 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1990 - 1998
  3. Module Name:
  4. prop.c
  5. Abstract:
  6. This is the NT SCSI port driver. This module contains code relating to
  7. property queries
  8. Authors:
  9. Peter Wieland
  10. Environment:
  11. kernel mode only
  12. Notes:
  13. Revision History:
  14. --*/
  15. #include "port.h"
  16. NTSTATUS
  17. SpBuildDeviceDescriptor(
  18. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  19. IN PSTORAGE_DEVICE_DESCRIPTOR Descriptor,
  20. IN OUT PULONG DescriptorLength
  21. );
  22. NTSTATUS
  23. SpBuildDeviceIdDescriptor(
  24. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  25. IN PSTORAGE_DEVICE_ID_DESCRIPTOR Descriptor,
  26. IN OUT PULONG DescriptorLength
  27. );
  28. NTSTATUS
  29. SpBuildAdapterDescriptor(
  30. IN PADAPTER_EXTENSION Adapter,
  31. IN PSTORAGE_ADAPTER_DESCRIPTOR Descriptor,
  32. IN OUT PULONG DescriptorLength
  33. );
  34. #ifdef ALLOC_PRAGMA
  35. #pragma alloc_text(PAGE, SpBuildDeviceDescriptor)
  36. #pragma alloc_text(PAGE, SpBuildDeviceIdDescriptor)
  37. #pragma alloc_text(PAGE, SpBuildAdapterDescriptor)
  38. #pragma alloc_text(PAGE, ScsiPortQueryProperty)
  39. #pragma alloc_text(PAGE, SpQueryDeviceText)
  40. #endif
  41. NTSTATUS
  42. ScsiPortQueryProperty(
  43. IN PDEVICE_OBJECT DeviceObject,
  44. IN PIRP QueryIrp
  45. )
  46. /*++
  47. Routine Description:
  48. This routine will handle a property query request. It will build the
  49. descriptor on it's own if possible, or it may forward the request down
  50. to lower level drivers.
  51. Since this routine may forward the request downwards the caller should
  52. not complete the irp
  53. This routine is asynchronous.
  54. This routine must be called at <= IRQL_DISPATCH
  55. This routine must be called with the remove lock held
  56. Arguments:
  57. DeviceObject - a pointer to the device object being queried
  58. QueryIrp - a pointer to the irp for the query
  59. Return Value:
  60. STATUS_PENDING if the request cannot be completed yet
  61. STATUS_SUCCESS if the query was successful
  62. STATUS_INVALID_PARAMETER_1 if the property id does not exist
  63. STATUS_INVALID_PARAMETER_2 if the query type is invalid
  64. STATUS_INVALID_PARAMETER_3 if an invalid optional parameter was passed
  65. STATUS_INVALID_DEVICE_REQUEST if this request cannot be handled by this
  66. device
  67. other error values as applicable
  68. --*/
  69. {
  70. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(QueryIrp);
  71. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  72. PSTORAGE_PROPERTY_QUERY query = QueryIrp->AssociatedIrp.SystemBuffer;
  73. ULONG queryLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
  74. NTSTATUS status;
  75. PAGED_CODE();
  76. //
  77. // We don't actually support mask queries.
  78. //
  79. if(query->QueryType >= PropertyMaskQuery) {
  80. status = STATUS_INVALID_PARAMETER_1;
  81. QueryIrp->IoStatus.Status = status;
  82. QueryIrp->IoStatus.Information = 0;
  83. SpReleaseRemoveLock(DeviceObject, QueryIrp);
  84. SpCompleteRequest(DeviceObject, QueryIrp, NULL, IO_NO_INCREMENT);
  85. return status;
  86. }
  87. switch(query->PropertyId) {
  88. case StorageDeviceProperty: {
  89. //
  90. // Make sure this is a target device.
  91. //
  92. if(!commonExtension->IsPdo) {
  93. status = STATUS_INVALID_DEVICE_REQUEST;
  94. break;
  95. }
  96. if(query->QueryType == PropertyExistsQuery) {
  97. status = STATUS_SUCCESS;
  98. } else {
  99. status = SpBuildDeviceDescriptor(
  100. (PLOGICAL_UNIT_EXTENSION) commonExtension,
  101. QueryIrp->AssociatedIrp.SystemBuffer,
  102. &queryLength);
  103. QueryIrp->IoStatus.Information = queryLength;
  104. }
  105. break;
  106. }
  107. case StorageAdapterProperty: {
  108. PDEVICE_OBJECT adapterObject = DeviceObject;
  109. //
  110. // if this is a target device then forward it down to the
  111. // underlying device object. This lets filters do their magic
  112. //
  113. if(commonExtension->IsPdo) {
  114. //
  115. // Call the lower device
  116. //
  117. IoSkipCurrentIrpStackLocation(QueryIrp);
  118. SpReleaseRemoveLock(DeviceObject, QueryIrp);
  119. status = IoCallDriver(commonExtension->LowerDeviceObject, QueryIrp);
  120. return status;
  121. }
  122. if(query->QueryType == PropertyExistsQuery) {
  123. status = STATUS_SUCCESS;
  124. } else {
  125. status = SpBuildAdapterDescriptor(
  126. (PADAPTER_EXTENSION) commonExtension,
  127. QueryIrp->AssociatedIrp.SystemBuffer,
  128. &queryLength);
  129. QueryIrp->IoStatus.Information = queryLength;
  130. }
  131. break;
  132. }
  133. case StorageDeviceIdProperty: {
  134. PLOGICAL_UNIT_EXTENSION logicalUnit;
  135. //
  136. // Make sure this is a target device.
  137. //
  138. if(!commonExtension->IsPdo) {
  139. status = STATUS_INVALID_DEVICE_REQUEST;
  140. break;
  141. }
  142. logicalUnit = DeviceObject->DeviceExtension;
  143. //
  144. // Check to see if we have a device identifier page. If not then
  145. // fail any calls for this type of identifier.
  146. //
  147. if(logicalUnit->DeviceIdentifierPage != NULL) {
  148. if(query->QueryType == PropertyExistsQuery) {
  149. status = STATUS_SUCCESS;
  150. } else {
  151. status = SpBuildDeviceIdDescriptor(
  152. logicalUnit,
  153. QueryIrp->AssociatedIrp.SystemBuffer,
  154. &queryLength);
  155. QueryIrp->IoStatus.Information = queryLength;
  156. }
  157. } else {
  158. status = STATUS_NOT_SUPPORTED;
  159. }
  160. break;
  161. }
  162. default: {
  163. //
  164. // If this is a target device then some filter beneath us may
  165. // handle this property.
  166. //
  167. if(commonExtension->IsPdo) {
  168. //
  169. // Call the lower device.
  170. //
  171. IoSkipCurrentIrpStackLocation(QueryIrp);
  172. SpReleaseRemoveLock(DeviceObject, QueryIrp);
  173. status = IoCallDriver(commonExtension->LowerDeviceObject, QueryIrp);
  174. return status;
  175. }
  176. //
  177. // Nope, this property really doesn't exist
  178. //
  179. status = STATUS_INVALID_PARAMETER_1;
  180. QueryIrp->IoStatus.Information = 0;
  181. break;
  182. }
  183. }
  184. if(status != STATUS_PENDING) {
  185. QueryIrp->IoStatus.Status = status;
  186. SpReleaseRemoveLock(DeviceObject, QueryIrp);
  187. SpCompleteRequest(DeviceObject, QueryIrp, NULL, IO_DISK_INCREMENT);
  188. }
  189. return status;
  190. }
  191. NTSTATUS
  192. SpBuildDeviceDescriptor(
  193. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  194. IN PSTORAGE_DEVICE_DESCRIPTOR Descriptor,
  195. IN OUT PULONG DescriptorLength
  196. )
  197. /*++
  198. Routine Description:
  199. This routine will create a device descriptor based on the information in
  200. it's device extension. It will copy as much data as possible into
  201. the Descriptor and will update the DescriptorLength to indicate the
  202. number of bytes copied
  203. Arguments:
  204. DeviceObject - a pointer to the PDO we are building a descriptor for
  205. Descriptor - a buffer to store the descriptor in
  206. DescriptorLength - the length of the buffer and the number of bytes
  207. returned
  208. QueryIrp - unused
  209. Return Value:
  210. status
  211. --*/
  212. {
  213. PSCSIPORT_DRIVER_EXTENSION driverExtension =
  214. IoGetDriverObjectExtension(LogicalUnit->DeviceObject->DriverObject,
  215. ScsiPortInitialize);
  216. LONG maxLength = *DescriptorLength;
  217. LONG bytesRemaining = maxLength;
  218. LONG realLength = sizeof(STORAGE_DEVICE_DESCRIPTOR);
  219. LONG serialNumberLength;
  220. PUCHAR currentOffset = (PUCHAR) Descriptor;
  221. LONG inquiryLength;
  222. PINQUIRYDATA inquiryData = &(LogicalUnit->InquiryData);
  223. STORAGE_DEVICE_DESCRIPTOR tmp;
  224. PAGED_CODE();
  225. ASSERT_PDO(LogicalUnit->DeviceObject);
  226. ASSERT(Descriptor != NULL);
  227. serialNumberLength = LogicalUnit->SerialNumber.Length + 1;
  228. //
  229. // Figure out what the total size of this structure is going to be
  230. //
  231. inquiryLength = 4 + inquiryData->AdditionalLength;
  232. if(inquiryLength > INQUIRYDATABUFFERSIZE) {
  233. inquiryLength = INQUIRYDATABUFFERSIZE;
  234. }
  235. realLength += inquiryLength + 31; // 31 = length of the 3 id strings +
  236. // 3 nuls
  237. //
  238. // Add the length of the serial number.
  239. //
  240. realLength += serialNumberLength;
  241. //
  242. // Zero the buffer provided.
  243. //
  244. RtlZeroMemory(Descriptor, *DescriptorLength);
  245. //
  246. // Build the device descriptor structure on the stack then copy as much as
  247. // can be copied over
  248. //
  249. RtlZeroMemory(&tmp, sizeof(STORAGE_DEVICE_DESCRIPTOR));
  250. tmp.Version = sizeof(STORAGE_DEVICE_DESCRIPTOR);
  251. tmp.Size = realLength;
  252. tmp.DeviceType = inquiryData->DeviceType;
  253. tmp.DeviceTypeModifier = inquiryData->DeviceTypeModifier;
  254. tmp.RemovableMedia = inquiryData->RemovableMedia;
  255. tmp.CommandQueueing = inquiryData->CommandQueue;
  256. tmp.SerialNumberOffset = 0xffffffff;
  257. tmp.BusType = driverExtension->BusType;
  258. RtlCopyMemory(currentOffset,
  259. &tmp,
  260. min(sizeof(STORAGE_DEVICE_DESCRIPTOR), bytesRemaining));
  261. bytesRemaining -= sizeof(STORAGE_DEVICE_DESCRIPTOR);
  262. if(bytesRemaining <= 0) {
  263. *DescriptorLength = maxLength;
  264. return STATUS_SUCCESS;
  265. }
  266. currentOffset = ((PUCHAR) Descriptor) + (maxLength - bytesRemaining);
  267. //
  268. // Copy over as much inquiry data as we can and update the raw byte count
  269. //
  270. RtlCopyMemory(currentOffset, inquiryData, min(inquiryLength, bytesRemaining));
  271. bytesRemaining -= inquiryLength;
  272. if(bytesRemaining <= 0) {
  273. *DescriptorLength = maxLength;
  274. Descriptor->RawPropertiesLength = maxLength -
  275. sizeof(STORAGE_DEVICE_DESCRIPTOR);
  276. return STATUS_SUCCESS;
  277. }
  278. Descriptor->RawPropertiesLength = inquiryLength;
  279. currentOffset = ((PUCHAR) Descriptor) + (maxLength - bytesRemaining);
  280. //
  281. // Now we need to start copying inquiry strings
  282. //
  283. //
  284. // first the vendor id
  285. //
  286. RtlCopyMemory(currentOffset,
  287. inquiryData->VendorId,
  288. min(bytesRemaining, sizeof(UCHAR) * 8));
  289. bytesRemaining -= sizeof(UCHAR) * 9; // include trailing null
  290. if(bytesRemaining >= 0) {
  291. Descriptor->VendorIdOffset = (ULONG)((ULONG_PTR) currentOffset -
  292. (ULONG_PTR) Descriptor);
  293. }
  294. if(bytesRemaining <= 0) {
  295. *DescriptorLength = maxLength;
  296. return STATUS_SUCCESS;
  297. }
  298. currentOffset = ((PUCHAR) Descriptor) + (maxLength - bytesRemaining);
  299. //
  300. // now the product id
  301. //
  302. RtlCopyMemory(currentOffset,
  303. inquiryData->ProductId,
  304. min(bytesRemaining, 16));
  305. bytesRemaining -= 17; // include trailing null
  306. if(bytesRemaining >= 0) {
  307. Descriptor->ProductIdOffset = (ULONG)((ULONG_PTR) currentOffset -
  308. (ULONG_PTR) Descriptor);
  309. }
  310. if(bytesRemaining <= 0) {
  311. *DescriptorLength = maxLength;
  312. return STATUS_SUCCESS;
  313. }
  314. currentOffset = ((PUCHAR) Descriptor) + (maxLength - bytesRemaining);
  315. //
  316. // And the product revision
  317. //
  318. RtlCopyMemory(currentOffset,
  319. inquiryData->ProductRevisionLevel,
  320. min(bytesRemaining, 4));
  321. bytesRemaining -= 5;
  322. if(bytesRemaining >= 0) {
  323. Descriptor->ProductRevisionOffset = (ULONG)((ULONG_PTR) currentOffset -
  324. (ULONG_PTR) Descriptor);
  325. }
  326. if(bytesRemaining <= 0) {
  327. *DescriptorLength = maxLength;
  328. return STATUS_SUCCESS;
  329. }
  330. currentOffset = ((PUCHAR) Descriptor) + (maxLength - bytesRemaining);
  331. //
  332. // If the device provides a SCSI serial number (vital product data page 80)
  333. // the report it.
  334. //
  335. if(LogicalUnit->SerialNumber.Length != 0) {
  336. //
  337. // And the product revision
  338. //
  339. RtlCopyMemory(currentOffset,
  340. LogicalUnit->SerialNumber.Buffer,
  341. min(bytesRemaining, serialNumberLength));
  342. bytesRemaining -= serialNumberLength;
  343. if(bytesRemaining >= 0) {
  344. Descriptor->SerialNumberOffset = (ULONG)((ULONG_PTR) currentOffset -
  345. (ULONG_PTR) Descriptor);
  346. }
  347. if(bytesRemaining <= 0) {
  348. *DescriptorLength = maxLength;
  349. return STATUS_SUCCESS;
  350. }
  351. }
  352. *DescriptorLength = maxLength - bytesRemaining;
  353. return STATUS_SUCCESS;
  354. }
  355. NTSTATUS
  356. SpBuildAdapterDescriptor(
  357. IN PADAPTER_EXTENSION Adapter,
  358. IN PSTORAGE_ADAPTER_DESCRIPTOR Descriptor,
  359. IN OUT PULONG DescriptorLength
  360. )
  361. {
  362. PSCSIPORT_DRIVER_EXTENSION driverExtension =
  363. IoGetDriverObjectExtension(Adapter->DeviceObject->DriverObject,
  364. ScsiPortInitialize);
  365. PIO_SCSI_CAPABILITIES capabilities = &(Adapter->Capabilities);
  366. STORAGE_ADAPTER_DESCRIPTOR tmp;
  367. PAGED_CODE();
  368. ASSERT_FDO(Adapter->DeviceObject);
  369. //
  370. // Call to IoGetDriverObjectExtension can return NULL
  371. //
  372. if (driverExtension == NULL) {
  373. *DescriptorLength = 0;
  374. return STATUS_UNSUCCESSFUL;
  375. }
  376. tmp.Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
  377. tmp.Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR);
  378. tmp.MaximumTransferLength = capabilities->MaximumTransferLength;
  379. tmp.MaximumPhysicalPages = capabilities->MaximumPhysicalPages;
  380. tmp.AlignmentMask = capabilities->AlignmentMask;
  381. tmp.AdapterUsesPio = capabilities->AdapterUsesPio;
  382. tmp.AdapterScansDown = capabilities->AdapterScansDown;
  383. tmp.CommandQueueing = capabilities->TaggedQueuing;
  384. tmp.AcceleratedTransfer = TRUE;
  385. tmp.BusType = (BOOLEAN) driverExtension->BusType;
  386. tmp.BusMajorVersion = 2;
  387. tmp.BusMinorVersion = 0;
  388. RtlCopyMemory(Descriptor,
  389. &tmp,
  390. min(*DescriptorLength, sizeof(STORAGE_ADAPTER_DESCRIPTOR)));
  391. *DescriptorLength = min(*DescriptorLength, sizeof(STORAGE_ADAPTER_DESCRIPTOR));
  392. return STATUS_SUCCESS;
  393. }
  394. NTSTATUS
  395. SpQueryDeviceText(
  396. IN PDEVICE_OBJECT LogicalUnit,
  397. IN DEVICE_TEXT_TYPE TextType,
  398. IN LCID LocaleId,
  399. IN OUT PWSTR *DeviceText
  400. )
  401. {
  402. PLOGICAL_UNIT_EXTENSION luExtension = LogicalUnit->DeviceExtension;
  403. UCHAR ansiBuffer[256];
  404. ANSI_STRING ansiText;
  405. UNICODE_STRING unicodeText;
  406. NTSTATUS status;
  407. PAGED_CODE();
  408. RtlInitUnicodeString(&unicodeText, NULL);
  409. if(TextType == DeviceTextDescription) {
  410. PSCSIPORT_DEVICE_TYPE deviceInfo =
  411. SpGetDeviceTypeInfo(luExtension->InquiryData.DeviceType);
  412. PUCHAR c;
  413. LONG i;
  414. RtlZeroMemory(ansiBuffer, sizeof(ansiBuffer));
  415. RtlCopyMemory(ansiBuffer,
  416. luExtension->InquiryData.VendorId,
  417. sizeof(luExtension->InquiryData.VendorId));
  418. c = ansiBuffer;
  419. for(i = sizeof(luExtension->InquiryData.VendorId); i >= 0; i--) {
  420. if((c[i] != '\0') &&
  421. (c[i] != ' ')) {
  422. break;
  423. }
  424. c[i] = '\0';
  425. }
  426. c = &(c[i + 1]);
  427. sprintf(c, " ");
  428. c++;
  429. RtlCopyMemory(c,
  430. luExtension->InquiryData.ProductId,
  431. sizeof(luExtension->InquiryData.ProductId));
  432. for(i = sizeof(luExtension->InquiryData.ProductId); i >= 0; i--) {
  433. if((c[i] != '\0') &&
  434. (c[i] != ' ')) {
  435. break;
  436. }
  437. c[i] = '\0';
  438. }
  439. c = &(c[i + 1]);
  440. sprintf(c, " SCSI %s Device", deviceInfo->DeviceTypeString);
  441. } else if (TextType == DeviceTextLocationInformation) {
  442. sprintf(ansiBuffer, "Bus Number %d, Target ID %d, LUN %d",
  443. luExtension->PathId,
  444. luExtension->TargetId,
  445. luExtension->Lun);
  446. } else {
  447. return STATUS_NOT_SUPPORTED;
  448. }
  449. RtlInitAnsiString(&ansiText, ansiBuffer);
  450. status = RtlAnsiStringToUnicodeString(&unicodeText,
  451. &ansiText,
  452. TRUE);
  453. *DeviceText = unicodeText.Buffer;
  454. return status;
  455. }
  456. NTSTATUS
  457. SpBuildDeviceIdDescriptor(
  458. IN PLOGICAL_UNIT_EXTENSION LogicalUnit,
  459. IN PSTORAGE_DEVICE_ID_DESCRIPTOR Descriptor,
  460. IN OUT PULONG DescriptorLength
  461. )
  462. /*++
  463. Routine Description:
  464. This routine will create a device id descriptor based on the device
  465. identifier page retrieved during discovery. It is an error to call this
  466. routine if no device identifier page exists.
  467. This routine will copy as much data as possible into the Descriptor and
  468. will update the DescriptorLength to indicate the number of bytes copied.
  469. Arguments:
  470. DeviceObject - a pointer to the PDO we are building a descriptor for
  471. Descriptor - a buffer to store the descriptor in
  472. DescriptorLength - the length of the buffer and the number of bytes
  473. returned
  474. QueryIrp - unused
  475. Return Value:
  476. status
  477. --*/
  478. {
  479. PVPD_IDENTIFICATION_PAGE idPage = LogicalUnit->DeviceIdentifierPage;
  480. ULONG idOffset;
  481. ULONG maxLength = *DescriptorLength;
  482. PUCHAR destOffset;
  483. LONG identifierLength;
  484. ULONG identifierCount = 0;
  485. PAGED_CODE();
  486. ASSERT_PDO(LogicalUnit->DeviceObject);
  487. ASSERT(Descriptor != NULL);
  488. ASSERT(LogicalUnit->DeviceIdentifierPage != NULL);
  489. if(maxLength < sizeof(STORAGE_DESCRIPTOR_HEADER)) {
  490. return STATUS_INVALID_PARAMETER;
  491. }
  492. //
  493. // Initialize the header of the descriptor.
  494. //
  495. RtlZeroMemory(Descriptor, *DescriptorLength);
  496. Descriptor->Version = sizeof(STORAGE_DEVICE_ID_DESCRIPTOR);
  497. Descriptor->Size = FIELD_OFFSET(STORAGE_DEVICE_ID_DESCRIPTOR, Identifiers);
  498. //
  499. // Prepare to copy the identifiers directly into the buffer.
  500. //
  501. destOffset = Descriptor->Identifiers;
  502. //
  503. // Walk through the id page. Count the number of descriptors and
  504. // calculate the size of the descriptor page.
  505. //
  506. for(idOffset = 0; idOffset < idPage->PageLength;) {
  507. PVPD_IDENTIFICATION_DESCRIPTOR src;
  508. USHORT identifierSize;
  509. src = (PVPD_IDENTIFICATION_DESCRIPTOR) &(idPage->Descriptors[idOffset]);
  510. identifierSize = FIELD_OFFSET(STORAGE_IDENTIFIER, Identifier);
  511. identifierSize += src->IdentifierLength;
  512. //
  513. // Align the identifier size to 32-bits.
  514. //
  515. identifierSize += sizeof(ULONG);
  516. identifierSize &= ~(sizeof(ULONG) - 1);
  517. identifierCount += 1;
  518. Descriptor->Size += identifierSize;
  519. if(Descriptor->Size <= maxLength) {
  520. PSTORAGE_IDENTIFIER dest;
  521. dest = (PSTORAGE_IDENTIFIER) destOffset;
  522. dest->CodeSet = src->CodeSet;
  523. dest->Type = src->IdentifierType;
  524. dest->Association = src->Association;
  525. dest->IdentifierSize = src->IdentifierLength;
  526. dest->NextOffset = identifierSize;
  527. RtlCopyMemory(dest->Identifier,
  528. src->Identifier,
  529. src->IdentifierLength);
  530. destOffset += dest->NextOffset;
  531. }
  532. idOffset += sizeof(PVPD_IDENTIFICATION_DESCRIPTOR);
  533. idOffset += src->IdentifierLength;
  534. }
  535. if(*DescriptorLength >= FIELD_OFFSET(STORAGE_DEVICE_ID_DESCRIPTOR,
  536. Identifiers)) {
  537. Descriptor->NumberOfIdentifiers = identifierCount;
  538. }
  539. *DescriptorLength = min(Descriptor->Size, *DescriptorLength);
  540. return STATUS_SUCCESS;
  541. }