Annotation of ntddk/src/scsi/scsitape/class/tape.c, revision 1.1

1.1     ! root        1: /*++
        !             2: 
        !             3: Copyright (c) 1991  Microsoft Corporation
        !             4: 
        !             5: Module Name:
        !             6: 
        !             7:     tape.c
        !             8: 
        !             9: Abstract:
        !            10: 
        !            11:     This is the tape class driver.
        !            12: 
        !            13: Authors:
        !            14: 
        !            15:     Mike Glass
        !            16:     Hunter Small
        !            17: 
        !            18: Environment:
        !            19: 
        !            20:     kernel mode only
        !            21: 
        !            22: Revision History:
        !            23: 
        !            24: --*/
        !            25: 
        !            26: #include "ntddk.h"
        !            27: #include "tape.h"
        !            28: 
        !            29: //
        !            30: // The following prototypes are the internal tape class routines.
        !            31: //
        !            32: 
        !            33: NTSTATUS
        !            34: DriverEntry(
        !            35:   IN PDRIVER_OBJECT DriverObject,
        !            36:   IN PUNICODE_STRING RegistryPath
        !            37:   );
        !            38: 
        !            39: VOID
        !            40: UpdateTapeInformationInRegistry(
        !            41:   IN PDEVICE_OBJECT     DeviceObject,
        !            42:   IN PSCSI_INQUIRY_DATA ScsiInquiryData,
        !            43:   IN ULONG              PortNumber,
        !            44:   IN ULONG              TapeNumber
        !            45:   );
        !            46: 
        !            47: NTSTATUS
        !            48: CreateTapeDeviceObject(
        !            49:   IN PDRIVER_OBJECT           DriverObject,
        !            50:   IN PULONG                   DeviceCount,
        !            51:   IN PIO_SCSI_CAPABILITIES    PortCapabilities,
        !            52:   IN PSCSI_INQUIRY_DATA       LunInfo,
        !            53:   IN PDEVICE_OBJECT           PortDeviceObject,
        !            54:   IN ULONG                    PortNumber
        !            55:   );
        !            56: 
        !            57: BOOLEAN
        !            58: FindScsiTapes(
        !            59:   IN PDRIVER_OBJECT DriverObject,
        !            60:   IN PDEVICE_OBJECT PortDeviceObject,
        !            61:   IN ULONG PortNumber
        !            62:   );
        !            63: 
        !            64: VOID
        !            65: SplitTapeRequest(
        !            66:     IN PDEVICE_OBJECT DeviceObject,
        !            67:     IN PIRP Irp,
        !            68:     IN ULONG MaximumBytes
        !            69:     );
        !            70: 
        !            71: VOID
        !            72: ScsiTapeError(
        !            73:     PDEVICE_OBJECT DeviceObject,
        !            74:     PSCSI_REQUEST_BLOCK Srb,
        !            75:     NTSTATUS *Status,
        !            76:     BOOLEAN *Retry
        !            77:     );
        !            78: 
        !            79: NTSTATUS
        !            80: ScsiTapeIoCompleteAssociated(
        !            81:     IN PDEVICE_OBJECT DeviceObject,
        !            82:     IN PIRP Irp,
        !            83:     IN PVOID Context
        !            84:     );
        !            85: 
        !            86: #ifdef ALLOC_PRAGMA
        !            87: #pragma alloc_text(init, DriverEntry)
        !            88: #pragma alloc_text(init, FindScsiTapes)
        !            89: #pragma alloc_text(init, CreateTapeDeviceObject)
        !            90: #pragma alloc_text(init, UpdateTapeInformationInRegistry)
        !            91: #endif
        !            92: 
        !            93: //
        !            94: // Start of code
        !            95: //
        !            96: 
        !            97: 
        !            98: NTSTATUS
        !            99: DriverEntry(
        !           100:   IN PDRIVER_OBJECT DriverObject,
        !           101:   IN PUNICODE_STRING RegistryPath
        !           102:   )
        !           103: 
        !           104: /*++
        !           105: 
        !           106: Routine Description:
        !           107: 
        !           108:     This is the system initialization entry point for installable drivers.
        !           109: 
        !           110: Arguments:
        !           111: 
        !           112:     DriverObject
        !           113: 
        !           114: Return Value:
        !           115: 
        !           116:     NT Status
        !           117: 
        !           118: --*/
        !           119: 
        !           120: {
        !           121:      ULONG          portNumber = 0;
        !           122:      PDEVICE_OBJECT portDeviceObject;
        !           123:      NTSTATUS       status;
        !           124:      STRING         deviceNameString;
        !           125:      UNICODE_STRING unicodeDeviceName;
        !           126:      PFILE_OBJECT   fileObject;
        !           127:      CCHAR          deviceNameBuffer[256];
        !           128:      BOOLEAN        tapeDeviceFound = FALSE;
        !           129: 
        !           130:      DebugPrint((1,"\n\nSCSI Tape Class Driver\n"));
        !           131: 
        !           132:      //
        !           133:      // Update driver object with entry points.
        !           134:      //
        !           135: 
        !           136:      DriverObject->MajorFunction[IRP_MJ_READ]  = ScsiTapeReadWrite;
        !           137:      DriverObject->MajorFunction[IRP_MJ_WRITE] = ScsiTapeReadWrite;
        !           138:      DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiTapeDeviceControl;
        !           139:      DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiTapeCreate;
        !           140: 
        !           141:      //
        !           142:      // Open port driver controller device objects by name.
        !           143:      //
        !           144: 
        !           145:      do {
        !           146: 
        !           147:           sprintf(deviceNameBuffer, "\\Device\\ScsiPort%d", portNumber);
        !           148: 
        !           149:           DebugPrint((2, "ScsiTapeInitialize: Open Port %s\n", deviceNameBuffer));
        !           150: 
        !           151:           RtlInitString(&deviceNameString, deviceNameBuffer);
        !           152: 
        !           153:           status = RtlAnsiStringToUnicodeString(&unicodeDeviceName,
        !           154:                                                 &deviceNameString,
        !           155:                                                 TRUE
        !           156:                                                 );
        !           157: 
        !           158:           ASSERT(NT_SUCCESS(status));
        !           159: 
        !           160: 
        !           161:           status = IoGetDeviceObjectPointer(&unicodeDeviceName,
        !           162:                                             FILE_READ_ATTRIBUTES,
        !           163:                                             &fileObject,
        !           164:                                             &portDeviceObject);
        !           165: 
        !           166:           if (NT_SUCCESS(status)) {
        !           167: 
        !           168:                if (FindScsiTapes(DriverObject, portDeviceObject, portNumber)) {
        !           169:                     tapeDeviceFound = TRUE;
        !           170:                }
        !           171:           }
        !           172: 
        !           173:           //
        !           174:           // Check next SCSI adapter.
        !           175:           //
        !           176: 
        !           177:           portNumber++;
        !           178: 
        !           179:      } while(NT_SUCCESS(status));
        !           180: 
        !           181:      return(tapeDeviceFound ? STATUS_SUCCESS: STATUS_NO_SUCH_DEVICE);
        !           182: 
        !           183: } // end DriverEntry()
        !           184: 
        !           185: 
        !           186: BOOLEAN
        !           187: FindScsiTapes(
        !           188:     IN PDRIVER_OBJECT DriverObject,
        !           189:     IN PDEVICE_OBJECT PortDeviceObject,
        !           190:     IN ULONG PortNumber
        !           191:     )
        !           192: 
        !           193: /*++
        !           194: 
        !           195: Routine Description:
        !           196: 
        !           197:     Call into port driver to get configuration information to find
        !           198:     tape devices.
        !           199: 
        !           200: Arguments:
        !           201: 
        !           202:     DriverObject
        !           203:     DeviceObject - Port driver device object.
        !           204: 
        !           205: Return Value:
        !           206: 
        !           207:     TRUE if tape device(s) found.
        !           208: 
        !           209: --*/
        !           210: 
        !           211: {
        !           212:     PIO_SCSI_CAPABILITIES       portCapabilities;
        !           213:     PULONG                      tapeCount;
        !           214:     PCHAR                       buffer;
        !           215:     PSCSI_INQUIRY_DATA          lunInfo;
        !           216:     PSCSI_ADAPTER_BUS_INFO      adapterInfo;
        !           217:     PINQUIRYDATA                inquiryData;
        !           218:     PCONFIGURATION_INFORMATION  configInfo;
        !           219:     NTSTATUS                    status;
        !           220:     ULONG                       scsiBus;
        !           221:     BOOLEAN                     tapeDeviceFound = FALSE;
        !           222: 
        !           223:     //
        !           224:     // Call port driver to get adapter capabilities.
        !           225:     //
        !           226: 
        !           227:     status = ScsiClassGetCapabilities(PortDeviceObject, &portCapabilities);
        !           228: 
        !           229:     if (!NT_SUCCESS(status)) {
        !           230:          DebugPrint((1, "FindScsiTapes: ScsiClassGetCabilities failed\n"));
        !           231: 
        !           232:     }
        !           233: 
        !           234:     //
        !           235:     // Call port driver to get inquiry information to find disks.
        !           236:     //
        !           237: 
        !           238:     status = ScsiClassGetInquiryData(PortDeviceObject, (PSCSI_ADAPTER_BUS_INFO *) &buffer);
        !           239: 
        !           240:     if (!NT_SUCCESS(status)) {
        !           241:         DebugPrint((1,"FindScsiDevices: ScsiClassGetInquiryData failed\n"));
        !           242:         return FALSE;
        !           243:     }
        !           244: 
        !           245:     configInfo = IoGetConfigurationInformation();
        !           246: 
        !           247:     tapeCount  = &configInfo->TapeCount;
        !           248: 
        !           249:     adapterInfo = (PVOID) buffer;
        !           250: 
        !           251:     //
        !           252:     // For each SCSI bus this adapter supports ...
        !           253:     //
        !           254: 
        !           255:     for (scsiBus=0; scsiBus < (ULONG)adapterInfo->NumberOfBuses; scsiBus++) {
        !           256: 
        !           257:         //
        !           258:         // Get the SCSI bus scan data for this bus.
        !           259:         //
        !           260: 
        !           261:         lunInfo = (PVOID) (buffer + adapterInfo->BusData[scsiBus].InquiryDataOffset);
        !           262: 
        !           263:         //
        !           264:         // Search list for unclaimed disk devices.
        !           265:         //
        !           266: 
        !           267:         while (adapterInfo->BusData[scsiBus].InquiryDataOffset) {
        !           268: 
        !           269:             inquiryData = (PVOID)lunInfo->InquiryData;
        !           270: 
        !           271:             DebugPrint((3,
        !           272:               "FindScsiTapes: Inquiry data at %lx\n",
        !           273:               inquiryData));
        !           274: 
        !           275:             if ((inquiryData->DeviceType == SEQUENTIAL_ACCESS_DEVICE) &&
        !           276:               (!lunInfo->DeviceClaimed)) {
        !           277: 
        !           278:                  if (TapeVerifyInquiry(lunInfo) == TRUE) {
        !           279: 
        !           280:                       status = CreateTapeDeviceObject(DriverObject,
        !           281:                                                       tapeCount,
        !           282:                                                       portCapabilities,
        !           283:                                                       lunInfo,
        !           284:                                                       PortDeviceObject,
        !           285:                                                       PortNumber);
        !           286: 
        !           287:                       if (NT_SUCCESS(status)) {
        !           288: 
        !           289:                            tapeDeviceFound = TRUE;
        !           290: 
        !           291:                            //
        !           292:                            // Increment tape count
        !           293:                            //
        !           294: 
        !           295:                            (*tapeCount)++;
        !           296: 
        !           297:                       }
        !           298:                  }
        !           299:             }
        !           300: 
        !           301:             //
        !           302:             // Get next LunInfo.
        !           303:             //
        !           304: 
        !           305:             if (lunInfo->NextInquiryDataOffset == 0) {
        !           306:                 break;
        !           307:             }
        !           308: 
        !           309:             lunInfo = (PVOID) (buffer + lunInfo->NextInquiryDataOffset);
        !           310: 
        !           311:          }
        !           312:     }
        !           313: 
        !           314:     ExFreePool(buffer);
        !           315:     return tapeDeviceFound;
        !           316: 
        !           317: } // end FindScsiTapes()
        !           318: 
        !           319: 
        !           320: VOID
        !           321: UpdateTapeInformationInRegistry(
        !           322:   IN PDEVICE_OBJECT     DeviceObject,
        !           323:   IN PSCSI_INQUIRY_DATA ScsiInquiryData,
        !           324:   IN ULONG              PortNumber,
        !           325:   IN ULONG              TapeNumber
        !           326:   )
        !           327: 
        !           328: /*++
        !           329: 
        !           330: Routine Description:
        !           331: 
        !           332:     This routine has knowledge about the layout of the device map information
        !           333:     in the registry.  It will update this information to include a value
        !           334:     entry specifying the dos device name that is assumed to get assigned
        !           335:     to this NT device name.  For more information on this assigning of the
        !           336:     dos device name look in the drive support routine in the hal that assigns
        !           337:     all dos names.  Since most version of tape firmware do not work and most
        !           338:     vendor did not bother to follow the specification the entire inquiry
        !           339:     information must also be stored in the registry so than someone can
        !           340:     figure out the firmware version.
        !           341: 
        !           342: Arguments:
        !           343: 
        !           344:     DeviceObject - A pointer to the device object for the tape device.
        !           345: 
        !           346:     ScsiInquiryData - a pointer to the scsi inquiry data structure defined in
        !           347:                       ntddscsi.h
        !           348: 
        !           349: Return Value:
        !           350: 
        !           351:     None
        !           352: 
        !           353: --*/
        !           354: 
        !           355: {
        !           356:     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
        !           357:     NTSTATUS          status;
        !           358:     OBJECT_ATTRIBUTES objectAttributes;
        !           359:     PUCHAR            buffer;
        !           360:     STRING            string;
        !           361:     UNICODE_STRING    unicodeName;
        !           362:     UNICODE_STRING    unicodeData;
        !           363:     HANDLE            targetKey;
        !           364:     PINQUIRYDATA      dataBuffer;
        !           365:     SCSI_REQUEST_BLOCK srb;
        !           366:     ULONG             length;
        !           367:     PCDB              cdb;
        !           368: 
        !           369:     buffer = ExAllocatePool(NonPagedPool, 1024);
        !           370:     dataBuffer = ExAllocatePool(NonPagedPoolCacheAligned, MAXIMUM_TAPE_INQUIRY_DATA);
        !           371:     if (buffer == NULL || dataBuffer == NULL) {
        !           372: 
        !           373:         if (buffer != NULL) {
        !           374:             ExFreePool(buffer);
        !           375:         }
        !           376: 
        !           377:         //
        !           378:         // There is not return value for this.  Since this is done at
        !           379:         // claim device time (currently only system initialization) getting
        !           380:         // the registry information correct will be the least of the worries.
        !           381:         //
        !           382: 
        !           383:         return;
        !           384:     }
        !           385:     sprintf(buffer,
        !           386:             "\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi\\Scsi Port %d\\Scsi Bus %d\\Target Id %d\\Logical Unit Id %d",
        !           387:             PortNumber,
        !           388:             ScsiInquiryData->PathId,
        !           389:             ScsiInquiryData->TargetId,
        !           390:             ScsiInquiryData->Lun);
        !           391: 
        !           392:     RtlInitString(&string, buffer);
        !           393:     status = RtlAnsiStringToUnicodeString(&unicodeName,
        !           394:                                           &string,
        !           395:                                           TRUE);
        !           396:     if (NT_SUCCESS(status)) {
        !           397: 
        !           398:         //
        !           399:         // Open the registry key for the scsi information for this
        !           400:         // scsibus, target, lun.
        !           401:         //
        !           402: 
        !           403:         InitializeObjectAttributes(&objectAttributes,
        !           404:                                    &unicodeName,
        !           405:                                    OBJ_CASE_INSENSITIVE,
        !           406:                                    NULL,
        !           407:                                    NULL);
        !           408:         status = ZwOpenKey(&targetKey,
        !           409:                            KEY_READ | KEY_WRITE,
        !           410:                            &objectAttributes);
        !           411:         RtlFreeUnicodeString(&unicodeName);
        !           412: 
        !           413:         if (NT_SUCCESS(status)) {
        !           414: 
        !           415:             //
        !           416:             // Now construct and attempt to create the registry value
        !           417:             // specifying the device name in the appropriate place in the
        !           418:             // device map.
        !           419:             //
        !           420: 
        !           421:             RtlInitUnicodeString(&unicodeName, L"DeviceName");
        !           422: 
        !           423:             sprintf(buffer, "Tape%d", TapeNumber);
        !           424:             RtlInitString(&string, buffer);
        !           425:             RtlAnsiStringToUnicodeString(&unicodeData,
        !           426:                                          &string,
        !           427:                                          TRUE);
        !           428:             if (NT_SUCCESS(status)) {
        !           429:                 status = ZwSetValueKey(targetKey,
        !           430:                                        &unicodeName,
        !           431:                                        0,
        !           432:                                        REG_SZ,
        !           433:                                        unicodeData.Buffer,
        !           434:                                        unicodeData.Length);
        !           435:                 RtlFreeUnicodeString(&unicodeData);
        !           436:             }
        !           437: 
        !           438:             //
        !           439:             // Now get the full inquiry information for the device.
        !           440:             //
        !           441: 
        !           442:             RtlZeroMemory(&srb, SCSI_REQUEST_BLOCK_SIZE);
        !           443: 
        !           444:             //
        !           445:             // Set timeout value.
        !           446:             //
        !           447: 
        !           448:             srb.TimeOutValue = 2;
        !           449: 
        !           450:             srb.CdbLength = 6;
        !           451: 
        !           452:             cdb = (PCDB)srb.Cdb;
        !           453: 
        !           454:             //
        !           455:             // Set CDB operation code.
        !           456:             //
        !           457: 
        !           458:             cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
        !           459: 
        !           460:             //
        !           461:             // Set CDB LUN.
        !           462:             //
        !           463: 
        !           464:             cdb->CDB6INQUIRY.LogicalUnitNumber = deviceExtension->Lun;
        !           465: 
        !           466:             //
        !           467:             // Set allocation length to inquiry data buffer size.
        !           468:             //
        !           469: 
        !           470:             cdb->CDB6INQUIRY.AllocationLength = MAXIMUM_TAPE_INQUIRY_DATA;
        !           471: 
        !           472:             status = ScsiClassSendSrbSynchronous(DeviceObject,
        !           473:                                                  &srb,
        !           474:                                                  dataBuffer,
        !           475:                                                  MAXIMUM_TAPE_INQUIRY_DATA,
        !           476:                                                  FALSE);
        !           477: 
        !           478:             if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_SUCCESS ||
        !           479:                 SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
        !           480: 
        !           481:                 //
        !           482:                 // Updated the length actually transfered.
        !           483:                 //
        !           484: 
        !           485:                 length = dataBuffer->AdditionalLength +
        !           486:                     FIELD_OFFSET(INQUIRYDATA, Reserved);
        !           487: 
        !           488:                 if (length > srb.DataTransferLength) {
        !           489:                     length = srb.DataTransferLength;
        !           490:                 }
        !           491: 
        !           492:                 RtlInitUnicodeString(&unicodeName, L"InquiryData");
        !           493: 
        !           494:                 status = ZwSetValueKey(targetKey,
        !           495:                                        &unicodeName,
        !           496:                                        0,
        !           497:                                        REG_BINARY,
        !           498:                                        dataBuffer,
        !           499:                                        length);
        !           500: 
        !           501:             }
        !           502: 
        !           503:             ZwClose(targetKey);
        !           504:         }
        !           505:     }
        !           506: 
        !           507:     ExFreePool(buffer);
        !           508:     ExFreePool(dataBuffer);
        !           509: }
        !           510: 
        !           511: 
        !           512: NTSTATUS
        !           513: CreateTapeDeviceObject(
        !           514:   IN PDRIVER_OBJECT           DriverObject,
        !           515:   IN PULONG                   DeviceCount,
        !           516:   IN PIO_SCSI_CAPABILITIES    PortCapabilities,
        !           517:   IN PSCSI_INQUIRY_DATA       LunInfo,
        !           518:   IN PDEVICE_OBJECT           PortDeviceObject,
        !           519:   IN ULONG                    PortNumber
        !           520:   )
        !           521: 
        !           522: /*++
        !           523: 
        !           524: Routine Description:
        !           525: 
        !           526:     This routine creates an object for the device and then searches
        !           527:     the device for partitions and creates an object for each partition.
        !           528: 
        !           529: Arguments:
        !           530: 
        !           531:     DriverObject - Pointer to driver object created by system.
        !           532:     DeviceCount - Pointer to number of previously installed tapes.
        !           533:     PortCapabilities - Pointer to port capabilities structure
        !           534:     LunInfo - Pointer to Logical Unit Information structure.
        !           535:     PortDeviceObject - Pointer to device object of SCSI adapter.
        !           536:     PortNumber - Number of the SCSI port.
        !           537: 
        !           538: Return Value:
        !           539: 
        !           540:     NTSTATUS
        !           541: 
        !           542: --*/
        !           543: 
        !           544: {
        !           545:      CCHAR               deviceNameBuffer[64];
        !           546:      CCHAR               dosNameBuffer[64];
        !           547:      STRING              deviceNameString;
        !           548:      UNICODE_STRING      unicodeString;
        !           549:      NTSTATUS            status;
        !           550:      PDEVICE_OBJECT      deviceObject;
        !           551:      ULONG               requiredStackSize;
        !           552:      PDEVICE_EXTENSION   deviceExtension;
        !           553:      PTAPE_DATA          tapeData;
        !           554:      UCHAR               pathId = LunInfo->PathId;
        !           555:      UCHAR               targetId = LunInfo->TargetId;
        !           556:      UCHAR               lun = LunInfo->Lun;
        !           557:      PVOID               senseData;
        !           558:      STRING              dosString;
        !           559:      UNICODE_STRING      dosUnicodeString;
        !           560: 
        !           561:      DebugPrint((3,"CreateDeviceObject: Enter routine\n"));
        !           562: 
        !           563:      //
        !           564:      // Create device object for this device.
        !           565:      //
        !           566: 
        !           567:      sprintf(deviceNameBuffer,
        !           568:              "\\Device\\Tape%d",
        !           569:              *DeviceCount);
        !           570: 
        !           571:      RtlInitString(&deviceNameString,
        !           572:                    deviceNameBuffer);
        !           573: 
        !           574:      DebugPrint((2,"CreateDeviceObjects: Create device object %s\n",
        !           575:                  deviceNameBuffer));
        !           576: 
        !           577:      status = RtlAnsiStringToUnicodeString(&unicodeString,
        !           578:                                            &deviceNameString,
        !           579:                                            TRUE);
        !           580: 
        !           581:      ASSERT(NT_SUCCESS(status));
        !           582: 
        !           583:      status = IoCreateDevice(DriverObject,
        !           584:                              DEVICE_EXTENSION_SIZE,
        !           585:                              &unicodeString,
        !           586:                              FILE_DEVICE_TAPE,
        !           587:                              FILE_REMOVABLE_MEDIA,
        !           588:                              FALSE,
        !           589:                              &deviceObject);
        !           590: 
        !           591:      if (!NT_SUCCESS(status)) {
        !           592:           DebugPrint((1,"CreateDeviceObjects: Can not create device %s\n",
        !           593:                       deviceNameBuffer));
        !           594: 
        !           595:           return status;
        !           596:      }
        !           597: 
        !           598:      //
        !           599:      // Claim the device.
        !           600:      //
        !           601: 
        !           602:      status = ScsiClassClaimDevice(
        !           603:          PortDeviceObject,
        !           604:          LunInfo,
        !           605:          FALSE,
        !           606:          &PortDeviceObject
        !           607:          );
        !           608: 
        !           609:      if (!NT_SUCCESS(status)) {
        !           610:          IoDeleteDevice(deviceObject);
        !           611:          return(status);
        !           612:      }
        !           613: 
        !           614:      //
        !           615:      // Create the dos port driver name.
        !           616:      //
        !           617: 
        !           618:      sprintf(dosNameBuffer,
        !           619:              "\\DosDevices\\TAPE%d",
        !           620:              *DeviceCount);
        !           621: 
        !           622:      RtlInitString(&dosString, dosNameBuffer);
        !           623: 
        !           624:      status = RtlAnsiStringToUnicodeString(&dosUnicodeString,
        !           625:                                            &dosString,
        !           626:                                            TRUE);
        !           627: 
        !           628:      if(!NT_SUCCESS(status)) {
        !           629:          dosUnicodeString.Buffer = NULL;
        !           630:      }
        !           631: 
        !           632:      if (dosUnicodeString.Buffer != NULL && unicodeString.Buffer != NULL) {
        !           633:          IoAssignArcName(&dosUnicodeString, &unicodeString);
        !           634:      }
        !           635: 
        !           636:      if (dosUnicodeString.Buffer != NULL) {
        !           637:          RtlFreeUnicodeString(&dosUnicodeString);
        !           638:      }
        !           639: 
        !           640:      if (unicodeString.Buffer != NULL ) {
        !           641:          RtlFreeUnicodeString(&unicodeString);
        !           642:      }
        !           643: 
        !           644:      //
        !           645:      // Indicate that IRPs should include MDLs.
        !           646:      //
        !           647: 
        !           648:      deviceObject->Flags |= DO_DIRECT_IO;
        !           649: 
        !           650:      //
        !           651:      // Set up required stack size in device object.
        !           652:      //
        !           653: 
        !           654:      deviceExtension = deviceObject->DeviceExtension;
        !           655: 
        !           656:      requiredStackSize = PortDeviceObject->StackSize + 1;
        !           657: 
        !           658:      deviceExtension->PortDeviceObject = PortDeviceObject;
        !           659: 
        !           660:      //
        !           661:      // Allocate spinlock for split request completion.
        !           662:      //
        !           663: 
        !           664:      KeInitializeSpinLock(&deviceExtension->SplitRequestSpinLock);
        !           665: 
        !           666:      deviceObject->StackSize = (CCHAR)requiredStackSize;
        !           667: 
        !           668:      //
        !           669:      // Save address of port driver capabilities.
        !           670:      //
        !           671: 
        !           672:      deviceExtension->PortCapabilities = PortCapabilities;
        !           673: 
        !           674:      //
        !           675:      // Save Current Partition number and inquiry data.
        !           676:      //
        !           677: 
        !           678:      tapeData = (PTAPE_DATA )(deviceExtension + 1 );
        !           679: 
        !           680:      tapeData->CurrentPartition = 0;
        !           681: 
        !           682:      tapeData->InquiryData = LunInfo;
        !           683: 
        !           684:      //
        !           685:      // Disable synchronous transfer for tape requests.
        !           686:      //
        !           687: 
        !           688:      deviceExtension->SrbFlags = SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
        !           689: 
        !           690:      //
        !           691:      // Allocate request sense buffer.
        !           692:      //
        !           693: 
        !           694:      senseData = ExAllocatePool(NonPagedPoolCacheAligned,
        !           695:                                 SENSE_BUFFER_SIZE);
        !           696: 
        !           697:      if (senseData == NULL) {
        !           698: 
        !           699:           //
        !           700:           // The buffer could not be allocated.
        !           701:           //
        !           702: 
        !           703:           IoDeleteDevice(deviceObject);
        !           704: 
        !           705:           return(STATUS_INSUFFICIENT_RESOURCES);
        !           706:      }
        !           707: 
        !           708:      //
        !           709:      // Set the sense data pointer in the device extension.
        !           710:      //
        !           711: 
        !           712:      deviceExtension->SenseData = senseData;
        !           713: 
        !           714:      //
        !           715:      // TargetId/LUN describes a device location on the SCSI bus.
        !           716:      // This information comes from the inquiry buffer.
        !           717:      //
        !           718: 
        !           719:      deviceExtension->PortNumber = (UCHAR) PortNumber;
        !           720:      deviceExtension->PathId = pathId;
        !           721:      deviceExtension->TargetId = targetId;
        !           722:      deviceExtension->Lun = lun;
        !           723: 
        !           724:      //
        !           725:      // Set timeout value in seconds.
        !           726:      //
        !           727: 
        !           728:      deviceExtension->TimeOutValue = 180;
        !           729: 
        !           730:      //
        !           731:      // Back pointer to device object.
        !           732:      //
        !           733: 
        !           734:      deviceExtension->DeviceObject = deviceObject;
        !           735: 
        !           736:      //
        !           737:      // Allocate buffer for drive geometry.
        !           738:      //
        !           739: 
        !           740:      deviceExtension->DiskGeometry =
        !           741:          ExAllocatePool(NonPagedPool, sizeof(DISK_GEOMETRY));
        !           742: 
        !           743:      if (!deviceExtension->DiskGeometry) {
        !           744: 
        !           745:          ExFreePool(senseData);
        !           746: 
        !           747:          //
        !           748:          // Release device.
        !           749:          //
        !           750: 
        !           751:          ScsiClassClaimDevice(PortDeviceObject,
        !           752:                               LunInfo,
        !           753:                               TRUE,
        !           754:                               &PortDeviceObject);
        !           755: 
        !           756: 
        !           757:          IoDeleteDevice(deviceObject);
        !           758:          return(STATUS_INSUFFICIENT_RESOURCES);
        !           759:      }
        !           760: 
        !           761:      //
        !           762:      // Initialize fixed block size of 512 bytes.
        !           763:      //
        !           764: 
        !           765:      deviceExtension->DiskGeometry->BytesPerSector = 512;
        !           766:      deviceExtension->SectorShift = 9;
        !           767: 
        !           768:      //
        !           769:      // Set tape error handler.
        !           770:      //
        !           771: 
        !           772:      deviceExtension->ClassError = ScsiTapeError;
        !           773: 
        !           774:      //
        !           775:      // Add tape device number to registry
        !           776:      //
        !           777: 
        !           778:      UpdateTapeInformationInRegistry(deviceObject,
        !           779:                                      LunInfo,
        !           780:                                      PortNumber,
        !           781:                                      *DeviceCount);
        !           782: 
        !           783:      return STATUS_SUCCESS;
        !           784: 
        !           785: } // end CreateTapeDeviceObject()
        !           786: 
        !           787: 
        !           788: NTSTATUS
        !           789: ScsiTapeReadWrite(
        !           790:     IN PDEVICE_OBJECT DeviceObject,
        !           791:     IN PIRP Irp
        !           792:     )
        !           793: 
        !           794: /*++
        !           795: 
        !           796: Routine Description:
        !           797: 
        !           798:     This is the tape class driver IO handler routine. It is the system entry
        !           799:     point for read and write requests. The number of bytes in the request are
        !           800:     checked against the maximum byte counts that the adapter supports and
        !           801:     requests are broken up into smaller sizes if necessary. Then the
        !           802:     device-specific handler is called.
        !           803: 
        !           804: Arguments:
        !           805: 
        !           806:     DeviceObject
        !           807:     Irp - IO request
        !           808: 
        !           809: Return Value:
        !           810: 
        !           811:     NT Status
        !           812: 
        !           813: --*/
        !           814: 
        !           815: {
        !           816:     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
        !           817:     PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
        !           818:     ULONG transferPages;
        !           819:     ULONG               transferByteCount =
        !           820:         currentIrpStack->Parameters.Read.Length;
        !           821:     LARGE_INTEGER       startingOffset =
        !           822:         currentIrpStack->Parameters.Read.ByteOffset;
        !           823:     ULONG               maximumTransferLength =
        !           824:         deviceExtension->PortCapabilities->MaximumTransferLength;
        !           825:     NTSTATUS            status;
        !           826: 
        !           827:     DebugPrint((3,"ScsiTapeRead: Enter routine\n"));
        !           828: 
        !           829:     if (DeviceObject->Flags & DO_VERIFY_VOLUME &&
        !           830:         !(currentIrpStack->Flags & SL_OVERRIDE_VERIFY_VOLUME)) {
        !           831: 
        !           832:         //
        !           833:         // if DO_VERIFY_VOLUME bit is set
        !           834:         // in device object flags, fail request.
        !           835:         //
        !           836: 
        !           837:         DebugPrint((3,"ScsiTapeRead: Volume verfication needed\n"));
        !           838: 
        !           839:         Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
        !           840:         Irp->IoStatus.Information = 0;
        !           841: 
        !           842:         IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
        !           843: 
        !           844:         IoCompleteRequest(Irp, 0);
        !           845: 
        !           846:         return STATUS_VERIFY_REQUIRED;
        !           847:     }
        !           848: 
        !           849:     //
        !           850:     // Calculate number of pages in this transfer.
        !           851:     //
        !           852: 
        !           853:     transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
        !           854:         MmGetMdlVirtualAddress(Irp->MdlAddress),
        !           855:         currentIrpStack->Parameters.Read.Length);
        !           856: 
        !           857:     //
        !           858:     // Check if request length is greater than the maximum number of
        !           859:     // bytes that the hardware can transfer.
        !           860:     //
        !           861: 
        !           862:     if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
        !           863:         transferPages > deviceExtension->PortCapabilities->MaximumPhysicalPages) {
        !           864: 
        !           865:          DebugPrint((2,"ScsiTapeRead: Request greater than maximum\n"));
        !           866:          DebugPrint((2,"ScsiTapeRead: Maximum is %lx\n",
        !           867:                      maximumTransferLength));
        !           868:          DebugPrint((2,"ScsiTapeRead: Byte count is %lx\n",
        !           869:                      currentIrpStack->Parameters.Read.Length));
        !           870: 
        !           871:          transferPages =
        !           872:             deviceExtension->PortCapabilities->MaximumPhysicalPages - 1;
        !           873: 
        !           874:          if (maximumTransferLength > transferPages << PAGE_SHIFT ) {
        !           875:              maximumTransferLength = transferPages << PAGE_SHIFT;
        !           876:          }
        !           877: 
        !           878:         //
        !           879:         // Check that maximum transfer size is not zero.
        !           880:         //
        !           881: 
        !           882:         if (maximumTransferLength == 0) {
        !           883:             maximumTransferLength = PAGE_SIZE;
        !           884:         }
        !           885: 
        !           886:         //
        !           887:         // Mark IRP with status pending.
        !           888:         //
        !           889: 
        !           890:         IoMarkIrpPending(Irp);
        !           891: 
        !           892:         //
        !           893:         // Request greater than port driver maximum.
        !           894:         // Break up into smaller routines.
        !           895:         //
        !           896: 
        !           897:         SplitTapeRequest(DeviceObject, Irp, maximumTransferLength);
        !           898: 
        !           899: 
        !           900:         return STATUS_PENDING;
        !           901:     }
        !           902: 
        !           903:     //
        !           904:     // Build SRB and CDB for this IRP.
        !           905:     //
        !           906: 
        !           907:     status = TapeReadWrite(DeviceObject, Irp);
        !           908: 
        !           909:     if (status == STATUS_PENDING) {
        !           910: 
        !           911:         //
        !           912:         // Return the results of the call to the port driver.
        !           913:         //
        !           914: 
        !           915:         return IoCallDriver(deviceExtension->PortDeviceObject, Irp);
        !           916: 
        !           917:     } else {
        !           918: 
        !           919:         //
        !           920:         // Complete request.
        !           921:         //
        !           922: 
        !           923:         IoCompleteRequest(Irp, 0);
        !           924: 
        !           925:         return status;
        !           926:     }
        !           927: 
        !           928: } // end ScsiTapeReadWrite()
        !           929: 
        !           930: 
        !           931: NTSTATUS
        !           932: ScsiTapeDeviceControl(
        !           933:   IN PDEVICE_OBJECT DeviceObject,
        !           934:   IN PIRP Irp
        !           935:   )
        !           936: 
        !           937: /*++
        !           938: 
        !           939: Routine Description:
        !           940: 
        !           941:     This routine is the dispatcher for device control requests. It
        !           942:     looks at the IOCTL code and calls the appropriate tape device
        !           943:     routine.
        !           944: 
        !           945: Arguments:
        !           946: 
        !           947:     DeviceObject
        !           948:     Irp - Request packet
        !           949: 
        !           950: Return Value:
        !           951: 
        !           952: --*/
        !           953: 
        !           954: {
        !           955:     PIO_STACK_LOCATION  irpStack = IoGetCurrentIrpStackLocation(Irp);
        !           956:     PDEVICE_EXTENSION   deviceExtension = DeviceObject->DeviceExtension;
        !           957:     NTSTATUS            status;
        !           958:     BOOLEAN             retried = FALSE;
        !           959: 
        !           960:     DebugPrint((3,"ScsiTapeDeviceControl: Enter routine\n"));
        !           961: 
        !           962:     switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
        !           963: 
        !           964:     case IOCTL_TAPE_GET_DRIVE_PARAMS:
        !           965: 
        !           966:          //
        !           967:          // Validate buffer length.
        !           968:          //
        !           969: 
        !           970:          if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
        !           971:              sizeof(TAPE_GET_DRIVE_PARAMETERS)) {
        !           972: 
        !           973:              status = STATUS_INFO_LENGTH_MISMATCH;
        !           974:              break;
        !           975:          }
        !           976: 
        !           977:         status = TapeGetDriveParameters(DeviceObject, Irp);
        !           978:         break;
        !           979: 
        !           980:     case IOCTL_TAPE_SET_DRIVE_PARAMS:
        !           981: 
        !           982:          //
        !           983:          // Validate buffer length.
        !           984:          //
        !           985: 
        !           986:          if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
        !           987:              sizeof(TAPE_SET_DRIVE_PARAMETERS)) {
        !           988: 
        !           989:              status = STATUS_INFO_LENGTH_MISMATCH;
        !           990:              break;
        !           991:          }
        !           992: 
        !           993:          status = TapeSetDriveParameters(DeviceObject, Irp);
        !           994:          break;
        !           995: 
        !           996:     case IOCTL_TAPE_GET_MEDIA_PARAMS:
        !           997: 
        !           998:          //
        !           999:          // Validate buffer length.
        !          1000:          //
        !          1001: 
        !          1002:          if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
        !          1003:              sizeof(TAPE_GET_MEDIA_PARAMETERS)) {
        !          1004: 
        !          1005:              status = STATUS_INFO_LENGTH_MISMATCH;
        !          1006:              break;
        !          1007:          }
        !          1008: 
        !          1009:          status = TapeGetMediaParameters(DeviceObject, Irp);
        !          1010:          break;
        !          1011: 
        !          1012:     case IOCTL_TAPE_SET_MEDIA_PARAMS:
        !          1013:     {
        !          1014:         PTAPE_SET_MEDIA_PARAMETERS tapeSetMediaParams =
        !          1015:             Irp->AssociatedIrp.SystemBuffer;
        !          1016:         ULONG sectorShift;
        !          1017: 
        !          1018:          //
        !          1019:          // Validate buffer length.
        !          1020:          //
        !          1021: 
        !          1022:          if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
        !          1023:              sizeof(TAPE_SET_MEDIA_PARAMETERS)) {
        !          1024: 
        !          1025:              status = STATUS_INFO_LENGTH_MISMATCH;
        !          1026:              break;
        !          1027:          }
        !          1028: 
        !          1029:         //
        !          1030:         // Make sure the block size is a power of 2.
        !          1031:         //
        !          1032: 
        !          1033:         WHICH_BIT(tapeSetMediaParams->BlockSize, sectorShift);
        !          1034: 
        !          1035:         if (tapeSetMediaParams->BlockSize != (ULONG)(1 << sectorShift)) {
        !          1036: 
        !          1037:             status = STATUS_INVALID_PARAMETER;
        !          1038:             break;
        !          1039:         }
        !          1040: 
        !          1041:         status = TapeSetMediaParameters(DeviceObject, Irp);
        !          1042: 
        !          1043:         if (NT_SUCCESS(status)) {
        !          1044: 
        !          1045:             //
        !          1046:             // Set the block size in the device object.
        !          1047:             //
        !          1048: 
        !          1049:             deviceExtension->DiskGeometry->BytesPerSector =
        !          1050:                 tapeSetMediaParams->BlockSize;
        !          1051:             deviceExtension->SectorShift = (UCHAR)sectorShift;
        !          1052: 
        !          1053:         }
        !          1054: 
        !          1055:          break;
        !          1056: 
        !          1057:     }
        !          1058: 
        !          1059:     case IOCTL_TAPE_CREATE_PARTITION:
        !          1060: 
        !          1061:          //
        !          1062:          // Validate buffer length.
        !          1063:          //
        !          1064: 
        !          1065:          if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
        !          1066:              sizeof(TAPE_CREATE_PARTITION)) {
        !          1067: 
        !          1068:              status = STATUS_INFO_LENGTH_MISMATCH;
        !          1069:              break;
        !          1070:          }
        !          1071: 
        !          1072:          status = TapeCreatePartition (DeviceObject, Irp);
        !          1073:          break;
        !          1074: 
        !          1075:     case IOCTL_TAPE_ERASE:
        !          1076: 
        !          1077:          //
        !          1078:          // Validate buffer length.
        !          1079:          //
        !          1080: 
        !          1081:          if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
        !          1082:              sizeof(TAPE_ERASE)) {
        !          1083: 
        !          1084:              status = STATUS_INFO_LENGTH_MISMATCH;
        !          1085:              break;
        !          1086:          }
        !          1087: 
        !          1088:          status = TapeErase(DeviceObject, Irp);
        !          1089:          break;
        !          1090: 
        !          1091:     case IOCTL_TAPE_PREPARE:
        !          1092: 
        !          1093:          //
        !          1094:          // Validate buffer length.
        !          1095:          //
        !          1096: 
        !          1097:          if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
        !          1098:              sizeof(TAPE_PREPARE)) {
        !          1099: 
        !          1100:              status = STATUS_INFO_LENGTH_MISMATCH;
        !          1101:              break;
        !          1102:          }
        !          1103: 
        !          1104:          status = TapePrepare(DeviceObject, Irp);
        !          1105:          break;
        !          1106: 
        !          1107:     case IOCTL_TAPE_WRITE_MARKS:
        !          1108: 
        !          1109:          //
        !          1110:          // Validate buffer length.
        !          1111:          //
        !          1112: 
        !          1113:          if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
        !          1114:              sizeof(TAPE_WRITE_MARKS)) {
        !          1115: 
        !          1116:              status = STATUS_INFO_LENGTH_MISMATCH;
        !          1117:              break;
        !          1118:          }
        !          1119: 
        !          1120:          status = TapeWriteMarks(DeviceObject, Irp);
        !          1121:          break;
        !          1122: 
        !          1123:     case IOCTL_TAPE_GET_POSITION:
        !          1124: 
        !          1125:          //
        !          1126:          // Validate buffer length.
        !          1127:          //
        !          1128: 
        !          1129:          if (irpStack->Parameters.DeviceIoControl.OutputBufferLength <
        !          1130:              sizeof(TAPE_GET_POSITION)) {
        !          1131: 
        !          1132:              status = STATUS_INFO_LENGTH_MISMATCH;
        !          1133:              break;
        !          1134:          }
        !          1135: 
        !          1136:          status = TapeGetPosition(DeviceObject, Irp);
        !          1137:          break;
        !          1138: 
        !          1139:     case IOCTL_TAPE_SET_POSITION:
        !          1140: 
        !          1141:          //
        !          1142:          // Validate buffer length.
        !          1143:          //
        !          1144: 
        !          1145:          if (irpStack->Parameters.DeviceIoControl.InputBufferLength <
        !          1146:              sizeof(TAPE_SET_POSITION)) {
        !          1147: 
        !          1148:              status = STATUS_INFO_LENGTH_MISMATCH;
        !          1149:              break;
        !          1150:          }
        !          1151: 
        !          1152:          status = TapeSetPosition(DeviceObject, Irp);
        !          1153:          break;
        !          1154: 
        !          1155:     case IOCTL_TAPE_GET_STATUS:
        !          1156: 
        !          1157:           status = TapeGetStatus (DeviceObject, Irp);
        !          1158:           break;
        !          1159: 
        !          1160:     default:
        !          1161: 
        !          1162:             //
        !          1163:             // Pass the request to the common device control routine.
        !          1164:             //
        !          1165: 
        !          1166:             return(ScsiClassDeviceControl(DeviceObject, Irp));
        !          1167: 
        !          1168:     } // end switch()
        !          1169: 
        !          1170:     ASSERT(status != STATUS_VERIFY_REQUIRED);
        !          1171: 
        !          1172:     //
        !          1173:     // Complete the request.
        !          1174:     //
        !          1175: 
        !          1176:     Irp->IoStatus.Status = status;
        !          1177:     IoCompleteRequest(Irp, 2);
        !          1178: 
        !          1179:     return status;
        !          1180: 
        !          1181: } // end ScsiScsiTapeDeviceControl()
        !          1182: 
        !          1183: 
        !          1184: NTSTATUS
        !          1185: ScsiTapeCreate (
        !          1186:   IN PDEVICE_OBJECT DeviceObject,
        !          1187:   IN PIRP Irp
        !          1188:   )
        !          1189: 
        !          1190: /*++
        !          1191: 
        !          1192: Routine Description:
        !          1193: 
        !          1194:     This routine handles CREATE/OPEN requests and does
        !          1195:     nothing more than return successful status.
        !          1196: 
        !          1197: Arguments:
        !          1198: 
        !          1199:     DeviceObject
        !          1200:     Irp
        !          1201: 
        !          1202: Return Value:
        !          1203: 
        !          1204:     NT Status
        !          1205: 
        !          1206: --*/
        !          1207: 
        !          1208: {
        !          1209:      UNREFERENCED_PARAMETER(DeviceObject);
        !          1210: 
        !          1211:      Irp->IoStatus.Status = STATUS_SUCCESS;
        !          1212: 
        !          1213:      IoCompleteRequest(Irp, 0);
        !          1214: 
        !          1215:      return STATUS_SUCCESS;
        !          1216: 
        !          1217: } // end ScsiTapeCreate()
        !          1218: 
        !          1219: 
        !          1220: VOID
        !          1221: SplitTapeRequest(
        !          1222:     IN PDEVICE_OBJECT DeviceObject,
        !          1223:     IN PIRP Irp,
        !          1224:     IN ULONG MaximumBytes
        !          1225:     )
        !          1226: 
        !          1227: /*++
        !          1228: 
        !          1229: Routine Description:
        !          1230: 
        !          1231:     Break request into smaller requests.
        !          1232:     Each new request will be the maximum transfer
        !          1233:     size that the port driver can handle or if it
        !          1234:     is the final request, it may be the residual
        !          1235:     size.
        !          1236: 
        !          1237:     The number of IRPs required to process this
        !          1238:     request is written in the current stack of
        !          1239:     the original IRP. Then as each new IRP completes
        !          1240:     the count in the original IRP is decremented.
        !          1241:     When the count goes to zero, the original IRP
        !          1242:     is completed.
        !          1243: 
        !          1244: Arguments:
        !          1245: 
        !          1246:     DeviceObject - Pointer to the device object
        !          1247:     Irp - Pointer to Irp
        !          1248: 
        !          1249: Return Value:
        !          1250: 
        !          1251:     None.
        !          1252: 
        !          1253: --*/
        !          1254: 
        !          1255: {
        !          1256:     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
        !          1257:     PIO_STACK_LOCATION currentIrpStack = IoGetCurrentIrpStackLocation(Irp);
        !          1258:     PIO_STACK_LOCATION nextIrpStack = IoGetNextIrpStackLocation(Irp);
        !          1259:     ULONG irpCount;
        !          1260:     ULONG transferByteCount =
        !          1261:         currentIrpStack->Parameters.Read.Length;
        !          1262:     PSCSI_REQUEST_BLOCK srb;
        !          1263:     LARGE_INTEGER startingOffset =
        !          1264:         currentIrpStack->Parameters.Read.ByteOffset;
        !          1265:     ULONG dataLength = MaximumBytes;
        !          1266:     PVOID dataBuffer = MmGetMdlVirtualAddress(Irp->MdlAddress);
        !          1267:     INTERLOCKED_RESULT remainingIrps;
        !          1268:     BOOLEAN completeOriginalIrp = FALSE;
        !          1269:     NTSTATUS status;
        !          1270:     ULONG i;
        !          1271: 
        !          1272:     //
        !          1273:     // Caluculate number of requests to break this IRP into.
        !          1274:     //
        !          1275: 
        !          1276:     irpCount = (transferByteCount + MaximumBytes - 1) / MaximumBytes;
        !          1277: 
        !          1278:     DebugPrint((2, "SplitTapeRequest: Requires %d IRPs\n", irpCount));
        !          1279: 
        !          1280:     DebugPrint((2, "SplitTapeRequest: Original IRP %lx\n", Irp));
        !          1281: 
        !          1282:     //
        !          1283:     // If all partial transfers complete successfully then
        !          1284:     // the status is already set up.
        !          1285:     // Failing partial transfer IRP will set status to
        !          1286:     // error and bytes transferred to 0 during IoCompletion.
        !          1287:     // Setting bytes transferred to 0 if an IRP
        !          1288:     // fails allows asynchronous partial transfers. This is an
        !          1289:     // optimization for the successful case.  As the irps complete
        !          1290:     // with partital or full transfers they will update the bytes
        !          1291:     // transfered.  This is handle as a special case since a read or
        !          1292:     // write can succeed but on part of the data is transfered.
        !          1293:     //
        !          1294: 
        !          1295:     Irp->IoStatus.Status = STATUS_SUCCESS;
        !          1296: 
        !          1297:     //
        !          1298:     // Save number of IRPs to complete count on current stack
        !          1299:     // of original IRP.
        !          1300:     //
        !          1301: 
        !          1302:     nextIrpStack->Parameters.Others.Argument1 = (PVOID)irpCount;
        !          1303: 
        !          1304:     for (i = 0; i < irpCount; i++) {
        !          1305: 
        !          1306:         PIRP newIrp;
        !          1307:         PIO_STACK_LOCATION newIrpStack;
        !          1308: 
        !          1309:         //
        !          1310:         // Allocate new IRP.
        !          1311:         //
        !          1312: 
        !          1313:         newIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
        !          1314: 
        !          1315:         if (newIrp == NULL) {
        !          1316: 
        !          1317:             DebugPrint((1,"SplitTapeRequest: Can't allocate Irp\n"));
        !          1318: 
        !          1319:             //
        !          1320:             // Decrement count of outstanding partial requests.
        !          1321:             //
        !          1322: 
        !          1323:             remainingIrps = ExInterlockedDecrementLong(
        !          1324:                 (PLONG)&nextIrpStack->Parameters.Others.Argument1,
        !          1325:                 &deviceExtension->SplitRequestSpinLock);
        !          1326: 
        !          1327:             //
        !          1328:             // Check if any outstanding IRPs.
        !          1329:             //
        !          1330: 
        !          1331:             if (remainingIrps == ResultZero) {
        !          1332:                 completeOriginalIrp = TRUE;
        !          1333:             }
        !          1334: 
        !          1335:             //
        !          1336:             // Update original IRP with failing status.
        !          1337:             //
        !          1338: 
        !          1339:             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
        !          1340:             Irp->IoStatus.Information = 0;
        !          1341: 
        !          1342:             //
        !          1343:             // Keep going with this request as outstanding partials
        !          1344:             // may be in progress.
        !          1345:             //
        !          1346: 
        !          1347:             goto KeepGoing;
        !          1348:         }
        !          1349: 
        !          1350:         DebugPrint((2, "SplitTapeRequest: New IRP %lx\n", newIrp));
        !          1351: 
        !          1352:         //
        !          1353:         // Write MDL address to new IRP.
        !          1354:         // In the port driver the SRB data length
        !          1355:         // field is used as an offset into the MDL,
        !          1356:         // so the same MDL can be used for each partial
        !          1357:         // transfer. This saves having to build a new
        !          1358:         // MDL for each partial transfer.
        !          1359:         //
        !          1360: 
        !          1361:         newIrp->MdlAddress = Irp->MdlAddress;
        !          1362: 
        !          1363:         //
        !          1364:         // At this point there is no current stack.
        !          1365:         // IoSetNextIrpStackLocation will make the
        !          1366:         // first stack location the current stack
        !          1367:         // so that the SRB address can be written
        !          1368:         // there.
        !          1369:         //
        !          1370: 
        !          1371:         IoSetNextIrpStackLocation(newIrp);
        !          1372: 
        !          1373:         newIrpStack = IoGetCurrentIrpStackLocation(newIrp);
        !          1374: 
        !          1375:         newIrpStack->MajorFunction = currentIrpStack->MajorFunction;
        !          1376: 
        !          1377:         newIrpStack->Parameters.Read.Length = dataLength;
        !          1378:         newIrpStack->Parameters.Read.ByteOffset = startingOffset;
        !          1379: 
        !          1380:         newIrpStack->DeviceObject = DeviceObject;
        !          1381: 
        !          1382:         //
        !          1383:         // Build SRB and CDB.
        !          1384:         //
        !          1385: 
        !          1386:         status = TapeReadWrite(DeviceObject, newIrp);
        !          1387: 
        !          1388:         if (!NT_SUCCESS(status)) {
        !          1389: 
        !          1390:             DebugPrint((1,"SplitTapeRequest: TapeReadWrite failed\n"));
        !          1391: 
        !          1392:             //
        !          1393:             // Decrement count of outstanding partial requests.
        !          1394:             //
        !          1395: 
        !          1396:             remainingIrps =ExInterlockedDecrementLong(
        !          1397:                 (PLONG)&nextIrpStack->Parameters.Others.Argument1,
        !          1398:                 &deviceExtension->SplitRequestSpinLock);
        !          1399: 
        !          1400:             //
        !          1401:             // Check if any outstanding IRPs.
        !          1402:             //
        !          1403: 
        !          1404:             if (remainingIrps == ResultZero) {
        !          1405:                 completeOriginalIrp = TRUE;
        !          1406:             }
        !          1407: 
        !          1408:             //
        !          1409:             // Update original IRP with failing status.
        !          1410:             //
        !          1411: 
        !          1412:             Irp->IoStatus.Status = status;
        !          1413:             Irp->IoStatus.Information = 0;
        !          1414: 
        !          1415:             //
        !          1416:             // Deallocate this partial IRP.
        !          1417:             //
        !          1418: 
        !          1419:             IoFreeIrp(newIrp);
        !          1420: 
        !          1421:             //
        !          1422:             // Keep going with this request as outstanding partials
        !          1423:             // may be in progress.
        !          1424:             //
        !          1425: 
        !          1426:             goto KeepGoing;
        !          1427:         }
        !          1428: 
        !          1429:         //
        !          1430:         // Adjust SRB for this partial transfer.
        !          1431:         //
        !          1432: 
        !          1433:         newIrpStack = IoGetNextIrpStackLocation(newIrp);
        !          1434: 
        !          1435:         srb = newIrpStack->Parameters.Others.Argument1;
        !          1436: 
        !          1437:         srb->DataBuffer = dataBuffer;
        !          1438: 
        !          1439:         //
        !          1440:         // Write original IRP address to new IRP.
        !          1441:         //
        !          1442: 
        !          1443:         newIrp->AssociatedIrp.MasterIrp = Irp;
        !          1444: 
        !          1445:         //
        !          1446:         // Set the completion routine to ScsiTapeIoCompleteAssociated.
        !          1447:         //
        !          1448: 
        !          1449:         IoSetCompletionRoutine(newIrp,
        !          1450:                                ScsiTapeIoCompleteAssociated,
        !          1451:                                srb,
        !          1452:                                TRUE,
        !          1453:                                TRUE,
        !          1454:                                TRUE);
        !          1455: 
        !          1456:         //
        !          1457:         // Call port driver with new request.
        !          1458:         //
        !          1459: 
        !          1460:         status = IoCallDriver(deviceExtension->PortDeviceObject, newIrp);
        !          1461: 
        !          1462:         if (!NT_SUCCESS(status)) {
        !          1463: 
        !          1464:             DebugPrint((1,"SplitTapeRequest: IoCallDriver returned error\n"));
        !          1465: 
        !          1466:             //
        !          1467:             // Decrement count of outstanding partial requests.
        !          1468:             //
        !          1469: 
        !          1470:             remainingIrps = ExInterlockedDecrementLong(
        !          1471:                 (PLONG)&nextIrpStack->Parameters.Others.Argument1,
        !          1472:                 &deviceExtension->SplitRequestSpinLock);
        !          1473: 
        !          1474:             //
        !          1475:             // Check if any outstanding IRPs.
        !          1476:             //
        !          1477: 
        !          1478:             if (remainingIrps == ResultZero) {
        !          1479:                 completeOriginalIrp = TRUE;
        !          1480:             }
        !          1481: 
        !          1482:             //
        !          1483:             // Update original IRP with failing status.
        !          1484:             //
        !          1485: 
        !          1486:             Irp->IoStatus.Status = status;
        !          1487:             Irp->IoStatus.Information = 0;
        !          1488: 
        !          1489:             //
        !          1490:             // Deallocate this partial IRP.
        !          1491:             //
        !          1492: 
        !          1493:             IoFreeIrp(newIrp);
        !          1494:         }
        !          1495: 
        !          1496: KeepGoing:
        !          1497: 
        !          1498:         //
        !          1499:         // Set up for next request.
        !          1500:         //
        !          1501: 
        !          1502:         dataBuffer = (PCHAR)dataBuffer + MaximumBytes;
        !          1503: 
        !          1504:         transferByteCount -= MaximumBytes;
        !          1505: 
        !          1506:         if (transferByteCount > MaximumBytes) {
        !          1507: 
        !          1508:             dataLength = MaximumBytes;
        !          1509: 
        !          1510:         } else {
        !          1511: 
        !          1512:             dataLength = transferByteCount;
        !          1513:         }
        !          1514: 
        !          1515:         //
        !          1516:         // Adjust disk byte offset.
        !          1517:         //
        !          1518: 
        !          1519:         startingOffset = RtlLargeIntegerAdd(startingOffset, RtlConvertUlongToLargeInteger(MaximumBytes));
        !          1520:     }
        !          1521: 
        !          1522:     //
        !          1523:     // Check if original IRP should be completed.
        !          1524:     //
        !          1525: 
        !          1526:     if (completeOriginalIrp) {
        !          1527: 
        !          1528:         IoCompleteRequest(Irp, 0);
        !          1529:     }
        !          1530: 
        !          1531:     return;
        !          1532: 
        !          1533: } // end SplitTapeRequest()
        !          1534: 
        !          1535: 
        !          1536: VOID
        !          1537: ScsiTapeError(
        !          1538:     PDEVICE_OBJECT DeviceObject,
        !          1539:     PSCSI_REQUEST_BLOCK Srb,
        !          1540:     NTSTATUS *Status,
        !          1541:     BOOLEAN *Retry
        !          1542:     )
        !          1543: 
        !          1544: /*++
        !          1545: 
        !          1546: Routine Description:
        !          1547: 
        !          1548:     When a request completes with error, the routine ScsiClassInterpretSenseInfo is
        !          1549:     called to determine from the sense data whether the request should be
        !          1550:     retried and what NT status to set in the IRP. Then this routine is called
        !          1551:     for tape requests to handle tape-specific errors and update the nt status
        !          1552:     and retry boolean.
        !          1553: 
        !          1554: Arguments:
        !          1555: 
        !          1556:     DeviceObject - Supplies a pointer to the device object.
        !          1557: 
        !          1558:     Srb - Supplies a pointer to the failing Srb.
        !          1559: 
        !          1560:     Status - NT Status used to set the IRP's completion status.
        !          1561: 
        !          1562:     Retry - Indicates that this request should be retried.
        !          1563: 
        !          1564: Return Value:
        !          1565: 
        !          1566:     None.
        !          1567: 
        !          1568: --*/
        !          1569: 
        !          1570: {
        !          1571:     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
        !          1572:     PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer;
        !          1573:     PIRP irp = Srb->OriginalRequest;
        !          1574:     ULONG residualBlocks;
        !          1575:     LONG length;
        !          1576: 
        !          1577:     //
        !          1578:     // Never retry tape requests.
        !          1579:     //
        !          1580: 
        !          1581:     *Retry = FALSE;
        !          1582: 
        !          1583:     //
        !          1584:     // Check that request sense buffer is valid.
        !          1585:     //
        !          1586: 
        !          1587:     if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) {
        !          1588: 
        !          1589:         switch (senseBuffer->SenseKey & 0xf) {
        !          1590: 
        !          1591:             case SCSI_SENSE_UNIT_ATTENTION:
        !          1592: 
        !          1593:                 switch (senseBuffer->AdditionalSenseCode) {
        !          1594: 
        !          1595:                     case SCSI_ADSENSE_MEDIUM_CHANGED:
        !          1596:                         DebugPrint((1,
        !          1597:                                     "InterpretSenseInfo: Media changed\n"));
        !          1598: 
        !          1599:                         *Status = STATUS_MEDIA_CHANGED;
        !          1600: 
        !          1601:                         break;
        !          1602: 
        !          1603:                     default:
        !          1604:                         DebugPrint((1,
        !          1605:                                     "InterpretSenseInfo: Bus reset\n"));
        !          1606: 
        !          1607:                         *Status = STATUS_BUS_RESET;
        !          1608: 
        !          1609:                         break;
        !          1610: 
        !          1611:                 }
        !          1612: 
        !          1613:                 break;
        !          1614: 
        !          1615:             case SCSI_SENSE_RECOVERED_ERROR:
        !          1616: 
        !          1617:                 //
        !          1618:                 // Check other indicators
        !          1619:                 //
        !          1620: 
        !          1621:                 if (senseBuffer->FileMark) {
        !          1622: 
        !          1623:                     switch (senseBuffer->AdditionalSenseCodeQualifier) {
        !          1624: 
        !          1625:                         case SCSI_SENSEQ_SETMARK_DETECTED :
        !          1626: 
        !          1627:                             DebugPrint((1,
        !          1628:                                         "InterpretSenseInfo: Setmark detected\n"));
        !          1629: 
        !          1630:                             *Status = STATUS_SETMARK_DETECTED;
        !          1631:                             break ;
        !          1632: 
        !          1633:                         case SCSI_SENSEQ_FILEMARK_DETECTED :
        !          1634:                         default:
        !          1635: 
        !          1636:                             DebugPrint((1,
        !          1637:                                         "InterpretSenseInfo: Filemark detected\n"));
        !          1638: 
        !          1639:                             *Status = STATUS_FILEMARK_DETECTED;
        !          1640:                             break ;
        !          1641: 
        !          1642:                     }
        !          1643: 
        !          1644:                 } else if ( senseBuffer->EndOfMedia ) {
        !          1645: 
        !          1646:                     switch( senseBuffer->AdditionalSenseCodeQualifier ) {
        !          1647: 
        !          1648:                         case SCSI_SENSEQ_BEGINNING_OF_MEDIA_DETECTED :
        !          1649: 
        !          1650:                             DebugPrint((1,
        !          1651:                                         "InterpretSenseInfo: Beginning of media detected\n"));
        !          1652: 
        !          1653:                             *Status = STATUS_BEGINNING_OF_MEDIA;
        !          1654:                             break ;
        !          1655: 
        !          1656:                         case SCSI_SENSEQ_END_OF_MEDIA_DETECTED :
        !          1657:                         default:
        !          1658: 
        !          1659:                             DebugPrint((1,
        !          1660:                                         "InterpretSenseInfo: End of media detected\n"));
        !          1661: 
        !          1662:                             *Status = STATUS_END_OF_MEDIA;
        !          1663:                             break ;
        !          1664: 
        !          1665:                     }
        !          1666:                 }
        !          1667: 
        !          1668:                 break;
        !          1669: 
        !          1670:             case SCSI_SENSE_NO_SENSE:
        !          1671: 
        !          1672:                 //
        !          1673:                 // Check other indicators
        !          1674:                 //
        !          1675: 
        !          1676:                 if (senseBuffer->FileMark) {
        !          1677: 
        !          1678:                     switch( senseBuffer->AdditionalSenseCodeQualifier ) {
        !          1679: 
        !          1680:                         case SCSI_SENSEQ_SETMARK_DETECTED :
        !          1681: 
        !          1682:                             DebugPrint((1,
        !          1683:                                         "InterpretSenseInfo: Setmark detected\n"));
        !          1684: 
        !          1685:                             *Status = STATUS_SETMARK_DETECTED;
        !          1686:                             break ;
        !          1687: 
        !          1688:                         case SCSI_SENSEQ_FILEMARK_DETECTED :
        !          1689:                         default:
        !          1690: 
        !          1691:                             DebugPrint((1,
        !          1692:                                         "InterpretSenseInfo: Filemark detected\n"));
        !          1693: 
        !          1694:                             *Status = STATUS_FILEMARK_DETECTED;
        !          1695:                             break ;
        !          1696:                     }
        !          1697: 
        !          1698:                 } else if (senseBuffer->EndOfMedia) {
        !          1699: 
        !          1700:                     switch(senseBuffer->AdditionalSenseCodeQualifier) {
        !          1701: 
        !          1702:                         case SCSI_SENSEQ_BEGINNING_OF_MEDIA_DETECTED :
        !          1703: 
        !          1704:                             DebugPrint((1,
        !          1705:                                         "InterpretSenseInfo: Beginning of media detected\n"));
        !          1706: 
        !          1707:                             *Status = STATUS_BEGINNING_OF_MEDIA;
        !          1708:                             break ;
        !          1709: 
        !          1710:                         case SCSI_SENSEQ_END_OF_MEDIA_DETECTED :
        !          1711:                         default:
        !          1712: 
        !          1713:                             DebugPrint((1,
        !          1714:                                         "InterpretSenseInfo: End of media detected\n"));
        !          1715: 
        !          1716:                             *Status = STATUS_END_OF_MEDIA;
        !          1717:                             break;
        !          1718: 
        !          1719:                     }
        !          1720:                 }
        !          1721: 
        !          1722:                 break;
        !          1723: 
        !          1724:             case SCSI_SENSE_BLANK_CHECK:
        !          1725: 
        !          1726:                 DebugPrint((1,
        !          1727:                             "InterpretSenseInfo: Media blank check\n"));
        !          1728: 
        !          1729:                 *Status = STATUS_NO_DATA_DETECTED;
        !          1730: 
        !          1731: 
        !          1732:                 break;
        !          1733: 
        !          1734:             case SCSI_SENSE_VOL_OVERFLOW:
        !          1735: 
        !          1736:                 DebugPrint((1,
        !          1737:                     "InterpretSenseInfo: End of Media Overflow\n"));
        !          1738: 
        !          1739:                 *Status = STATUS_EOM_OVERFLOW;
        !          1740: 
        !          1741: 
        !          1742:                 break;
        !          1743: 
        !          1744:             case SCSI_SENSE_NOT_READY:
        !          1745: 
        !          1746:                 switch (senseBuffer->AdditionalSenseCode) {
        !          1747: 
        !          1748:                     case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE:
        !          1749: 
        !          1750:                         DebugPrint((1,
        !          1751:                                     "InterpretSenseInfo:"
        !          1752:                                     " No Media in device.\n"));
        !          1753:                         *Status = STATUS_NO_MEDIA;
        !          1754:                         break;
        !          1755:                 }
        !          1756: 
        !          1757:                 break;
        !          1758: 
        !          1759:         } // end switch
        !          1760: 
        !          1761:         //
        !          1762:         // Check if a filemark or setmark was encountered,
        !          1763:         // or an end-of-media or no-data condition exists.
        !          1764:         //
        !          1765: 
        !          1766:         if (NT_WARNING(*Status) &&
        !          1767:             (Srb->Cdb[0] == SCSIOP_WRITE6 || Srb->Cdb[0] == SCSIOP_READ6)) {
        !          1768: 
        !          1769:             //
        !          1770:             // Not all bytes were transfered. Update information field with
        !          1771:             // number of bytes transfered from sense buffer.
        !          1772:             //
        !          1773: 
        !          1774:             if (senseBuffer->Valid) {
        !          1775:                 REVERSE_BYTES((PFOUR_BYTE)&residualBlocks,
        !          1776:                               (PFOUR_BYTE)senseBuffer->Information);
        !          1777:             } else {
        !          1778:                 residualBlocks = 0;
        !          1779:             }
        !          1780: 
        !          1781:             length = ((PCDB) Srb->Cdb)->CDB6READWRITETAPE.TransferLenLSB;
        !          1782:             length |= ((PCDB) Srb->Cdb)->CDB6READWRITETAPE.TransferLen << 8;
        !          1783:             length |= ((PCDB) Srb->Cdb)->CDB6READWRITETAPE.TransferLenMSB << 16;
        !          1784: 
        !          1785:             length -= residualBlocks;
        !          1786: 
        !          1787:             if (length < 0) {
        !          1788: 
        !          1789:                 length = 0;
        !          1790:                 *Status = STATUS_IO_DEVICE_ERROR;
        !          1791:             }
        !          1792: 
        !          1793: 
        !          1794:             length *= deviceExtension->DiskGeometry->BytesPerSector;
        !          1795: 
        !          1796:             //
        !          1797:             // If the miniport indicates fewer bytes were transfered then
        !          1798:             // use that value.
        !          1799:             //
        !          1800: 
        !          1801:             if ((ULONG) length > Srb->DataTransferLength) {
        !          1802:                 length = (LONG) Srb->DataTransferLength;
        !          1803:                 DebugPrint((1,"ScsiTapeError: Calculated length wronge using miniport length. \n"));
        !          1804: 
        !          1805:             }
        !          1806: 
        !          1807:             irp->IoStatus.Information = length;
        !          1808: 
        !          1809:             DebugPrint((1,"ScsiTapeError:  Transfer Count: %lx\n", Srb->DataTransferLength));
        !          1810:             DebugPrint((1," Residual Bytes: %lx\n", residualBlocks * deviceExtension->DiskGeometry->BytesPerSector));
        !          1811:             DebugPrint((1," Irp IoStatus Information = %lx\n", irp->IoStatus.Information));
        !          1812:         }
        !          1813: 
        !          1814:     }
        !          1815: 
        !          1816:     //
        !          1817:     // Call tape device specific error handler.
        !          1818:     //
        !          1819: 
        !          1820:     TapeError(DeviceObject->DeviceExtension,
        !          1821:               Srb,
        !          1822:               Status,
        !          1823:               Retry);
        !          1824: 
        !          1825:     return;
        !          1826: 
        !          1827: } // end ScsiTapeError()
        !          1828: 
        !          1829: NTSTATUS
        !          1830: ScsiTapeIoCompleteAssociated(
        !          1831:     IN PDEVICE_OBJECT DeviceObject,
        !          1832:     IN PIRP Irp,
        !          1833:     IN PVOID Context
        !          1834:     )
        !          1835: 
        !          1836: /*++
        !          1837: 
        !          1838: Routine Description:
        !          1839: 
        !          1840:     This routine executes when the port driver has completed a request.
        !          1841:     It looks at the SRB status in the completing SRB and if not success
        !          1842:     it checks for valid request sense buffer information. If valid, the
        !          1843:     info is used to update status with more precise message of type of
        !          1844:     error. This routine deallocates the SRB.  This routine is used for
        !          1845:     requests which were build by split request.  After it has processed
        !          1846:     the request it decrements the Irp count in the master Irp.  If the
        !          1847:     count goes to zero then the master Irp is completed.
        !          1848: 
        !          1849: Arguments:
        !          1850: 
        !          1851:     DeviceObject - Supplies the device object which represents the logical
        !          1852:         unit.
        !          1853: 
        !          1854:     Irp - Supplies the Irp which has completed.
        !          1855: 
        !          1856:     Context - Supplies a pointer to the SRB.
        !          1857: 
        !          1858: Return Value:
        !          1859: 
        !          1860:     NT status
        !          1861: 
        !          1862: --*/
        !          1863: 
        !          1864: {
        !          1865:     PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
        !          1866:     PSCSI_REQUEST_BLOCK srb = Context;
        !          1867:     PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
        !          1868:     INTERLOCKED_RESULT irpCount;
        !          1869:     PIRP originalIrp = Irp->AssociatedIrp.MasterIrp;
        !          1870:     NTSTATUS status;
        !          1871: 
        !          1872:     //
        !          1873:     // Check SRB status for success of completing request.
        !          1874:     //
        !          1875: 
        !          1876:     if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
        !          1877: 
        !          1878:         DebugPrint((2,"ScsiTapeIoCompleteAssociated: IRP %lx, SRB %lx", Irp, srb));
        !          1879: 
        !          1880:         //
        !          1881:         // Release the queue if it is frozen.
        !          1882:         //
        !          1883: 
        !          1884:         if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
        !          1885:             ScsiClassReleaseQueue(DeviceObject);
        !          1886:         }
        !          1887: 
        !          1888:         ScsiClassInterpretSenseInfo(
        !          1889:             DeviceObject,
        !          1890:             srb,
        !          1891:             irpStack->MajorFunction,
        !          1892:             irpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL ? irpStack->Parameters.DeviceIoControl.IoControlCode : 0,
        !          1893:             MAXIMUM_RETRIES - ((ULONG)irpStack->Parameters.Others.Argument4),
        !          1894:             &status);
        !          1895: 
        !          1896:         //
        !          1897:         // Return the highest error that occurs.  This way warning take precedence
        !          1898:         // over success and errors take precedence over errors.
        !          1899:         //
        !          1900: 
        !          1901:         if ((ULONG) status > (ULONG) originalIrp->IoStatus.Status) {
        !          1902: 
        !          1903:             //
        !          1904:             // Ignore any requests which were flushed.
        !          1905:             //
        !          1906: 
        !          1907:             if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_REQUEST_FLUSHED) {
        !          1908: 
        !          1909:                 originalIrp->IoStatus.Status = status;
        !          1910: 
        !          1911:             }
        !          1912: 
        !          1913:         }
        !          1914: 
        !          1915: 
        !          1916:     } // end if (SRB_STATUS(srb->SrbStatus) ...
        !          1917: 
        !          1918:     //
        !          1919:     // Return SRB to nonpaged pool.
        !          1920:     //
        !          1921: 
        !          1922:     if (srb->SrbFlags & SRB_FLAGS_ALLOCATED_FROM_ZONE) {
        !          1923: 
        !          1924:         ExInterlockedFreeToZone( deviceExtension->SrbZone,
        !          1925:                                  srb,
        !          1926:                                  deviceExtension->SrbZoneSpinLock);
        !          1927: 
        !          1928:     } else {
        !          1929: 
        !          1930:         ExFreePool(srb);
        !          1931: 
        !          1932:     }
        !          1933: 
        !          1934:     DebugPrint((2, "ScsiTapeIoCompleteAssociated: Partial xfer IRP %lx\n", Irp));
        !          1935: 
        !          1936:     //
        !          1937:     // Get next stack location. This original request is unused
        !          1938:     // except to keep track of the completing partial IRPs so the
        !          1939:     // stack location is valid.
        !          1940:     //
        !          1941: 
        !          1942:     irpStack = IoGetNextIrpStackLocation(originalIrp);
        !          1943: 
        !          1944:     //
        !          1945:     // Increment the status information with number of bytes transfered.
        !          1946:     //
        !          1947: 
        !          1948:     ExInterlockedAddUlong(&originalIrp->IoStatus.Information,
        !          1949:                           Irp->IoStatus.Information,
        !          1950:                           &deviceExtension->SplitRequestSpinLock );
        !          1951: 
        !          1952:     //
        !          1953:     //
        !          1954:     // If any of the asynchronous partial transfer IRPs fail with an error
        !          1955:     // with an error then the original IRP will return 0 bytes transfered.
        !          1956:     // This is an optimization for successful transfers.
        !          1957:     //
        !          1958: 
        !          1959:     if (NT_ERROR(originalIrp->IoStatus.Status)) {
        !          1960: 
        !          1961:         originalIrp->IoStatus.Information = 0;
        !          1962: 
        !          1963:         //
        !          1964:         // Set the hard error if necessary.
        !          1965:         //
        !          1966: 
        !          1967:         if (IoIsErrorUserInduced(originalIrp->IoStatus.Status)) {
        !          1968: 
        !          1969:             //
        !          1970:             // Store DeviceObject for filesystem.
        !          1971:             //
        !          1972: 
        !          1973:             IoSetHardErrorOrVerifyDevice(originalIrp, DeviceObject);
        !          1974: 
        !          1975:         }
        !          1976: 
        !          1977:     }
        !          1978: 
        !          1979:     //
        !          1980:     // Decrement and get the count of remaining IRPs.
        !          1981:     //
        !          1982: 
        !          1983:     irpCount = ExInterlockedDecrementLong(
        !          1984:             (PLONG)&irpStack->Parameters.Others.Argument1,
        !          1985:             &deviceExtension->SplitRequestSpinLock);
        !          1986: 
        !          1987:     DebugPrint((2, "ScsiTapeIoCompleteAssociated: Partial IRPs left %d\n",
        !          1988:                 irpCount));
        !          1989: 
        !          1990:     if (irpCount == ResultZero) {
        !          1991: 
        !          1992: 
        !          1993: #if DBG
        !          1994:         irpStack = IoGetCurrentIrpStackLocation(originalIrp);
        !          1995: 
        !          1996:         if (originalIrp->IoStatus.Information != irpStack->Parameters.Read.Length) {
        !          1997:             DebugPrint((1, "ScsiTapeIoCompleteAssociated: Short transfer.  Request length: %lx, Return length: %lx, Status: %lx\n",
        !          1998:                 irpStack->Parameters.Read.Length, originalIrp->IoStatus.Information, originalIrp->IoStatus.Status));
        !          1999:         }
        !          2000: #endif
        !          2001:         //
        !          2002:         // All partial IRPs have completed.
        !          2003:         //
        !          2004: 
        !          2005:         DebugPrint((2,
        !          2006:                  "ScsiTapeIoCompleteAssociated: All partial IRPs complete %lx\n",
        !          2007:                  originalIrp));
        !          2008: 
        !          2009:         IoCompleteRequest(originalIrp, IO_DISK_INCREMENT);
        !          2010:     }
        !          2011: 
        !          2012:     //
        !          2013:     // Deallocate IRP and indicate the I/O system should not attempt any more
        !          2014:     // processing.
        !          2015:     //
        !          2016: 
        !          2017:     IoFreeIrp(Irp);
        !          2018: 
        !          2019:     return STATUS_MORE_PROCESSING_REQUIRED;
        !          2020: 
        !          2021: } // end ScsiTapeIoCompleteAssociated()
        !          2022: 
        !          2023: 

unix.superglobalmegacorp.com

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