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.

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