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.

1099 lines
29 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 2000
  3. Module Name:
  4. pnp.c
  5. Abstract:
  6. This file contains plug and play code for the NT iSCSI port driver.
  7. Environment:
  8. kernel mode only
  9. Revision History:
  10. --*/
  11. #include "port.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE, iScsiPortAddDevice)
  14. #pragma alloc_text(PAGE, iScsiPortUnload)
  15. #endif // ALLOC_PRAGMA
  16. #define NUM_DEVICE_TYPE_INFO_ENTRIES 18
  17. extern ISCSI_DEVICE_TYPE DeviceTypeInfo[];
  18. VOID
  19. iSpInitFdoExtension(
  20. IN OUT PISCSI_FDO_EXTENSION
  21. );
  22. ISCSI_DEVICE_TYPE DeviceTypeInfo[NUM_DEVICE_TYPE_INFO_ENTRIES] = {
  23. {"Disk", "GenDisk", L"DiskPeripheral", TRUE},
  24. {"Sequential", "", L"TapePeripheral", TRUE},
  25. {"Printer", "GenPrinter", L"PrinterPeripheral", FALSE},
  26. {"Processor", "", L"OtherPeripheral", FALSE},
  27. {"Worm", "GenWorm", L"WormPeripheral", TRUE},
  28. {"CdRom", "GenCdRom", L"CdRomPeripheral", TRUE},
  29. {"Scanner", "GenScanner", L"ScannerPeripheral", FALSE},
  30. {"Optical", "GenOptical", L"OpticalDiskPeripheral", TRUE},
  31. {"Changer", "ScsiChanger", L"MediumChangerPeripheral", TRUE},
  32. {"Net", "ScsiNet", L"CommunicationsPeripheral", FALSE},
  33. {"ASCIT8", "ScsiASCIT8", L"ASCPrePressGraphicsPeripheral", FALSE},
  34. {"ASCIT8", "ScsiASCIT8", L"ASCPrePressGraphicsPeripheral", FALSE},
  35. {"Array", "ScsiArray", L"ArrayPeripheral", FALSE},
  36. {"Enclosure", "ScsiEnclosure", L"EnclosurePeripheral", FALSE},
  37. {"RBC", "ScsiRBC", L"RBCPeripheral", TRUE},
  38. {"CardReader", "ScsiCardReader", L"CardReaderPeripheral", FALSE},
  39. {"Bridge", "ScsiBridge", L"BridgePeripheral", FALSE},
  40. {"Other", "ScsiOther", L"OtherPeripheral", FALSE}
  41. };
  42. PISCSI_FDO_EXTENSION iSpGlobalFdoExtension = NULL;
  43. HANDLE iSpTdiNotificationHandle = NULL;
  44. NTSTATUS
  45. iScsiPortAddDevice(
  46. IN PDRIVER_OBJECT DriverObject,
  47. IN PDEVICE_OBJECT PhysicalDeviceObject
  48. )
  49. /*+++
  50. Routine Description:
  51. This routine handles add-device requests for the iSCSI port driver
  52. Arguments:
  53. DriverObject - a pointer to the driver object for this device
  54. PhysicalDeviceObject - a pointer to the PDO we are being added to
  55. Return Value:
  56. STATUS_SUCCESS if successful
  57. Appropriate NTStatus code on error
  58. --*/
  59. {
  60. PDEVICE_OBJECT deviceObject;
  61. PDEVICE_OBJECT newDeviceObject;
  62. PISCSI_FDO_EXTENSION fdoExtension;
  63. PCOMMON_EXTENSION commonExtension;
  64. NTSTATUS status;
  65. UNICODE_STRING deviceName;
  66. RtlInitUnicodeString(&deviceName, ISCSI_FDO_DEVICE_NAME);
  67. status = IoCreateDevice(DriverObject,
  68. sizeof(ISCSI_FDO_EXTENSION),
  69. &deviceName,
  70. FILE_DEVICE_NETWORK,
  71. 0,
  72. FALSE,
  73. &deviceObject);
  74. if (!NT_SUCCESS(status)) {
  75. DebugPrint((1, "iScsiPortAddDevice failed. Status %lx\n",
  76. status));
  77. return status;
  78. }
  79. newDeviceObject = IoAttachDeviceToDeviceStack(deviceObject,
  80. PhysicalDeviceObject);
  81. if (newDeviceObject == NULL) {
  82. DebugPrint((0,
  83. "IoAttachDeviceToDeviceStack failed in iScsiAddDevice\n"));
  84. IoDeleteDevice(deviceObject);
  85. return STATUS_UNSUCCESSFUL;
  86. }
  87. deviceObject->Flags |= DO_DIRECT_IO;
  88. fdoExtension = deviceObject->DeviceExtension;
  89. commonExtension = &(fdoExtension->CommonExtension);
  90. iSpGlobalFdoExtension = fdoExtension;
  91. RtlZeroMemory(fdoExtension, sizeof(ISCSI_FDO_EXTENSION));
  92. fdoExtension->LowerPdo = PhysicalDeviceObject;
  93. commonExtension->LowerDeviceObject = newDeviceObject;
  94. commonExtension->DeviceObject = deviceObject;
  95. commonExtension->IsPdo = FALSE;
  96. commonExtension->CurrentPnpState = 0xff;
  97. commonExtension->PreviousPnpState = 0xff;
  98. commonExtension->IsNetworkReady = FALSE;
  99. commonExtension->IsRemoved = NO_REMOVE;
  100. commonExtension->RemoveLock = 0;
  101. KeInitializeEvent(&(commonExtension->RemoveEvent),
  102. SynchronizationEvent,
  103. FALSE);
  104. KeInitializeSpinLock(&(fdoExtension->EnumerationSpinLock));
  105. IoInitializeTimer(deviceObject, iSpTickHandler, NULL);
  106. IoStartTimer(fdoExtension->DeviceObject);
  107. //
  108. // Initialize the entry points for this device
  109. //
  110. iScsiPortInitializeDispatchTables();
  111. commonExtension->MajorFunction = FdoMajorFunctionTable;
  112. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  113. DebugPrint((3, "Add Device was successful\n"));
  114. return STATUS_SUCCESS;
  115. }
  116. VOID
  117. iScsiPortUnload(
  118. IN PDRIVER_OBJECT DriverObject
  119. )
  120. {
  121. PISCSIPORT_DRIVER_EXTENSION driverExtension;
  122. driverExtension = IoGetDriverObjectExtension( DriverObject,
  123. (PVOID)ISCSI_TAG_DRIVER_EXTENSION);
  124. if (driverExtension != NULL) {
  125. ExFreePool(driverExtension->RegistryPath.Buffer);
  126. driverExtension->RegistryPath.Buffer = NULL;
  127. driverExtension->RegistryPath.Length = 0;
  128. driverExtension->RegistryPath.MaximumLength = 0;
  129. }
  130. iSpGlobalFdoExtension = NULL;
  131. iSpTdiNotificationHandle = NULL;
  132. return;
  133. }
  134. NTSTATUS
  135. iScsiPortFdoPnp(
  136. IN PDEVICE_OBJECT DeviceObject,
  137. IN PIRP Irp
  138. )
  139. {
  140. PCOMMON_EXTENSION commonExtension = DeviceObject->DeviceExtension;
  141. PISCSI_FDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  142. PIO_STACK_LOCATION irpStack;
  143. NTSTATUS status = STATUS_SUCCESS;
  144. ULONG isRemoved;
  145. BOOLEAN forwardIrp = FALSE;
  146. PAGED_CODE();
  147. irpStack = IoGetCurrentIrpStackLocation(Irp);
  148. DebugPrint((1, "FdoPnp for DeviceObject %x, Irp %x, MN %x\n",
  149. DeviceObject, Irp, (irpStack->MinorFunction)));
  150. isRemoved = iSpAcquireRemoveLock(DeviceObject, Irp);
  151. if (isRemoved) {
  152. iSpReleaseRemoveLock(DeviceObject, Irp);
  153. Irp->IoStatus.Status = STATUS_DEVICE_DOES_NOT_EXIST;
  154. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  155. return STATUS_DEVICE_DOES_NOT_EXIST;
  156. }
  157. switch (irpStack->MinorFunction) {
  158. case IRP_MN_START_DEVICE: {
  159. status = iSpSendIrpSynchronous(commonExtension->LowerDeviceObject,
  160. Irp);
  161. if (NT_SUCCESS(status)) {
  162. //
  163. // Register for notification from network interface
  164. // to be notified of network ready state
  165. //
  166. if ((commonExtension->IsNetworkReady) == FALSE) {
  167. iSpRegisterForNetworkNotification();
  168. }
  169. //
  170. // Initialize various fields in the
  171. // FDO Extension.
  172. //
  173. iSpInitFdoExtension(fdoExtension);
  174. Irp->IoStatus.Status = status;
  175. }
  176. break;
  177. }
  178. case IRP_MN_QUERY_STOP_DEVICE: {
  179. status = STATUS_SUCCESS;
  180. Irp->IoStatus.Status = status;
  181. forwardIrp = TRUE;
  182. break;
  183. }
  184. case IRP_MN_CANCEL_STOP_DEVICE: {
  185. status = STATUS_SUCCESS;
  186. Irp->IoStatus.Status = status;
  187. forwardIrp = TRUE;
  188. break;
  189. }
  190. case IRP_MN_STOP_DEVICE: {
  191. if (iSpTdiNotificationHandle != NULL) {
  192. TdiDeregisterPnPHandlers(iSpTdiNotificationHandle);
  193. iSpTdiNotificationHandle = NULL;
  194. }
  195. //
  196. // If network node hasn't been released yet,
  197. // release it now
  198. //
  199. if ((fdoExtension->LocalNodesInitialized) == TRUE) {
  200. ULONG inx;
  201. for (inx = 0; inx < (fdoExtension->NumberOfTargets);
  202. inx++) {
  203. iSpStopNetwork(fdoExtension->PDOList[inx]);
  204. fdoExtension->PDOList[inx] = NULL;
  205. }
  206. fdoExtension->LocalNodesInitialized = FALSE;
  207. fdoExtension->NumberOfTargets = 0;
  208. }
  209. fdoExtension->LocalNodesInitialized = FALSE;
  210. Irp->IoStatus.Status = status;
  211. Irp->IoStatus.Information = 0L;
  212. if (NT_SUCCESS(status)) {
  213. forwardIrp = TRUE;
  214. }
  215. break;
  216. }
  217. case IRP_MN_QUERY_REMOVE_DEVICE: {
  218. DebugPrint((0, "Query remove received.\n"));
  219. status = STATUS_SUCCESS;
  220. Irp->IoStatus.Status = status;
  221. forwardIrp = TRUE;
  222. break;
  223. }
  224. case IRP_MN_CANCEL_REMOVE_DEVICE: {
  225. status = STATUS_SUCCESS;
  226. Irp->IoStatus.Status = status;
  227. forwardIrp = TRUE;
  228. break;
  229. }
  230. case IRP_MN_REMOVE_DEVICE: {
  231. //
  232. // Deregister network notification if we
  233. // already haven't
  234. //
  235. if (iSpTdiNotificationHandle != NULL) {
  236. TdiDeregisterPnPHandlers(iSpTdiNotificationHandle);
  237. iSpTdiNotificationHandle = NULL;
  238. }
  239. //
  240. // If network node hasn't been released yet,
  241. // release it now
  242. //
  243. if ((fdoExtension->LocalNodesInitialized) == TRUE) {
  244. ULONG inx;
  245. for (inx = 0; inx < (fdoExtension->NumberOfTargets);
  246. inx++) {
  247. iSpStopNetwork(fdoExtension->PDOList[inx]);
  248. IoDeleteDevice(fdoExtension->PDOList[inx]);
  249. fdoExtension->PDOList[inx] = NULL;
  250. }
  251. fdoExtension->LocalNodesInitialized = FALSE;
  252. fdoExtension->NumberOfTargets = 0;
  253. }
  254. fdoExtension->LocalNodesInitialized = FALSE;
  255. iSpReleaseRemoveLock(DeviceObject, Irp);
  256. commonExtension->IsRemoved = REMOVE_PENDING;
  257. DebugPrint((1, "Waiting for remove event.\n"));
  258. KeWaitForSingleObject(&(commonExtension->RemoveEvent),
  259. Executive,
  260. KernelMode,
  261. FALSE,
  262. NULL);
  263. DebugPrint((1, "Will process remove now.\n"));
  264. status = iSpSendIrpSynchronous(commonExtension->LowerDeviceObject,
  265. Irp);
  266. if (NT_SUCCESS(status)) {
  267. IoDetachDevice(commonExtension->LowerDeviceObject);
  268. IoDeleteDevice(commonExtension->DeviceObject);
  269. Irp->IoStatus.Status = STATUS_SUCCESS;
  270. } else {
  271. commonExtension->IsRemoved = NO_REMOVE;
  272. Irp->IoStatus.Status = status;
  273. }
  274. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  275. return status;
  276. break;
  277. }
  278. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  279. PIO_WORKITEM workItem = NULL;
  280. PDEVICE_RELATIONS deviceRelations;
  281. PDEVICE_OBJECT lowerDevice;
  282. ULONG relationSize;
  283. DEVICE_RELATION_TYPE relationType;
  284. relationType =
  285. irpStack->Parameters.QueryDeviceRelations.Type;
  286. if (relationType != BusRelations) {
  287. forwardIrp = TRUE;
  288. break;
  289. }
  290. if ((fdoExtension->EnumerationComplete) == TRUE) {
  291. ASSERT((fdoExtension->NumberOfTargets) > 0);
  292. relationSize = sizeof(DEVICE_RELATIONS) +
  293. (sizeof(PDEVICE_OBJECT) *
  294. (fdoExtension->NumberOfTargets));
  295. deviceRelations = iSpAllocatePool(PagedPool,
  296. relationSize,
  297. ISCSI_TAG_DEVICE_RELATIONS);
  298. if (deviceRelations != NULL) {
  299. PDEVICE_OBJECT pdo;
  300. ULONG inx;
  301. deviceRelations->Count =
  302. fdoExtension->NumberOfTargets;
  303. for (inx = 0; (inx < (fdoExtension->NumberOfTargets));
  304. inx++) {
  305. pdo = fdoExtension->PDOList[inx];
  306. ASSERT(pdo != NULL);
  307. ObReferenceObject(pdo);
  308. deviceRelations->Objects[inx] = pdo;
  309. }
  310. Irp->IoStatus.Status = STATUS_SUCCESS;
  311. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  312. IoCopyCurrentIrpStackLocationToNext(Irp);
  313. lowerDevice =
  314. fdoExtension->CommonExtension.LowerDeviceObject;
  315. iSpReleaseRemoveLock(DeviceObject, Irp);
  316. return IoCallDriver(lowerDevice, Irp);
  317. } else {
  318. Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  319. Irp->IoStatus.Information = 0L;
  320. iSpReleaseRemoveLock(DeviceObject, Irp);
  321. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  322. return STATUS_INSUFFICIENT_RESOURCES;
  323. }
  324. }
  325. status = STATUS_SUCCESS;
  326. //
  327. // Setup the local network nodes if not already done
  328. //
  329. if ((fdoExtension->LocalNodesInitialized) == FALSE) {
  330. status = iSpInitializeLocalNodes(DeviceObject);
  331. }
  332. if (NT_SUCCESS(status)) {
  333. //
  334. // Allocate a workitem to perform device
  335. // enumeration
  336. //
  337. fdoExtension->EnumerationThreadLaunched = FALSE;
  338. workItem = IoAllocateWorkItem(DeviceObject);
  339. if (workItem != NULL) {
  340. IoMarkIrpPending(Irp);
  341. fdoExtension->EnumerationIrp = Irp;
  342. fdoExtension->EnumerationComplete = FALSE;
  343. fdoExtension->EnumerationWorkItem = workItem;
  344. IoQueueWorkItem(workItem,
  345. iSpEnumerateDevicesAsynchronous,
  346. DelayedWorkQueue,
  347. fdoExtension);
  348. iSpReleaseRemoveLock(DeviceObject, Irp);
  349. return STATUS_PENDING;
  350. } else {
  351. Irp->IoStatus.Information = 0L;
  352. status = STATUS_INSUFFICIENT_RESOURCES;
  353. }
  354. break;
  355. } else {
  356. DebugPrint((1, "Could not setup the node. Status : %x\n",
  357. status));
  358. Irp->IoStatus.Status = status;
  359. Irp->IoStatus.Information = 0L;
  360. }
  361. break;
  362. }
  363. default: {
  364. forwardIrp = TRUE;
  365. break;
  366. }
  367. } // switch (irpStack->MinorFunction)
  368. iSpReleaseRemoveLock(DeviceObject, Irp);
  369. if (forwardIrp == TRUE) {
  370. IoSkipCurrentIrpStackLocation(Irp);
  371. return IoCallDriver(commonExtension->LowerDeviceObject,
  372. Irp);
  373. } else {
  374. status = Irp->IoStatus.Status;
  375. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  376. }
  377. return status;
  378. }
  379. NTSTATUS
  380. iSpSendIrpSynchronous(
  381. IN PDEVICE_OBJECT DeviceObject,
  382. IN PIRP Irp
  383. )
  384. {
  385. NTSTATUS status;
  386. KEVENT event;
  387. PAGED_CODE();
  388. if (DeviceObject == NULL) {
  389. DebugPrint((1, "DeviceObject NULL. Irp %x\n",
  390. Irp));
  391. return Irp->IoStatus.Status;
  392. }
  393. KeInitializeEvent(&event, NotificationEvent, FALSE);
  394. IoCopyCurrentIrpStackLocationToNext(Irp);
  395. IoSetCompletionRoutine(Irp,
  396. iSpSetEvent,
  397. &event,
  398. TRUE,
  399. TRUE,
  400. TRUE);
  401. status = IoCallDriver(DeviceObject, Irp);
  402. if (status == STATUS_PENDING) {
  403. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  404. status = Irp->IoStatus.Status;
  405. }
  406. return status;
  407. }
  408. NTSTATUS
  409. iScsiPortGetDeviceId(
  410. IN PDEVICE_OBJECT Pdo,
  411. OUT PUNICODE_STRING UnicodeString
  412. )
  413. /*++
  414. Routine Description:
  415. This routine will allocate space for and fill in a device id string for
  416. the specified Pdo. This string is generated from the bus type (scsi) and
  417. the type of the device.
  418. Arguments:
  419. Pdo - a pointer to the physical device object being queried
  420. UnicodeString - a pointer to an already allocated unicode string structure.
  421. This routine will allocate and fill in the buffer of this
  422. structure
  423. Returns:
  424. status
  425. --*/
  426. {
  427. PISCSI_PDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  428. PINQUIRYDATA inquiryData = &(pdoExtension->InquiryData);
  429. UCHAR buffer[256];
  430. PUCHAR rawIdString = buffer;
  431. ANSI_STRING ansiIdString;
  432. ULONG whichString;
  433. PAGED_CODE();
  434. ASSERT(UnicodeString != NULL);
  435. RtlZeroMemory(buffer, sizeof(buffer));
  436. sprintf(rawIdString,
  437. "SCSI\\%s",
  438. iSpGetDeviceTypeInfo(inquiryData->DeviceType)->DeviceTypeString);
  439. rawIdString += strlen(rawIdString);
  440. ASSERT(*rawIdString == '\0');
  441. for(whichString = 0; whichString < 3; whichString++) {
  442. PUCHAR headerString;
  443. PUCHAR sourceString;
  444. ULONG sourceStringLength;
  445. ULONG i;
  446. switch(whichString) {
  447. //
  448. // Vendor Id
  449. //
  450. case 0: {
  451. sourceString = inquiryData->VendorId;
  452. sourceStringLength = sizeof(inquiryData->VendorId);
  453. headerString = "Ven";
  454. break;
  455. }
  456. //
  457. // Product Id
  458. //
  459. case 1: {
  460. sourceString = inquiryData->ProductId;
  461. sourceStringLength = sizeof(inquiryData->ProductId);
  462. headerString = "Prod";
  463. break;
  464. }
  465. //
  466. // Product Revision Level
  467. //
  468. case 2: {
  469. sourceString = inquiryData->ProductRevisionLevel;
  470. sourceStringLength = sizeof(inquiryData->ProductRevisionLevel);
  471. headerString = "Rev";
  472. break;
  473. }
  474. }
  475. //
  476. // Start at the end of the source string and back up until we find a
  477. // non-space, non-null character.
  478. //
  479. for(; sourceStringLength > 0; sourceStringLength--) {
  480. if((sourceString[sourceStringLength - 1] != ' ') &&
  481. (sourceString[sourceStringLength - 1] != '\0')) {
  482. break;
  483. }
  484. }
  485. //
  486. // Throw the header string into the block
  487. //
  488. sprintf(rawIdString, "&%s_", headerString);
  489. rawIdString += strlen(headerString) + 2;
  490. //
  491. // Spew the string into the device id
  492. //
  493. for(i = 0; i < sourceStringLength; i++) {
  494. *rawIdString = (sourceString[i] != ' ') ? (sourceString[i]) :
  495. ('_');
  496. rawIdString++;
  497. }
  498. ASSERT(*rawIdString == '\0');
  499. }
  500. RtlInitAnsiString(&ansiIdString, buffer);
  501. DebugPrint((1, "DeviceId for logical unit %#p is %Z\n",
  502. Pdo, &ansiIdString));
  503. return RtlAnsiStringToUnicodeString(UnicodeString, &ansiIdString, TRUE);
  504. }
  505. NTSTATUS
  506. iScsiPortGetInstanceId(
  507. IN PDEVICE_OBJECT Pdo,
  508. OUT PUNICODE_STRING UnicodeString
  509. )
  510. /*++
  511. Routine Description:
  512. This routine will allocate space for and fill in an instance id string for
  513. the specified Pdo. This string will be generated either from the device
  514. type + serial number of the device (if it has a serial number) or from
  515. the address of the device.
  516. Arguments:
  517. Pdo - a pointer to the physical device object being queried
  518. UnicodeString - a pointer to an already allocated unicode string structure.
  519. This routine will allocate and fill in the buffer of this
  520. structure
  521. Returns:
  522. status
  523. --*/
  524. {
  525. PISCSI_PDO_EXTENSION pdoExtension = Pdo->DeviceExtension;
  526. PDRIVER_OBJECT driverObject = Pdo->DriverObject;
  527. PISCSI_DEVICE_TYPE deviceTypeInfo;
  528. UCHAR idStringBuffer[64];
  529. ANSI_STRING ansiIdString;
  530. PAGED_CODE();
  531. ASSERT(UnicodeString != NULL);
  532. //
  533. // can't use serial number even if it exists since a device which is
  534. // multiply connected to the same bus (dual-ported device) will have
  535. // the same serial number at each connection and would confuse the PNP.
  536. //
  537. sprintf(idStringBuffer,
  538. "%x%x%x",
  539. pdoExtension->PathId,
  540. pdoExtension->TargetId,
  541. pdoExtension->Lun
  542. );
  543. RtlInitAnsiString(&ansiIdString, idStringBuffer);
  544. return RtlAnsiStringToUnicodeString(UnicodeString, &ansiIdString, TRUE);
  545. }
  546. NTSTATUS
  547. iScsiPortGetCompatibleIds(
  548. IN PDRIVER_OBJECT DriverObject,
  549. IN PINQUIRYDATA InquiryData,
  550. OUT PUNICODE_STRING UnicodeString
  551. )
  552. /*++
  553. Routine Description:
  554. This routine will allocate space for and fill in a compatible id multi
  555. string for the specified Pdo. This string is generated using the bus and
  556. device types for the device
  557. Arguments:
  558. InquiryData - the inquiry data to generate compatible ids from.
  559. UnicodeString - a pointer to an already allocated unicode string structure.
  560. This routine will allocate and fill in the buffer of this
  561. structure
  562. Returns:
  563. status
  564. --*/
  565. {
  566. UCHAR s[sizeof("SCSI\\DEVICE_TYPE_GOES_HERE")];
  567. PSTR stringBuffer[] = {
  568. s,
  569. "SCSI\\RAW",
  570. NULL};
  571. //
  572. // Fill in the scsi specific string
  573. //
  574. sprintf(stringBuffer[0],
  575. "SCSI\\%s",
  576. iSpGetDeviceTypeInfo(InquiryData->DeviceType)->DeviceTypeString);
  577. //
  578. // Set up the first id string
  579. //
  580. return iScsiPortStringArrayToMultiString(
  581. DriverObject,
  582. UnicodeString,
  583. stringBuffer);
  584. }
  585. NTSTATUS
  586. iScsiPortGetHardwareIds(
  587. IN PDRIVER_OBJECT DriverObject,
  588. IN PINQUIRYDATA InquiryData,
  589. OUT PUNICODE_STRING UnicodeString
  590. )
  591. /*++
  592. Routine Description:
  593. This routine will allocate space for and fill in a hardware id multi
  594. string for the specified Pdo. This string is generated using the device
  595. type and the inquiry data.
  596. Arguments:
  597. InquiryData - the inquiry data to be converted into id strings.
  598. UnicodeString - a pointer to an already allocated unicode string structure.
  599. This routine will allocate and fill in the buffer of this
  600. structure
  601. Returns:
  602. status
  603. --*/
  604. #define NUMBER_HARDWARE_STRINGS 6
  605. {
  606. PISCSI_DEVICE_TYPE devTypeInfo =
  607. iSpGetDeviceTypeInfo(InquiryData->DeviceType);
  608. ULONG i;
  609. PSTR strings[NUMBER_HARDWARE_STRINGS + 1];
  610. UCHAR scratch[64];
  611. NTSTATUS status;
  612. PAGED_CODE();
  613. //
  614. // Zero out the string buffer
  615. //
  616. RtlZeroMemory(strings, sizeof(strings));
  617. try {
  618. for(i = 0; i < NUMBER_HARDWARE_STRINGS; i++) {
  619. RtlZeroMemory(scratch, sizeof(scratch));
  620. //
  621. // Build each of the hardware id's
  622. //
  623. switch(i) {
  624. //
  625. // Bus + Dev Type + Vendor + Product + Revision
  626. //
  627. case 0: {
  628. sprintf(scratch, "SCSI\\%s", devTypeInfo->DeviceTypeString);
  629. CopyField(scratch + strlen(scratch),
  630. InquiryData->VendorId,
  631. 8,
  632. '_');
  633. CopyField(scratch + strlen(scratch),
  634. InquiryData->ProductId,
  635. 16,
  636. '_');
  637. CopyField(scratch + strlen(scratch),
  638. InquiryData->ProductRevisionLevel,
  639. 4,
  640. '_');
  641. break;
  642. }
  643. //
  644. // bus + device + vendor + product
  645. //
  646. case 1: {
  647. sprintf(scratch, "SCSI\\%s", devTypeInfo->DeviceTypeString);
  648. CopyField(scratch + strlen(scratch),
  649. InquiryData->VendorId,
  650. 8,
  651. '_');
  652. CopyField(scratch + strlen(scratch),
  653. InquiryData->ProductId,
  654. 16,
  655. '_');
  656. break;
  657. }
  658. //
  659. // bus + device + vendor
  660. //
  661. case 2: {
  662. sprintf(scratch, "SCSI\\%s", devTypeInfo->DeviceTypeString);
  663. CopyField(scratch + strlen(scratch),
  664. InquiryData->VendorId,
  665. 8,
  666. '_');
  667. break;
  668. }
  669. //
  670. // bus \ vendor + product + revision[0]
  671. //
  672. case 3: {
  673. sprintf(scratch, "SCSI\\");
  674. //
  675. // Fall through to the next set.
  676. //
  677. }
  678. //
  679. // vendor + product + revision[0] (win9x)
  680. //
  681. case 4: {
  682. CopyField(scratch + strlen(scratch),
  683. InquiryData->VendorId,
  684. 8,
  685. '_');
  686. CopyField(scratch + strlen(scratch),
  687. InquiryData->ProductId,
  688. 16,
  689. '_');
  690. CopyField(scratch + strlen(scratch),
  691. InquiryData->ProductRevisionLevel,
  692. 1,
  693. '_');
  694. break;
  695. }
  696. case 5: {
  697. sprintf(scratch, "%s", devTypeInfo->GenericTypeString);
  698. break;
  699. }
  700. default: {
  701. ASSERT(FALSE);
  702. break;
  703. }
  704. }
  705. if(strlen(scratch) != 0) {
  706. strings[i] =
  707. iSpAllocatePool(PagedPool,
  708. strlen(scratch) + sizeof(UCHAR),
  709. ISCSI_TAG_PNP_ID);
  710. if(strings[i] == NULL) {
  711. status = STATUS_INSUFFICIENT_RESOURCES;
  712. leave;
  713. }
  714. strcpy(strings[i], scratch);
  715. } else {
  716. break;
  717. }
  718. }
  719. status = iScsiPortStringArrayToMultiString(DriverObject,
  720. UnicodeString,
  721. strings);
  722. leave;
  723. } finally {
  724. for(i = 0; i < NUMBER_HARDWARE_STRINGS; i++) {
  725. if(strings[i]) {
  726. ExFreePool(strings[i]);
  727. }
  728. }
  729. }
  730. return status;
  731. }
  732. #undef NUMBER_HARDWARE_STRINGS
  733. VOID
  734. CopyField(
  735. IN PUCHAR Destination,
  736. IN PUCHAR Source,
  737. IN ULONG Count,
  738. IN UCHAR Change
  739. )
  740. /*++
  741. Routine Description:
  742. This routine will copy Count string bytes from Source to Destination. If
  743. it finds a nul byte in the Source it will translate that and any subsequent
  744. bytes into Change. It will also replace spaces with the specified character.
  745. Arguments:
  746. Destination - the location to copy bytes
  747. Source - the location to copy bytes from
  748. Count - the number of bytes to be copied
  749. Return Value:
  750. none
  751. --*/
  752. {
  753. ULONG i = 0;
  754. BOOLEAN pastEnd = FALSE;
  755. PAGED_CODE();
  756. for(i = 0; i < Count; i++) {
  757. if(!pastEnd) {
  758. if(Source[i] == 0) {
  759. pastEnd = TRUE;
  760. Destination[i] = Change;
  761. } else if(Source[i] == ' ') {
  762. Destination[i] = Change;
  763. } else {
  764. Destination[i] = Source[i];
  765. }
  766. } else {
  767. Destination[i] = Change;
  768. }
  769. }
  770. return;
  771. }
  772. PISCSI_DEVICE_TYPE
  773. iSpGetDeviceTypeInfo(
  774. IN UCHAR DeviceType
  775. )
  776. {
  777. PAGED_CODE();
  778. if(DeviceType >= NUM_DEVICE_TYPE_INFO_ENTRIES) {
  779. return &(DeviceTypeInfo[NUM_DEVICE_TYPE_INFO_ENTRIES - 1]);
  780. } else {
  781. return &(DeviceTypeInfo[DeviceType]);
  782. }
  783. };
  784. VOID
  785. iSpInitFdoExtension(
  786. IN OUT PISCSI_FDO_EXTENSION FdoExtension
  787. )
  788. {
  789. PIO_SCSI_CAPABILITIES capabilities;
  790. capabilities = &(FdoExtension->IoScsiCapabilities);
  791. //
  792. // For now, we are going to hard code most of the values
  793. //
  794. capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
  795. capabilities->MaximumTransferLength = 0x8000;
  796. capabilities->MaximumPhysicalPages = 9;
  797. capabilities->SupportedAsynchronousEvents = 0;
  798. capabilities->AlignmentMask = 0;
  799. capabilities->TaggedQueuing = FALSE;
  800. capabilities->AdapterScansDown = FALSE;
  801. capabilities->AdapterUsesPio = FALSE;
  802. }