|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.