|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1992 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: scsiscan.c ! 8: ! 9: Abstract: ! 10: ! 11: The scsi scanner class driver tranlates IRPs to SRBs with embedded CDBs ! 12: and sends them to its devices through the port driver. ! 13: ! 14: Author: ! 15: ! 16: Mike Glass (mglass) ! 17: ! 18: Environment: ! 19: ! 20: kernel mode only ! 21: ! 22: Notes: ! 23: ! 24: Revision History: ! 25: ! 26: --*/ ! 27: ! 28: #include "ntddk.h" ! 29: #include "scsi.h" ! 30: #include "class.h" ! 31: ! 32: #define DEVICE_EXTENSION_SIZE sizeof(DEVICE_EXTENSION) ! 33: ! 34: ! 35: BOOLEAN ! 36: FindScsiScanners( ! 37: IN PDRIVER_OBJECT DriveObject, ! 38: IN PDEVICE_OBJECT PortDeviceObject ! 39: ); ! 40: ! 41: NTSTATUS ! 42: CreateScannerDeviceObject( ! 43: IN PDRIVER_OBJECT DriverObject, ! 44: IN PDEVICE_OBJECT PortDeviceObject, ! 45: IN PULONG DeviceCount, ! 46: IN PCHAR ArcName, ! 47: IN PIO_SCSI_CAPABILITIES PortCapabilities, ! 48: IN PSCSI_INQUIRY_DATA LunInfo ! 49: ); ! 50: ! 51: NTSTATUS ! 52: ScsiScannerOpen( ! 53: IN PDEVICE_OBJECT DeviceObject, ! 54: IN PIRP Irp ! 55: ); ! 56: ! 57: NTSTATUS ! 58: ScsiScannerReadWrite( ! 59: IN PDEVICE_OBJECT DeviceObject, ! 60: IN PIRP Irp ! 61: ); ! 62: ! 63: NTSTATUS ! 64: ScsiScannerDeviceControl( ! 65: IN PDEVICE_OBJECT DeviceObject, ! 66: IN PIRP Irp ! 67: ); ! 68: ! 69: VOID ! 70: BuildScannerRequest( ! 71: PDEVICE_OBJECT DeviceObject, ! 72: PIRP Irp ! 73: ); ! 74: ! 75: VOID ! 76: ScsiScannerError( ! 77: PDEVICE_OBJECT DeviceObject, ! 78: IN PSCSI_REQUEST_BLOCK Srb, ! 79: IN OUT NTSTATUS *Status, ! 80: IN OUT BOOLEAN *Retry ! 81: ); ! 82: ! 83: VOID ! 84: SplitRequest( ! 85: IN PDEVICE_OBJECT DeviceObject, ! 86: IN PIRP Irp, ! 87: IN ULONG MaximumBytes ! 88: ); ! 89: ! 90: ! 91: NTSTATUS ! 92: DriverEntry( ! 93: IN PDRIVER_OBJECT DriverObject, ! 94: IN PUNICODE_STRING RegistryPath ! 95: ) ! 96: ! 97: /*++ ! 98: ! 99: Routine Description: ! 100: ! 101: This routine initializes the scanner class driver. The driver ! 102: opens the port driver by name and then receives configuration ! 103: information used to attach to the scanner devices. ! 104: ! 105: Arguments: ! 106: ! 107: DriverObject ! 108: ! 109: Return Value: ! 110: ! 111: NT Status ! 112: ! 113: --*/ ! 114: ! 115: { ! 116: ULONG portNumber = 0; ! 117: NTSTATUS status; ! 118: PFILE_OBJECT fileObject; ! 119: PDEVICE_OBJECT portDeviceObject; ! 120: STRING deviceNameString; ! 121: CCHAR deviceNameBuffer[64]; ! 122: UNICODE_STRING unicodeDeviceName; ! 123: BOOLEAN foundOne = FALSE; ! 124: ! 125: DebugPrint((1,"\n\nSCSI Scanner Class Driver\n")); ! 126: ! 127: // ! 128: // Set up the device driver entry points. ! 129: // ! 130: ! 131: DriverObject->MajorFunction[IRP_MJ_READ] = ScsiScannerReadWrite; ! 132: DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiScannerReadWrite; ! 133: DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiScannerDeviceControl; ! 134: DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiScannerOpen; ! 135: ! 136: // ! 137: // Open port driver device objects by name. ! 138: // ! 139: ! 140: do { ! 141: ! 142: // ! 143: // Create port driver name. ! 144: // ! 145: ! 146: sprintf(deviceNameBuffer, ! 147: "\\Device\\ScsiPort%d", ! 148: portNumber++); ! 149: ! 150: DebugPrint((2,"ScsiScannerInitialize: Open %s\n", ! 151: deviceNameBuffer)); ! 152: ! 153: RtlInitString(&deviceNameString, ! 154: deviceNameBuffer); ! 155: ! 156: status = RtlAnsiStringToUnicodeString(&unicodeDeviceName, ! 157: &deviceNameString, ! 158: TRUE); ! 159: ! 160: if (!NT_SUCCESS(status)) { ! 161: ! 162: DebugPrint((1, ! 163: "ScsiScannerInitialize: Could not initalize unicode string %s\n", ! 164: deviceNameString)); ! 165: ! 166: break; ! 167: } ! 168: ! 169: status = IoGetDeviceObjectPointer(&unicodeDeviceName, ! 170: FILE_READ_ATTRIBUTES, ! 171: &fileObject, ! 172: &portDeviceObject); ! 173: ! 174: if (NT_SUCCESS(status)) { ! 175: ! 176: // ! 177: // SCSI port driver exists. ! 178: // ! 179: ! 180: if (FindScsiScanners(DriverObject, ! 181: portDeviceObject)) { ! 182: ! 183: foundOne = TRUE; ! 184: } ! 185: ! 186: // ! 187: // Dereference the file object since the port device pointer is no ! 188: // longer needed. The claim device code refences the port driver ! 189: // pointer that is actually being used. ! 190: // ! 191: ! 192: ObDereferenceObject(fileObject); ! 193: } ! 194: ! 195: } while (NT_SUCCESS(status)); ! 196: ! 197: if (foundOne) { ! 198: return STATUS_SUCCESS; ! 199: } else { ! 200: return STATUS_NO_SUCH_DEVICE; ! 201: } ! 202: ! 203: } // end DriverEntry() ! 204: ! 205: ! 206: BOOLEAN ! 207: FindScsiScanners( ! 208: IN PDRIVER_OBJECT DriverObject, ! 209: IN PDEVICE_OBJECT PortDeviceObject ! 210: ) ! 211: ! 212: /*++ ! 213: ! 214: Routine Description: ! 215: ! 216: Connect to SCSI port driver. Get adapter capabilities and ! 217: SCSI bus configuration information. Search inquiry data ! 218: for scanner devices to process. ! 219: ! 220: Arguments: ! 221: ! 222: Scanner class driver object ! 223: SCSI port driver device object ! 224: ! 225: Return Value: ! 226: ! 227: NONE ! 228: ! 229: --*/ ! 230: ! 231: { ! 232: PIO_SCSI_CAPABILITIES portCapabilities; ! 233: PCHAR buffer; ! 234: PSCSI_INQUIRY_DATA lunInfo; ! 235: PSCSI_ADAPTER_BUS_INFO adapterInfo; ! 236: PINQUIRYDATA inquiryData; ! 237: ULONG scsiBus; ! 238: ULONG scannerCount = 0; ! 239: NTSTATUS status; ! 240: ! 241: // ! 242: // Call port driver to get adapter capabilities. ! 243: // ! 244: ! 245: status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities); ! 246: ! 247: if (!NT_SUCCESS(status)) { ! 248: DebugPrint((1,"FindScsiDevices: ScsiClassGetCapabilities failed\n")); ! 249: return FALSE; ! 250: } ! 251: ! 252: // ! 253: // Call port driver to get inquiry information to find Scanners. ! 254: // ! 255: ! 256: status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *)&buffer); ! 257: ! 258: if (!NT_SUCCESS(status)) { ! 259: DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n")); ! 260: return FALSE; ! 261: } ! 262: ! 263: adapterInfo = (PVOID)buffer; ! 264: ! 265: // ! 266: // For each SCSI bus this adapter supports ... ! 267: // ! 268: ! 269: for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) { ! 270: ! 271: // ! 272: // Get the SCSI bus scan data for this bus. ! 273: // ! 274: ! 275: lunInfo = (PVOID)(buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset); ! 276: ! 277: // ! 278: // Search list for unclaimed disk devices. ! 279: // ! 280: ! 281: while (adapterInfo->BusData[scsiBus].InquiryDataOffset) { ! 282: ! 283: inquiryData = (PVOID)lunInfo->InquiryData; ! 284: ! 285: DebugPrint((3,"FindScsiDevices: Inquiry data at %lx\n", ! 286: inquiryData)); ! 287: ! 288: // ! 289: // Check for SCANNER devices and PROCESSOR devices, as some ! 290: // scanners use this device type. ! 291: // ! 292: ! 293: if (((inquiryData->DeviceType == SCANNER_DEVICE) || ! 294: (inquiryData->DeviceType == PROCESSOR_DEVICE)) && ! 295: (!lunInfo->DeviceClaimed)) { ! 296: ! 297: DebugPrint((1,"FindScsiDevices: Vendor string is %.24s\n", ! 298: inquiryData->VendorId)); ! 299: ! 300: // ! 301: // Create device objects for device ! 302: // ! 303: ! 304: status = CreateScannerDeviceObject(DriverObject, ! 305: PortDeviceObject, ! 306: &scannerCount, ! 307: NULL, ! 308: portCapabilities, ! 309: lunInfo); ! 310: ! 311: if (NT_SUCCESS(status)) { ! 312: ! 313: // ! 314: // Increment device count. ! 315: // ! 316: ! 317: scannerCount++; ! 318: ! 319: } ! 320: } ! 321: ! 322: // ! 323: // Get next LunInfo. ! 324: // ! 325: ! 326: if (lunInfo->NextInquiryDataOffset == 0) { ! 327: break; ! 328: } ! 329: ! 330: lunInfo = (PVOID)(buffer + lunInfo->NextInquiryDataOffset); ! 331: } ! 332: } ! 333: ! 334: ExFreePool(buffer); ! 335: if (scannerCount > 0) {; ! 336: return TRUE; ! 337: } else { ! 338: return FALSE; ! 339: } ! 340: ! 341: } // end FindScsiScanners() ! 342: ! 343: ! 344: NTSTATUS ! 345: CreateScannerDeviceObject( ! 346: IN PDRIVER_OBJECT DriverObject, ! 347: IN PDEVICE_OBJECT PortDeviceObject, ! 348: IN PULONG DeviceCount, ! 349: IN PCHAR ArcName, ! 350: IN PIO_SCSI_CAPABILITIES PortCapabilities, ! 351: IN PSCSI_INQUIRY_DATA LunInfo ! 352: ) ! 353: ! 354: /*++ ! 355: ! 356: Routine Description: ! 357: ! 358: This routine creates an object for the device and then calls the ! 359: SCSI port driver for media capacity and sector size. ! 360: ! 361: Arguments: ! 362: ! 363: DriverObject - Pointer to driver object created by system. ! 364: PortDeviceObject - to connect to SCSI port driver. ! 365: DeviceCount - Number of previously installed scanners. ! 366: PortCapabilities - Pointer to structure returned by SCSI port ! 367: driver describing adapter capabilites (and limitations). ! 368: LunInfo - Pointer to configuration information for this device. ! 369: ! 370: Return Value: ! 371: ! 372: NTSTATUS ! 373: ! 374: --*/ ! 375: { ! 376: UCHAR ntNameBuffer[64]; ! 377: STRING ntNameString; ! 378: UNICODE_STRING ntUnicodeString; ! 379: UCHAR dosNameBuffer[64]; ! 380: STRING dosString; ! 381: UNICODE_STRING dosUnicodeString; ! 382: NTSTATUS status; ! 383: PDEVICE_OBJECT deviceObject = NULL; ! 384: PDEVICE_EXTENSION deviceExtension; ! 385: PVOID senseData = NULL; ! 386: ! 387: // ! 388: // Claim the device. ! 389: // ! 390: ! 391: status = ScsiClassClaimDevice(PortDeviceObject, ! 392: LunInfo, ! 393: FALSE, ! 394: &PortDeviceObject); ! 395: ! 396: if (!NT_SUCCESS(status)) { ! 397: return(status); ! 398: } ! 399: ! 400: // ! 401: // Create device object for this device. ! 402: // ! 403: ! 404: sprintf(ntNameBuffer, ! 405: "\\Device\\Scanner%d", ! 406: *DeviceCount); ! 407: ! 408: RtlInitString(&ntNameString, ! 409: ntNameBuffer); ! 410: ! 411: DebugPrint((2,"CreateScannerDeviceObjects: Create device object %s\n", ! 412: ntNameBuffer)); ! 413: ! 414: // ! 415: // Convert ANSI string to Unicode. ! 416: // ! 417: ! 418: status = RtlAnsiStringToUnicodeString(&ntUnicodeString, ! 419: &ntNameString, ! 420: TRUE); ! 421: ! 422: if (!NT_SUCCESS(status)) { ! 423: ! 424: DebugPrint((1, ! 425: "CreateDiskDeviceObjects: Cannot convert string %s\n", ! 426: ntNameBuffer)); ! 427: ! 428: // ! 429: // Release the device since an error occured. ! 430: // ! 431: ! 432: ScsiClassClaimDevice(PortDeviceObject, ! 433: LunInfo, ! 434: TRUE, ! 435: NULL); ! 436: ! 437: return(status); ! 438: } ! 439: ! 440: // ! 441: // Create device object for this scanner. ! 442: // ! 443: ! 444: status = IoCreateDevice(DriverObject, ! 445: DEVICE_EXTENSION_SIZE, ! 446: &ntUnicodeString, ! 447: FILE_DEVICE_SCANNER, ! 448: 0, ! 449: FALSE, ! 450: &deviceObject); ! 451: ! 452: if (!NT_SUCCESS(status)) { ! 453: DebugPrint((1,"CreateScannerDeviceObjects: Can not create device %s\n", ! 454: ntNameBuffer)); ! 455: ! 456: RtlFreeUnicodeString(&ntUnicodeString); ! 457: deviceObject = NULL; ! 458: goto CreateScannerDeviceObjectExit; ! 459: } ! 460: ! 461: // ! 462: // Create the DosDevice name. ! 463: // ! 464: ! 465: sprintf(dosNameBuffer, ! 466: "\\DosDevices\\Scanner%d", ! 467: *DeviceCount); ! 468: ! 469: RtlInitString(&dosString, dosNameBuffer); ! 470: ! 471: status = RtlAnsiStringToUnicodeString(&dosUnicodeString, ! 472: &dosString, ! 473: TRUE); ! 474: ! 475: if (!NT_SUCCESS(status)) { ! 476: dosUnicodeString.Buffer = NULL; ! 477: } ! 478: ! 479: if (dosUnicodeString.Buffer != NULL && ntUnicodeString.Buffer != NULL) { ! 480: IoAssignArcName(&dosUnicodeString, &ntUnicodeString); ! 481: } ! 482: ! 483: if (dosUnicodeString.Buffer != NULL) { ! 484: RtlFreeUnicodeString(&dosUnicodeString); ! 485: } ! 486: ! 487: RtlFreeUnicodeString(&ntUnicodeString); ! 488: ! 489: // ! 490: // Indicate that IRPs should include MDLs. ! 491: // ! 492: ! 493: deviceObject->Flags |= DO_DIRECT_IO; ! 494: ! 495: // ! 496: // Set up required stack size in device object. ! 497: // ! 498: ! 499: deviceObject->StackSize = PortDeviceObject->StackSize + 1; ! 500: ! 501: deviceExtension = deviceObject->DeviceExtension; ! 502: ! 503: // ! 504: // Allocate spinlock for split request completion. ! 505: // ! 506: ! 507: KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock); ! 508: ! 509: // ! 510: // This is the physical device. ! 511: // ! 512: ! 513: deviceExtension->PhysicalDevice = deviceObject; ! 514: ! 515: // ! 516: // Copy port device object to device extension. ! 517: // ! 518: ! 519: deviceExtension->PortDeviceObject = PortDeviceObject; ! 520: ! 521: // ! 522: // Save address of port driver capabilities. ! 523: // ! 524: ! 525: deviceExtension->PortCapabilities = PortCapabilities; ! 526: ! 527: // ! 528: // Disable synchronous transfer for scanner requests. ! 529: // ! 530: ! 531: deviceExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER; ! 532: ! 533: // ! 534: // Allocate request sense buffer. ! 535: // ! 536: ! 537: senseData = ExAllocatePool(NonPagedPoolCacheAligned, SENSE_BUFFER_SIZE); ! 538: ! 539: if (senseData == NULL) { ! 540: ! 541: // ! 542: // The buffer cannot be allocated. ! 543: // ! 544: ! 545: status = STATUS_INSUFFICIENT_RESOURCES; ! 546: goto CreateScannerDeviceObjectExit; ! 547: } ! 548: ! 549: // ! 550: // Set the sense data pointer in the device extension. ! 551: // ! 552: ! 553: deviceExtension->SenseData = senseData; ! 554: ! 555: // ! 556: // Scanners are not partitionable so starting offset is 0. ! 557: // ! 558: ! 559: deviceExtension->StartingOffset.LowPart = 0; ! 560: deviceExtension->StartingOffset.HighPart = 0; ! 561: ! 562: // ! 563: // Path/TargetId/LUN describes a device location on the SCSI bus. ! 564: // This information comes from the LunInfo buffer. ! 565: // ! 566: ! 567: deviceExtension->PathId = LunInfo->PathId; ! 568: deviceExtension->TargetId = LunInfo->TargetId; ! 569: deviceExtension->Lun = LunInfo->Lun; ! 570: ! 571: // ! 572: // Set timeout value in seconds. ! 573: // ! 574: ! 575: deviceExtension->TimeOutValue = 60; ! 576: ! 577: // ! 578: // Back pointer to device object. ! 579: // ! 580: ! 581: deviceExtension->DeviceObject = deviceObject; ! 582: ! 583: // ! 584: // Set routine address in device extension to be called ! 585: // when a request completes with error. ! 586: // ! 587: ! 588: deviceExtension->ClassError = ScsiScannerError; ! 589: ! 590: return(STATUS_SUCCESS); ! 591: ! 592: CreateScannerDeviceObjectExit: ! 593: ! 594: // ! 595: // Release the device since an error occured. ! 596: // ! 597: ! 598: ScsiClassClaimDevice(PortDeviceObject, ! 599: LunInfo, ! 600: TRUE, ! 601: NULL); ! 602: ! 603: if (senseData != NULL) { ! 604: ExFreePool(senseData); ! 605: } ! 606: ! 607: if (deviceObject != NULL) { ! 608: IoDeleteDevice(deviceObject); ! 609: } ! 610: ! 611: return status; ! 612: ! 613: } // end CreateScannerDeviceObject() ! 614: ! 615: ! 616: NTSTATUS ! 617: ScsiScannerOpen( ! 618: IN PDEVICE_OBJECT DeviceObject, ! 619: IN PIRP Irp ! 620: ) ! 621: ! 622: /*++ ! 623: ! 624: Routine Description: ! 625: ! 626: This routine is called to establish a connection to the device ! 627: class driver. It does no more than return STATUS_SUCCESS. ! 628: ! 629: Arguments: ! 630: ! 631: DeviceObject - Device object for a device. ! 632: Irp - Open request packet ! 633: ! 634: Return Value: ! 635: ! 636: NT Status - STATUS_SUCCESS ! 637: ! 638: --*/ ! 639: ! 640: { ! 641: // ! 642: // Set status in Irp. ! 643: // ! 644: ! 645: Irp->IoStatus.Status = STATUS_SUCCESS; ! 646: ! 647: // ! 648: // Complete request at raised IRQ. ! 649: // ! 650: ! 651: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 652: return STATUS_SUCCESS; ! 653: ! 654: } // end ScsiScannerOpen() ! 655: ! 656: ! 657: NTSTATUS ! 658: ScsiScannerReadWrite( ! 659: IN PDEVICE_OBJECT DeviceObject, ! 660: IN PIRP Irp ! 661: ) ! 662: ! 663: /*++ ! 664: ! 665: Routine Description: ! 666: ! 667: This is the entry called by the I/O system for scanner IO. ! 668: ! 669: Arguments: ! 670: ! 671: DeviceObject - the system object for the device. ! 672: Irp - IRP involved. ! 673: ! 674: Return Value: ! 675: ! 676: NT Status ! 677: ! 678: --*/ ! 679: ! 680: { ! 681: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 682: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); ! 683: ULONG transferByteCount = currentIrpStack->Parameters.Write.Length; ! 684: LARGE_INTEGER startingOffset = ! 685: currentIrpStack->Parameters.Write.ByteOffset; ! 686: ULONG maximumTransferLength = ! 687: deviceExtension->PortCapabilities->MaximumTransferLength; ! 688: ULONG transferPages; ! 689: ! 690: DebugPrint((3,"ScsiScannerReadWrite: Enter routine\n")); ! 691: ! 692: // ! 693: // Mark IRP with status pending. ! 694: // ! 695: ! 696: IoMarkIrpPending(Irp); ! 697: ! 698: // ! 699: // Check if request length is greater than the maximum number of ! 700: // bytes that the hardware can transfer. ! 701: // ! 702: ! 703: if (currentIrpStack->Parameters.Read.Length > maximumTransferLength) { ! 704: ! 705: DebugPrint((2,"ScsiScannerReadWrite: Request greater than maximum\n")); ! 706: DebugPrint((2,"ScsiScannerReadWrite: Maximum is %lx\n", ! 707: maximumTransferLength)); ! 708: DebugPrint((2,"ScsiScannerReadWrite: Byte count is %lx\n", ! 709: currentIrpStack->Parameters.Write.Length)); ! 710: ! 711: // ! 712: // Request greater than port driver maximum. ! 713: // Break up into smaller routines. ! 714: // ! 715: ! 716: SplitRequest(DeviceObject, Irp, maximumTransferLength); ! 717: ! 718: return STATUS_PENDING; ! 719: } ! 720: ! 721: // ! 722: // Calculate number of pages in this transfer. ! 723: // ! 724: ! 725: transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES( ! 726: MmGetMdlVirtualAddress(Irp->MdlAddress), ! 727: currentIrpStack->Parameters.Write.Length); ! 728: ! 729: // ! 730: // Check if number of pages is greater than adapter's maximum ! 731: // number of physical breaks. ! 732: // ! 733: ! 734: if (transferPages > ! 735: deviceExtension->PortCapabilities->MaximumPhysicalPages) { ! 736: ! 737: DebugPrint((1,"ScsiScannerReadWrite: Request greater than maximum\n")); ! 738: DebugPrint((1,"ScsiScannerReadWrite: Maximum pages is %lx\n", ! 739: deviceExtension->PortCapabilities->MaximumPhysicalPages)); ! 740: DebugPrint((1,"ScsiScannerReadWrite: Number of pages is %lx\n", ! 741: transferPages)); ! 742: ! 743: // ! 744: // Calculate maximum bytes to transfer that gaurantees ! 745: // not exceeding the maximum number of page breaks, ! 746: // assuming that the transfer may not be page alligned. ! 747: // ! 748: ! 749: maximumTransferLength = ! 750: (deviceExtension->PortCapabilities->MaximumPhysicalPages - 1) * PAGE_SIZE; ! 751: ! 752: // ! 753: // Request greater than port driver maximum. ! 754: // Break up into smaller routines. ! 755: // ! 756: ! 757: SplitRequest(DeviceObject, Irp, maximumTransferLength); ! 758: ! 759: return STATUS_PENDING; ! 760: } ! 761: ! 762: // ! 763: // Build SRB and CDB for this IRP. ! 764: // ! 765: ! 766: BuildScannerRequest(DeviceObject, Irp); ! 767: ! 768: // ! 769: // Return the results of the call to the port driver. ! 770: // ! 771: ! 772: return IoCallDriver(deviceExtension->PortDeviceObject, Irp); ! 773: ! 774: } // end ScsiScannerReadWrite() ! 775: ! 776: ! 777: NTSTATUS ! 778: ScsiScannerDeviceControl( ! 779: IN PDEVICE_OBJECT DeviceObject, ! 780: IN PIRP Irp ! 781: ) ! 782: ! 783: /*++ ! 784: ! 785: Routine Description: ! 786: ! 787: This is the NT device control handler for Scanners. ! 788: ! 789: Arguments: ! 790: ! 791: DeviceObject - for this Scanner ! 792: ! 793: Irp - IO Request packet ! 794: ! 795: Return Value: ! 796: ! 797: NTSTATUS ! 798: ! 799: --*/ ! 800: ! 801: { ! 802: PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp); ! 803: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 804: SCSI_REQUEST_BLOCK srb; ! 805: PCDB cdb = (PCDB)srb.Cdb; ! 806: PVOID outputBuffer = Irp->AssociatedIrp.SystemBuffer; ! 807: ULONG bytesTransferred = 0; ! 808: NTSTATUS status; ! 809: ! 810: DebugPrint((3,"ScsiScannerDeviceControl: Enter routine\n")); ! 811: ! 812: // ! 813: // Zero CDB in SRB on stack. ! 814: // ! 815: ! 816: RtlZeroMemory(cdb, MAXIMUM_CDB_SIZE); ! 817: ! 818: switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { ! 819: ! 820: default: ! 821: ! 822: // ! 823: // Pass the request to the common device control routine. ! 824: // ! 825: ! 826: return(ScsiClassDeviceControl(DeviceObject, Irp)); ! 827: ! 828: break; ! 829: ! 830: } // end switch() ! 831: ! 832: // ! 833: // Update IRP with completion status. ! 834: // ! 835: ! 836: Irp->IoStatus.Status = status; ! 837: ! 838: // ! 839: // Complete the request. ! 840: // ! 841: ! 842: IoCompleteRequest(Irp, IO_DISK_INCREMENT); ! 843: DebugPrint((2, "ScsiScannerDeviceControl: Status is %lx\n", status)); ! 844: return status; ! 845: ! 846: } // end ScsiScannerDeviceControl() ! 847: ! 848: VOID ! 849: BuildScannerRequest( ! 850: PDEVICE_OBJECT DeviceObject, ! 851: PIRP Irp ! 852: ) ! 853: ! 854: /*++ ! 855: ! 856: Routine Description: ! 857: ! 858: Build SRB and CDB requests to scsi device. ! 859: ! 860: Arguments: ! 861: ! 862: DeviceObject - Device object representing this scanner device. ! 863: Irp - System IO request packet. ! 864: ! 865: Return Value: ! 866: ! 867: None. ! 868: ! 869: --*/ ! 870: ! 871: { ! 872: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 873: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); ! 874: PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); ! 875: PSCSI_REQUEST_BLOCK srb; ! 876: PCDB cdb; ! 877: ULONG transferLength; ! 878: ! 879: // ! 880: // Allocate an Srb. ! 881: // ! 882: ! 883: if (deviceExtension->SrbZone != NULL && ! 884: (srb = ExInterlockedAllocateFromZone( ! 885: deviceExtension->SrbZone, ! 886: deviceExtension->SrbZoneSpinLock)) != NULL) { ! 887: ! 888: srb->SrbFlags = SRB_FLAGS_ALLOCATED_FROM_ZONE; ! 889: ! 890: } else { ! 891: ! 892: // ! 893: // Allocate Srb from non-paged pool. ! 894: // This call must succeed. ! 895: // ! 896: ! 897: srb = ExAllocatePool(NonPagedPoolMustSucceed, SCSI_REQUEST_BLOCK_SIZE); ! 898: ! 899: srb->SrbFlags = 0; ! 900: } ! 901: ! 902: // ! 903: // Write length to SRB. ! 904: // ! 905: ! 906: srb->Length = SCSI_REQUEST_BLOCK_SIZE; ! 907: ! 908: // ! 909: // Set up IRP Address. ! 910: // ! 911: ! 912: srb->OriginalRequest = Irp; ! 913: ! 914: // ! 915: // Set up target id and logical unit number. ! 916: // ! 917: ! 918: srb->PathId = deviceExtension->PathId; ! 919: srb->TargetId = deviceExtension->TargetId; ! 920: srb->Lun = deviceExtension->Lun; ! 921: ! 922: srb->Function = SRB_FUNCTION_EXECUTE_SCSI; ! 923: ! 924: srb->DataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); ! 925: ! 926: // ! 927: // Save byte count of transfer in SRB Extension. ! 928: // ! 929: ! 930: srb->DataTransferLength = currentIrpStack->Parameters.Write.Length; ! 931: ! 932: // ! 933: // Initialize the queue actions field. ! 934: // ! 935: ! 936: srb->QueueAction = SRB_SIMPLE_TAG_REQUEST; ! 937: ! 938: // ! 939: // Queue sort key is not used. ! 940: // ! 941: ! 942: srb->QueueSortKey = 0; ! 943: ! 944: // ! 945: // Indicate auto request sense by specifying buffer and size. ! 946: // ! 947: ! 948: srb->SenseInfoBuffer = deviceExtension->SenseData; ! 949: ! 950: srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE; ! 951: ! 952: // ! 953: // Set timeout value in seconds. ! 954: // ! 955: ! 956: srb->TimeOutValue = deviceExtension->TimeOutValue; ! 957: ! 958: // ! 959: // Zero statuses. ! 960: // ! 961: ! 962: srb->SrbStatus = srb->ScsiStatus = 0; ! 963: ! 964: srb->NextSrb = 0; ! 965: ! 966: // ! 967: // Calculate number of blocks to transfer. ! 968: // ! 969: ! 970: transferLength = currentIrpStack->Parameters.Write.Length; ! 971: ! 972: // ! 973: // Get pointer to CDB in SRB. ! 974: // ! 975: ! 976: cdb = (PCDB)srb->Cdb; ! 977: ! 978: // ! 979: // Indicate that 6-byte CDB's will be used. ! 980: // ! 981: ! 982: srb->CdbLength = 6; ! 983: ! 984: cdb->PRINT.LogicalUnitNumber = deviceExtension->Lun; ! 985: ! 986: // ! 987: // Zero out reserved field. ! 988: // ! 989: ! 990: cdb->PRINT.Reserved = 0; ! 991: ! 992: // ! 993: // Move little endian values into CDB in big endian format. ! 994: // ! 995: ! 996: cdb->PRINT.TransferLength[2] = ((PFOUR_BYTE)&transferLength)->Byte0; ! 997: cdb->PRINT.TransferLength[1] = ((PFOUR_BYTE)&transferLength)->Byte1; ! 998: cdb->PRINT.TransferLength[0] = ((PFOUR_BYTE)&transferLength)->Byte2; ! 999: ! 1000: cdb->PRINT.Control = 0; ! 1001: ! 1002: // ! 1003: // Set transfer direction flag and Cdb command. ! 1004: // ! 1005: ! 1006: if (currentIrpStack->MajorFunction == IRP_MJ_READ) { ! 1007: ! 1008: srb->SrbFlags |= SRB_FLAGS_DATA_IN; ! 1009: cdb->CDB6READWRITE.OperationCode = SCSIOP_READ6; ! 1010: ! 1011: } else { ! 1012: ! 1013: srb->SrbFlags |= SRB_FLAGS_DATA_OUT; ! 1014: cdb->CDB6READWRITE.OperationCode = SCSIOP_WRITE6; ! 1015: } ! 1016: ! 1017: // ! 1018: // Or in the default flags from the device object. ! 1019: // ! 1020: ! 1021: srb->SrbFlags |= deviceExtension->SrbFlags; ! 1022: ! 1023: // ! 1024: // Set up major SCSI function. ! 1025: // ! 1026: ! 1027: nextIrpStack->MajorFunction = IRP_MJ_SCSI; ! 1028: ! 1029: // ! 1030: // Save SRB address in next stack for port driver. ! 1031: // ! 1032: ! 1033: nextIrpStack->Parameters.Scsi.Srb = srb; ! 1034: ! 1035: // ! 1036: // Save retry count in current IRP stack. ! 1037: // ! 1038: ! 1039: currentIrpStack->Parameters.Others.Argument4 = (PVOID)MAXIMUM_RETRIES; ! 1040: ! 1041: // ! 1042: // Set up IoCompletion routine address. ! 1043: // ! 1044: ! 1045: IoSetCompletionRoutine(Irp, ScsiClassIoComplete, srb, TRUE, TRUE, FALSE); ! 1046: ! 1047: return; ! 1048: ! 1049: } // end BuildScannerRequest() ! 1050: ! 1051: VOID ! 1052: ! 1053: ScsiScannerError( ! 1054: PDEVICE_OBJECT DeviceObject, ! 1055: IN PSCSI_REQUEST_BLOCK Srb, ! 1056: IN OUT NTSTATUS *Status, ! 1057: IN OUT BOOLEAN *Retry ! 1058: ) ! 1059: ! 1060: /*++ ! 1061: ! 1062: Routine Description: ! 1063: ! 1064: Build SRB and CDB requests to scsi device. ! 1065: ! 1066: Arguments: ! 1067: ! 1068: DeviceObject - Device object representing this scanner device. ! 1069: Srb - Scsi request block. ! 1070: ! 1071: Return Value: ! 1072: ! 1073: None. ! 1074: ! 1075: --*/ ! 1076: ! 1077: { ! 1078: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 1079: ! 1080: // ! 1081: // Check if status is underrun. STATUS_DATA_OVERRUN is an indication of ! 1082: // either data underrun or overrun. ! 1083: // ! 1084: ! 1085: if (*Status == STATUS_DATA_OVERRUN) { ! 1086: *Status = STATUS_SUCCESS; ! 1087: } ! 1088: ! 1089: return; ! 1090: ! 1091: } // end ScsiScannerError() ! 1092: ! 1093: ! 1094: VOID ! 1095: SplitRequest( ! 1096: IN PDEVICE_OBJECT DeviceObject, ! 1097: IN PIRP Irp, ! 1098: IN ULONG MaximumBytes ! 1099: ) ! 1100: ! 1101: /*++ ! 1102: ! 1103: Routine Description: ! 1104: ! 1105: Break request into smaller requests. Each new request will be the ! 1106: maximum transfer size that the port driver can handle or if it ! 1107: is the final request, it may be the residual size. ! 1108: ! 1109: The number of IRPs required to process this request is written in the ! 1110: current stack of the original IRP. Then as each new IRP completes ! 1111: the count in the original IRP is decremented. When the count goes to ! 1112: zero, the original IRP is completed. ! 1113: ! 1114: Arguments: ! 1115: ! 1116: DeviceObject - Pointer to the class device object to be addressed. ! 1117: ! 1118: Irp - Pointer to Irp the orginal request. ! 1119: ! 1120: Return Value: ! 1121: ! 1122: None. ! 1123: ! 1124: --*/ ! 1125: ! 1126: { ! 1127: PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; ! 1128: PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp); ! 1129: PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp); ! 1130: ULONG transferByteCount = currentIrpStack->Parameters.Read.Length; ! 1131: LARGE_INTEGER startingOffset = currentIrpStack->Parameters.Read.ByteOffset; ! 1132: PVOID dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress); ! 1133: ULONG dataLength = MaximumBytes; ! 1134: ULONG irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes; ! 1135: PSCSI_REQUEST_BLOCK srb; ! 1136: ULONG i; ! 1137: ! 1138: DebugPrint((1, "SplitRequest: Requires %d IRPs\n", irpCount)); ! 1139: DebugPrint((1, "SplitRequest: Original IRP %lx\n", Irp)); ! 1140: ! 1141: // ! 1142: // If all partial transfers complete successfully then the status and ! 1143: // bytes transferred are already set up. Failing a partial-transfer IRP ! 1144: // will set status to error and bytes transferred to 0 during ! 1145: // IoCompletion. Setting bytes transferred to 0 if an IRP fails allows ! 1146: // asynchronous partial transfers. This is an optimization for the ! 1147: // successful case. ! 1148: // ! 1149: ! 1150: Irp->IoStatus.Status = STATUS_SUCCESS; ! 1151: Irp->IoStatus.Information = transferByteCount; ! 1152: ! 1153: // ! 1154: // Save number of IRPs to complete count on current stack ! 1155: // of original IRP. ! 1156: // ! 1157: ! 1158: nextIrpStack->Parameters.Others.Argument1 = (PVOID) irpCount; ! 1159: ! 1160: for (i = 0; i < irpCount; i++) { ! 1161: ! 1162: PIRP newIrp; ! 1163: PIO_STACK_LOCATION newIrpStack; ! 1164: ! 1165: // ! 1166: // Allocate new IRP. ! 1167: // ! 1168: ! 1169: newIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE); ! 1170: ! 1171: if (newIrp == NULL) { ! 1172: ! 1173: DebugPrint((1,"SplitRequest: Can't allocate Irp\n")); ! 1174: ! 1175: // ! 1176: // If an Irp can't be allocated then the orginal request cannot ! 1177: // be executed. If this is the first request then just fail the ! 1178: // orginal request; otherwise just return. When the pending ! 1179: // requests complete, they will complete the original request. ! 1180: // In either case set the IRP status to failure. ! 1181: // ! 1182: ! 1183: Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; ! 1184: Irp->IoStatus.Information = 0; ! 1185: ! 1186: if (i == 0) { ! 1187: IoCompleteRequest(Irp, IO_NO_INCREMENT); ! 1188: } ! 1189: ! 1190: return; ! 1191: } ! 1192: ! 1193: DebugPrint((2, "SplitRequest: New IRP %lx\n", newIrp)); ! 1194: ! 1195: // ! 1196: // Write MDL address to new IRP. In the port driver the SRB data ! 1197: // buffer field is used as an offset into the MDL, so the same MDL ! 1198: // can be used for each partial transfer. This saves having to build ! 1199: // a new MDL for each partial transfer. ! 1200: // ! 1201: ! 1202: newIrp->MdlAddress = Irp->MdlAddress; ! 1203: ! 1204: // ! 1205: // At this point there is no current stack. IoSetNextIrpStackLocation ! 1206: // will make the first stack location the current stack so that the ! 1207: // SRB address can be written there. ! 1208: // ! 1209: ! 1210: IoSetNextIrpStackLocation(newIrp); ! 1211: newIrpStack = IoGetCurrentIrpStackLocation(newIrp); ! 1212: ! 1213: newIrpStack->MajorFunction = currentIrpStack->MajorFunction; ! 1214: newIrpStack->Parameters.Read.Length = dataLength; ! 1215: newIrpStack->Parameters.Read.ByteOffset = startingOffset; ! 1216: newIrpStack->DeviceObject = DeviceObject; ! 1217: ! 1218: // ! 1219: // Build SRB and CDB. ! 1220: // ! 1221: ! 1222: BuildScannerRequest(DeviceObject, newIrp); ! 1223: ! 1224: // ! 1225: // Adjust SRB for this partial transfer. ! 1226: // ! 1227: ! 1228: newIrpStack = IoGetNextIrpStackLocation(newIrp); ! 1229: ! 1230: srb = newIrpStack->Parameters.Others.Argument1; ! 1231: srb->DataBuffer = dataBuffer; ! 1232: ! 1233: // ! 1234: // Write original IRP address to new IRP. ! 1235: // ! 1236: ! 1237: newIrp->AssociatedIrp.MasterIrp = Irp; ! 1238: ! 1239: // ! 1240: // Set the completion routine to ScsiClassIoCompleteAssociated. ! 1241: // ! 1242: ! 1243: IoSetCompletionRoutine(newIrp, ! 1244: ScsiClassIoCompleteAssociated, ! 1245: srb, ! 1246: TRUE, ! 1247: TRUE, ! 1248: TRUE); ! 1249: ! 1250: // ! 1251: // Call port driver with new request. ! 1252: // ! 1253: ! 1254: IoCallDriver(deviceExtension->PortDeviceObject, newIrp); ! 1255: ! 1256: // ! 1257: // Set up for next request. ! 1258: // ! 1259: ! 1260: dataBuffer = (PCHAR)dataBuffer + MaximumBytes; ! 1261: ! 1262: transferByteCount -= MaximumBytes; ! 1263: ! 1264: if (transferByteCount > MaximumBytes) { ! 1265: ! 1266: dataLength = MaximumBytes; ! 1267: ! 1268: } else { ! 1269: ! 1270: dataLength = transferByteCount; ! 1271: } ! 1272: ! 1273: // ! 1274: // Adjust disk byte offset. ! 1275: // ! 1276: ! 1277: startingOffset = LiAdd(startingOffset, LiFromUlong(MaximumBytes)); ! 1278: } ! 1279: ! 1280: return; ! 1281: ! 1282: } // end SplitRequest() ! 1283:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.