|
|
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.