Annotation of ntddk/src/scsi/scsiscan/scsiscan.c, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.